Skip to content

Commit 7b12a41

Browse files
authored
gh-152631: Fix ast.parse on lazy imports with older feature_version (#152632)
1 parent bb7e16a commit 7b12a41

4 files changed

Lines changed: 181 additions & 31 deletions

File tree

‎Grammar/python.gram‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,25 @@ import_stmt[stmt_ty](memo):
218218
# -----------------
219219

220220
import_name[stmt_ty]:
221-
| lazy="lazy"? 'import' a=dotted_as_names { _PyAST_Import(a, lazy ? 1 : 0, EXTRA) }
221+
| "lazy" 'import' a=dotted_as_names {
222+
CHECK_VERSION(stmt_ty, 15, "Lazy imports are",
223+
_PyAST_Import(a, 1, EXTRA)) }
224+
| 'import' a=dotted_as_names { _PyAST_Import(a, 0, EXTRA) }
222225

223226
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
224227
import_from[stmt_ty]:
225228
| invalid_import_from
226-
| lazy="lazy"? 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
227-
_PyPegen_checked_from_import(p, a, b, c, lazy, EXTRA) }
228-
| lazy="lazy"? 'from' a=('.' | '...')+ 'import' b=import_from_targets {
229-
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), lazy ? 1 : 0, EXTRA) }
229+
| lazy="lazy" 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
230+
CHECK_VERSION(stmt_ty, 15, "Lazy imports are",
231+
_PyPegen_checked_from_import(p, a, b, c, lazy, EXTRA)) }
232+
| "lazy" 'from' a=('.' | '...')+ 'import' b=import_from_targets {
233+
CHECK_VERSION(stmt_ty, 15, "Lazy imports are",
234+
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), 1, EXTRA)) }
235+
| 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
236+
_PyPegen_checked_from_import(p, a, b, c, NULL, EXTRA) }
237+
| 'from' a=('.' | '...')+ 'import' b=import_from_targets {
238+
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), 0, EXTRA) }
239+
230240
import_from_targets[asdl_alias_seq*]:
231241
| '(' a=import_from_as_names [','] ')' { a }
232242
| import_from_as_names !','

‎Lib/test/test_ast/test_ast.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,19 @@ def test_type_params_default_feature_version(self):
10311031
with self.assertRaises(SyntaxError):
10321032
ast.parse(sample, feature_version=(3, 12))
10331033

1034+
def test_lazy_imports_feature_version(self):
1035+
samples = [
1036+
"lazy import os",
1037+
"lazy from .. import name",
1038+
"lazy from mod import some",
1039+
]
1040+
for sample in samples:
1041+
with self.subTest(sample):
1042+
ast.parse(sample)
1043+
ast.parse(sample, feature_version=(3, 15))
1044+
with self.assertRaises(SyntaxError):
1045+
ast.parse(sample, feature_version=(3, 14))
1046+
10341047
def test_invalid_major_feature_version(self):
10351048
with self.assertRaises(ValueError):
10361049
ast.parse('pass', feature_version=(2, 7))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :func:`ast.parse` ability to parse lazy imports with *feature_version*
2+
older than 3.15, now it properly raises :exc:`SyntaxError`.

‎Parser/parser.c‎

Lines changed: 151 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)