-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[pyupgrade] Gated behind a preview of separate diagnostics (UP010)
#20020
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
Closed
Closed
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e04c737
feat(UP010): separate diagnostics for each unused __future__ import
355e753
feat(up010): update snapshots
2f8a912
feat(UP010): use secondary annotation to underlying certain unused im…
affcf04
Merge branch 'astral-sh:main' into feat/ruff-19561-preview
IDrokin117 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
208 changes: 208 additions & 0 deletions
208
.../rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP010_0.py__preview.snap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| --- | ||
| source: crates/ruff_linter/src/rules/pyupgrade/mod.rs | ||
| --- | ||
| UP010 [*] Unnecessary `__future__` imports `generators`, `nested_scopes` for target Python version | ||
| --> UP010_0.py:1:1 | ||
| | | ||
| 1 | from __future__ import nested_scopes, generators | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^-------------^^---------- | ||
| | | | | ||
| | | Unused import `generators` | ||
| | Unused import `nested_scopes` | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| 3 | from __future__ import absolute_import, division | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| - from __future__ import nested_scopes, generators | ||
| 1 | from __future__ import with_statement, unicode_literals | ||
| 2 | from __future__ import absolute_import, division | ||
| 3 | from __future__ import generator_stop | ||
|
|
||
| UP010 [*] Unnecessary `__future__` imports `unicode_literals`, `with_statement` for target Python version | ||
| --> UP010_0.py:2:1 | ||
| | | ||
| 1 | from __future__ import nested_scopes, generators | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^--------------^^---------------- | ||
| | | | | ||
| | | Unused import `unicode_literals` | ||
| | Unused import `with_statement` | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | from __future__ import generator_stop | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 1 | from __future__ import nested_scopes, generators | ||
| - from __future__ import with_statement, unicode_literals | ||
| 2 | from __future__ import absolute_import, division | ||
| 3 | from __future__ import generator_stop | ||
| 4 | from __future__ import print_function, generator_stop | ||
|
|
||
| UP010 [*] Unnecessary `__future__` imports `absolute_import`, `division` for target Python version | ||
| --> UP010_0.py:3:1 | ||
| | | ||
| 1 | from __future__ import nested_scopes, generators | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| 3 | from __future__ import absolute_import, division | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^-------- | ||
| | | | | ||
| | | Unused import `division` | ||
| | Unused import `absolute_import` | ||
| 4 | from __future__ import generator_stop | ||
| 5 | from __future__ import print_function, generator_stop | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 1 | from __future__ import nested_scopes, generators | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| - from __future__ import absolute_import, division | ||
| 3 | from __future__ import generator_stop | ||
| 4 | from __future__ import print_function, generator_stop | ||
| 5 | from __future__ import invalid_module, generators | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generator_stop` for target Python version | ||
| --> UP010_0.py:4:1 | ||
| | | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | from __future__ import generator_stop | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 5 | from __future__ import print_function, generator_stop | ||
| 6 | from __future__ import invalid_module, generators | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 1 | from __future__ import nested_scopes, generators | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| 3 | from __future__ import absolute_import, division | ||
| - from __future__ import generator_stop | ||
| 4 | from __future__ import print_function, generator_stop | ||
| 5 | from __future__ import invalid_module, generators | ||
| 6 | | ||
|
|
||
| UP010 [*] Unnecessary `__future__` imports `generator_stop`, `print_function` for target Python version | ||
| --> UP010_0.py:5:1 | ||
| | | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | from __future__ import generator_stop | ||
| 5 | from __future__ import print_function, generator_stop | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^--------------^^-------------- | ||
| | | | | ||
| | | Unused import `generator_stop` | ||
| | Unused import `print_function` | ||
| 6 | from __future__ import invalid_module, generators | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 2 | from __future__ import with_statement, unicode_literals | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | from __future__ import generator_stop | ||
| - from __future__ import print_function, generator_stop | ||
| 5 | from __future__ import invalid_module, generators | ||
| 6 | | ||
| 7 | if True: | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generators` for target Python version | ||
| --> UP010_0.py:6:1 | ||
| | | ||
| 4 | from __future__ import generator_stop | ||
| 5 | from __future__ import print_function, generator_stop | ||
| 6 | from __future__ import invalid_module, generators | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------- | ||
| | | | ||
| | Unused import `generators` | ||
| 7 | | ||
| 8 | if True: | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 3 | from __future__ import absolute_import, division | ||
| 4 | from __future__ import generator_stop | ||
| 5 | from __future__ import print_function, generator_stop | ||
| - from __future__ import invalid_module, generators | ||
| 6 + from __future__ import invalid_module | ||
| 7 | | ||
| 8 | if True: | ||
| 9 | from __future__ import generator_stop | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generator_stop` for target Python version | ||
| --> UP010_0.py:9:5 | ||
| | | ||
| 8 | if True: | ||
| 9 | from __future__ import generator_stop | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 10 | from __future__ import generators | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 6 | from __future__ import invalid_module, generators | ||
| 7 | | ||
| 8 | if True: | ||
| - from __future__ import generator_stop | ||
| 9 | from __future__ import generators | ||
| 10 | | ||
| 11 | if True: | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generators` for target Python version | ||
| --> UP010_0.py:10:5 | ||
| | | ||
| 8 | if True: | ||
| 9 | from __future__ import generator_stop | ||
| 10 | from __future__ import generators | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 11 | | ||
| 12 | if True: | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 7 | | ||
| 8 | if True: | ||
| 9 | from __future__ import generator_stop | ||
| - from __future__ import generators | ||
| 10 | | ||
| 11 | if True: | ||
| 12 | from __future__ import generator_stop | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generator_stop` for target Python version | ||
| --> UP010_0.py:13:5 | ||
| | | ||
| 12 | if True: | ||
| 13 | from __future__ import generator_stop | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 14 | from __future__ import invalid_module, generators | ||
| 15 | from __future__ import generators # comment | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 10 | from __future__ import generators | ||
| 11 | | ||
| 12 | if True: | ||
| - from __future__ import generator_stop | ||
| 13 | from __future__ import invalid_module, generators | ||
| 14 | from __future__ import generators # comment | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generators` for target Python version | ||
| --> UP010_0.py:14:5 | ||
| | | ||
| 12 | if True: | ||
| 13 | from __future__ import generator_stop | ||
| 14 | from __future__ import invalid_module, generators | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------- | ||
| | | | ||
| | Unused import `generators` | ||
| 15 | from __future__ import generators # comment | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 11 | | ||
| 12 | if True: | ||
| 13 | from __future__ import generator_stop | ||
| - from __future__ import invalid_module, generators | ||
| 14 + from __future__ import invalid_module | ||
| 15 | from __future__ import generators # comment | ||
|
|
||
| UP010 [*] Unnecessary `__future__` import `generators` for target Python version | ||
| --> UP010_0.py:15:5 | ||
| | | ||
| 13 | from __future__ import generator_stop | ||
| 14 | from __future__ import invalid_module, generators | ||
| 15 | from __future__ import generators # comment | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | | ||
| help: Remove unnecessary `__future__` import | ||
| 12 | if True: | ||
| 13 | from __future__ import generator_stop | ||
| 14 | from __future__ import invalid_module, generators | ||
| - from __future__ import generators # comment | ||
| note: This is an unsafe fix and may change runtime behavior | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I think if we do go this route, we should narrow the primary diagnostic range to just
__future__(or maybefrom __future__orfrom __future__ import) to keep the two ranges from overlapping:I think I'd still prefer either one diagnostic per import, or just leaving the diagnostic as it is on stable, over this, though. But I'm curious to hear what Micha thinks. Thank you for exploring this!
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.
I'd have to double-check but narrowing the range changes the places where suppression comments are allowed.
E.g, the following currently works but I suspect won't work if we narrow the range
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 yeah, using multiple annotated ranges and highlighting the entire import statement doesn't help improve readability.
I only found this usage in cargo:
They use the
unused1as the primary range and mark theimplblock as a secondary annotation. But doing the same in Ruff requires figuring out how to make our suppression system understand that this diagnostic represents two separate violations (the current assumption is that diagnostics only represent a single error.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.
Ah, would narrowing the noqa range actually be a benefit of separate diagnostics here? Something like this doesn't currently work:
You have to put the noqa here:
at least that's the only place I found that works.
But yeah, I think secondary annotations are probably better for highlighting additional context that helps to explain the main diagnostic but likely falls outside the normal snippet context window, like in your Rust example.
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.
It appears that the previous implementation, which uses separate diagnostics, functions well for
# noqa: UP010per import object. Should I revert to that approach?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.
I'm leaning towards leaving it as is. I don't think that any of the tried approaches greatly improve the rendered diagnostics to justify a breaking change. But maybe Brent thinks differently? I'd otherwise close this PR and suggest that we revisit the rendering once we have figured out how to better handle those cases with our diagnostic system. But thank you a lot for trying out all those different approaches. It was very helpful to drive the decision-making and show where there's some need to improve our diagnostic system.
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.
Yeah, I think I agree with Micha. Thank you for working on this, I also agree that it was very helpful to see the different options!