From b0f89fa8143dbd4ae935cde95f8e7ec1ee4f6c44 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 13 Jun 2023 17:37:13 +0200 Subject: [PATCH] Support glob patterns in pep8_naming ignore-names (#5024) ## Summary Support glob patterns in pep8_naming ignore-names. Closes #2787 ## Test Plan Added new tests. --- Cargo.lock | 1 + .../fixtures/pep8_naming/ignore_names/N802.py | 14 ++++ .../fixtures/pep8_naming/ignore_names/N803.py | 12 ++++ .../fixtures/pep8_naming/ignore_names/N804.py | 22 ++++++ .../fixtures/pep8_naming/ignore_names/N805.py | 42 +++++++++++ .../fixtures/pep8_naming/ignore_names/N806.py | 6 ++ .../fixtures/pep8_naming/ignore_names/N815.py | 19 +++++ .../fixtures/pep8_naming/ignore_names/N816.py | 8 +++ crates/ruff/src/rules/pep8_naming/mod.rs | 29 +++++++- .../rules/invalid_argument_name.rs | 9 ++- ...id_first_argument_name_for_class_method.rs | 2 +- .../invalid_first_argument_name_for_method.rs | 2 +- .../rules/invalid_function_name.rs | 9 ++- .../mixed_case_variable_in_class_scope.rs | 2 +- .../mixed_case_variable_in_global_scope.rs | 2 +- .../non_lowercase_variable_in_function.rs | 2 +- crates/ruff/src/rules/pep8_naming/settings.rs | 69 ++++++++++++++++--- ...ing__tests__ignore_names_N802_N802.py.snap | 22 ++++++ ...ing__tests__ignore_names_N803_N803.py.snap | 22 ++++++ ...ing__tests__ignore_names_N804_N804.py.snap | 29 ++++++++ ...ing__tests__ignore_names_N805_N805.py.snap | 47 +++++++++++++ ...ing__tests__ignore_names_N806_N806.py.snap | 21 ++++++ ...ing__tests__ignore_names_N815_N815.py.snap | 58 ++++++++++++++++ ...ing__tests__ignore_names_N816_N816.py.snap | 29 ++++++++ crates/ruff/src/settings/mod.rs | 3 +- crates/ruff/src/settings/types.rs | 13 ++++ crates/ruff_cache/Cargo.toml | 1 + crates/ruff_cache/src/cache_key.rs | 7 ++ ruff.schema.json | 2 +- 29 files changed, 482 insertions(+), 22 deletions(-) create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py create mode 100644 crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N802_N802.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N803_N803.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N804_N804.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N805_N805.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N806_N806.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N815_N815.py.snap create mode 100644 crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N816_N816.py.snap diff --git a/Cargo.lock b/Cargo.lock index 50fd9272f2..8ffd30015d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1880,6 +1880,7 @@ name = "ruff_cache" version = "0.0.0" dependencies = [ "filetime", + "glob", "globset", "itertools", "regex", diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py new file mode 100644 index 0000000000..5bd0717e9b --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N802.py @@ -0,0 +1,14 @@ +import unittest + +def badAllowed(): + pass + +def stillBad(): + pass + +class Test(unittest.TestCase): + def badAllowed(self): + return super().tearDown() + + def stillBad(self): + return super().tearDown() diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py new file mode 100644 index 0000000000..2c2d7ba2be --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N803.py @@ -0,0 +1,12 @@ +def func(_, a, badAllowed): + return _, a, badAllowed + +def func(_, a, stillBad): + return _, a, stillBad + +class Class: + def method(self, _, a, badAllowed): + return _, a, badAllowed + + def method(self, _, a, stillBad): + return _, a, stillBad diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py new file mode 100644 index 0000000000..c3f9598417 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N804.py @@ -0,0 +1,22 @@ +from abc import ABCMeta + + +class Class: + def __init_subclass__(self, default_name, **kwargs): + ... + + @classmethod + def badAllowed(self, x, /, other): + ... + + @classmethod + def stillBad(self, x, /, other): + ... + + +class MetaClass(ABCMeta): + def badAllowed(self): + pass + + def stillBad(self): + pass diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py new file mode 100644 index 0000000000..ae5206483e --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N805.py @@ -0,0 +1,42 @@ +from abc import ABCMeta + +import pydantic + + +class Class: + def badAllowed(this): + pass + + def stillBad(this): + pass + + if False: + + def badAllowed(this): + pass + + def stillBad(this): + pass + + @pydantic.validator + def badAllowed(cls, my_field: str) -> str: + pass + + @pydantic.validator + def stillBad(cls, my_field: str) -> str: + pass + + @pydantic.validator("my_field") + def badAllowed(cls, my_field: str) -> str: + pass + + @pydantic.validator("my_field") + def stillBad(cls, my_field: str) -> str: + pass + +class PosOnlyClass: + def badAllowed(this, blah, /, self, something: str): + pass + + def stillBad(this, blah, /, self, something: str): + pass diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py new file mode 100644 index 0000000000..7ece45c61b --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N806.py @@ -0,0 +1,6 @@ +def assign(): + badAllowed = 0 + stillBad = 0 + + BAD_ALLOWED = 0 + STILL_BAD = 0 diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py new file mode 100644 index 0000000000..02c39544ca --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N815.py @@ -0,0 +1,19 @@ +class C: + badAllowed = 0 + stillBad = 0 + + _badAllowed = 0 + _stillBad = 0 + + bad_Allowed = 0 + still_Bad = 0 + +class D(TypedDict): + badAllowed: bool + stillBad: bool + + _badAllowed: list + _stillBad: list + + bad_Allowed: set + still_Bad: set diff --git a/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py new file mode 100644 index 0000000000..5ae20d20fe --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pep8_naming/ignore_names/N816.py @@ -0,0 +1,8 @@ +badAllowed = 0 +stillBad = 0 + +_badAllowed = 0 +_stillBad = 0 + +bad_Allowed = 0 +still_Bad = 0 diff --git a/crates/ruff/src/rules/pep8_naming/mod.rs b/crates/ruff/src/rules/pep8_naming/mod.rs index 98f58c1e12..e9c965c9ac 100644 --- a/crates/ruff/src/rules/pep8_naming/mod.rs +++ b/crates/ruff/src/rules/pep8_naming/mod.rs @@ -5,13 +5,14 @@ pub mod settings; #[cfg(test)] mod tests { - use std::path::Path; + use std::path::{Path, PathBuf}; use anyhow::Result; use test_case::test_case; use crate::registry::Rule; use crate::rules::pep8_naming; + use crate::settings::types::IdentifierPattern; use crate::test::test_path; use crate::{assert_messages, settings}; @@ -104,4 +105,30 @@ mod tests { assert_messages!(diagnostics); Ok(()) } + + #[test_case(Rule::InvalidFunctionName, "N802.py")] + #[test_case(Rule::InvalidArgumentName, "N803.py")] + #[test_case(Rule::InvalidFirstArgumentNameForClassMethod, "N804.py")] + #[test_case(Rule::InvalidFirstArgumentNameForMethod, "N805.py")] + #[test_case(Rule::NonLowercaseVariableInFunction, "N806.py")] + #[test_case(Rule::MixedCaseVariableInClassScope, "N815.py")] + #[test_case(Rule::MixedCaseVariableInGlobalScope, "N816.py")] + fn ignore_names(rule_code: Rule, path: &str) -> Result<()> { + let snapshot = format!("ignore_names_{}_{path}", rule_code.noqa_code()); + let diagnostics = test_path( + PathBuf::from_iter(["pep8_naming", "ignore_names", path]).as_path(), + &settings::Settings { + pep8_naming: pep8_naming::settings::Settings { + ignore_names: vec![ + IdentifierPattern::new("*Allowed").unwrap(), + IdentifierPattern::new("*ALLOWED").unwrap(), + ], + ..Default::default() + }, + ..settings::Settings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } } diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_argument_name.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_argument_name.rs index c2c8fe8d08..b1dca74a30 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_argument_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_argument_name.rs @@ -3,6 +3,8 @@ use rustpython_parser::ast::{Arg, Ranged}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use crate::settings::types::IdentifierPattern; + /// ## What it does /// Checks for argument names that do not follow the `snake_case` convention. /// @@ -48,9 +50,12 @@ impl Violation for InvalidArgumentName { pub(crate) fn invalid_argument_name( name: &str, arg: &Arg, - ignore_names: &[String], + ignore_names: &[IdentifierPattern], ) -> Option { - if ignore_names.iter().any(|ignore_name| ignore_name == name) { + if ignore_names + .iter() + .any(|ignore_name| ignore_name.matches(name)) + { return None; } if name.to_lowercase() != name { diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs index 05f42674d1..e181cfd37c 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs @@ -82,7 +82,7 @@ pub(crate) fn invalid_first_argument_name_for_class_method( .pep8_naming .ignore_names .iter() - .any(|ignore_name| ignore_name == name) + .any(|ignore_name| ignore_name.matches(name)) { return None; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs index eeedca93c1..b9c198d1ca 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs @@ -81,7 +81,7 @@ pub(crate) fn invalid_first_argument_name_for_method( .pep8_naming .ignore_names .iter() - .any(|ignore_name| ignore_name == name) + .any(|ignore_name| ignore_name.matches(name)) { return None; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs index 3713bc8ef2..4e2b9c8867 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/invalid_function_name.rs @@ -7,6 +7,8 @@ use ruff_python_ast::source_code::Locator; use ruff_python_semantic::analyze::visibility; use ruff_python_semantic::model::SemanticModel; +use crate::settings::types::IdentifierPattern; + /// ## What it does /// Checks for functions names that do not follow the `snake_case` naming /// convention. @@ -52,12 +54,15 @@ pub(crate) fn invalid_function_name( stmt: &Stmt, name: &str, decorator_list: &[Decorator], - ignore_names: &[String], + ignore_names: &[IdentifierPattern], model: &SemanticModel, locator: &Locator, ) -> Option { // Ignore any explicitly-ignored function names. - if ignore_names.iter().any(|ignore_name| ignore_name == name) { + if ignore_names + .iter() + .any(|ignore_name| ignore_name.matches(name)) + { return None; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs index 2cb0793789..4fd006a82e 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_class_scope.rs @@ -62,7 +62,7 @@ pub(crate) fn mixed_case_variable_in_class_scope( .pep8_naming .ignore_names .iter() - .any(|ignore_name| ignore_name == name) + .any(|ignore_name| ignore_name.matches(name)) { return; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs index b0312c50d6..6ea71b349d 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/mixed_case_variable_in_global_scope.rs @@ -71,7 +71,7 @@ pub(crate) fn mixed_case_variable_in_global_scope( .pep8_naming .ignore_names .iter() - .any(|ignore_name| ignore_name == name) + .any(|ignore_name| ignore_name.matches(name)) { return; } diff --git a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs index ed7648fb34..f395e6fefd 100644 --- a/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs +++ b/crates/ruff/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs @@ -60,7 +60,7 @@ pub(crate) fn non_lowercase_variable_in_function( .pep8_naming .ignore_names .iter() - .any(|ignore_name| ignore_name == name) + .any(|ignore_name| ignore_name.matches(name)) { return; } diff --git a/crates/ruff/src/rules/pep8_naming/settings.rs b/crates/ruff/src/rules/pep8_naming/settings.rs index cfacb63632..12e301ecb8 100644 --- a/crates/ruff/src/rules/pep8_naming/settings.rs +++ b/crates/ruff/src/rules/pep8_naming/settings.rs @@ -1,9 +1,14 @@ //! Settings for the `pep8-naming` plugin. +use std::error::Error; +use std::fmt; + use serde::{Deserialize, Serialize}; use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions}; +use crate::settings::types::IdentifierPattern; + const IGNORE_NAMES: [&str; 12] = [ "setUp", "tearDown", @@ -36,7 +41,7 @@ pub struct Options { ignore-names = ["callMethod"] "# )] - /// A list of names to ignore when considering `pep8-naming` violations. + /// A list of names (or patterns) to ignore when considering `pep8-naming` violations. pub ignore_names: Option>, #[option( default = r#"[]"#, @@ -72,7 +77,7 @@ pub struct Options { #[derive(Debug, CacheKey)] pub struct Settings { - pub ignore_names: Vec, + pub ignore_names: Vec, pub classmethod_decorators: Vec, pub staticmethod_decorators: Vec, } @@ -80,21 +85,59 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Self { - ignore_names: IGNORE_NAMES.map(String::from).to_vec(), + ignore_names: IGNORE_NAMES + .iter() + .map(|name| IdentifierPattern::new(name).unwrap()) + .collect(), classmethod_decorators: Vec::new(), staticmethod_decorators: Vec::new(), } } } -impl From for Settings { - fn from(options: Options) -> Self { - Self { - ignore_names: options - .ignore_names - .unwrap_or_else(|| IGNORE_NAMES.map(String::from).to_vec()), +impl TryFrom for Settings { + type Error = SettingsError; + + fn try_from(options: Options) -> Result { + Ok(Self { + ignore_names: match options.ignore_names { + Some(names) => names + .into_iter() + .map(|name| { + IdentifierPattern::new(&name).map_err(SettingsError::InvalidIgnoreName) + }) + .collect::, Self::Error>>()?, + None => IGNORE_NAMES + .into_iter() + .map(|name| IdentifierPattern::new(name).unwrap()) + .collect(), + }, classmethod_decorators: options.classmethod_decorators.unwrap_or_default(), staticmethod_decorators: options.staticmethod_decorators.unwrap_or_default(), + }) + } +} + +/// Error returned by the [`TryFrom`] implementation of [`Settings`]. +#[derive(Debug)] +pub enum SettingsError { + InvalidIgnoreName(glob::PatternError), +} + +impl fmt::Display for SettingsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SettingsError::InvalidIgnoreName(err) => { + write!(f, "Invalid pattern in ignore-names: {err}") + } + } + } +} + +impl Error for SettingsError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + SettingsError::InvalidIgnoreName(err) => Some(err), } } } @@ -102,7 +145,13 @@ impl From for Settings { impl From for Options { fn from(settings: Settings) -> Self { Self { - ignore_names: Some(settings.ignore_names), + ignore_names: Some( + settings + .ignore_names + .into_iter() + .map(|pattern| pattern.as_str().to_owned()) + .collect(), + ), classmethod_decorators: Some(settings.classmethod_decorators), staticmethod_decorators: Some(settings.staticmethod_decorators), } diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N802_N802.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N802_N802.py.snap new file mode 100644 index 0000000000..9b33e0be3e --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N802_N802.py.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N802.py:6:5: N802 Function name `stillBad` should be lowercase + | +4 | pass +5 | +6 | def stillBad(): + | ^^^^^^^^ N802 +7 | pass + | + +N802.py:13:9: N802 Function name `stillBad` should be lowercase + | +11 | return super().tearDown() +12 | +13 | def stillBad(self): + | ^^^^^^^^ N802 +14 | return super().tearDown() + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N803_N803.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N803_N803.py.snap new file mode 100644 index 0000000000..92918cc420 --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N803_N803.py.snap @@ -0,0 +1,22 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N803.py:4:16: N803 Argument name `stillBad` should be lowercase + | +2 | return _, a, badAllowed +3 | +4 | def func(_, a, stillBad): + | ^^^^^^^^ N803 +5 | return _, a, stillBad + | + +N803.py:11:28: N803 Argument name `stillBad` should be lowercase + | + 9 | return _, a, badAllowed +10 | +11 | def method(self, _, a, stillBad): + | ^^^^^^^^ N803 +12 | return _, a, stillBad + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N804_N804.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N804_N804.py.snap new file mode 100644 index 0000000000..c308109147 --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N804_N804.py.snap @@ -0,0 +1,29 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N804.py:5:27: N804 First argument of a class method should be named `cls` + | +4 | class Class: +5 | def __init_subclass__(self, default_name, **kwargs): + | ^^^^ N804 +6 | ... + | + +N804.py:13:18: N804 First argument of a class method should be named `cls` + | +12 | @classmethod +13 | def stillBad(self, x, /, other): + | ^^^^ N804 +14 | ... + | + +N804.py:21:18: N804 First argument of a class method should be named `cls` + | +19 | pass +20 | +21 | def stillBad(self): + | ^^^^ N804 +22 | pass + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N805_N805.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N805_N805.py.snap new file mode 100644 index 0000000000..46bfb51c01 --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N805_N805.py.snap @@ -0,0 +1,47 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N805.py:10:18: N805 First argument of a method should be named `self` + | + 8 | pass + 9 | +10 | def stillBad(this): + | ^^^^ N805 +11 | pass + | + +N805.py:18:22: N805 First argument of a method should be named `self` + | +16 | pass +17 | +18 | def stillBad(this): + | ^^^^ N805 +19 | pass + | + +N805.py:26:18: N805 First argument of a method should be named `self` + | +25 | @pydantic.validator +26 | def stillBad(cls, my_field: str) -> str: + | ^^^ N805 +27 | pass + | + +N805.py:34:18: N805 First argument of a method should be named `self` + | +33 | @pydantic.validator("my_field") +34 | def stillBad(cls, my_field: str) -> str: + | ^^^ N805 +35 | pass + | + +N805.py:41:18: N805 First argument of a method should be named `self` + | +39 | pass +40 | +41 | def stillBad(this, blah, /, self, something: str): + | ^^^^ N805 +42 | pass + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N806_N806.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N806_N806.py.snap new file mode 100644 index 0000000000..eff8113cce --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N806_N806.py.snap @@ -0,0 +1,21 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N806.py:3:5: N806 Variable `stillBad` in function should be lowercase + | +1 | def assign(): +2 | badAllowed = 0 +3 | stillBad = 0 + | ^^^^^^^^ N806 +4 | +5 | BAD_ALLOWED = 0 + | + +N806.py:6:5: N806 Variable `STILL_BAD` in function should be lowercase + | +5 | BAD_ALLOWED = 0 +6 | STILL_BAD = 0 + | ^^^^^^^^^ N806 + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N815_N815.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N815_N815.py.snap new file mode 100644 index 0000000000..90cdc67709 --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N815_N815.py.snap @@ -0,0 +1,58 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N815.py:3:5: N815 Variable `stillBad` in class scope should not be mixedCase + | +1 | class C: +2 | badAllowed = 0 +3 | stillBad = 0 + | ^^^^^^^^ N815 +4 | +5 | _badAllowed = 0 + | + +N815.py:6:5: N815 Variable `_stillBad` in class scope should not be mixedCase + | +5 | _badAllowed = 0 +6 | _stillBad = 0 + | ^^^^^^^^^ N815 +7 | +8 | bad_Allowed = 0 + | + +N815.py:9:5: N815 Variable `still_Bad` in class scope should not be mixedCase + | + 8 | bad_Allowed = 0 + 9 | still_Bad = 0 + | ^^^^^^^^^ N815 +10 | +11 | class D(TypedDict): + | + +N815.py:13:5: N815 Variable `stillBad` in class scope should not be mixedCase + | +11 | class D(TypedDict): +12 | badAllowed: bool +13 | stillBad: bool + | ^^^^^^^^ N815 +14 | +15 | _badAllowed: list + | + +N815.py:16:5: N815 Variable `_stillBad` in class scope should not be mixedCase + | +15 | _badAllowed: list +16 | _stillBad: list + | ^^^^^^^^^ N815 +17 | +18 | bad_Allowed: set + | + +N815.py:19:5: N815 Variable `still_Bad` in class scope should not be mixedCase + | +18 | bad_Allowed: set +19 | still_Bad: set + | ^^^^^^^^^ N815 + | + + diff --git a/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N816_N816.py.snap b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N816_N816.py.snap new file mode 100644 index 0000000000..9535fc1ba6 --- /dev/null +++ b/crates/ruff/src/rules/pep8_naming/snapshots/ruff__rules__pep8_naming__tests__ignore_names_N816_N816.py.snap @@ -0,0 +1,29 @@ +--- +source: crates/ruff/src/rules/pep8_naming/mod.rs +--- +N816.py:2:1: N816 Variable `stillBad` in global scope should not be mixedCase + | +1 | badAllowed = 0 +2 | stillBad = 0 + | ^^^^^^^^ N816 +3 | +4 | _badAllowed = 0 + | + +N816.py:5:1: N816 Variable `_stillBad` in global scope should not be mixedCase + | +4 | _badAllowed = 0 +5 | _stillBad = 0 + | ^^^^^^^^^ N816 +6 | +7 | bad_Allowed = 0 + | + +N816.py:8:1: N816 Variable `still_Bad` in global scope should not be mixedCase + | +7 | bad_Allowed = 0 +8 | still_Bad = 0 + | ^^^^^^^^^ N816 + | + + diff --git a/crates/ruff/src/settings/mod.rs b/crates/ruff/src/settings/mod.rs index b98c010dd4..fb5d6f8894 100644 --- a/crates/ruff/src/settings/mod.rs +++ b/crates/ruff/src/settings/mod.rs @@ -265,7 +265,8 @@ impl Settings { .unwrap_or_default(), pep8_naming: config .pep8_naming - .map(pep8_naming::settings::Settings::from) + .map(pep8_naming::settings::Settings::try_from) + .transpose()? .unwrap_or_default(), pycodestyle: config .pycodestyle diff --git a/crates/ruff/src/settings/types.rs b/crates/ruff/src/settings/types.rs index 2346d7506a..63e6376e93 100644 --- a/crates/ruff/src/settings/types.rs +++ b/crates/ruff/src/settings/types.rs @@ -249,3 +249,16 @@ impl Deref for Version { &self.0 } } + +/// Pattern to match an identifier. +/// +/// # Notes +/// +/// [`glob::Pattern`] matches a little differently than we ideally want to. +/// Specifically it uses `**` to match an arbitrary number of subdirectories, +/// luckily this not relevant since identifiers don't contains slashes. +/// +/// For reference pep8-naming uses +/// [`fnmatch`](https://docs.python.org/3.11/library/fnmatch.html) for +/// pattern matching. +pub type IdentifierPattern = glob::Pattern; diff --git a/crates/ruff_cache/Cargo.toml b/crates/ruff_cache/Cargo.toml index 89445ed6c8..b166bbf36a 100644 --- a/crates/ruff_cache/Cargo.toml +++ b/crates/ruff_cache/Cargo.toml @@ -12,6 +12,7 @@ license = { workspace = true } [dependencies] itertools = { workspace = true } +glob = { workspace = true } globset = { workspace = true } regex = { workspace = true } filetime = { workspace = true } diff --git a/crates/ruff_cache/src/cache_key.rs b/crates/ruff_cache/src/cache_key.rs index c05bf48ead..ee9669df09 100644 --- a/crates/ruff_cache/src/cache_key.rs +++ b/crates/ruff_cache/src/cache_key.rs @@ -5,6 +5,7 @@ use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; +use glob::Pattern; use itertools::Itertools; use regex::Regex; @@ -375,3 +376,9 @@ impl CacheKey for Regex { self.as_str().cache_key(state); } } + +impl CacheKey for Pattern { + fn cache_key(&self, state: &mut CacheKeyHasher) { + self.as_str().cache_key(state); + } +} diff --git a/ruff.schema.json b/ruff.schema.json index 4af020e35b..d7d091bb3f 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1397,7 +1397,7 @@ } }, "ignore-names": { - "description": "A list of names to ignore when considering `pep8-naming` violations.", + "description": "A list of names (or patterns) to ignore when considering `pep8-naming` violations.", "type": [ "array", "null"