-
-
Notifications
You must be signed in to change notification settings - Fork 34.3k
gh-146492: Improve SyntaxError for missing comma between import clauses #146493
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
base: main
Are you sure you want to change the base?
Changes from all commits
3b4d41c
a52ae91
66e3bec
e0b46ea
ca28947
1fae8ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2206,6 +2206,25 @@ | |
| Traceback (most recent call last): | ||
| SyntaxError: cannot assign to None | ||
|
|
||
| # Check that we don't raise a "cannot use name as import target" error | ||
| # when there's a syntax error after the import target. | ||
|
|
||
| >>> import a as b(-) | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| >>> import a as b None | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| >>> import a as b as c | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| >>> from x import a as b None | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| # Check that we dont raise the "trailing comma" error if there is more | ||
| # input to the left of the valid part that we parsed. | ||
|
|
||
|
|
@@ -2225,6 +2244,58 @@ | |
| Traceback (most recent call last): | ||
| SyntaxError: Expected one or more names after 'import' | ||
|
|
||
| # Missing comma between import clauses | ||
|
|
||
| >>> import a b | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we only pinning the message text for a few simple one-line cases here? For example, these both reproduce the new behavior: compile("import a, b c", "<repro>", "exec")
compile("from x import (a\n b)", "<repro>", "exec")with: But from what I can see, the new tests here don't assert the caret/range at all, and they also don't cover either a later-clause case or the parenthesized multiline form. Would it make sense to add at least one range-aware assertion and one nontrivial shape, so the main user-visible part of the change is actually locked down?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added some more tests to exercise some other forms and to assert the expected error range. Let me know if there are any other forms you think would be worth covering |
||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> import a, b c | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> import a.a as a b.b | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> import a.a as a b.b as b | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> from x import a b | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> from x import a as a b | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> from x import (a | ||
| ... b) | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> from x import (a as a | ||
| ... b) | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| >>> from x import (a, | ||
| ... b as b | ||
| ... c) | ||
| Traceback (most recent call last): | ||
| SyntaxError: expected comma between import clauses | ||
|
|
||
| # Check that we don't raise the "missing comma" error for invalid import targets. | ||
|
|
||
| >>> import a b() | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| >>> from x import a b[c] | ||
| Traceback (most recent call last): | ||
| SyntaxError: invalid syntax | ||
|
|
||
| >>> (): int | ||
| Traceback (most recent call last): | ||
| SyntaxError: only single target (not tuple) can be annotated | ||
|
|
@@ -3505,6 +3576,40 @@ def test_ifexp_body_stmt_else_stmt(self): | |
| ]: | ||
| self._check_error(f"x = {lhs_stmt} if 1 else {rhs_stmt}", msg) | ||
|
|
||
| def test_import_missing_comma(self): | ||
| self._check_error("import a.a b.b", | ||
| "expected comma between import clauses", | ||
| offset=8, end_offset=8 + len("a.a b.b")) | ||
| self._check_error( | ||
| """if 1: | ||
| from x import ( | ||
| a, | ||
| b | ||
| c, | ||
| ) | ||
| """, | ||
| errtext="expected comma between import clauses", | ||
| lineno=4, | ||
| end_lineno=5, | ||
| offset=17, | ||
| end_offset=18, | ||
| ) | ||
| self._check_error( | ||
| """if 1: | ||
| from x import ( | ||
| a, | ||
| b as b | ||
| c as c, | ||
| ) | ||
| """, | ||
| errtext="expected comma between import clauses", | ||
| lineno=4, | ||
| end_lineno=5, | ||
| offset=22, | ||
| end_offset=18, | ||
| ) | ||
|
|
||
|
|
||
|
|
||
| class LazyImportRestrictionTestCase(SyntaxErrorTestCase): | ||
| """Test syntax restrictions for lazy imports.""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Improve :exc:`SyntaxError` message for missing comma between import clauses | ||
| in :keyword:`import statements <import>`. Patch by Brian Schubert. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm missing something, is this rule a bit too broad now?
This prints:
In all three cases, adding a comma still wouldn't make the code valid, so this doesn't seem like a real
missing comma between import clausessituation. Should this only trigger when the would-be second clause is actually a valid import target?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I see what you mean. I might argue that the missing comma is the "first" error in each of those cases, and that the rest is more-or-less an unrelated additional syntax error. Adding a comma would at least make those cases more correct and move the syntax error location start of the "real" problem. But I'm happy to exclude those if you prefer.
I pushed a commit that prevents this from triggering for those cases. It still triggers for this case:
but I'm not sure there's a good way to exclude this too without making it much more complicated.