From b108c693faac39ee86d90b49a34d3ef044728236 Mon Sep 17 00:00:00 2001 From: Harutaka Kawamura Date: Fri, 21 Oct 2022 01:20:44 +0900 Subject: [PATCH] Implement N811, 812, 813, 814, and 817 (#457) --- README.md | 5 ++ resources/test/fixtures/N811.py | 1 + resources/test/fixtures/N812.py | 1 + resources/test/fixtures/N813.py | 1 + resources/test/fixtures/N814.py | 1 + resources/test/fixtures/N817.py | 1 + src/check_ast.rs | 58 ++++++++++++++ src/checks.rs | 50 ++++++++++++ src/linter.rs | 5 ++ src/pep8_naming/checks.rs | 79 +++++++++++++++++++ .../ruff__linter__tests__N811_N811.py.snap | 16 ++++ .../ruff__linter__tests__N812_N812.py.snap | 16 ++++ .../ruff__linter__tests__N813_N813.py.snap | 16 ++++ .../ruff__linter__tests__N814_N814.py.snap | 16 ++++ .../ruff__linter__tests__N817_N817.py.snap | 16 ++++ 15 files changed, 282 insertions(+) create mode 100644 resources/test/fixtures/N811.py create mode 100644 resources/test/fixtures/N812.py create mode 100644 resources/test/fixtures/N813.py create mode 100644 resources/test/fixtures/N814.py create mode 100644 resources/test/fixtures/N817.py create mode 100644 src/snapshots/ruff__linter__tests__N811_N811.py.snap create mode 100644 src/snapshots/ruff__linter__tests__N812_N812.py.snap create mode 100644 src/snapshots/ruff__linter__tests__N813_N813.py.snap create mode 100644 src/snapshots/ruff__linter__tests__N814_N814.py.snap create mode 100644 src/snapshots/ruff__linter__tests__N817_N817.py.snap diff --git a/README.md b/README.md index 317aefbc03..c9465036c5 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,11 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com | N804 | InvalidFirstArgumentNameForClassMethod | First argument of a class method should be named `cls` | | | N805 | InvalidFirstArgumentNameForMethod | First argument of a method should be named `self` | | | N807 | DunderFunctionName | function name should not start and end with '__' | | +| N811 | ConstantImportedAsNonConstant | constant '...' imported as non constant '...' | | +| N812 | LowercaseImportedAsNonLowercase | lowercase '...' imported as non lowercase '...' | | +| N813 | CamelcaseImportedAsLowercase | camelcase '...' imported as lowercase '...' | | +| N814 | CamelcaseImportedAsConstant | camelcase '...' imported as constant '...' | | +| N817 | CamelcaseImportedAsAcronym | camelcase '...' imported as acronym '...' | | ### flake8-comprehensions diff --git a/resources/test/fixtures/N811.py b/resources/test/fixtures/N811.py new file mode 100644 index 0000000000..11e1e5263d --- /dev/null +++ b/resources/test/fixtures/N811.py @@ -0,0 +1 @@ +from mod import BAD as bad diff --git a/resources/test/fixtures/N812.py b/resources/test/fixtures/N812.py new file mode 100644 index 0000000000..ef7de8c677 --- /dev/null +++ b/resources/test/fixtures/N812.py @@ -0,0 +1 @@ +from mod import bad as Bad diff --git a/resources/test/fixtures/N813.py b/resources/test/fixtures/N813.py new file mode 100644 index 0000000000..085fd6460a --- /dev/null +++ b/resources/test/fixtures/N813.py @@ -0,0 +1 @@ +from mod import CamelCase as camelcase diff --git a/resources/test/fixtures/N814.py b/resources/test/fixtures/N814.py new file mode 100644 index 0000000000..284207ed7e --- /dev/null +++ b/resources/test/fixtures/N814.py @@ -0,0 +1 @@ +from mod import CamelCase as CAMELCASE diff --git a/resources/test/fixtures/N817.py b/resources/test/fixtures/N817.py new file mode 100644 index 0000000000..758b067339 --- /dev/null +++ b/resources/test/fixtures/N817.py @@ -0,0 +1 @@ +from mod import CamelCase as CC diff --git a/src/check_ast.rs b/src/check_ast.rs index a3e80eb244..80273c5d24 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -533,6 +533,64 @@ where }, ) } + + if let Some(asname) = &alias.node.asname { + if self.settings.enabled.contains(&CheckCode::N811) { + if let Some(check) = + pep8_naming::checks::constant_imported_as_non_constant( + stmt, + &alias.node.name, + asname, + ) + { + self.checks.push(check); + } + } + + if self.settings.enabled.contains(&CheckCode::N812) { + if let Some(check) = + pep8_naming::checks::lowercase_imported_as_non_lowercase( + stmt, + &alias.node.name, + asname, + ) + { + self.checks.push(check); + } + } + + if self.settings.enabled.contains(&CheckCode::N813) { + if let Some(check) = + pep8_naming::checks::camelcase_imported_as_lowercase( + stmt, + &alias.node.name, + asname, + ) + { + self.checks.push(check); + } + } + + if self.settings.enabled.contains(&CheckCode::N814) { + if let Some(check) = pep8_naming::checks::camelcase_imported_as_constant( + stmt, + &alias.node.name, + asname, + ) { + self.checks.push(check); + } + } + + if self.settings.enabled.contains(&CheckCode::N817) { + if let Some(check) = pep8_naming::checks::camelcase_imported_as_acronym( + stmt, + &alias.node.name, + asname, + ) { + self.checks.push(check); + } + } + } } } StmtKind::Raise { exc, .. } => { diff --git a/src/checks.rs b/src/checks.rs index 9ab9be7832..8ab98dc757 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -159,6 +159,11 @@ pub enum CheckCode { N804, N805, N807, + N811, + N812, + N813, + N814, + N817, // Meta M001, } @@ -344,6 +349,11 @@ pub enum CheckKind { InvalidFirstArgumentNameForClassMethod, InvalidFirstArgumentNameForMethod, DunderFunctionName, + ConstantImportedAsNonConstant(String, String), + LowercaseImportedAsNonLowercase(String, String), + CamelcaseImportedAsLowercase(String, String), + CamelcaseImportedAsConstant(String, String), + CamelcaseImportedAsAcronym(String, String), // Meta UnusedNOQA(Option>), } @@ -520,6 +530,21 @@ impl CheckCode { CheckCode::N804 => CheckKind::InvalidFirstArgumentNameForClassMethod, CheckCode::N805 => CheckKind::InvalidFirstArgumentNameForMethod, CheckCode::N807 => CheckKind::DunderFunctionName, + CheckCode::N811 => { + CheckKind::ConstantImportedAsNonConstant("...".to_string(), "...".to_string()) + } + CheckCode::N812 => { + CheckKind::LowercaseImportedAsNonLowercase("...".to_string(), "...".to_string()) + } + CheckCode::N813 => { + CheckKind::CamelcaseImportedAsLowercase("...".to_string(), "...".to_string()) + } + CheckCode::N814 => { + CheckKind::CamelcaseImportedAsConstant("...".to_string(), "...".to_string()) + } + CheckCode::N817 => { + CheckKind::CamelcaseImportedAsAcronym("...".to_string(), "...".to_string()) + } // Meta CheckCode::M001 => CheckKind::UnusedNOQA(None), } @@ -652,6 +677,11 @@ impl CheckCode { CheckCode::N804 => CheckCategory::PEP8Naming, CheckCode::N805 => CheckCategory::PEP8Naming, CheckCode::N807 => CheckCategory::PEP8Naming, + CheckCode::N811 => CheckCategory::PEP8Naming, + CheckCode::N812 => CheckCategory::PEP8Naming, + CheckCode::N813 => CheckCategory::PEP8Naming, + CheckCode::N814 => CheckCategory::PEP8Naming, + CheckCode::N817 => CheckCategory::PEP8Naming, CheckCode::M001 => CheckCategory::Meta, } } @@ -795,6 +825,11 @@ impl CheckKind { CheckKind::InvalidFirstArgumentNameForClassMethod => &CheckCode::N804, CheckKind::InvalidFirstArgumentNameForMethod => &CheckCode::N805, CheckKind::DunderFunctionName => &CheckCode::N807, + CheckKind::ConstantImportedAsNonConstant(..) => &CheckCode::N811, + CheckKind::LowercaseImportedAsNonLowercase(..) => &CheckCode::N812, + CheckKind::CamelcaseImportedAsLowercase(..) => &CheckCode::N813, + CheckKind::CamelcaseImportedAsConstant(..) => &CheckCode::N814, + CheckKind::CamelcaseImportedAsAcronym(..) => &CheckCode::N817, // Meta CheckKind::UnusedNOQA(_) => &CheckCode::M001, } @@ -1188,6 +1223,21 @@ impl CheckKind { CheckKind::DunderFunctionName => { "function name should not start and end with '__'".to_string() } + CheckKind::ConstantImportedAsNonConstant(name, asname) => { + format!("constant '{name}' imported as non constant '{asname}'") + } + CheckKind::LowercaseImportedAsNonLowercase(name, asname) => { + format!("lowercase '{name}' imported as non lowercase '{asname}'") + } + CheckKind::CamelcaseImportedAsLowercase(name, asname) => { + format!("camelcase '{name}' imported as lowercase '{asname}'") + } + CheckKind::CamelcaseImportedAsConstant(name, asname) => { + format!("camelcase '{name}' imported as constant '{asname}'") + } + CheckKind::CamelcaseImportedAsAcronym(name, asname) => { + format!("camelcase '{name}' imported as acronym '{asname}'") + } // Meta CheckKind::UnusedNOQA(codes) => match codes { None => "Unused `noqa` directive".to_string(), diff --git a/src/linter.rs b/src/linter.rs index e37a894189..7eb8589ae7 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -359,6 +359,11 @@ mod tests { #[test_case(CheckCode::N804, Path::new("N804.py"); "N804")] #[test_case(CheckCode::N805, Path::new("N805.py"); "N805")] #[test_case(CheckCode::N807, Path::new("N807.py"); "N807")] + #[test_case(CheckCode::N811, Path::new("N811.py"); "N811")] + #[test_case(CheckCode::N812, Path::new("N812.py"); "N812")] + #[test_case(CheckCode::N813, Path::new("N813.py"); "N813")] + #[test_case(CheckCode::N814, Path::new("N814.py"); "N814")] + #[test_case(CheckCode::N817, Path::new("N817.py"); "N817")] #[test_case(CheckCode::T201, Path::new("T201.py"); "T201")] #[test_case(CheckCode::T203, Path::new("T203.py"); "T203")] #[test_case(CheckCode::U001, Path::new("U001.py"); "U001")] diff --git a/src/pep8_naming/checks.rs b/src/pep8_naming/checks.rs index 42a6b56136..3c6d9650f0 100644 --- a/src/pep8_naming/checks.rs +++ b/src/pep8_naming/checks.rs @@ -1,3 +1,4 @@ +use itertools::Itertools; use rustpython_ast::{Arguments, Expr, ExprKind, Stmt}; use crate::ast::types::{Range, Scope, ScopeKind}; @@ -112,3 +113,81 @@ pub fn dunder_function_name(func_def: &Stmt, scope: &Scope, name: &str) -> Optio None } + +pub fn constant_imported_as_non_constant( + import_from: &Stmt, + name: &str, + asname: &str, +) -> Option { + if name.chars().all(|c| c.is_uppercase()) && !asname.chars().all(|c| c.is_uppercase()) { + return Some(Check::new( + CheckKind::ConstantImportedAsNonConstant(name.to_string(), asname.to_string()), + Range::from_located(import_from), + )); + } + None +} + +pub fn lowercase_imported_as_non_lowercase( + import_from: &Stmt, + name: &str, + asname: &str, +) -> Option { + if name.chars().all(|c| c.is_lowercase()) && asname.to_lowercase() != asname { + return Some(Check::new( + CheckKind::LowercaseImportedAsNonLowercase(name.to_string(), asname.to_string()), + Range::from_located(import_from), + )); + } + None +} + +fn is_camelcase(name: &str) -> bool { + !name.chars().all(|c| c.is_uppercase()) && !name.chars().all(|c| c.is_lowercase()) +} + +fn is_acronym(name: &str, asname: &str) -> bool { + name.chars().filter(|c| c.is_uppercase()).join("") == asname +} + +pub fn camelcase_imported_as_lowercase( + import_from: &Stmt, + name: &str, + asname: &str, +) -> Option { + if is_camelcase(name) && asname.chars().all(|c| c.is_lowercase()) { + return Some(Check::new( + CheckKind::CamelcaseImportedAsLowercase(name.to_string(), asname.to_string()), + Range::from_located(import_from), + )); + } + None +} + +pub fn camelcase_imported_as_constant( + import_from: &Stmt, + name: &str, + asname: &str, +) -> Option { + if is_camelcase(name) && asname.chars().all(|c| c.is_uppercase()) && !is_acronym(name, asname) { + return Some(Check::new( + CheckKind::CamelcaseImportedAsConstant(name.to_string(), asname.to_string()), + Range::from_located(import_from), + )); + } + None +} + +pub fn camelcase_imported_as_acronym( + import_from: &Stmt, + name: &str, + asname: &str, +) -> Option { + if is_camelcase(name) && asname.chars().all(|c| c.is_uppercase()) && is_acronym(name, asname) { + return Some(Check::new( + CheckKind::CamelcaseImportedAsAcronym(name.to_string(), asname.to_string()), + Range::from_located(import_from), + )); + } + None +} diff --git a/src/snapshots/ruff__linter__tests__N811_N811.py.snap b/src/snapshots/ruff__linter__tests__N811_N811.py.snap new file mode 100644 index 0000000000..1557bb292a --- /dev/null +++ b/src/snapshots/ruff__linter__tests__N811_N811.py.snap @@ -0,0 +1,16 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + ConstantImportedAsNonConstant: + - BAD + - bad + location: + row: 1 + column: 1 + end_location: + row: 1 + column: 27 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__N812_N812.py.snap b/src/snapshots/ruff__linter__tests__N812_N812.py.snap new file mode 100644 index 0000000000..c544463961 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__N812_N812.py.snap @@ -0,0 +1,16 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + LowercaseImportedAsNonLowercase: + - bad + - Bad + location: + row: 1 + column: 1 + end_location: + row: 1 + column: 27 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__N813_N813.py.snap b/src/snapshots/ruff__linter__tests__N813_N813.py.snap new file mode 100644 index 0000000000..1ee762e27c --- /dev/null +++ b/src/snapshots/ruff__linter__tests__N813_N813.py.snap @@ -0,0 +1,16 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + CamelcaseImportedAsLowercase: + - CamelCase + - camelcase + location: + row: 1 + column: 1 + end_location: + row: 1 + column: 39 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__N814_N814.py.snap b/src/snapshots/ruff__linter__tests__N814_N814.py.snap new file mode 100644 index 0000000000..d2d6f03c5a --- /dev/null +++ b/src/snapshots/ruff__linter__tests__N814_N814.py.snap @@ -0,0 +1,16 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + CamelcaseImportedAsConstant: + - CamelCase + - CAMELCASE + location: + row: 1 + column: 1 + end_location: + row: 1 + column: 39 + fix: ~ + diff --git a/src/snapshots/ruff__linter__tests__N817_N817.py.snap b/src/snapshots/ruff__linter__tests__N817_N817.py.snap new file mode 100644 index 0000000000..b367886280 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__N817_N817.py.snap @@ -0,0 +1,16 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: + CamelcaseImportedAsAcronym: + - CamelCase + - CC + location: + row: 1 + column: 1 + end_location: + row: 1 + column: 32 + fix: ~ +