[flake8-naming]: Respect import conventions (N817) (#12922)

This commit is contained in:
Micha Reiser 2024-08-16 17:28:57 +02:00 committed by GitHub
parent c319414e54
commit aba0d83c11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 75 additions and 11 deletions

View file

@ -1,2 +1,6 @@
import mod.CaMel as CM import mod.CaMel as CM
from mod import CamelCase as CC from mod import CamelCase as CC
# OK depending on configured import convention
import xml.etree.ElementTree as ET

View file

@ -707,11 +707,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
} }
if checker.enabled(Rule::CamelcaseImportedAsAcronym) { if checker.enabled(Rule::CamelcaseImportedAsAcronym) {
if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym( if let Some(diagnostic) = pep8_naming::rules::camelcase_imported_as_acronym(
name, name, asname, alias, stmt, checker,
asname,
alias,
stmt,
&checker.settings.pep8_naming.ignore_names,
) { ) {
checker.diagnostics.push(diagnostic); checker.diagnostics.push(diagnostic);
} }
@ -1026,7 +1022,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
asname, asname,
alias, alias,
stmt, stmt,
&checker.settings.pep8_naming.ignore_names, checker,
) { ) {
checker.diagnostics.push(diagnostic); checker.diagnostics.push(diagnostic);
} }

View file

@ -8,11 +8,12 @@ mod tests {
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
use rustc_hash::FxHashMap;
use test_case::test_case; use test_case::test_case;
use crate::registry::Rule; use crate::registry::Rule;
use crate::rules::pep8_naming;
use crate::rules::pep8_naming::settings::IgnoreNames; use crate::rules::pep8_naming::settings::IgnoreNames;
use crate::rules::{flake8_import_conventions, pep8_naming};
use crate::test::test_path; use crate::test::test_path;
use crate::{assert_messages, settings}; use crate::{assert_messages, settings};
@ -87,6 +88,25 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn camelcase_imported_as_incorrect_convention() -> Result<()> {
let diagnostics = test_path(
Path::new("pep8_naming").join("N817.py").as_path(),
&settings::LinterSettings {
flake8_import_conventions: flake8_import_conventions::settings::Settings {
aliases: FxHashMap::from_iter([(
"xml.etree.ElementTree".to_string(),
"XET".to_string(),
)]),
..Default::default()
},
..settings::LinterSettings::for_rule(Rule::CamelcaseImportedAsAcronym)
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test] #[test]
fn classmethod_decorators() -> Result<()> { fn classmethod_decorators() -> Result<()> {
let diagnostics = test_path( let diagnostics = test_path(

View file

@ -1,12 +1,11 @@
use ruff_python_ast::{Alias, Stmt};
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{Alias, Stmt};
use ruff_python_stdlib::str::{self}; use ruff_python_stdlib::str::{self};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::rules::pep8_naming::helpers; use crate::rules::pep8_naming::helpers;
use crate::rules::pep8_naming::settings::IgnoreNames;
/// ## What it does /// ## What it does
/// Checks for `CamelCase` imports that are aliased as acronyms. /// Checks for `CamelCase` imports that are aliased as acronyms.
@ -23,6 +22,10 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
/// Note that this rule is distinct from `camelcase-imported-as-constant` /// Note that this rule is distinct from `camelcase-imported-as-constant`
/// to accommodate selective enforcement. /// to accommodate selective enforcement.
/// ///
/// Also note that import aliases following an import convention according to the
/// [`lint.flake8-boolean-trap.extend-allowed-calls`] option are allowed.
///
///
/// ## Example /// ## Example
/// ```python /// ```python
/// from example import MyClassName as MCN /// from example import MyClassName as MCN
@ -34,6 +37,9 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
/// ``` /// ```
/// ///
/// [PEP 8]: https://peps.python.org/pep-0008/ /// [PEP 8]: https://peps.python.org/pep-0008/
///
/// ## Options
/// - `lint.flake8-import-conventions.banned-aliases`
#[violation] #[violation]
pub struct CamelcaseImportedAsAcronym { pub struct CamelcaseImportedAsAcronym {
name: String, name: String,
@ -54,17 +60,32 @@ pub(crate) fn camelcase_imported_as_acronym(
asname: &str, asname: &str,
alias: &Alias, alias: &Alias,
stmt: &Stmt, stmt: &Stmt,
ignore_names: &IgnoreNames, checker: &Checker,
) -> Option<Diagnostic> { ) -> Option<Diagnostic> {
if helpers::is_camelcase(name) if helpers::is_camelcase(name)
&& !str::is_cased_lowercase(asname) && !str::is_cased_lowercase(asname)
&& str::is_cased_uppercase(asname) && str::is_cased_uppercase(asname)
&& helpers::is_acronym(name, asname) && helpers::is_acronym(name, asname)
{ {
let ignore_names = &checker.settings.pep8_naming.ignore_names;
// Ignore any explicitly-allowed names. // Ignore any explicitly-allowed names.
if ignore_names.matches(name) || ignore_names.matches(asname) { if ignore_names.matches(name) || ignore_names.matches(asname) {
return None; return None;
} }
// Ignore names that follow a community-agreed import convention.
if checker
.settings
.flake8_import_conventions
.aliases
.get(&*alias.name)
.map(String::as_str)
== Some(asname)
{
return None;
}
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
CamelcaseImportedAsAcronym { CamelcaseImportedAsAcronym {
name: name.to_string(), name: name.to_string(),

View file

@ -0,0 +1,23 @@
---
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
---
N817.py:1:8: N817 CamelCase `CaMel` imported as acronym `CM`
|
1 | import mod.CaMel as CM
| ^^^^^^^^^^^^^^^ N817
2 | from mod import CamelCase as CC
|
N817.py:2:17: N817 CamelCase `CamelCase` imported as acronym `CC`
|
1 | import mod.CaMel as CM
2 | from mod import CamelCase as CC
| ^^^^^^^^^^^^^^^ N817
|
N817.py:6:8: N817 CamelCase `ElementTree` imported as acronym `ET`
|
5 | # OK depending on configured import convention
6 | import xml.etree.ElementTree as ET
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ N817
|