feat: add autofix for PLR0402 (#2504)

This commit is contained in:
Florian Best 2023-02-03 05:25:16 +01:00 committed by GitHub
parent d4cef9305a
commit 7e9b9cc7b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 34 deletions

View File

@ -1344,7 +1344,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| PLR0133 | constant-comparison | Two constants compared in a comparison, consider replacing `{left_constant} {op} {right_constant}` | | | PLR0133 | constant-comparison | Two constants compared in a comparison, consider replacing `{left_constant} {op} {right_constant}` | |
| PLR0206 | property-with-parameters | Cannot have defined parameters for properties | | | PLR0206 | property-with-parameters | Cannot have defined parameters for properties | |
| PLR0402 | consider-using-from-import | Use `from {module} import {name}` in lieu of alias | | | PLR0402 | consider-using-from-import | Use `from {module} import {name}` in lieu of alias | 🛠 |
| PLR0913 | too-many-args | Too many arguments to function call ({c_args}/{max_args}) | | | PLR0913 | too-many-args | Too many arguments to function call ({c_args}/{max_args}) | |
| PLR0915 | too-many-statements | Too many statements ({statements}/{max_statements}) | | | PLR0915 | too-many-statements | Too many statements ({statements}/{max_statements}) | |
| PLR1701 | consider-merging-isinstance | Merge these isinstance calls: `isinstance({obj}, ({types}))` | | | PLR1701 | consider-merging-isinstance | Merge these isinstance calls: `isinstance({obj}, ({types}))` | |

View File

@ -9,6 +9,7 @@ from collections import OrderedDict as o_dict
import os.path as path # [consider-using-from-import] import os.path as path # [consider-using-from-import]
import os.path as p import os.path as p
import foo.bar.foobar as foobar # [consider-using-from-import] import foo.bar.foobar as foobar # [consider-using-from-import]
import foo.bar.foobar as foobar, sys # [consider-using-from-import]
import os import os
import os as OS import os as OS
from sys import version from sys import version

View File

@ -922,7 +922,7 @@ where
pylint::rules::useless_import_alias(self, alias); pylint::rules::useless_import_alias(self, alias);
} }
if self.settings.rules.enabled(&Rule::ConsiderUsingFromImport) { if self.settings.rules.enabled(&Rule::ConsiderUsingFromImport) {
pylint::rules::use_from_import(self, alias); pylint::rules::use_from_import(self, stmt, alias, names);
} }
if let Some(asname) = &alias.node.asname { if let Some(asname) = &alias.node.asname {

View File

@ -1,27 +1,45 @@
use rustpython_ast::Alias; use rustpython_ast::Alias;
use rustpython_parser::ast::Stmt;
use ruff_macros::derive_message_formats;
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::define_violation; use crate::fix::Fix;
use crate::registry::Diagnostic; use crate::registry::Diagnostic;
use crate::violation::Violation; use crate::violation::{Availability, Violation};
use ruff_macros::derive_message_formats; use crate::{define_violation, AutofixKind};
define_violation!( define_violation!(
pub struct ConsiderUsingFromImport { pub struct ConsiderUsingFromImport {
pub module: String, pub module: String,
pub name: String, pub name: String,
pub fixable: bool,
} }
); );
impl Violation for ConsiderUsingFromImport { impl Violation for ConsiderUsingFromImport {
const AUTOFIX: Option<AutofixKind> = Some(AutofixKind::new(Availability::Always));
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
let ConsiderUsingFromImport { module, name } = self; let ConsiderUsingFromImport { module, name, .. } = self;
format!("Use `from {module} import {name}` in lieu of alias") format!("Use `from {module} import {name}` in lieu of alias")
} }
fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {
let ConsiderUsingFromImport { fixable, .. } = self;
if *fixable {
Some(|ConsiderUsingFromImport { module, name, .. }| {
format!("Replace with `from {module} import {name}`")
})
} else {
None
}
}
} }
/// PLR0402 /// PLR0402
pub fn use_from_import(checker: &mut Checker, alias: &Alias) { pub fn use_from_import(checker: &mut Checker, stmt: &Stmt, alias: &Alias, names: &[Alias]) {
let Some(asname) = &alias.node.asname else { let Some(asname) = &alias.node.asname else {
return; return;
}; };
@ -31,11 +49,22 @@ pub fn use_from_import(checker: &mut Checker, alias: &Alias) {
if name != asname { if name != asname {
return; return;
} }
checker.diagnostics.push(Diagnostic::new(
let fixable = names.len() == 1;
let mut diagnostic = Diagnostic::new(
ConsiderUsingFromImport { ConsiderUsingFromImport {
module: module.to_string(), module: module.to_string(),
name: name.to_string(), name: name.to_string(),
fixable,
}, },
Range::from_located(alias), Range::from_located(alias),
)); );
if fixable && checker.patch(diagnostic.kind.rule()) {
diagnostic.amend(Fix::replacement(
format!("from {module} import {asname}"),
stmt.location,
stmt.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
} }

View File

@ -41,109 +41,109 @@ expression: diagnostics
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 15 row: 16
column: 14 column: 14
end_location: end_location:
row: 15 row: 16
column: 24 column: 24
fix: fix:
content: content:
- bar - bar
location: location:
row: 15 row: 16
column: 14 column: 14
end_location: end_location:
row: 15 row: 16
column: 24 column: 24
parent: ~ parent: ~
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 18 row: 19
column: 18 column: 18
end_location: end_location:
row: 18 row: 19
column: 28 column: 28
fix: fix:
content: content:
- bar - bar
location: location:
row: 18 row: 19
column: 18 column: 18
end_location: end_location:
row: 18 row: 19
column: 28 column: 28
parent: ~ parent: ~
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 19 row: 20
column: 22 column: 22
end_location: end_location:
row: 19 row: 20
column: 38 column: 38
fix: fix:
content: content:
- foobar - foobar
location: location:
row: 19 row: 20
column: 22 column: 22
end_location: end_location:
row: 19 row: 20
column: 38 column: 38
parent: ~ parent: ~
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 21 row: 22
column: 14 column: 14
end_location: end_location:
row: 21 row: 22
column: 24 column: 24
fix: fix:
content: content:
- foo - foo
location: location:
row: 21 row: 22
column: 14 column: 14
end_location: end_location:
row: 21 row: 22
column: 24 column: 24
parent: ~ parent: ~
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 22 row: 23
column: 26 column: 26
end_location: end_location:
row: 22 row: 23
column: 38 column: 38
fix: fix:
content: content:
- foo2 - foo2
location: location:
row: 22 row: 23
column: 26 column: 26
end_location: end_location:
row: 22 row: 23
column: 38 column: 38
parent: ~ parent: ~
- kind: - kind:
UselessImportAlias: ~ UselessImportAlias: ~
location: location:
row: 24 row: 25
column: 20 column: 20
end_location: end_location:
row: 24 row: 25
column: 36 column: 36
fix: fix:
content: content:
- foobar - foobar
location: location:
row: 24 row: 25
column: 20 column: 20
end_location: end_location:
row: 24 row: 25
column: 36 column: 36
parent: ~ parent: ~

View File

@ -6,24 +6,55 @@ expression: diagnostics
ConsiderUsingFromImport: ConsiderUsingFromImport:
module: os module: os
name: path name: path
fixable: true
location: location:
row: 9 row: 9
column: 7 column: 7
end_location: end_location:
row: 9 row: 9
column: 22 column: 22
fix: ~ fix:
content:
- from os import path
location:
row: 9
column: 0
end_location:
row: 9
column: 22
parent: ~ parent: ~
- kind: - kind:
ConsiderUsingFromImport: ConsiderUsingFromImport:
module: foo.bar module: foo.bar
name: foobar name: foobar
fixable: true
location: location:
row: 11 row: 11
column: 7 column: 7
end_location: end_location:
row: 11 row: 11
column: 31 column: 31
fix:
content:
- from foo.bar import foobar
location:
row: 11
column: 0
end_location:
row: 11
column: 31
parent: ~
- kind:
ConsiderUsingFromImport:
module: foo.bar
name: foobar
fixable: false
location:
row: 12
column: 7
end_location:
row: 12
column: 31
fix: ~ fix: ~
parent: ~ parent: ~