-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[pyupgrade
] Avoid reporting __future__
features as unnecessary when they are used (UP010
)
#19769
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
Conversation
f11b18d
to
31bbfe8
Compare
|
190d13b
to
c243b8d
Compare
Note: This requires gating behind preview because it changes the rule's suppression ranges. |
Thanks Micha, that makes sense. Hopefully the preview-gating isn't too involved, so I think I'll still take a look at this. Your special case is also very interesting. Apparently assigning to >>> from __future__ import print_function
>>> import __future__
>>> __future__.print_function
_Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 1048576)
>>> print_function = 1
>>> __future__.print_function
_Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 1048576)
>>> __future__.print_function = 1
>>> __future__.print_function
1
>>> from __future__ import print_function
>>> print_function
1 I'm not sure if we need this to be covered by F401, though, since F811 flags it as |
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.
Thanks, this looks good to me in general. I just had a few minor suggestions on the code itself.
More broadly, I think we should probably split this into two PRs. Converting to a binding-based rule and checking for uses of the __future__
imports is a bug fix that resolves the linked issue. But emitting separate diagnostics for each unused import and updating the ranges accordingly are conceptually separate and need to be preview-gated as Micha said. I think they're separate enough that it would be easier to review them in a separate PR.
I do think these changes are nice and worth having, just a better fit for a separate patch, in my opinion.
.iter() | ||
.map(|alias| &alias.name) | ||
.map(ast::Identifier::as_str), | ||
vec![alias.name.as_str()].into_iter(), |
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 we could use std::iter::once
here to avoid allocating a Vec
just to call into_iter
.
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.
Noticed. Replaced with std::iter::once
crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_future_import.rs
Show resolved
Hide resolved
crates/ruff_linter/src/rules/pyupgrade/rules/unnecessary_future_import.rs
Show resolved
Hide resolved
if unused_imports.is_empty() { | ||
/// Process unused future import statements and generate diagnostics with fixes. | ||
/// Filters out required isort imports and creates removal fixes for unused aliases. | ||
fn process_unused_future_import(checker: &Checker, stmt: &Stmt, alias: &Alias, node_id: NodeId) { |
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 not totally sold on splitting off this helper function. I think with judicious use of let-else
we could put this back since it won't be too indented. But I don't feel too strongly either way.
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.
Removed helper function.
moved UnnecessaryFutureImport rule from `statement.rs` to `deferred_scopes.rs` reworked unused future rules determination, now checks bindings added appropriate test cases and snapshots
c243b8d
to
f2b99b9
Compare
@ntBre Thanks for your review.
Sorry, but I don't understand how to split the PR into two independent PRs. If I fix the bug which implies determining used names from the
only |
I think you can update the range of the fix without updating the range of the diagnostic itself. The diagnostic range is used for the noqa code and needs to be modified only in Lines 109 to 116 in f0b03c3
For the bug fix, I think you'd need to preserve the old behavior of gathering all of the unused imports in the same import line and emitting a single diagnostic. This is work we have to do one way or another because even if we keep the changes in the same PR, we have to preserve the old behavior when preview is disabled. One way of implementing this might be grouping the diagnostics by parent statement, which you're already computing. Hopefully it's not too much trouble. |
changed RuleGroup to Preview
CodSpeed Instrumentation Performance ReportMerging #19769 will not alter performanceComparing Summary
|
revert diagnosis report changes
It was very helpful, thanks. I believe I implemented what you suggested. So
I will create a second PR with Preview changes when you approve the current PR. |
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.
Excellent, thank you!
I'll look forward to the preview PR (if you're still interested, no pressure!). The ranges highlighting only the specific unused import were really nice :) but this neatly avoids a breaking change for now.
pyupgrade
] Reworked to not report future features as unnecessary when they are used (UP010
)pyupgrade
] Avoid reporting __future__
features as unnecessary when they are used (UP010
)
* main: (29 commits) [ty] add docstrings to completions based on type (#20008) [`pyupgrade`] Avoid reporting `__future__` features as unnecessary when they are used (`UP010`) (#19769) [`flake8-use-pathlib`] Add fixes for `PTH102` and `PTH103` (#19514) [ty] correctly ignore field specifiers when not specified (#20002) `Option::unwrap` is now const (#20007) [ty] Re-arrange "list modules" implementation for Salsa caching [ty] Test "list modules" versus "resolve module" in every mdtest [ty] Wire up "list modules" API to make module completions work [ty] Tweak some completion tests [ty] Add "list modules" implementation [ty] Lightly expose `FileModule` and `NamespacePackage` fields [ty] Add some more helper routines to `ModulePath` [ty] Fix a bug when converting `ModulePath` to `ModuleName` [ty] Split out another constructor for `ModuleName` [ty] Add stub-file tests to existing module resolver [ty] Expose some routines in the module resolver [ty] Add more path helper functions [`flake8-annotations`] Remove unused import in example (`ANN401`) (#20000) [ty] distinguish base conda from child conda (#19990) [ty] Fix server hang (#19991) ...
Summary
Resolves #19561
Fixes the unnecessary-future-import (UP010) rule to correctly identify when imported future modules are actually used in the code, preventing false positives.
I assume there is no way to check usage in
analyze::statements
, because we don't have any usage bindings for imports. To determine unused imports, we have to fully scan the file to create bindings and then check usage, similar to unused-import (F401). So,Rule::UnnecessaryFutureImport
was moved from theanalyze::statements
to theanalyze::deferred_scopes
stage. This caused the need to change the logic of future import handling to a bindings-based approach.Also, the diagnostic report was changed.
Before
after
I believe this is the correct way, because
generators
may be used, butnested_scopes
is not.Special case
I've found out about some specific case.
Here we can treat
nested_scopes
as an unused import because the variablenested_scopes
shadows it and we can safely remove the future import (my fix does it).But F401 not triggered for such case (sandbox)
In my mind,
print_function
here is an unused import and should be deleted (my IDE highlight it). What do you think?Test Plan
Added test cases and snapshots: