Skip to content

Commit b51aa0b

Browse files
committed
gh-123539: Improve SyntaxError msg for import as with not a name
1 parent 9e079c2 commit b51aa0b

File tree

4 files changed

+857
-513
lines changed

4 files changed

+857
-513
lines changed

Grammar/python.gram

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,17 @@ import_from_targets[asdl_alias_seq*]:
218218
import_from_as_names[asdl_alias_seq*]:
219219
| a[asdl_alias_seq*]=','.import_from_as_name+ { a }
220220
import_from_as_name[alias_ty]:
221-
| a=NAME b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
222-
(b) ? ((expr_ty) b)->v.Name.id : NULL,
223-
EXTRA) }
221+
| a=NAME 'as' b=NAME &(',' | ')' | NEWLINE) {
222+
_PyAST_alias(a->v.Name.id, b->v.Name.id, EXTRA) }
223+
| invalid_import_from_as_name
224+
| a=NAME { _PyAST_alias(a->v.Name.id, NULL, EXTRA) }
224225
dotted_as_names[asdl_alias_seq*]:
225226
| a[asdl_alias_seq*]=','.dotted_as_name+ { a }
226227
dotted_as_name[alias_ty]:
227-
| a=dotted_name b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
228-
(b) ? ((expr_ty) b)->v.Name.id : NULL,
229-
EXTRA) }
228+
| a=dotted_name 'as' b=NAME &(',' | NEWLINE) {
229+
_PyAST_alias(a->v.Name.id, b->v.Name.id, EXTRA) }
230+
| invalid_dotted_as_name
231+
| a=dotted_name { _PyAST_alias(a->v.Name.id, NULL, EXTRA) }
230232
dotted_name[expr_ty]:
231233
| a=dotted_name '.' b=NAME { _PyPegen_join_names_with_dot(p, a, b) }
232234
| NAME
@@ -1321,6 +1323,14 @@ invalid_import_from_targets:
13211323
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
13221324
| token=NEWLINE {
13231325
RAISE_SYNTAX_ERROR_STARTING_FROM(token, "Expected one or more names after 'import'") }
1326+
invalid_dotted_as_name:
1327+
| dotted_name 'as' a=expression {
1328+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
1329+
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
1330+
invalid_import_from_as_name:
1331+
| NAME 'as' a=expression {
1332+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
1333+
"cannot use %s as import target", _PyPegen_get_expr_name(a)) }
13241334

13251335
invalid_with_stmt:
13261336
| ['async'] 'with' ','.(expression ['as' star_target])+ NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }

Lib/test/test_syntax.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,56 @@
18321832
Traceback (most recent call last):
18331833
SyntaxError: Expected one or more names after 'import'
18341834
1835+
>>> import a as b.c
1836+
Traceback (most recent call last):
1837+
SyntaxError: cannot use attribute as import target
1838+
1839+
>>> import a.b as (a, b)
1840+
Traceback (most recent call last):
1841+
SyntaxError: cannot use tuple as import target
1842+
1843+
>>> import a, a.b as 1
1844+
Traceback (most recent call last):
1845+
SyntaxError: cannot use literal as import target
1846+
1847+
>>> import a.b as 'a', a
1848+
Traceback (most recent call last):
1849+
SyntaxError: cannot use literal as import target
1850+
1851+
>>> from a import (b as c.d)
1852+
Traceback (most recent call last):
1853+
SyntaxError: cannot use attribute as import target
1854+
1855+
>>> from a import b as 1
1856+
Traceback (most recent call last):
1857+
SyntaxError: cannot use literal as import target
1858+
1859+
>>> from a import (
1860+
... b as f())
1861+
Traceback (most recent call last):
1862+
SyntaxError: cannot use function call as import target
1863+
1864+
>>> from a import (
1865+
... b as [],
1866+
... )
1867+
Traceback (most recent call last):
1868+
SyntaxError: cannot use list as import target
1869+
1870+
>>> from a import (
1871+
... b,
1872+
... c as ()
1873+
... )
1874+
Traceback (most recent call last):
1875+
SyntaxError: cannot use tuple as import target
1876+
1877+
>>> from a import b, с as d[e]
1878+
Traceback (most recent call last):
1879+
SyntaxError: cannot use subscript as import target
1880+
1881+
>>> from a import с as d[e], b
1882+
Traceback (most recent call last):
1883+
SyntaxError: cannot use subscript as import target
1884+
18351885
>>> (): int
18361886
Traceback (most recent call last):
18371887
SyntaxError: only single target (not tuple) can be annotated
@@ -2857,6 +2907,26 @@ def test_match_stmt_invalid_as_expr(self):
28572907
end_offset=15 + len("obj.attr"),
28582908
)
28592909

2910+
def test_invalid_import_stmt_as_expr(self):
2911+
self._check_error(
2912+
"import a as obj.attr",
2913+
errtext="cannot use attribute as import target",
2914+
lineno=1,
2915+
end_lineno=1,
2916+
offset=13,
2917+
end_offset=13 + len("obj.attr"),
2918+
)
2919+
2920+
def test_invalid_import_from_stmt_as_expr(self):
2921+
self._check_error(
2922+
"from a import b as obj.attr",
2923+
errtext="cannot use attribute as import target",
2924+
lineno=1,
2925+
end_lineno=1,
2926+
offset=20,
2927+
end_offset=20 + len("obj.attr"),
2928+
)
2929+
28602930

28612931
def load_tests(loader, tests, pattern):
28622932
tests.addTest(doctest.DocTestSuite())
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve :exc:`SyntaxError` message for using ``import as`` with not a name.

0 commit comments

Comments
 (0)