From 337f5e7abce52feecd483e0ef8775c1ee85cd429 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 17 Feb 2023 17:09:00 -0500 Subject: [PATCH] Ignore namedtuple methods in flake8-self --- .../test/fixtures/flake8_self/SLF001.py | 13 ++-- crates/ruff/src/lib_wasm.rs | 5 +- crates/ruff/src/rules/flake8_self/mod.rs | 1 + .../rules/private_member_access.rs | 7 +++ crates/ruff/src/rules/flake8_self/settings.rs | 60 +++++++++++++++++++ ...ests__private-member-access_SLF001.py.snap | 28 ++++----- crates/ruff/src/settings/configuration.rs | 7 ++- crates/ruff/src/settings/defaults.rs | 5 +- crates/ruff/src/settings/mod.rs | 6 +- crates/ruff/src/settings/options.rs | 7 ++- ruff.schema.json | 27 +++++++++ 11 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 crates/ruff/src/rules/flake8_self/settings.rs diff --git a/crates/ruff/resources/test/fixtures/flake8_self/SLF001.py b/crates/ruff/resources/test/fixtures/flake8_self/SLF001.py index 04ed45f7ebb94..ddb448838eddd 100644 --- a/crates/ruff/resources/test/fixtures/flake8_self/SLF001.py +++ b/crates/ruff/resources/test/fixtures/flake8_self/SLF001.py @@ -56,12 +56,6 @@ def __really_private_func(self, arg): foo = Foo() -print(foo.public_thing) -print(foo.public_func()) -print(foo.__dict__) -print(foo.__str__()) -print(foo().__class__) - print(foo._private_thing) # SLF001 print(foo.__really_private_thing) # SLF001 print(foo._private_func()) # SLF001 @@ -69,3 +63,10 @@ def __really_private_func(self, arg): print(foo.bar._private) # SLF001 print(foo()._private_thing) # SLF001 print(foo()._private_thing__) # SLF001 + +print(foo.public_thing) +print(foo.public_func()) +print(foo.__dict__) +print(foo.__str__()) +print(foo().__class__) +print(foo._asdict()) diff --git a/crates/ruff/src/lib_wasm.rs b/crates/ruff/src/lib_wasm.rs index 10cdd7ec80d85..3579938702caf 100644 --- a/crates/ruff/src/lib_wasm.rs +++ b/crates/ruff/src/lib_wasm.rs @@ -11,8 +11,8 @@ use crate::registry::Rule; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes, - flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming, - pycodestyle, pydocstyle, pylint, pyupgrade, + flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, + pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, }; use crate::rustpython_helpers::tokenize; use crate::settings::configuration::Configuration; @@ -142,6 +142,7 @@ pub fn defaultSettings() -> Result { flake8_errmsg: Some(flake8_errmsg::settings::Settings::default().into()), flake8_pytest_style: Some(flake8_pytest_style::settings::Settings::default().into()), flake8_quotes: Some(flake8_quotes::settings::Settings::default().into()), + flake8_self: Some(flake8_self::settings::Settings::default().into()), flake8_implicit_str_concat: Some( flake8_implicit_str_concat::settings::Settings::default().into(), ), diff --git a/crates/ruff/src/rules/flake8_self/mod.rs b/crates/ruff/src/rules/flake8_self/mod.rs index d5099b6fd64f2..11c22c31f2359 100644 --- a/crates/ruff/src/rules/flake8_self/mod.rs +++ b/crates/ruff/src/rules/flake8_self/mod.rs @@ -1,5 +1,6 @@ //! Rules from [flake8-self](https://pypi.org/project/flake8-self/). pub(crate) mod rules; +pub mod settings; #[cfg(test)] mod tests { diff --git a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs index b111a9711e702..8f2a7d546aa03 100644 --- a/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff/src/rules/flake8_self/rules/private_member_access.rs @@ -22,6 +22,9 @@ define_violation!( /// versions, that it will have the same type, or that it will have the same /// behavior. Instead, use the class's public interface. /// + /// ## Options + /// * `flake8-self.ignore-names` + /// /// ## Example /// ```python /// class Class: @@ -62,6 +65,10 @@ pub fn private_member_access(checker: &mut Checker, expr: &Expr) { if (attr.starts_with("__") && !attr.ends_with("__")) || (attr.starts_with('_') && !attr.starts_with("__")) { + if checker.settings.flake8_self.ignore_names.contains(attr) { + return; + } + if let ExprKind::Call { func, .. } = &value.node { // Ignore `super()` calls. let call_path = collect_call_path(func); diff --git a/crates/ruff/src/rules/flake8_self/settings.rs b/crates/ruff/src/rules/flake8_self/settings.rs new file mode 100644 index 0000000000000..aa626006629d8 --- /dev/null +++ b/crates/ruff/src/rules/flake8_self/settings.rs @@ -0,0 +1,60 @@ +//! Settings for the `flake8-self` plugin. + +use ruff_macros::ConfigurationOptions; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +// By default, ignore the `namedtuple` methods and attributes, which are underscore-prefixed to +// prevent conflicts with field names. +const IGNORE_NAMES: [&str; 5] = ["_make", "_asdict", "_replace", "_fields", "_field_defaults"]; + +#[derive( + Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, JsonSchema, +)] +#[serde( + deny_unknown_fields, + rename_all = "kebab-case", + rename = "Flake8SelfOptions" +)] +pub struct Options { + #[option( + default = r#"["_make", "_asdict", "_replace", "_fields", "_field_defaults"]"#, + value_type = "list[str]", + example = r#" + ignore-names = ["_new"] + "# + )] + /// A list of names to ignore when considering `flake8-self` violations. + pub ignore_names: Option>, +} + +#[derive(Debug, Hash)] +pub struct Settings { + pub ignore_names: Vec, +} + +impl Default for Settings { + fn default() -> Self { + Self { + ignore_names: IGNORE_NAMES.map(String::from).to_vec(), + } + } +} + +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 From for Options { + fn from(settings: Settings) -> Self { + Self { + ignore_names: Some(settings.ignore_names), + } + } +} diff --git a/crates/ruff/src/rules/flake8_self/snapshots/ruff__rules__flake8_self__tests__private-member-access_SLF001.py.snap b/crates/ruff/src/rules/flake8_self/snapshots/ruff__rules__flake8_self__tests__private-member-access_SLF001.py.snap index 4452e905dffeb..2f2f1bbf88a39 100644 --- a/crates/ruff/src/rules/flake8_self/snapshots/ruff__rules__flake8_self__tests__private-member-access_SLF001.py.snap +++ b/crates/ruff/src/rules/flake8_self/snapshots/ruff__rules__flake8_self__tests__private-member-access_SLF001.py.snap @@ -50,10 +50,10 @@ expression: diagnostics PrivateMemberAccess: access: _private_thing location: - row: 65 + row: 59 column: 6 end_location: - row: 65 + row: 59 column: 24 fix: ~ parent: ~ @@ -61,10 +61,10 @@ expression: diagnostics PrivateMemberAccess: access: __really_private_thing location: - row: 66 + row: 60 column: 6 end_location: - row: 66 + row: 60 column: 32 fix: ~ parent: ~ @@ -72,10 +72,10 @@ expression: diagnostics PrivateMemberAccess: access: _private_func location: - row: 67 + row: 61 column: 6 end_location: - row: 67 + row: 61 column: 23 fix: ~ parent: ~ @@ -83,10 +83,10 @@ expression: diagnostics PrivateMemberAccess: access: __really_private_func location: - row: 68 + row: 62 column: 6 end_location: - row: 68 + row: 62 column: 31 fix: ~ parent: ~ @@ -94,10 +94,10 @@ expression: diagnostics PrivateMemberAccess: access: _private location: - row: 69 + row: 63 column: 6 end_location: - row: 69 + row: 63 column: 22 fix: ~ parent: ~ @@ -105,10 +105,10 @@ expression: diagnostics PrivateMemberAccess: access: _private_thing location: - row: 70 + row: 64 column: 6 end_location: - row: 70 + row: 64 column: 26 fix: ~ parent: ~ @@ -116,10 +116,10 @@ expression: diagnostics PrivateMemberAccess: access: _private_thing__ location: - row: 71 + row: 65 column: 6 end_location: - row: 71 + row: 65 column: 28 fix: ~ parent: ~ diff --git a/crates/ruff/src/settings/configuration.rs b/crates/ruff/src/settings/configuration.rs index 79382524f8f83..0a1f928d49008 100644 --- a/crates/ruff/src/settings/configuration.rs +++ b/crates/ruff/src/settings/configuration.rs @@ -17,8 +17,8 @@ use crate::rule_selector::RuleSelector; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes, - flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming, - pycodestyle, pydocstyle, pylint, pyupgrade, + flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, + pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, }; use crate::settings::options::Options; use crate::settings::types::{ @@ -73,6 +73,7 @@ pub struct Configuration { pub flake8_import_conventions: Option, pub flake8_pytest_style: Option, pub flake8_quotes: Option, + pub flake8_self: Option, pub flake8_tidy_imports: Option, pub flake8_type_checking: Option, pub flake8_unused_arguments: Option, @@ -185,6 +186,7 @@ impl Configuration { flake8_import_conventions: options.flake8_import_conventions, flake8_pytest_style: options.flake8_pytest_style, flake8_quotes: options.flake8_quotes, + flake8_self: options.flake8_self, flake8_tidy_imports: options.flake8_tidy_imports, flake8_type_checking: options.flake8_type_checking, flake8_unused_arguments: options.flake8_unused_arguments, @@ -251,6 +253,7 @@ impl Configuration { .or(config.flake8_import_conventions), flake8_pytest_style: self.flake8_pytest_style.or(config.flake8_pytest_style), flake8_quotes: self.flake8_quotes.or(config.flake8_quotes), + flake8_self: self.flake8_self.or(config.flake8_self), flake8_tidy_imports: self.flake8_tidy_imports.or(config.flake8_tidy_imports), flake8_type_checking: self.flake8_type_checking.or(config.flake8_type_checking), flake8_unused_arguments: self diff --git a/crates/ruff/src/settings/defaults.rs b/crates/ruff/src/settings/defaults.rs index 3ad76d61d8067..c9a4a6a9203c6 100644 --- a/crates/ruff/src/settings/defaults.rs +++ b/crates/ruff/src/settings/defaults.rs @@ -12,8 +12,8 @@ use crate::rule_selector::{prefix_to_selector, RuleSelector}; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes, - flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming, - pycodestyle, pydocstyle, pylint, pyupgrade, + flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, + pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, }; pub const PREFIXES: &[RuleSelector] = &[ @@ -86,6 +86,7 @@ impl Default for Settings { flake8_import_conventions: flake8_import_conventions::settings::Settings::default(), flake8_pytest_style: flake8_pytest_style::settings::Settings::default(), flake8_quotes: flake8_quotes::settings::Settings::default(), + flake8_self: flake8_self::settings::Settings::default(), flake8_tidy_imports: flake8_tidy_imports::Settings::default(), flake8_type_checking: flake8_type_checking::settings::Settings::default(), flake8_unused_arguments: flake8_unused_arguments::settings::Settings::default(), diff --git a/crates/ruff/src/settings/mod.rs b/crates/ruff/src/settings/mod.rs index e964032a3ecad..a4e24a7873a22 100644 --- a/crates/ruff/src/settings/mod.rs +++ b/crates/ruff/src/settings/mod.rs @@ -17,8 +17,8 @@ use crate::rule_selector::{RuleSelector, Specificity}; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes, - flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming, - pycodestyle, pydocstyle, pylint, pyupgrade, + flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, + pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, }; use crate::settings::configuration::Configuration; use crate::settings::types::{PerFileIgnore, PythonVersion, SerializationFormat}; @@ -115,6 +115,7 @@ pub struct Settings { pub flake8_import_conventions: flake8_import_conventions::settings::Settings, pub flake8_pytest_style: flake8_pytest_style::settings::Settings, pub flake8_quotes: flake8_quotes::settings::Settings, + pub flake8_self: flake8_self::settings::Settings, pub flake8_tidy_imports: flake8_tidy_imports::Settings, pub flake8_type_checking: flake8_type_checking::settings::Settings, pub flake8_unused_arguments: flake8_unused_arguments::settings::Settings, @@ -201,6 +202,7 @@ impl Settings { .map(Into::into) .unwrap_or_default(), flake8_quotes: config.flake8_quotes.map(Into::into).unwrap_or_default(), + flake8_self: config.flake8_self.map(Into::into).unwrap_or_default(), flake8_tidy_imports: config .flake8_tidy_imports .map(Into::into) diff --git a/crates/ruff/src/settings/options.rs b/crates/ruff/src/settings/options.rs index 6a21b0b6b6cda..550040514a773 100644 --- a/crates/ruff/src/settings/options.rs +++ b/crates/ruff/src/settings/options.rs @@ -9,8 +9,8 @@ use crate::rule_selector::RuleSelector; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes, - flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming, - pycodestyle, pydocstyle, pylint, pyupgrade, + flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, + pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade, }; use crate::settings::types::{PythonVersion, SerializationFormat, Version}; @@ -442,6 +442,9 @@ pub struct Options { /// Options for the `flake8-quotes` plugin. pub flake8_quotes: Option, #[option_group] + /// Options for the `flake8_self` plugin. + pub flake8_self: Option, + #[option_group] /// Options for the `flake8-tidy-imports` plugin. pub flake8_tidy_imports: Option, #[option_group] diff --git a/ruff.schema.json b/ruff.schema.json index ca0c78246655c..2a203158d572c 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -209,6 +209,17 @@ } ] }, + "flake8-self": { + "description": "Options for the `flake8_self` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8SelfOptions" + }, + { + "type": "null" + } + ] + }, "flake8-tidy-imports": { "description": "Options for the `flake8-tidy-imports` plugin.", "anyOf": [ @@ -817,6 +828,22 @@ }, "additionalProperties": false }, + "Flake8SelfOptions": { + "type": "object", + "properties": { + "ignore-names": { + "description": "A list of names to ignore when considering `flake8-self` violations.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "Flake8TidyImportsOptions": { "type": "object", "properties": {