[pylint] Implement import-self (W0406) (#4154)

This commit is contained in:
Chris Chan 2023-05-04 21:05:15 +01:00 committed by GitHub
parent 93cfce674a
commit c2921e957b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 127 additions and 0 deletions

View file

@ -0,0 +1,3 @@
import import_self.module
from import_self import module
from . import module

View file

@ -1000,6 +1000,13 @@ where
if self.settings.rules.enabled(Rule::ManualFromImport) {
pylint::rules::manual_from_import(self, stmt, alias, names);
}
if self.settings.rules.enabled(Rule::ImportSelf) {
if let Some(diagnostic) =
pylint::rules::import_self(alias, self.module_path.as_deref())
{
self.diagnostics.push(diagnostic);
}
}
if let Some(asname) = &alias.node.asname {
let name = alias.node.name.split('.').last().unwrap();
@ -1477,6 +1484,17 @@ where
}
}
if self.settings.rules.enabled(Rule::ImportSelf) {
if let Some(diagnostic) = pylint::rules::import_from_self(
*level,
module.as_deref(),
names,
self.module_path.as_deref(),
) {
self.diagnostics.push(diagnostic);
}
}
if self.settings.rules.enabled(Rule::BannedImportFrom) {
if let Some(diagnostic) = flake8_import_conventions::rules::banned_import_from(
stmt,

View file

@ -204,6 +204,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
(Pylint, "R5501") => Rule::CollapsibleElseIf,
(Pylint, "W0120") => Rule::UselessElseOnLoop,
(Pylint, "W0129") => Rule::AssertOnStringLiteral,
(Pylint, "W0406") => Rule::ImportSelf,
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
(Pylint, "W0603") => Rule::GlobalStatement,
(Pylint, "W0711") => Rule::BinaryOpException,

View file

@ -156,6 +156,7 @@ ruff_macros::register_rules!(
rules::pylint::rules::BadStringFormatType,
rules::pylint::rules::BidirectionalUnicode,
rules::pylint::rules::BinaryOpException,
rules::pylint::rules::ImportSelf,
rules::pylint::rules::InvalidCharacterBackspace,
rules::pylint::rules::InvalidCharacterSub,
rules::pylint::rules::InvalidCharacterEsc,

View file

@ -40,6 +40,7 @@ mod tests {
#[test_case(Rule::ContinueInFinally, Path::new("continue_in_finally.py"); "PLE0116")]
#[test_case(Rule::GlobalStatement, Path::new("global_statement.py"); "PLW0603")]
#[test_case(Rule::GlobalVariableNotAssigned, Path::new("global_variable_not_assigned.py"); "PLW0602")]
#[test_case(Rule::ImportSelf, Path::new("import_self/module.py"); "PLW0406")]
#[test_case(Rule::InvalidAllFormat, Path::new("invalid_all_format.py"); "PLE0605")]
#[test_case(Rule::InvalidAllObject, Path::new("invalid_all_object.py"); "PLE0604")]
#[test_case(Rule::InvalidCharacterBackspace, Path::new("invalid_characters.py"); "PLE2510")]

View file

@ -0,0 +1,70 @@
use rustpython_parser::ast::Alias;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::resolve_imported_module_path;
#[violation]
pub struct ImportSelf {
pub name: String,
}
impl Violation for ImportSelf {
#[derive_message_formats]
fn message(&self) -> String {
let Self { name } = self;
format!("Module `{name}` imports itself")
}
}
/// PLW0406
pub fn import_self(alias: &Alias, module_path: Option<&[String]>) -> Option<Diagnostic> {
let Some(module_path) = module_path else {
return None;
};
if alias.node.name.split('.').eq(module_path) {
return Some(Diagnostic::new(
ImportSelf {
name: alias.node.name.clone(),
},
alias.range(),
));
}
None
}
/// PLW0406
pub fn import_from_self(
level: Option<usize>,
module: Option<&str>,
names: &[Alias],
module_path: Option<&[String]>,
) -> Option<Diagnostic> {
let Some(module_path) = module_path else {
return None;
};
let Some(imported_module_path) = resolve_imported_module_path(level, module, Some(module_path)) else {
return None;
};
if imported_module_path
.split('.')
.eq(&module_path[..module_path.len() - 1])
{
if let Some(alias) = names
.iter()
.find(|alias| alias.node.name == module_path[module_path.len() - 1])
{
return Some(Diagnostic::new(
ImportSelf {
name: format!("{}.{}", imported_module_path, alias.node.name),
},
alias.range(),
));
}
}
None
}

View file

@ -10,6 +10,7 @@ pub use comparison_of_constant::{comparison_of_constant, ComparisonOfConstant};
pub use continue_in_finally::{continue_in_finally, ContinueInFinally};
pub use global_statement::{global_statement, GlobalStatement};
pub use global_variable_not_assigned::GlobalVariableNotAssigned;
pub use import_self::{import_from_self, import_self, ImportSelf};
pub use invalid_all_format::{invalid_all_format, InvalidAllFormat};
pub use invalid_all_object::{invalid_all_object, InvalidAllObject};
pub use invalid_envvar_default::{invalid_envvar_default, InvalidEnvvarDefault};
@ -57,6 +58,7 @@ mod comparison_of_constant;
mod continue_in_finally;
mod global_statement;
mod global_variable_not_assigned;
mod import_self;
mod invalid_all_format;
mod invalid_all_object;
mod invalid_envvar_default;

View file

@ -0,0 +1,28 @@
---
source: crates/ruff/src/rules/pylint/mod.rs
---
module.py:1:8: PLW0406 Module `import_self.module` imports itself
|
1 | import import_self.module
| ^^^^^^^^^^^^^^^^^^ PLW0406
2 | from import_self import module
3 | from . import module
|
module.py:2:25: PLW0406 Module `import_self.module` imports itself
|
2 | import import_self.module
3 | from import_self import module
| ^^^^^^ PLW0406
4 | from . import module
|
module.py:3:15: PLW0406 Module `import_self.module` imports itself
|
3 | import import_self.module
4 | from import_self import module
5 | from . import module
| ^^^^^^ PLW0406
|