From e78fee6d2b3d5f8f0155f2868106a526920e89ef Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Wed, 15 May 2024 11:30:20 -0700 Subject: [PATCH 01/20] docs for updated F401 behavior #11168,#11314 --- .../src/rules/pyflakes/rules/unused_import.rs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index 6fe44cf88a578..0d54609d15123 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -46,16 +46,32 @@ enum UnusedImportContext { /// from module import member as member /// ``` /// +/// Within `__init__.py` re-export a symbol with an `__all__` declaration containing a string +/// matching the symbol, as in: +/// +/// ```python +/// # __init__.py +/// import some_module +/// +/// __all__ = [ "some_module"] +/// ``` +/// /// ## Fix safety /// -/// When `ignore_init_module_imports` is disabled, fixes can remove for unused imports in `__init__` files. -/// These fixes are considered unsafe because they can change the public interface. +/// Fixes to remove unused imports are safe, except in `__init__.py` files, where they could +/// change the public interface. Fixes in `__init__.py` files are currently gated within preview +/// mode. +/// +/// In preview mode, `__init__.py` files containing unused first party imports will have +/// safe fixes to add those imports `__all__` if there is exactly one `__all__` declaration +/// (otherwise the fixes recommend conversion to "redundant" import aliases). +/// Unused standard library and third-party imports in `__init__.py` have unsafe fixes to remove +/// the import statement. /// /// ## Example /// ```python /// import numpy as np # unused import /// -/// /// def area(radius): /// return 3.14 * radius**2 /// ``` @@ -76,9 +92,6 @@ enum UnusedImportContext { /// print("numpy is not installed") /// ``` /// -/// ## Options -/// - `lint.ignore-init-module-imports` -/// /// ## References /// - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) /// - [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec) From c9ac09b01066fa3caece3d6b8556750a113a3f96 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Wed, 15 May 2024 11:36:52 -0700 Subject: [PATCH 02/20] cargo insta review -- accept doc changes --- .../integration_test__rule_f401.snap | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap index 2c69bfa92bcd0..d50067bc7997d 100644 --- a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap +++ b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap @@ -34,16 +34,32 @@ marking it as unused, as in: from module import member as member ``` +Within `__init__.py` re-export a symbol with an `__all__` declaration containing a string +matching the symbol, as in: + +```python +# __init__.py +import some_module + +__all__ = [ "some_module"] +``` + ## Fix safety -When `ignore_init_module_imports` is disabled, fixes can remove for unused imports in `__init__` files. -These fixes are considered unsafe because they can change the public interface. +Fixes to remove unused imports are safe, except in `__init__.py` files, where they could +change the public interface. Fixes in `__init__.py` files are currently gated within preview +mode. + +In preview mode, `__init__.py` files containing unused first party imports will have +safe fixes to add those imports `__all__` if there is exactly one `__all__` declaration +(otherwise the fixes recommend conversion to "redundant" import aliases). +Unused standard library and third-party imports in `__init__.py` have unsafe fixes to remove +the import statement. ## Example ```python import numpy as np # unused import - def area(radius): return 3.14 * radius**2 ``` @@ -64,9 +80,6 @@ else: print("numpy is not installed") ``` -## Options -- `lint.ignore-init-module-imports` - ## References - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) - [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec) From fb1ac9782142bee8b26d1f830fd40991984937d1 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Wed, 15 May 2024 13:29:38 -0700 Subject: [PATCH 03/20] wording improvements in after zanie's comments --- .../src/rules/pyflakes/rules/unused_import.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index 0d54609d15123..bac9f466573e6 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -46,8 +46,8 @@ enum UnusedImportContext { /// from module import member as member /// ``` /// -/// Within `__init__.py` re-export a symbol with an `__all__` declaration containing a string -/// matching the symbol, as in: +/// Alternatively, you can use `__all__` to declare a symbol as part of the module's +/// interface, as in: /// /// ```python /// # __init__.py @@ -58,15 +58,14 @@ enum UnusedImportContext { /// /// ## Fix safety /// -/// Fixes to remove unused imports are safe, except in `__init__.py` files, where they could -/// change the public interface. Fixes in `__init__.py` files are currently gated within preview -/// mode. +/// Fixes to remove unused imports are safe, except in `__init__.py` files. /// -/// In preview mode, `__init__.py` files containing unused first party imports will have -/// safe fixes to add those imports `__all__` if there is exactly one `__all__` declaration -/// (otherwise the fixes recommend conversion to "redundant" import aliases). -/// Unused standard library and third-party imports in `__init__.py` have unsafe fixes to remove -/// the import statement. +/// Applying fixes to `__init__.py` files is currently in preview. The fix offered depends on the +/// type of the unused import. Ruff will suggest a safe fix to export first-party imports with +/// either a redundant alias or, if already present in the file, an `__all__` entry. If multiple +/// `__all__` declarations are present, Ruff will not offer a fix. Ruff will suggest an unsafe fix +/// to remove third-party and standard library imports -- the fix is unsafe because the module's +/// interface changes. /// /// ## Example /// ```python From 7706561af7564b6cf6ce46fee7751b720eea8512 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Wed, 15 May 2024 13:32:52 -0700 Subject: [PATCH 04/20] cargo insta review -- accept documentation change --- .../integration_test__rule_f401.snap | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap index d50067bc7997d..c3abb002b046f 100644 --- a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap +++ b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap @@ -34,8 +34,8 @@ marking it as unused, as in: from module import member as member ``` -Within `__init__.py` re-export a symbol with an `__all__` declaration containing a string -matching the symbol, as in: +Alternatively, you can use `__all__` to declare a symbol as part of the module's +interface, as in: ```python # __init__.py @@ -46,15 +46,14 @@ __all__ = [ "some_module"] ## Fix safety -Fixes to remove unused imports are safe, except in `__init__.py` files, where they could -change the public interface. Fixes in `__init__.py` files are currently gated within preview -mode. +Fixes to remove unused imports are safe, except in `__init__.py` files. -In preview mode, `__init__.py` files containing unused first party imports will have -safe fixes to add those imports `__all__` if there is exactly one `__all__` declaration -(otherwise the fixes recommend conversion to "redundant" import aliases). -Unused standard library and third-party imports in `__init__.py` have unsafe fixes to remove -the import statement. +Applying fixes to `__init__.py` files is currently in preview. The fix offered depends on the +type of the unused import. Ruff will suggest a safe fix to export first-party imports with +either a redundant alias or, if already present in the file, an `__all__` entry. If multiple +`__all__` declarations are present, Ruff will not offer a fix. Ruff will suggest an unsafe fix +to remove third-party and standard library imports -- the fix is unsafe because the module's +interface changes. ## Example ```python From 36b43314980104a1f34e5304847e93237f6f1013 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 12:10:11 -0700 Subject: [PATCH 05/20] add deprecation warning for option lint.ignore_init_module_imports in ruff_workspace --- crates/ruff_workspace/src/options.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index fbd76b7e84e8f..71cb0ee84ee17 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -703,6 +703,10 @@ pub struct LintCommonOptions { ignore-init-module-imports = false "# )] + #[deprecated( + since = "0.4.4", + note = "`ignore-init-module-imports` will be removed in a future version because F401 now recommends appropriate fixes for unused imports in `__init__.py` (currently in preview mode). See documentation for more information and please update your configuration." + )] pub ignore_init_module_imports: Option, /// A list of objects that should be treated equivalently to a From 63a96765cab0ddb1f8ef5496fdbed346645b2de8 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 12:50:48 -0700 Subject: [PATCH 06/20] add module member name field to UnusedImport violation; redundant-alias message to use that instead of the binding name --- .../src/rules/pyflakes/rules/unused_import.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index bac9f466573e6..6d258fb789259 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -99,6 +99,8 @@ enum UnusedImportContext { pub struct UnusedImport { /// Qualified name of the import name: String, + /// Unqualified name of the import + module: String, /// Name of the import binding binding: String, context: Option, @@ -129,6 +131,7 @@ impl Violation for UnusedImport { fn fix_title(&self) -> Option { let UnusedImport { name, + module, binding, multiple, .. @@ -142,9 +145,7 @@ impl Violation for UnusedImport { Some(UnusedImportContext::Init { first_party: true, dunder_all_count: 0, - }) => Some(format!( - "Use an explicit re-export: `{binding} as {binding}`" - )), + }) => Some(format!("Use an explicit re-export: `{module} as {module}`")), _ => Some(if *multiple { "Remove unused import".to_string() @@ -332,6 +333,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut let mut diagnostic = Diagnostic::new( UnusedImport { name: binding.import.qualified_name().to_string(), + module: binding.import.member_name().to_string(), binding: binding.name.to_string(), context, multiple, @@ -356,6 +358,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut let mut diagnostic = Diagnostic::new( UnusedImport { name: binding.import.qualified_name().to_string(), + module: binding.import.member_name().to_string(), binding: binding.name.to_string(), context: None, multiple: false, From f656ca4dcd24c49e6927de22f4908b34968e0f65 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 12:54:04 -0700 Subject: [PATCH 07/20] cargo insta review -- accept change in diff for incorrect fix title --- ...es__pyflakes__tests__preview__F401_F401_24____init__.py.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F401_F401_24____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F401_F401_24____init__.py.snap index 46850ca6619e6..f7db8b02e72f1 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F401_F401_24____init__.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F401_F401_24____init__.py.snap @@ -39,4 +39,4 @@ __init__.py:36:26: F401 `.renamed` imported but unused; consider removing, addin 36 | from . import renamed as bees # F401: no fix | ^^^^ F401 | - = help: Use an explicit re-export: `bees as bees` + = help: Use an explicit re-export: `renamed as renamed` From 1bfa7b1ba18214b22dd9fd4f60f6b9e09b296cbc Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:26:59 -0700 Subject: [PATCH 08/20] restore deprecated behavior for f401 when linter.ignore_init_module_imports=false: emit unsafe fixes to remove unused imports even in __init__.py --- .../src/rules/pyflakes/rules/unused_import.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index 6d258fb789259..d8440ca376936 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -24,6 +24,7 @@ enum UnusedImportContext { Init { first_party: bool, dunder_all_count: usize, + ignore_init_module_imports: bool, }, } @@ -91,6 +92,10 @@ enum UnusedImportContext { /// print("numpy is not installed") /// ``` /// +/// ## Options +/// - Deprecated `lint.ignore-init-module-imports` to `true`. When set to `false`, unused imports +/// in `__init__.py` files are removed (unsafe). +/// /// ## References /// - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) /// - [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec) @@ -140,11 +145,13 @@ impl Violation for UnusedImport { Some(UnusedImportContext::Init { first_party: true, dunder_all_count: 1, + ignore_init_module_imports: true, }) => Some(format!("Add unused import `{binding}` to __all__")), Some(UnusedImportContext::Init { first_party: true, dunder_all_count: 0, + ignore_init_module_imports: true, }) => Some(format!("Use an explicit re-export: `{module} as {module}`")), _ => Some(if *multiple { @@ -257,7 +264,8 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut } let in_init = checker.path().ends_with("__init__.py"); - let fix_init = checker.settings.preview.is_enabled(); + let fix_init = !checker.settings.ignore_init_module_imports; + let preview_mode = checker.settings.preview.is_enabled(); let dunder_all_exprs = find_dunder_all_exprs(checker.semantic()); // Generate a diagnostic for every import, but share fixes across all imports within the same @@ -288,6 +296,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut checker, ), dunder_all_count: dunder_all_exprs.len(), + ignore_init_module_imports: !fix_init, }) } else { None @@ -301,7 +310,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut first_party: true, .. }) - ) + ) && preview_mode }); // generate fixes that are shared across bindings in the statement From 4f0b79e8b280e3177e35b0fec3122e8dfd7dae07 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:29:52 -0700 Subject: [PATCH 09/20] tests for f401 in stable w/o deprecated option --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 20 ++++++++++++++++ ...sts__F401_stable_F401_24____init__.py.snap | 23 ++++++++++++++++++ ...le_F401_25__all_nonempty____init__.py.snap | 23 ++++++++++++++++++ ...table_F401_26__all_empty____init__.py.snap | 16 +++++++++++++ ...le_F401_27__all_mistyped____init__.py.snap | 16 +++++++++++++ ...le_F401_28__all_multiple____init__.py.snap | 16 +++++++++++++ ...F401_29__all_conditional____init__.py.snap | 24 +++++++++++++++++++ 7 files changed, 138 insertions(+) create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_24____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_25__all_nonempty____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_26__all_empty____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_27__all_mistyped____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_28__all_multiple____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_29__all_conditional____init__.py.snap diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 4d31234106aba..e4e15a1bc5a1c 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -229,6 +229,26 @@ mod tests { Ok(()) } + #[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_25__all_nonempty/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_26__all_empty/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_27__all_mistyped/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_28__all_multiple/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_29__all_conditional/__init__.py"))] + fn f401_stable(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!( + "{}_stable_{}", + rule_code.noqa_code(), + path.to_string_lossy() + ); + let diagnostics = test_path( + Path::new("pyflakes").join(path).as_path(), + &LinterSettings::for_rule(rule_code), + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test] fn f841_dummy_variable_rgx() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_24____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_24____init__.py.snap new file mode 100644 index 0000000000000..e1e8ca664f400 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_24____init__.py.snap @@ -0,0 +1,23 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:19:8: F401 `sys` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +19 | import sys # F401: remove unused + | ^^^ F401 + | + = help: Remove unused import: `sys` + +__init__.py:33:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +33 | from . import unused # F401: change to redundant alias + | ^^^^^^ F401 + | + = help: Use an explicit re-export: `unused as unused` + +__init__.py:36:26: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +36 | from . import renamed as bees # F401: no fix + | ^^^^ F401 + | + = help: Use an explicit re-export: `renamed as renamed` diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_25__all_nonempty____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_25__all_nonempty____init__.py.snap new file mode 100644 index 0000000000000..faeb9037ef744 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_25__all_nonempty____init__.py.snap @@ -0,0 +1,23 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:19:8: F401 `sys` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +19 | import sys # F401: remove unused + | ^^^ F401 + | + = help: Remove unused import: `sys` + +__init__.py:36:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +36 | from . import unused # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Add unused import `unused` to __all__ + +__init__.py:39:26: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +39 | from . import renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Add unused import `bees` to __all__ diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_26__all_empty____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_26__all_empty____init__.py.snap new file mode 100644 index 0000000000000..d01839e564728 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_26__all_empty____init__.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Add unused import `unused` to __all__ + +__init__.py:8:26: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +8 | from . import renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Add unused import `bees` to __all__ diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_27__all_mistyped____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_27__all_mistyped____init__.py.snap new file mode 100644 index 0000000000000..c665795df9447 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_27__all_mistyped____init__.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused # F401: recommend add to all w/o fix + | ^^^^^^ F401 + | + = help: Add unused import `unused` to __all__ + +__init__.py:8:26: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +8 | from . import renamed as bees # F401: recommend add to all w/o fix + | ^^^^ F401 + | + = help: Add unused import `bees` to __all__ diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_28__all_multiple____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_28__all_multiple____init__.py.snap new file mode 100644 index 0000000000000..219539886e329 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_28__all_multiple____init__.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused, renamed as bees # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Add unused import `unused` to __all__ + +__init__.py:5:34: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused, renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Add unused import `bees` to __all__ diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_29__all_conditional____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_29__all_conditional____init__.py.snap new file mode 100644 index 0000000000000..0100397db388f --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_stable_F401_29__all_conditional____init__.py.snap @@ -0,0 +1,24 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:8:15: F401 `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | + 6 | import sys + 7 | + 8 | from . import unused, exported, renamed as bees + | ^^^^^^ F401 + 9 | +10 | if sys.version_info > (3, 9): + | + = help: Remove unused import + +__init__.py:8:44: F401 `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | + 6 | import sys + 7 | + 8 | from . import unused, exported, renamed as bees + | ^^^^ F401 + 9 | +10 | if sys.version_info > (3, 9): + | + = help: Remove unused import From 3202de885b36632b582baac81739ba71ccdfc8ac Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:32:25 -0700 Subject: [PATCH 10/20] tests for f401 in stable w/ deprecated option: emit unsafe fixes to remove unused imports even in __init__.py --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 23 +++++++++ ...eprecated_option_F401_24____init__.py.snap | 47 +++++++++++++++++ ...on_F401_25__all_nonempty____init__.py.snap | 50 +++++++++++++++++++ ...ption_F401_26__all_empty____init__.py.snap | 34 +++++++++++++ ...on_F401_27__all_mistyped____init__.py.snap | 34 +++++++++++++ ...on_F401_28__all_multiple____init__.py.snap | 34 +++++++++++++ ...F401_29__all_conditional____init__.py.snap | 44 ++++++++++++++++ 7 files changed, 266 insertions(+) create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_24____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_25__all_nonempty____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_26__all_empty____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_27__all_mistyped____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_28__all_multiple____init__.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_29__all_conditional____init__.py.snap diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index e4e15a1bc5a1c..107cb96fb3769 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -249,6 +249,29 @@ mod tests { Ok(()) } + #[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_25__all_nonempty/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_26__all_empty/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_27__all_mistyped/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_28__all_multiple/__init__.py"))] + #[test_case(Rule::UnusedImport, Path::new("F401_29__all_conditional/__init__.py"))] + fn f401_deprecated_option(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!( + "{}_deprecated_option_{}", + rule_code.noqa_code(), + path.to_string_lossy() + ); + let diagnostics = test_path( + Path::new("pyflakes").join(path).as_path(), + &LinterSettings { + ignore_init_module_imports: false, + ..LinterSettings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test] fn f841_dummy_variable_rgx() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_24____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_24____init__.py.snap new file mode 100644 index 0000000000000..3f44409c80a34 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_24____init__.py.snap @@ -0,0 +1,47 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:19:8: F401 [*] `sys` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +19 | import sys # F401: remove unused + | ^^^ F401 + | + = help: Remove unused import: `sys` + +ℹ Unsafe fix +16 16 | import argparse as argparse # Ok: is redundant alias +17 17 | +18 18 | +19 |-import sys # F401: remove unused +20 19 | +21 20 | +22 21 | # first-party + +__init__.py:33:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +33 | from . import unused # F401: change to redundant alias + | ^^^^^^ F401 + | + = help: Remove unused import: `.unused` + +ℹ Unsafe fix +30 30 | from . import aliased as aliased # Ok: is redundant alias +31 31 | +32 32 | +33 |-from . import unused # F401: change to redundant alias +34 33 | +35 34 | +36 35 | from . import renamed as bees # F401: no fix + +__init__.py:36:26: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +36 | from . import renamed as bees # F401: no fix + | ^^^^ F401 + | + = help: Remove unused import: `.renamed` + +ℹ Unsafe fix +33 33 | from . import unused # F401: change to redundant alias +34 34 | +35 35 | +36 |-from . import renamed as bees # F401: no fix diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_25__all_nonempty____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_25__all_nonempty____init__.py.snap new file mode 100644 index 0000000000000..f75cb2f1dc9e6 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_25__all_nonempty____init__.py.snap @@ -0,0 +1,50 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:19:8: F401 [*] `sys` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +19 | import sys # F401: remove unused + | ^^^ F401 + | + = help: Remove unused import: `sys` + +ℹ Unsafe fix +16 16 | import argparse # Ok: is exported in __all__ +17 17 | +18 18 | +19 |-import sys # F401: remove unused +20 19 | +21 20 | +22 21 | # first-party + +__init__.py:36:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +36 | from . import unused # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Remove unused import: `.unused` + +ℹ Unsafe fix +33 33 | from . import exported # Ok: is exported in __all__ +34 34 | +35 35 | +36 |-from . import unused # F401: add to __all__ +37 36 | +38 37 | +39 38 | from . import renamed as bees # F401: add to __all__ + +__init__.py:39:26: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +39 | from . import renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Remove unused import: `.renamed` + +ℹ Unsafe fix +36 36 | from . import unused # F401: add to __all__ +37 37 | +38 38 | +39 |-from . import renamed as bees # F401: add to __all__ +40 39 | +41 40 | +42 41 | __all__ = ["argparse", "exported"] diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_26__all_empty____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_26__all_empty____init__.py.snap new file mode 100644 index 0000000000000..0fa48cf5f179e --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_26__all_empty____init__.py.snap @@ -0,0 +1,34 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Remove unused import: `.unused` + +ℹ Unsafe fix +2 2 | """ +3 3 | +4 4 | +5 |-from . import unused # F401: add to __all__ +6 5 | +7 6 | +8 7 | from . import renamed as bees # F401: add to __all__ + +__init__.py:8:26: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +8 | from . import renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Remove unused import: `.renamed` + +ℹ Unsafe fix +5 5 | from . import unused # F401: add to __all__ +6 6 | +7 7 | +8 |-from . import renamed as bees # F401: add to __all__ +9 8 | +10 9 | +11 10 | __all__ = [] diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_27__all_mistyped____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_27__all_mistyped____init__.py.snap new file mode 100644 index 0000000000000..a4f1d557bdef4 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_27__all_mistyped____init__.py.snap @@ -0,0 +1,34 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused # F401: recommend add to all w/o fix + | ^^^^^^ F401 + | + = help: Remove unused import: `.unused` + +ℹ Unsafe fix +2 2 | """ +3 3 | +4 4 | +5 |-from . import unused # F401: recommend add to all w/o fix +6 5 | +7 6 | +8 7 | from . import renamed as bees # F401: recommend add to all w/o fix + +__init__.py:8:26: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +8 | from . import renamed as bees # F401: recommend add to all w/o fix + | ^^^^ F401 + | + = help: Remove unused import: `.renamed` + +ℹ Unsafe fix +5 5 | from . import unused # F401: recommend add to all w/o fix +6 6 | +7 7 | +8 |-from . import renamed as bees # F401: recommend add to all w/o fix +9 8 | +10 9 | +11 10 | __all__ = None diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_28__all_multiple____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_28__all_multiple____init__.py.snap new file mode 100644 index 0000000000000..daeee1984e4aa --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_28__all_multiple____init__.py.snap @@ -0,0 +1,34 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:5:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused, renamed as bees # F401: add to __all__ + | ^^^^^^ F401 + | + = help: Remove unused import + +ℹ Unsafe fix +2 2 | """ +3 3 | +4 4 | +5 |-from . import unused, renamed as bees # F401: add to __all__ +6 5 | +7 6 | +8 7 | __all__ = []; + +__init__.py:5:34: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | +5 | from . import unused, renamed as bees # F401: add to __all__ + | ^^^^ F401 + | + = help: Remove unused import + +ℹ Unsafe fix +2 2 | """ +3 3 | +4 4 | +5 |-from . import unused, renamed as bees # F401: add to __all__ +6 5 | +7 6 | +8 7 | __all__ = []; diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_29__all_conditional____init__.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_29__all_conditional____init__.py.snap new file mode 100644 index 0000000000000..392a58cf7aa16 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F401_deprecated_option_F401_29__all_conditional____init__.py.snap @@ -0,0 +1,44 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +__init__.py:8:15: F401 [*] `.unused` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | + 6 | import sys + 7 | + 8 | from . import unused, exported, renamed as bees + | ^^^^^^ F401 + 9 | +10 | if sys.version_info > (3, 9): + | + = help: Remove unused import + +ℹ Unsafe fix +5 5 | +6 6 | import sys +7 7 | +8 |-from . import unused, exported, renamed as bees + 8 |+from . import exported +9 9 | +10 10 | if sys.version_info > (3, 9): +11 11 | from . import also_exported + +__init__.py:8:44: F401 [*] `.renamed` imported but unused; consider removing, adding to `__all__`, or using a redundant alias + | + 6 | import sys + 7 | + 8 | from . import unused, exported, renamed as bees + | ^^^^ F401 + 9 | +10 | if sys.version_info > (3, 9): + | + = help: Remove unused import + +ℹ Unsafe fix +5 5 | +6 6 | import sys +7 7 | +8 |-from . import unused, exported, renamed as bees + 8 |+from . import exported +9 9 | +10 10 | if sys.version_info > (3, 9): +11 11 | from . import also_exported From 97d1526a253bd2f884421f4b3cc7f86c1029d9b8 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:39:43 -0700 Subject: [PATCH 11/20] add deprecation message for `ignore-init-module-imports` in settings files --- crates/ruff_workspace/src/configuration.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 240ab7a12fd8f..75a677ba52be6 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -660,7 +660,12 @@ impl LintConfiguration { .collect(); #[allow(deprecated)] - let ignore_init_module_imports = options.common.ignore_init_module_imports; + let ignore_init_module_imports = { + if options.common.ignore_init_module_imports.is_some_and(|t| t) { + warn_user_once!("The `ignore-init-module-imports` option has been deprecated because Ruff will soon suggest reexports in `__init__.py` files with safe fixes when possible (currently in preview mode). Please update your configuration to remove `ignore-init-module-imports` because it will be removed in a future version."); + } + options.common.ignore_init_module_imports + }; Ok(LintConfiguration { exclude: options.exclude.map(|paths| { From 8d3ffbd33477dfd7573b96304c4f0450a0f99fe0 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:44:07 -0700 Subject: [PATCH 12/20] cargo insta review -- accept changed documentation --- crates/ruff/tests/snapshots/integration_test__rule_f401.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap index c3abb002b046f..eea73ed27953f 100644 --- a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap +++ b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap @@ -79,6 +79,10 @@ else: print("numpy is not installed") ``` +## Options +- Deprecated `lint.ignore-init-module-imports` to `true`. When set to `false`, unused imports +in `__init__.py` files are removed (unsafe). + ## References - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) - [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec) From 249d8481756448dfd4425e0432155d39d79cb224 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:49:45 -0700 Subject: [PATCH 13/20] cargo dev generate-all --- ruff.schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/ruff.schema.json b/ruff.schema.json index ec514be5fc8a4..9827c7d241014 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2119,6 +2119,7 @@ }, "ignore-init-module-imports": { "description": "Avoid automatically removing unused imports in `__init__.py` files. Such imports will still be flagged, but with a dedicated message suggesting that the import is either added to the module's `__all__` symbol, or re-exported with a redundant alias (e.g., `import os as os`).\n\nThis option is enabled by default, but you can opt-in to removal of imports via an unsafe fix.", + "deprecated": true, "type": [ "boolean", "null" From b6871c93a7edb46e3e57fbe8be24fe56844d3684 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 15:54:07 -0700 Subject: [PATCH 14/20] tweak boolean condition --- .../src/rules/pyflakes/rules/unused_import.rs | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index d8440ca376936..b734c4162fe6b 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -314,26 +314,27 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope, diagnostics: &mut }); // generate fixes that are shared across bindings in the statement - let (fix_remove, fix_reexport) = if (!in_init || fix_init) && !in_except_handler { - ( - fix_by_removing_imports( - checker, - import_statement, - to_remove.iter().map(|(binding, _)| binding), - in_init, + let (fix_remove, fix_reexport) = + if (!in_init || fix_init || preview_mode) && !in_except_handler { + ( + fix_by_removing_imports( + checker, + import_statement, + to_remove.iter().map(|(binding, _)| binding), + in_init, + ) + .ok(), + fix_by_reexporting( + checker, + import_statement, + &to_reexport.iter().map(|(b, _)| b).collect::>(), + &dunder_all_exprs, + ) + .ok(), ) - .ok(), - fix_by_reexporting( - checker, - import_statement, - &to_reexport.iter().map(|(b, _)| b).collect::>(), - &dunder_all_exprs, - ) - .ok(), - ) - } else { - (None, None) - }; + } else { + (None, None) + }; for ((binding, context), fix) in iter::Iterator::chain( iter::zip(to_remove, iter::repeat(fix_remove)), From 715da2e1bc295b25f27c5b48df72615ef02487b3 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 16:02:25 -0700 Subject: [PATCH 15/20] correct documentation formatting --- crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index b734c4162fe6b..7d36cde76aca3 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -69,20 +69,24 @@ enum UnusedImportContext { /// interface changes. /// /// ## Example +/// /// ```python /// import numpy as np # unused import /// +/// /// def area(radius): /// return 3.14 * radius**2 /// ``` /// /// Use instead: +/// /// ```python /// def area(radius): /// return 3.14 * radius**2 /// ``` /// /// To check the availability of a module, use `importlib.util.find_spec`: +/// /// ```python /// from importlib.util import find_spec /// From 21fe25e677c56fffe457e1e1daa7229c84058caf Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 16:12:01 -0700 Subject: [PATCH 16/20] cargo insta review -- accept documentation change --- crates/ruff/tests/snapshots/integration_test__rule_f401.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap index eea73ed27953f..e613061c8fab5 100644 --- a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap +++ b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap @@ -56,20 +56,24 @@ to remove third-party and standard library imports -- the fix is unsafe because interface changes. ## Example + ```python import numpy as np # unused import + def area(radius): return 3.14 * radius**2 ``` Use instead: + ```python def area(radius): return 3.14 * radius**2 ``` To check the availability of a module, use `importlib.util.find_spec`: + ```python from importlib.util import find_spec From 26f80c1c60c94099444472dd330cb8a403ace47f Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 20:50:52 -0700 Subject: [PATCH 17/20] emit the deprecation warning if the option is set, regardless of value per zanie --- crates/ruff_workspace/src/configuration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 75a677ba52be6..e634ceeb10e59 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -661,7 +661,7 @@ impl LintConfiguration { #[allow(deprecated)] let ignore_init_module_imports = { - if options.common.ignore_init_module_imports.is_some_and(|t| t) { + if options.common.ignore_init_module_imports.is_some() { warn_user_once!("The `ignore-init-module-imports` option has been deprecated because Ruff will soon suggest reexports in `__init__.py` files with safe fixes when possible (currently in preview mode). Please update your configuration to remove `ignore-init-module-imports` because it will be removed in a future version."); } options.common.ignore_init_module_imports From 2be489f52b64c53377773a328b84185130f41702 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 20:52:15 -0700 Subject: [PATCH 18/20] improve wording of deprecation warning by using zanie's suggestion --- crates/ruff_workspace/src/configuration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index e634ceeb10e59..7cb2a5c5083fc 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -662,7 +662,7 @@ impl LintConfiguration { #[allow(deprecated)] let ignore_init_module_imports = { if options.common.ignore_init_module_imports.is_some() { - warn_user_once!("The `ignore-init-module-imports` option has been deprecated because Ruff will soon suggest reexports in `__init__.py` files with safe fixes when possible (currently in preview mode). Please update your configuration to remove `ignore-init-module-imports` because it will be removed in a future version."); + warn_user_once!("The `ignore-init-module-imports` option is deprecated and will be removed in a future release. Ruff's handling of imports in `__init__.py` files has been improved (in preview) and unused imports will always be flagged."); } options.common.ignore_init_module_imports }; From 943ee257d19a6e38c3402e17d19bb15da4d72b6e Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 20:55:56 -0700 Subject: [PATCH 19/20] list only the option, not information about it, in the docstring of a rule per zanie --- crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index 7d36cde76aca3..3ce0f56c12ca3 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -97,8 +97,7 @@ enum UnusedImportContext { /// ``` /// /// ## Options -/// - Deprecated `lint.ignore-init-module-imports` to `true`. When set to `false`, unused imports -/// in `__init__.py` files are removed (unsafe). +/// - `lint.ignore-init-module-imports` /// /// ## References /// - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) From 6028415be71bc60c2a0fc9ac03f0abb1e51acae0 Mon Sep 17 00:00:00 2001 From: PLR <51248199+plredmond@users.noreply.github.com> Date: Mon, 20 May 2024 21:54:16 -0700 Subject: [PATCH 20/20] cargo insta review -- accept change in documentation --- crates/ruff/tests/snapshots/integration_test__rule_f401.snap | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap index e613061c8fab5..09b9e23c32d05 100644 --- a/crates/ruff/tests/snapshots/integration_test__rule_f401.snap +++ b/crates/ruff/tests/snapshots/integration_test__rule_f401.snap @@ -84,8 +84,7 @@ else: ``` ## Options -- Deprecated `lint.ignore-init-module-imports` to `true`. When set to `false`, unused imports -in `__init__.py` files are removed (unsafe). +- `lint.ignore-init-module-imports` ## References - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement)