From a945357da9baff1b5887d35720f5fcf41626a4d6 Mon Sep 17 00:00:00 2001 From: Lucas Vieira dos Santos Date: Sun, 1 Sep 2024 16:27:49 +0200 Subject: [PATCH 1/7] [pylint] depracted dunder methods in Python 3 (PLW3201) Add message for when the dunder method name is no longer valid in Python 3. --- .../fixtures/pylint/bad_dunder_method_name.py | 3 ++ .../ruff_linter/src/rules/pylint/helpers.rs | 27 ++++++++++++++++++ .../pylint/rules/bad_dunder_method_name.rs | 28 ++++++++++++++++--- ...ts__PLW3201_bad_dunder_method_name.py.snap | 8 +++++- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py index cf264981284c2..0385284c798d2 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py @@ -94,6 +94,9 @@ def __prepare__(): def __mro_entries__(self, bases): pass + # Deprecated in Python 3 + def __unicode__(self): + pass def __foo_bar__(): # this is not checked by the [bad-dunder-name] rule ... diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 081f034f97191..dab3b607173e2 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -307,3 +307,30 @@ pub(super) fn is_known_dunder_method(method: &str) -> bool { | "_generate_next_value_" ) } + +/// Returns `true` if the method is a known dunder method that is only allowed in Python 2. +pub(super) fn is_deprecated_dunder_method_in_python3(method: &str) -> bool { + matches!( + method, + "__unicode__" + | "__div__" + | "__rdiv__" + | "__idiv__" + | "__nonzero__" + | "__metaclass__" + | "__cmp__" + | "__getslice__" + | "__setslice__" + | "__delslice__" + | "__oct__" + | "__hex__" + | "__members__" + | "__method__" + | "__corece__" + | "__long__" + | "__rcmp__" + | "__iop__" + | "__rop__" + | "__op__" + ) +} diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs index 2812cf214aab5..e77a1490d128f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -5,13 +5,20 @@ use ruff_python_ast::identifier::Identifier; use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; +use crate::rules::pylint::helpers::is_deprecated_dunder_method_in_python3; use crate::rules::pylint::helpers::is_known_dunder_method; +#[derive(PartialEq, Eq, Debug)] +enum Kind { + Misspelled, + DeprecatedInPython3, +} + /// ## What it does -/// Checks for misspelled and unknown dunder names in method definitions. +/// Checks for misspelled, unknown, and deprecated dunder names in method definitions. /// /// ## Why is this bad? -/// Misspelled dunder name methods may cause your code to not function +/// Misspelled or deprecated dunder name methods may cause your code to not function /// as expected. /// /// Since dunder methods are associated with customizing the behavior @@ -45,13 +52,19 @@ use crate::rules::pylint::helpers::is_known_dunder_method; #[violation] pub struct BadDunderMethodName { name: String, + kind: Kind, } impl Violation for BadDunderMethodName { #[derive_message_formats] fn message(&self) -> String { - let BadDunderMethodName { name } = self; - format!("Bad or misspelled dunder method name `{name}`") + let BadDunderMethodName { name, kind } = self; + match kind { + Kind::Misspelled => format!("Bad or misspelled dunder method name `{name}`"), + Kind::DeprecatedInPython3 => { + format!("Deprecated dunder method name in Python 3 `{name}`") + } + } } } @@ -78,9 +91,16 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, method: &ast::StmtFu return; } + let kind = if is_deprecated_dunder_method_in_python3(&method.name) { + Kind::DeprecatedInPython3 + } else { + Kind::Misspelled + }; + checker.diagnostics.push(Diagnostic::new( BadDunderMethodName { name: method.name.to_string(), + kind, }, method.identifier(), )); diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap index fb777d47a8fd1..8757dd5579c03 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap @@ -58,4 +58,10 @@ bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__ 25 | pass | - +bad_dunder_method_name.py:98:9: PLW3201 Deprecated dunder method name in Python 3 `__unicode__` + | +97 | # Deprecated in Python 3 +98 | def __unicode__(self): + | ^^^^^^^^^^^ PLW3201 +99 | pass + | From 824a3a46980f7a9376450b9939e789c67f73c232 Mon Sep 17 00:00:00 2001 From: Lucas Vieira dos Santos Date: Mon, 2 Sep 2024 19:19:59 +0200 Subject: [PATCH 2/7] Remove placeholder dunder methods --- crates/ruff_linter/src/rules/pylint/helpers.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index dab3b607173e2..0bb97acdbf400 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -326,11 +326,8 @@ pub(super) fn is_deprecated_dunder_method_in_python3(method: &str) -> bool { | "__hex__" | "__members__" | "__method__" - | "__corece__" + | "__coerce__" | "__long__" | "__rcmp__" - | "__iop__" - | "__rop__" - | "__op__" ) } From f5d5a4bdcdc9ec3e7d8bb3ef5b2ac489bbf4e736 Mon Sep 17 00:00:00 2001 From: Lucas Vieira dos Santos Date: Mon, 2 Sep 2024 21:13:22 +0200 Subject: [PATCH 3/7] Add enum for dunder method type --- .../ruff_linter/src/rules/pylint/helpers.rs | 33 +++++++++-------- .../pylint/rules/bad_dunder_method_name.rs | 35 +++++++++---------- ...ts__PLW3201_bad_dunder_method_name.py.snap | 2 +- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 0bb97acdbf400..eafeeefb350f3 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -168,10 +168,16 @@ impl<'a> Visitor<'_> for SequenceIndexVisitor<'a> { } } -/// Returns `true` if a method is a known dunder method. -pub(super) fn is_known_dunder_method(method: &str) -> bool { - matches!( - method, +/// The kind of dunder method. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(super) enum DunderMethodKind { + Known, + Removed, +} + +/// Returns the kind of dunder method. +pub(super) fn dunder_method_kind(method: &str) -> Option { + match method { "__abs__" | "__add__" | "__aenter__" @@ -304,14 +310,7 @@ pub(super) fn is_known_dunder_method(method: &str) -> bool { | "_missing_" | "_ignore_" | "_order_" - | "_generate_next_value_" - ) -} - -/// Returns `true` if the method is a known dunder method that is only allowed in Python 2. -pub(super) fn is_deprecated_dunder_method_in_python3(method: &str) -> bool { - matches!( - method, + | "_generate_next_value_" => Some(DunderMethodKind::Known), "__unicode__" | "__div__" | "__rdiv__" @@ -328,6 +327,12 @@ pub(super) fn is_deprecated_dunder_method_in_python3(method: &str) -> bool { | "__method__" | "__coerce__" | "__long__" - | "__rcmp__" - ) + | "__rcmp__" => Some(DunderMethodKind::Removed), + _ => None, + } +} + +/// Returns `true` if a method is a known dunder method. +pub(super) fn is_known_dunder_method(method: &str) -> bool { + dunder_method_kind(method) == Some(DunderMethodKind::Known) } diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs index e77a1490d128f..5d9005e675e19 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -5,20 +5,19 @@ use ruff_python_ast::identifier::Identifier; use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; -use crate::rules::pylint::helpers::is_deprecated_dunder_method_in_python3; -use crate::rules::pylint::helpers::is_known_dunder_method; +use crate::rules::pylint::helpers::{dunder_method_kind, DunderMethodKind}; -#[derive(PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] enum Kind { Misspelled, - DeprecatedInPython3, + RemovedInPython3, } /// ## What it does -/// Checks for misspelled, unknown, and deprecated dunder names in method definitions. +/// Checks for misspelled, unknown, and no longer supported dunder names in method definitions. /// /// ## Why is this bad? -/// Misspelled or deprecated dunder name methods may cause your code to not function +/// Misspelled or no longer supported dunder name methods may cause your code to not function /// as expected. /// /// Since dunder methods are associated with customizing the behavior @@ -61,8 +60,8 @@ impl Violation for BadDunderMethodName { let BadDunderMethodName { name, kind } = self; match kind { Kind::Misspelled => format!("Bad or misspelled dunder method name `{name}`"), - Kind::DeprecatedInPython3 => { - format!("Deprecated dunder method name in Python 3 `{name}`") + Kind::RemovedInPython3 => { + format!("Python 2 or older only dunder method name `{name}`") } } } @@ -76,12 +75,11 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, method: &ast::StmtFu } // If the name is explicitly allowed, skip it. - if is_known_dunder_method(&method.name) - || checker - .settings - .pylint - .allow_dunder_method_names - .contains(method.name.as_str()) + if checker + .settings + .pylint + .allow_dunder_method_names + .contains(method.name.as_str()) || matches!(method.name.as_str(), "_") { return; @@ -91,10 +89,11 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, method: &ast::StmtFu return; } - let kind = if is_deprecated_dunder_method_in_python3(&method.name) { - Kind::DeprecatedInPython3 - } else { - Kind::Misspelled + // If the method is known, skip it. + let kind = match dunder_method_kind(&method.name) { + Some(DunderMethodKind::Known) => return, + Some(DunderMethodKind::Removed) => Kind::RemovedInPython3, + None => Kind::Misspelled, }; checker.diagnostics.push(Diagnostic::new( diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap index 8757dd5579c03..abe506a86fd2e 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap @@ -58,7 +58,7 @@ bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__ 25 | pass | -bad_dunder_method_name.py:98:9: PLW3201 Deprecated dunder method name in Python 3 `__unicode__` +bad_dunder_method_name.py:98:9: PLW3201 Python 2 or older only dunder method name `__unicode__` | 97 | # Deprecated in Python 3 98 | def __unicode__(self): From fc9744e7f6ac50b05716b6d22d19b553dc38ada7 Mon Sep 17 00:00:00 2001 From: Lucas Vieira dos Santos Date: Mon, 2 Sep 2024 21:16:18 +0200 Subject: [PATCH 4/7] Remove comma in documentation --- .../src/rules/pylint/rules/bad_dunder_method_name.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs index 5d9005e675e19..b33bbad692e38 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -14,7 +14,7 @@ enum Kind { } /// ## What it does -/// Checks for misspelled, unknown, and no longer supported dunder names in method definitions. +/// Checks for misspelled, unknown and no longer supported dunder names in method definitions. /// /// ## Why is this bad? /// Misspelled or no longer supported dunder name methods may cause your code to not function From 9fff288e74a3a131629e6eb411c70de4a189650d Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Tue, 3 Sep 2024 08:06:03 +0200 Subject: [PATCH 5/7] Apply suggestions from code review --- .../resources/test/fixtures/pylint/bad_dunder_method_name.py | 2 +- ...rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py index 0385284c798d2..32c8c4c44d887 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/bad_dunder_method_name.py @@ -94,7 +94,7 @@ def __prepare__(): def __mro_entries__(self, bases): pass - # Deprecated in Python 3 + # Removed with Python 3 def __unicode__(self): pass diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap index abe506a86fd2e..3073909f8a48f 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap @@ -60,7 +60,7 @@ bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__ bad_dunder_method_name.py:98:9: PLW3201 Python 2 or older only dunder method name `__unicode__` | -97 | # Deprecated in Python 3 +97 | # Removed with Python 3 98 | def __unicode__(self): | ^^^^^^^^^^^ PLW3201 99 | pass From 086f6c5e53480c21ab681f676b9597a60b688f45 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Tue, 3 Sep 2024 08:10:57 +0200 Subject: [PATCH 6/7] Sort dunder methods by name --- .../ruff_linter/src/rules/pylint/helpers.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index eafeeefb350f3..8fcadb6b10b91 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -311,23 +311,23 @@ pub(super) fn dunder_method_kind(method: &str) -> Option { | "_ignore_" | "_order_" | "_generate_next_value_" => Some(DunderMethodKind::Known), - "__unicode__" - | "__div__" - | "__rdiv__" - | "__idiv__" - | "__nonzero__" - | "__metaclass__" | "__cmp__" - | "__getslice__" - | "__setslice__" + | "__coerce__" | "__delslice__" - | "__oct__" + | "__div__" + | "__getslice__" | "__hex__" + | "__idiv__" + | "__long__" | "__members__" + | "__metaclass__" | "__method__" - | "__coerce__" - | "__long__" - | "__rcmp__" => Some(DunderMethodKind::Removed), + | "__nonzero__" + | "__oct__" + | "__rcmp__" + | "__rdiv__" + | "__setslice__" + | "__unicode__"=> Some(DunderMethodKind::Removed), _ => None, } } From f075343775f6b02e8562a3a7e8d705d0e98ceafc Mon Sep 17 00:00:00 2001 From: Lucas Vieira dos Santos Date: Tue, 3 Sep 2024 19:21:57 +0200 Subject: [PATCH 7/7] Remove distinction between mispelled and removed dunder methods --- .../ruff_linter/src/rules/pylint/helpers.rs | 41 +++---------------- .../pylint/rules/bad_dunder_method_name.rs | 39 +++++------------- ...ts__PLW3201_bad_dunder_method_name.py.snap | 14 +++---- 3 files changed, 23 insertions(+), 71 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/helpers.rs b/crates/ruff_linter/src/rules/pylint/helpers.rs index 8fcadb6b10b91..081f034f97191 100644 --- a/crates/ruff_linter/src/rules/pylint/helpers.rs +++ b/crates/ruff_linter/src/rules/pylint/helpers.rs @@ -168,16 +168,10 @@ impl<'a> Visitor<'_> for SequenceIndexVisitor<'a> { } } -/// The kind of dunder method. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum DunderMethodKind { - Known, - Removed, -} - -/// Returns the kind of dunder method. -pub(super) fn dunder_method_kind(method: &str) -> Option { - match method { +/// Returns `true` if a method is a known dunder method. +pub(super) fn is_known_dunder_method(method: &str) -> bool { + matches!( + method, "__abs__" | "__add__" | "__aenter__" @@ -310,29 +304,6 @@ pub(super) fn dunder_method_kind(method: &str) -> Option { | "_missing_" | "_ignore_" | "_order_" - | "_generate_next_value_" => Some(DunderMethodKind::Known), - | "__cmp__" - | "__coerce__" - | "__delslice__" - | "__div__" - | "__getslice__" - | "__hex__" - | "__idiv__" - | "__long__" - | "__members__" - | "__metaclass__" - | "__method__" - | "__nonzero__" - | "__oct__" - | "__rcmp__" - | "__rdiv__" - | "__setslice__" - | "__unicode__"=> Some(DunderMethodKind::Removed), - _ => None, - } -} - -/// Returns `true` if a method is a known dunder method. -pub(super) fn is_known_dunder_method(method: &str) -> bool { - dunder_method_kind(method) == Some(DunderMethodKind::Known) + | "_generate_next_value_" + ) } diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs index b33bbad692e38..95dc16ab9cd6f 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -5,16 +5,10 @@ use ruff_python_ast::identifier::Identifier; use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; -use crate::rules::pylint::helpers::{dunder_method_kind, DunderMethodKind}; - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum Kind { - Misspelled, - RemovedInPython3, -} +use crate::rules::pylint::helpers::is_known_dunder_method; /// ## What it does -/// Checks for misspelled, unknown and no longer supported dunder names in method definitions. +/// Checks for dunder methods that have no special meaning in Python 3. /// /// ## Why is this bad? /// Misspelled or no longer supported dunder name methods may cause your code to not function @@ -51,19 +45,13 @@ enum Kind { #[violation] pub struct BadDunderMethodName { name: String, - kind: Kind, } impl Violation for BadDunderMethodName { #[derive_message_formats] fn message(&self) -> String { - let BadDunderMethodName { name, kind } = self; - match kind { - Kind::Misspelled => format!("Bad or misspelled dunder method name `{name}`"), - Kind::RemovedInPython3 => { - format!("Python 2 or older only dunder method name `{name}`") - } - } + let BadDunderMethodName { name } = self; + format!("Dunder method `{name}` has no special meaning in Python 3") } } @@ -75,11 +63,12 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, method: &ast::StmtFu } // If the name is explicitly allowed, skip it. - if checker - .settings - .pylint - .allow_dunder_method_names - .contains(method.name.as_str()) + if is_known_dunder_method(&method.name) + || checker + .settings + .pylint + .allow_dunder_method_names + .contains(method.name.as_str()) || matches!(method.name.as_str(), "_") { return; @@ -89,17 +78,9 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, method: &ast::StmtFu return; } - // If the method is known, skip it. - let kind = match dunder_method_kind(&method.name) { - Some(DunderMethodKind::Known) => return, - Some(DunderMethodKind::Removed) => Kind::RemovedInPython3, - None => Kind::Misspelled, - }; - checker.diagnostics.push(Diagnostic::new( BadDunderMethodName { name: method.name.to_string(), - kind, }, method.identifier(), )); diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap index 3073909f8a48f..a98abee052372 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pylint/mod.rs --- -bad_dunder_method_name.py:5:9: PLW3201 Bad or misspelled dunder method name `_init_` +bad_dunder_method_name.py:5:9: PLW3201 Dunder method `_init_` has no special meaning in Python 3 | 4 | class Apples: 5 | def _init_(self): # [bad-dunder-name] @@ -9,7 +9,7 @@ bad_dunder_method_name.py:5:9: PLW3201 Bad or misspelled dunder method name `_in 6 | pass | -bad_dunder_method_name.py:8:9: PLW3201 Bad or misspelled dunder method name `__hello__` +bad_dunder_method_name.py:8:9: PLW3201 Dunder method `__hello__` has no special meaning in Python 3 | 6 | pass 7 | @@ -18,7 +18,7 @@ bad_dunder_method_name.py:8:9: PLW3201 Bad or misspelled dunder method name `__h 9 | print("hello") | -bad_dunder_method_name.py:11:9: PLW3201 Bad or misspelled dunder method name `__init_` +bad_dunder_method_name.py:11:9: PLW3201 Dunder method `__init_` has no special meaning in Python 3 | 9 | print("hello") 10 | @@ -28,7 +28,7 @@ bad_dunder_method_name.py:11:9: PLW3201 Bad or misspelled dunder method name `__ 13 | pass | -bad_dunder_method_name.py:15:9: PLW3201 Bad or misspelled dunder method name `_init_` +bad_dunder_method_name.py:15:9: PLW3201 Dunder method `_init_` has no special meaning in Python 3 | 13 | pass 14 | @@ -38,7 +38,7 @@ bad_dunder_method_name.py:15:9: PLW3201 Bad or misspelled dunder method name `_i 17 | pass | -bad_dunder_method_name.py:19:9: PLW3201 Bad or misspelled dunder method name `___neg__` +bad_dunder_method_name.py:19:9: PLW3201 Dunder method `___neg__` has no special meaning in Python 3 | 17 | pass 18 | @@ -48,7 +48,7 @@ bad_dunder_method_name.py:19:9: PLW3201 Bad or misspelled dunder method name `__ 21 | pass | -bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__inv__` +bad_dunder_method_name.py:23:9: PLW3201 Dunder method `__inv__` has no special meaning in Python 3 | 21 | pass 22 | @@ -58,7 +58,7 @@ bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__ 25 | pass | -bad_dunder_method_name.py:98:9: PLW3201 Python 2 or older only dunder method name `__unicode__` +bad_dunder_method_name.py:98:9: PLW3201 Dunder method `__unicode__` has no special meaning in Python 3 | 97 | # Removed with Python 3 98 | def __unicode__(self):