-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
F401 + F811 - auto-fix removes both top the level import and any inside-function import #10905
Comments
Thanks, that makes sense. |
This patch fixes things, in that the two fixes don't end up creating invalid code at the end of the day when they're combined: --- a/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs
+++ b/crates/ruff_linter/src/checkers/ast/analyze/deferred_scopes.rs
@@ -1,4 +1,4 @@
-use ruff_diagnostics::{Diagnostic, Fix};
+use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_semantic::analyze::visibility;
use ruff_python_semantic::{Binding, BindingKind, Imported, ResolvedReference, ScopeKind};
use ruff_text_size::Ranged;
@@ -294,9 +294,33 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
checker.stylist(),
checker.indexer(),
)?;
- Ok(Fix::safe_edit(edit).isolate(Checker::isolation(
- checker.semantic().parent_statement_id(source),
- )))
+ // We also add a no-op edit to force conflicts with the fix for `unused-imports`.
+ // Consider:
+ // ```python
+ // import sys
+ //
+ // def foo():
+ // import sys
+ // return sys.version_info
+ // ```
+ //
+ // Assume you omit this no-op edit. If you run Ruff with `unused-imports` and
+ // `redefined-while-unused` over this snippet, it will generate two fixes:
+ // (1) remove the unused `sys` import; and
+ // (2) remove the "redundant redefinition" of `sys`, under the assumption that
+ // `sys` is already imported and available.
+ //
+ // By adding this no-op edit, we force the `unused-imports` fix to conflict
+ // with the `redefined-while-unused` fix, and thus will avoid applying both
+ // fixes in the same pass.
+ let noop_edit = Edit::range_replacement(
+ checker.locator().slice(shadowed).to_string(),
+ shadowed.range(),
+ );
+ Ok(Fix::safe_edits(edit, std::iter::once(noop_edit))
+ .isolate(Checker::isolation(
+ checker.semantic().parent_statement_id(source),
+ )))
}); (Logic inspired by ruff/crates/ruff_linter/src/importer/mod.rs Lines 277 to 296 in 812b097
It's still not ideal, though, as it ends up applying this fix: --- foo.py
+++ foo.py
@@ -1,4 +1,3 @@
-import os # F401
def function(): when ideally it would remove the local import rather than the top-level import |
Maybe we should change F811 to only remove the "shadowed" import if they're in the same scope? I need to look back at why we changed that in the first place. |
## Summary This PR adds an override to the fixer to ensure that we apply any `redefined-while-unused` fixes prior to `unused-import`. Closes #10905.
Hello!
Here's a minimal example, applying auto-fix to the following:
Results in the following:
This makes for a fix that breaks the code.
The text was updated successfully, but these errors were encountered: