Remove unused imports in `__init__.py` files by default (#1042)

This commit is contained in:
Charlie Marsh 2022-12-04 14:45:54 -05:00 committed by GitHub
parent 0c9c6a1c1c
commit 76439235af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 26 deletions

View File

@ -1270,25 +1270,6 @@ Summary
### Options ### Options
#### [`dummy_variable_rgx`](#dummy_variable_rgx)
A regular expression used to identify "dummy" variables, or those which should be ignored when evaluating
(e.g.) unused-variable checks.
**Default value**: `"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"` (matches `_`, `__`, and `_var`, but not `_var_`)
**Type**: `Regex`
**Example usage**:
```toml
[tool.ruff]
# Only ignore variables named "_".
dummy_variable_rgx = "^_$"
```
---
#### [`exclude`](#exclude) #### [`exclude`](#exclude)
A list of file patterns to exclude from linting. A list of file patterns to exclude from linting.
@ -1302,7 +1283,7 @@ Exclusions are based on globs, and can be either:
(to exclude any Python files in `directory`). Note that these paths are relative to the (to exclude any Python files in `directory`). Note that these paths are relative to the
project root (e.g., the directory containing your `pyproject.toml`). project root (e.g., the directory containing your `pyproject.toml`).
Note that you'll typically want to use [`extend_exclude`](#extend-exclude) to modify the excluded Note that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify the excluded
paths. paths.
**Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]` **Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]`
@ -1509,6 +1490,44 @@ line-length = 120
--- ---
#### [`dummy-variable-rgx`](#dummy-variable-rgx)
A regular expression used to identify "dummy" variables, or those which should be ignored when evaluating
(e.g.) unused-variable checks.
**Default value**: `"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"` (matches `_`, `__`, and `_var`, but not `_var_`)
**Type**: `Regex`
**Example usage**:
```toml
[tool.ruff]
# Only ignore variables named "_".
dummy-variable-rgx = "^_$"
```
---
#### [`ignore-init-module-imports`](#ignore-init-module-imports)
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`).
**Default value**: `false`
**Type**: `bool`
**Example usage**:
```toml
[tool.ruff]
ignore-init-module-imports = true
```
---
#### [`format`](#format) #### [`format`](#format)
The style in which violation messages should be formatted: `"text"` (default), `"grouped"` The style in which violation messages should be formatted: `"text"` (default), `"grouped"`

View File

@ -253,6 +253,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -295,6 +296,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: Some(100), line_length: Some(100),
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -337,6 +339,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: Some(100), line_length: Some(100),
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -379,6 +382,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -421,6 +425,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -471,6 +476,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![
@ -548,6 +554,7 @@ mod tests {
fixable: None, fixable: None,
format: None, format: None,
ignore: Some(vec![]), ignore: Some(vec![]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![ select: Some(vec![

View File

@ -3095,8 +3095,9 @@ impl<'a> Checker<'a> {
let child = self.parents[defined_by]; let child = self.parents[defined_by];
let parent = defined_in.map(|defined_in| self.parents[defined_in]); let parent = defined_in.map(|defined_in| self.parents[defined_in]);
let in_init_py = self.path.ends_with("__init__.py"); let ignore_init = self.settings.ignore_init_module_imports
let fix = if !in_init_py && self.patch(&CheckCode::F401) { && self.path.ends_with("__init__.py");
let fix = if !ignore_init && self.patch(&CheckCode::F401) {
let deleted: Vec<&Stmt> = self let deleted: Vec<&Stmt> = self
.deletions .deletions
.iter() .iter()
@ -3126,7 +3127,7 @@ impl<'a> Checker<'a> {
for (full_name, range) in unused_imports { for (full_name, range) in unused_imports {
let mut check = Check::new( let mut check = Check::new(
CheckKind::UnusedImport(full_name.clone(), in_init_py), CheckKind::UnusedImport(full_name.clone(), ignore_init),
*range, *range,
); );
if let Some(fix) = fix.as_ref() { if let Some(fix) = fix.as_ref() {

View File

@ -1803,9 +1803,12 @@ impl CheckKind {
CheckKind::UndefinedName(name) => { CheckKind::UndefinedName(name) => {
format!("Undefined name `{name}`") format!("Undefined name `{name}`")
} }
CheckKind::UnusedImport(name, in_init_py) => { CheckKind::UnusedImport(name, ignore_init) => {
if *in_init_py { if *ignore_init {
format!("`{name}` imported but unused and missing from `__all__`") format!(
"`{name}` imported but unused; consider adding to `__all__` or using a \
redundant alias"
)
} else { } else {
format!("`{name}` imported but unused") format!("`{name}` imported but unused")
} }

View File

@ -29,6 +29,7 @@ pub struct Configuration {
pub fixable: Vec<CheckCodePrefix>, pub fixable: Vec<CheckCodePrefix>,
pub format: SerializationFormat, pub format: SerializationFormat,
pub ignore: Vec<CheckCodePrefix>, pub ignore: Vec<CheckCodePrefix>,
pub ignore_init_module_imports: bool,
pub line_length: usize, pub line_length: usize,
pub per_file_ignores: Vec<PerFileIgnore>, pub per_file_ignores: Vec<PerFileIgnore>,
pub select: Vec<CheckCodePrefix>, pub select: Vec<CheckCodePrefix>,
@ -125,6 +126,7 @@ impl Configuration {
unfixable: options.unfixable.unwrap_or_default(), unfixable: options.unfixable.unwrap_or_default(),
format: options.format.unwrap_or_default(), format: options.format.unwrap_or_default(),
ignore: options.ignore.unwrap_or_default(), ignore: options.ignore.unwrap_or_default(),
ignore_init_module_imports: options.ignore_init_module_imports.unwrap_or_default(),
line_length: options.line_length.unwrap_or(88), line_length: options.line_length.unwrap_or(88),
per_file_ignores: options per_file_ignores: options
.per_file_ignores .per_file_ignores

View File

@ -35,6 +35,7 @@ pub struct Settings {
pub external: BTreeSet<String>, pub external: BTreeSet<String>,
pub fixable: FxHashSet<CheckCode>, pub fixable: FxHashSet<CheckCode>,
pub format: SerializationFormat, pub format: SerializationFormat,
pub ignore_init_module_imports: bool,
pub line_length: usize, pub line_length: usize,
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, BTreeSet<CheckCode>)>, pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, BTreeSet<CheckCode>)>,
pub show_source: bool, pub show_source: bool,
@ -79,6 +80,7 @@ impl Settings {
flake8_bugbear: config.flake8_bugbear, flake8_bugbear: config.flake8_bugbear,
flake8_quotes: config.flake8_quotes, flake8_quotes: config.flake8_quotes,
flake8_tidy_imports: config.flake8_tidy_imports, flake8_tidy_imports: config.flake8_tidy_imports,
ignore_init_module_imports: config.ignore_init_module_imports,
isort: config.isort, isort: config.isort,
mccabe: config.mccabe, mccabe: config.mccabe,
line_length: config.line_length, line_length: config.line_length,
@ -100,6 +102,7 @@ impl Settings {
external: BTreeSet::default(), external: BTreeSet::default(),
fixable: FxHashSet::from_iter([check_code]), fixable: FxHashSet::from_iter([check_code]),
format: SerializationFormat::Text, format: SerializationFormat::Text,
ignore_init_module_imports: false,
line_length: 88, line_length: 88,
per_file_ignores: vec![], per_file_ignores: vec![],
show_source: false, show_source: false,
@ -125,6 +128,7 @@ impl Settings {
external: BTreeSet::default(), external: BTreeSet::default(),
fixable: FxHashSet::from_iter(check_codes), fixable: FxHashSet::from_iter(check_codes),
format: SerializationFormat::Text, format: SerializationFormat::Text,
ignore_init_module_imports: false,
line_length: 88, line_length: 88,
per_file_ignores: vec![], per_file_ignores: vec![],
show_source: false, show_source: false,

View File

@ -23,6 +23,7 @@ pub struct Options {
pub fixable: Option<Vec<CheckCodePrefix>>, pub fixable: Option<Vec<CheckCodePrefix>>,
pub format: Option<SerializationFormat>, pub format: Option<SerializationFormat>,
pub ignore: Option<Vec<CheckCodePrefix>>, pub ignore: Option<Vec<CheckCodePrefix>>,
pub ignore_init_module_imports: Option<bool>,
pub line_length: Option<usize>, pub line_length: Option<usize>,
pub select: Option<Vec<CheckCodePrefix>>, pub select: Option<Vec<CheckCodePrefix>>,
pub show_source: Option<bool>, pub show_source: Option<bool>,

View File

@ -142,6 +142,7 @@ mod tests {
fix: None, fix: None,
fixable: None, fixable: None,
ignore: None, ignore: None,
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: None, select: None,
@ -182,6 +183,7 @@ line-length = 79
fix: None, fix: None,
fixable: None, fixable: None,
ignore: None, ignore: None,
ignore_init_module_imports: None,
line_length: Some(79), line_length: Some(79),
per_file_ignores: None, per_file_ignores: None,
select: None, select: None,
@ -221,6 +223,7 @@ exclude = ["foo.py"]
extend_select: None, extend_select: None,
external: None, external: None,
ignore: None, ignore: None,
ignore_init_module_imports: None,
extend_ignore: None, extend_ignore: None,
fixable: None, fixable: None,
format: None, format: None,
@ -262,6 +265,7 @@ select = ["E501"]
fix: None, fix: None,
fixable: None, fixable: None,
ignore: None, ignore: None,
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: Some(vec![CheckCodePrefix::E501]), select: Some(vec![CheckCodePrefix::E501]),
@ -303,6 +307,7 @@ ignore = ["E501"]
fix: None, fix: None,
fixable: None, fixable: None,
ignore: Some(vec![CheckCodePrefix::E501]), ignore: Some(vec![CheckCodePrefix::E501]),
ignore_init_module_imports: None,
line_length: None, line_length: None,
per_file_ignores: None, per_file_ignores: None,
select: None, select: None,
@ -381,6 +386,7 @@ other-attribute = 1
extend_select: None, extend_select: None,
external: Some(vec!["V101".to_string()]), external: Some(vec!["V101".to_string()]),
ignore: None, ignore: None,
ignore_init_module_imports: None,
extend_ignore: None, extend_ignore: None,
fixable: None, fixable: None,
format: None, format: None,