Skip to content
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 - Distinguish between imports we wish to remove and those we wish to make explicit-exports #11168

Merged
merged 36 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e8ccbc1
[ruff F401 #10390 #10391] categorize imports that this rule will appl…
plredmond Apr 25, 2024
c3cb1fc
[ruff F401 #10390 #10391] add import category to ImportBinding struct
plredmond Apr 25, 2024
2555105
[ruff F401 #10390 #10391] edit to make imports explicit
plredmond Apr 25, 2024
66d9249
[ruff F401 #10390 #10391] narrower categories
plredmond Apr 25, 2024
2990bb6
[ruff F401 #10390 #10391] note some renames that would help with read…
plredmond Apr 26, 2024
9b70c3b
[ruff F401 #10390 #10391] split import bindings by fix we wish to apply
plredmond Apr 26, 2024
0d52dc7
[ruff F401 #10390 #10391] tweak "fix_imports"; rename it and only ret…
plredmond Apr 26, 2024
55c4906
[ruff F401 #10390 #10391] another "fix_imports" function but this one…
plredmond Apr 26, 2024
80bbdd4
[ruff F401 #10390 #10391] generate two fixes (instead of one) for the…
plredmond Apr 26, 2024
a35ca67
[ruff F401 #10390 #10391] remove categorize
plredmond Apr 26, 2024
f29708f
[ruff F401 #10390 #10391] rename/remove/cleanup
plredmond Apr 26, 2024
a8f5373
[ruff F401 #10390 #10391] rename and adjust new "fix_imports" function
plredmond Apr 26, 2024
d666bac
[ruff F401 #10390 #10391] cleanup the other fix-imports function
plredmond Apr 26, 2024
c05285f
[ruff F401 #10390 #10391] add fixture tests for F401 w/__init__.py; r…
plredmond Apr 27, 2024
f286764
[ruff F401 #10390 #10391] clippy
plredmond Apr 27, 2024
203bf01
[ruff F401 #10390 #10391] move comment about tests
plredmond Apr 27, 2024
bd22137
[ruff F401 #10390 #10391] unit tests for make_redundant_alias
plredmond Apr 29, 2024
c764517
[ruff F401 #10390 #10391] cargo insta review
plredmond Apr 29, 2024
1405bae
[ruff F401 #10390 #10391] rebase and change an argument to an altered…
plredmond Apr 29, 2024
56bec82
[ruff F401 #10390 #10391] ruff format the test fixtures
plredmond Apr 29, 2024
b827bfc
[ruff F401 #10390 #10391] note that the empty py files are used by a …
plredmond Apr 29, 2024
482cb75
[ruff F401 #10390 #10391] cargo insta review for the reformatted test…
plredmond Apr 30, 2024
667a901
[ruff F401 #10390 #10391] rename loop binding variables
plredmond Apr 30, 2024
c6a3ef4
[ruff F401 #10390 #10391] flip incorrectly reversed preview-flag-check
plredmond Apr 30, 2024
5ead877
[ruff F401 #10390 #10391] restore the old condition used to enable/di…
plredmond Apr 30, 2024
1800eb7
[ruff F401 #10390 #10391] delete the init_unused_import_opt_in_to_fix…
plredmond Apr 30, 2024
37c5152
[ruff F401 #10390 #10391] add information to unused-import-context; u…
plredmond Apr 30, 2024
76608fe
[ruff F401 #10390 #10391] attach context to import-bindings earlier, …
plredmond Apr 30, 2024
50d37b6
[ruff F401 #10390 #10391] rename to_explicit -> to_reexport
plredmond Apr 30, 2024
130ce57
[ruff F401 #10390 #10391] pass iterators to fix_by_* methods instead …
plredmond Apr 30, 2024
18c3001
[ruff F401 #10390 #10391] better (but not perfect) help text
plredmond Apr 30, 2024
53d6807
optimize a shortcircuiting boolean expression per micha
plredmond May 1, 2024
c8876b2
use an array instead of a vec per micha
plredmond May 1, 2024
71e191a
[ruff F401 #10390 #10391] swap arg order; move imports to top level
plredmond May 1, 2024
dacbe73
correct level to is_first_party
plredmond May 1, 2024
31768b6
charlie patch to remove the unfinished dunder_all mutation
plredmond May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""__init__.py without __all__

Unused stdlib and third party imports are unsafe removals

Unused first party imports get changed to redundant aliases
"""


# stdlib

import os # Ok: is used

_ = os


import argparse as argparse # Ok: is redundant alias


import sys # F401: remove unused


# first-party


from . import used # Ok: is used

_ = used


from . import aliased as aliased # Ok: is redundant alias


from . import unused # F401: change to redundant alias


from . import renamed as bees # F401: no fix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""__init__.py with __all__

Unused stdlib and third party imports are unsafe removals

Unused first party imports get added to __all__
"""


# stdlib

import os # Ok: is used

_ = os


import argparse # Ok: is exported in __all__


import sys # F401: remove unused


# first-party


from . import used # Ok: is used

_ = used


from . import aliased as aliased # Ok: is redundant alias


from . import exported # Ok: is exported in __all__


# from . import unused # F401: add to __all__


# from . import renamed as bees # F401: add to __all__


__all__ = ["argparse", "exported"]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# empty module imported by __init__.py for test fixture
58 changes: 56 additions & 2 deletions crates/ruff_linter/src/fix/edits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,28 @@ pub(crate) fn remove_unused_imports<'a>(
}
}

/// Edits to make the specified imports explicit, e.g. change `import x` to `import x as x`.
pub(crate) fn make_redundant_alias<'a>(
member_names: impl Iterator<Item = &'a str>,
plredmond marked this conversation as resolved.
Show resolved Hide resolved
stmt: &Stmt,
plredmond marked this conversation as resolved.
Show resolved Hide resolved
) -> Vec<Edit> {
let aliases = match stmt {
Stmt::Import(ast::StmtImport { names, .. }) => names,
Stmt::ImportFrom(ast::StmtImportFrom { names, .. }) => names,
_ => {
return Vec::new();
}
};
member_names
.filter_map(|name| {
aliases
.iter()
.find(|alias| alias.asname.is_none() && name == alias.name.id)
.map(|alias| Edit::range_replacement(format!("{name} as {name}"), alias.range))
})
.collect()
}

#[derive(Debug, Copy, Clone)]
pub(crate) enum Parentheses {
/// Remove parentheses, if the removed argument is the only argument left.
Expand Down Expand Up @@ -457,11 +479,12 @@ fn all_lines_fit(
mod tests {
use anyhow::Result;

use ruff_diagnostics::Edit;
use ruff_python_parser::parse_suite;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextSize};
use ruff_text_size::{Ranged, TextRange, TextSize};

use crate::fix::edits::{next_stmt_break, trailing_semicolon};
use crate::fix::edits::{make_redundant_alias, next_stmt_break, trailing_semicolon};

#[test]
fn find_semicolon() -> Result<()> {
Expand Down Expand Up @@ -532,4 +555,35 @@ x = 1 \
TextSize::from(12)
);
}

#[test]
fn redundant_alias() {
let contents = "import x, y as y, z as bees";
let program = parse_suite(contents).unwrap();
let stmt = program.first().unwrap();
assert_eq!(
make_redundant_alias(["x"].into_iter(), stmt),
vec![Edit::range_replacement(
String::from("x as x"),
TextRange::new(TextSize::new(7), TextSize::new(8)),
)],
"make just one item redundant"
);
assert_eq!(
make_redundant_alias(vec!["x", "y"].into_iter(), stmt),
vec![Edit::range_replacement(
String::from("x as x"),
TextRange::new(TextSize::new(7), TextSize::new(8)),
)],
"the second item is already a redundant alias"
);
assert_eq!(
make_redundant_alias(vec!["x", "z"].into_iter(), stmt),
vec![Edit::range_replacement(
String::from("x as x"),
TextRange::new(TextSize::new(7), TextSize::new(8)),
)],
"the third item is already aliased to something else"
);
}
}
16 changes: 3 additions & 13 deletions crates/ruff_linter/src/rules/pyflakes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ mod tests {
}

#[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))]
#[test_case(Rule::UnusedImport, Path::new("__init__.py"))]
#[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))]
#[test_case(Rule::UnusedImport, Path::new("F401_25__all/__init__.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
Expand Down Expand Up @@ -249,19 +252,6 @@ mod tests {
Ok(())
}

#[test]
fn init_unused_import_opt_in_to_fix() -> Result<()> {
let diagnostics = test_path(
Path::new("pyflakes/__init__.py"),
&LinterSettings {
ignore_init_module_imports: false,
..LinterSettings::for_rules(vec![Rule::UnusedImport])
},
)?;
assert_messages!(diagnostics);
Ok(())
}

#[test]
fn default_builtins() -> Result<()> {
let diagnostics = test_path(
Expand Down
Loading
Loading