mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +00:00
[pylint
] Implement import-self (W0406
) (#4154)
This commit is contained in:
parent
93cfce674a
commit
c2921e957b
10 changed files with 127 additions and 0 deletions
0
crates/ruff/resources/test/fixtures/pylint/import_self/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pylint/import_self/__init__.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/pylint/import_self/module.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/pylint/import_self/module.py
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
import import_self.module
|
||||
from import_self import module
|
||||
from . import module
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")]
|
||||
|
|
70
crates/ruff/src/rules/pylint/rules/import_self.rs
Normal file
70
crates/ruff/src/rules/pylint/rules/import_self.rs
Normal 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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue