8000 gh-125331: Allow the parser to activate future imports on the fly by pablogsal · Pull Request #125482 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-125331: Allow the parser to activate future imports on the fly #125482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 14, 2025
Merged
Prev Previous commit
Next Next commit
Apply suggestions from code review
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
  • Loading branch information
3 people committed Feb 13, 2025
commit 4ef188ce8274eaa9e28cb9cec3a50fbf6d1145ec
4 changes: 1 addition & 3 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,7 @@ import_name[stmt_ty]: 'import' a=dotted_as_names { _PyAST_Import(a, EXTRA) }
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
import_from[stmt_ty]:
| 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
_PyPegen_check_future_import(p,
_PyAST_ImportFrom(b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA)
) }
_PyPegen_checked_future_import(p, b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA) }
| 'from' a=('.' | '...')+ 'import' b=import_from_targets {
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), EXTRA) }
import_from_targets[asdl_alias_seq*]:
Expand Down
15 changes: 15 additions & 0 deletions Lib/test/test_flufl.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ def test_guido_as_bdfl(self):
# parser reports the start of the token
self.assertEqual(cm.exception.offset, 3)

def test_barry_as_bdfl_look_ma_with_no_compiler_flags(self):
# Check that the future import is handled by the parser
# even if the compiler flags are not passed.
code = "from __future__ import barry_as_FLUFL;2 {0} 3"
compile(code.format('<>'), '<BDFL test>', 'exec')
with self.assertRaises(SyntaxError) as cm:
compile(code.format('!='), '<FLUFL test>', 'exec')
self.assertRegex(str(cm.exception), "with Barry as BDFL, use '<>' instead of '!='")
self.assertIn('2 != 3', cm.exception.text)
self.assertEqual(cm.exception.filename, '<FLUFL test>')
self.assertEqual(cm.exception.lineno, 1)
self.assertEqual(cm.exception.offset, len(code) - 4)




if __name__ == '__main__':
unittest.main()
1 change: 0 additions & 1 deletion Lib/test/test_grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,5 @@ async def foo():
with self.assertRaises(Done):
foo().send(None)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Using ``from __future__ import barry_as_FLUFL`` works now when using
multiple statements on the same line. Additionally the effect is respected
even if the import is used even if the flags are not passed to
:func:`compile`. Patch by Pablo Galindo
28 changes: 11 additions & 17 deletions Parser/action_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1696,22 +1696,16 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings,
}

stmt_ty
_PyPegen_check_future_import(Parser *p, stmt_ty importfrom) {
if (importfrom->kind != ImportFrom_kind) {
goto exit;
}
asdl_alias_seq *names = importfrom->v.ImportFrom.names;
if (asdl_seq_LEN(names) != 1) {
goto exit;
}
identifier mod = importfrom->v.ImportFrom.module;
if (PyUnicode_CompareWithASCIIString(mod, "__future__") != 0) {
goto exit;
}
alias_ty alias = asdl_seq_GET(names, 0);
if (PyUnicode_CompareWithASCIIString(alias->name, "barry_as_FLUFL") == 0) {
p->flags |= PyPARSE_BARRY_AS_BDFL;
_PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * names, int level,
int lineno, int col_offset, int end_lineno, int end_col_offset,
PyArena *arena) {
if (PyUnicode_CompareWithASCIIString(module, "__future__") == 0) {
for (Py_ssize_t i = 0; i < asdl_seq_LEN(names); i++) {
alias_ty alias = asdl_seq_GET(names, i);
8000 if (PyUnicode_CompareWithASCIIString(alias->name, "barry_as_FLUFL") == 0) {
p->flags |= PyPARSE_BARRY_AS_BDFL;
}
}
}
exit:
return importfrom;
return _PyAST_ImportFrom(module, names, level, lineno, col_offset, end_lineno, end_col_offset, arena);
}
2 changes: 1 addition & 1 deletion Parser/parser.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Parser/pegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *);
void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension);
void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions);
stmt_ty _PyPegen_checke 66A0 d_future_import(Parser *p, identifier module, asdl_alias_seq *,
int , int, int , int , int , PyArena *);

// Parser API

Expand All @@ -361,8 +363,6 @@ asdl_stmt_seq *_PyPegen_interactive_exit(Parser *);
// TODO: move to the correct place in this file
expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b);

stmt_ty _PyPegen_check_future_import(Parser *p, stmt_ty importfrom);

// Generated function in parse.c - function definition in python.gram
void *_PyPegen_parse(Parser *);

Expand Down
0