-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: support block-level wrong-import-position pragma suppression #10590
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 6 commits
8cace41
a7e937a
f957d35
1015d06
4c56438
7fb7b18
13f6f12
81bcdac
771ac7c
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 |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Allow ``wrong-import-position`` pragma on non-import lines to suppress following imports until the next non-import statement. | ||
|
|
||
| Closes #10589 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,11 @@ | ||
| """Checks that disabling 'wrong-import-position' on a statement prevents it from | ||
| invalidating subsequent imports.""" | ||
| """Test wrong-import-position pragma on non-import statement.""" | ||
| # pylint: disable=unused-import | ||
|
|
||
| CONSTANT = True # pylint: disable=wrong-import-position | ||
|
|
||
| import os | ||
| import sys | ||
|
|
||
| CONSTANT_A = False # pylint: disable=wrong-import-position | ||
| import time | ||
|
|
||
| CONSTANT_B = True | ||
| import logging # [wrong-import-position] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| wrong-import-position:11:0:11:14::"Import ""import logging"" should be placed at the top of the module":UNDEFINED |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||||||||||
| """Test wrong-import-position pragma scoping.""" | ||||||||||||||||||
| # pylint: disable=unused-import | ||||||||||||||||||
|
|
||||||||||||||||||
| import os | ||||||||||||||||||
| import sys | ||||||||||||||||||
|
|
||||||||||||||||||
| # Pragma on non-import suppresses following imports until next non-import | ||||||||||||||||||
| CONSTANT_A = False # pylint: disable=wrong-import-position | ||||||||||||||||||
| import time | ||||||||||||||||||
|
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. Can we add a test case where this
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. @jacobtylerwalls You are correct - there is inconsistent behavior and the question is what is the expected behaviour? For the following example: import os
import sys
CONSTANT = True # pylint: disable=wrong-import-position
try: # or if/for/while/with/def/class
import json
...
import time # <-- Is this flagged?The currently PR code produce the following behaviour:
Could you please help here define the expected behavior here?
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. I think we need to just define what a consecutive import is and then stick to the letter of the rule. (We disable until the consecutive imports stop.) For me, these two are consecutive imports: try:
import black
except ImportError:
import ruff
import timeThese two are not: try:
import black
except ImportError:
HAS_BLACK = False
else:
HAS_BLACK = True
import timeSame with if PY314:
import annotationlib
import time # consecutive
if PY314:
import annotationlib
def get_annotations():
pass # a non-import statement
import time # no longer consecutiveDoes that seem sane? 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. @jacobtylerwalls provides 4 examples of what he expects from the wrong-import-position rule itself. Your Expected 1 agrees with pylint 4.0.3. Your Expected 2 disagrees. It seems like 4.0.3 treats the whole try-block as an import (a βwrong-import-position importβ?, a WIPI?), because the try-clause smells like an import. The contents of the except-clause and else-clause are ignored. See Also note that the try clause could contain non-imports before and after the βimport blackβ, but those would not matter to the wrong-import-position algorithm. The try-block would STILL be assessed as an import for the purpose of this rule. Your Expected 3 -- disagrees with 4.0.3. ANY if-block is a non-import (non-WIPI) see Your Expected 4 -- agrees, but still, function def in the content of the if-block doesn't matter. If I was king, I think I wouldn't even try to parse the contents of try/if/while/for/with. I'd treat them (their block, that is) as non-import regardless of content -- that is, just like the if-statement seems to be treated now. 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. Or, another POV -- I could see an argument for flattening try-blocks and ignoring its exception paths. with because you're representing the success path. And you'd want to recurse to handle the try inside try. And I'm still not seeing a good rationale for flattening
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. @jacobtylerwalls Thanks for the detailed explanation! Before I implement, I want to confirm: @ruck94301 suggested a simpler approach - treat all control-flow blocks as non-imports regardless of content. Would you prefer that simpler approach, or should I implement your 'consecutive imports' logic that inspects block contents?
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. I found @ruck94301's reminder to keep it not clever compelling. Let's do this:
Most important for me is just treating |
||||||||||||||||||
|
|
||||||||||||||||||
| CONSTANT_B = True | ||||||||||||||||||
| import logging # [wrong-import-position] | ||||||||||||||||||
|
|
||||||||||||||||||
| # Inline pragma on import line | ||||||||||||||||||
| CONSTANT_C = 42 | ||||||||||||||||||
| import json # pylint: disable=wrong-import-position | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| wrong-import-position:12:0:12:14::"Import ""import logging"" should be placed at the top of the module":UNDEFINED |
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.
Now we can update this to reflect the larger change we are making.