From b4419c34ea8f820157cf428e2bf5f7f2d415c894 Mon Sep 17 00:00:00 2001 From: Brendon Happ <33680533+brendonh8@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:54:40 -0400 Subject: [PATCH] Ignore `@override` method when enforcing `bad-dunder-name` rule (#7224) ## Summary Closes #6958. If a method has the `override` decorator, there is nothing you can do about incorrect dunder methods, so they should be ignored. ## Test Plan Overridden incorrect dunder method was added to the tests to verify ruff doesn't catch it when evaluating the file. Snapshot changes are all just line number changes --- .../fixtures/pylint/bad_dunder_method_name.py | 8 +++ .../pylint/rules/bad_dunder_method_name.rs | 17 ++--- ...ts__PLW3201_bad_dunder_method_name.py.snap | 66 +++++++++---------- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/crates/ruff/resources/test/fixtures/pylint/bad_dunder_method_name.py b/crates/ruff/resources/test/fixtures/pylint/bad_dunder_method_name.py index 46d8be249bc95..ee4a12b43522d 100644 --- a/crates/ruff/resources/test/fixtures/pylint/bad_dunder_method_name.py +++ b/crates/ruff/resources/test/fixtures/pylint/bad_dunder_method_name.py @@ -1,3 +1,6 @@ +from typing import override + + class Apples: def _init_(self): # [bad-dunder-name] pass @@ -21,6 +24,11 @@ def __inv__(self): # [bad-dunder-name] # author likely meant to call the invert dunder method pass + @override + def _ignore__(self): # [bad-dunder-name] + # overridden dunder methods should be ignored + pass + def hello(self): print("hello") diff --git a/crates/ruff/src/rules/pylint/rules/bad_dunder_method_name.rs b/crates/ruff/src/rules/pylint/rules/bad_dunder_method_name.rs index e7a3149e4fcf3..5ac20b018f5d0 100644 --- a/crates/ruff/src/rules/pylint/rules/bad_dunder_method_name.rs +++ b/crates/ruff/src/rules/pylint/rules/bad_dunder_method_name.rs @@ -2,18 +2,12 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::identifier::Identifier; use ruff_python_ast::Stmt; +use ruff_python_semantic::analyze::visibility; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for any misspelled dunder name method and for any method -/// defined with `_..._` that's not one of the pre-defined methods -/// -/// The pre-defined methods encompass all of Python's standard dunder -/// methods. -/// -/// Note this includes all methods starting and ending with at least -/// one underscore to detect mistakes. +/// Checks for misspelled and unknown dunder names in method definitions. /// /// ## Why is this bad? /// Misspelled dunder name methods may cause your code to not function @@ -24,6 +18,10 @@ use crate::checkers::ast::Checker; /// that diverges from standard Python dunder methods could potentially /// confuse someone reading the code. /// +/// This rule will detect all methods starting and ending with at least +/// one underscore (e.g., `_str_`), but ignores known dunder methods (like +/// `__init__`), as well as methods that are marked with `@override`. +/// /// ## Example /// ```python /// class Foo: @@ -62,6 +60,9 @@ pub(crate) fn bad_dunder_method_name(checker: &mut Checker, class_body: &[Stmt]) method.name.starts_with('_') && method.name.ends_with('_') }) { + if visibility::is_override(&method.decorator_list, checker.semantic()) { + continue; + } checker.diagnostics.push(Diagnostic::new( BadDunderMethodName { name: method.name.to_string(), diff --git a/crates/ruff/src/rules/pylint/snapshots/ruff__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap b/crates/ruff/src/rules/pylint/snapshots/ruff__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap index f3c6b8166115c..286c40fb39b5b 100644 --- a/crates/ruff/src/rules/pylint/snapshots/ruff__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap +++ b/crates/ruff/src/rules/pylint/snapshots/ruff__rules__pylint__tests__PLW3201_bad_dunder_method_name.py.snap @@ -1,61 +1,61 @@ --- source: crates/ruff/src/rules/pylint/mod.rs --- -bad_dunder_method_name.py:2:9: PLW3201 Bad or misspelled dunder method name `_init_`. (bad-dunder-name) +bad_dunder_method_name.py:5:9: PLW3201 Bad or misspelled dunder method name `_init_`. (bad-dunder-name) | -1 | class Apples: -2 | def _init_(self): # [bad-dunder-name] +4 | class Apples: +5 | def _init_(self): # [bad-dunder-name] | ^^^^^^ PLW3201 -3 | pass +6 | pass | -bad_dunder_method_name.py:5:9: PLW3201 Bad or misspelled dunder method name `__hello__`. (bad-dunder-name) +bad_dunder_method_name.py:8:9: PLW3201 Bad or misspelled dunder method name `__hello__`. (bad-dunder-name) | -3 | pass -4 | -5 | def __hello__(self): # [bad-dunder-name] +6 | pass +7 | +8 | def __hello__(self): # [bad-dunder-name] | ^^^^^^^^^ PLW3201 -6 | print("hello") +9 | print("hello") | -bad_dunder_method_name.py:8:9: PLW3201 Bad or misspelled dunder method name `__init_`. (bad-dunder-name) +bad_dunder_method_name.py:11:9: PLW3201 Bad or misspelled dunder method name `__init_`. (bad-dunder-name) | - 6 | print("hello") - 7 | - 8 | def __init_(self): # [bad-dunder-name] + 9 | print("hello") +10 | +11 | def __init_(self): # [bad-dunder-name] | ^^^^^^^ PLW3201 - 9 | # author likely unintentionally misspelled the correct init dunder. -10 | pass +12 | # author likely unintentionally misspelled the correct init dunder. +13 | pass | -bad_dunder_method_name.py:12:9: PLW3201 Bad or misspelled dunder method name `_init_`. (bad-dunder-name) +bad_dunder_method_name.py:15:9: PLW3201 Bad or misspelled dunder method name `_init_`. (bad-dunder-name) | -10 | pass -11 | -12 | def _init_(self): # [bad-dunder-name] +13 | pass +14 | +15 | def _init_(self): # [bad-dunder-name] | ^^^^^^ PLW3201 -13 | # author likely unintentionally misspelled the correct init dunder. -14 | pass +16 | # author likely unintentionally misspelled the correct init dunder. +17 | pass | -bad_dunder_method_name.py:16:9: PLW3201 Bad or misspelled dunder method name `___neg__`. (bad-dunder-name) +bad_dunder_method_name.py:19:9: PLW3201 Bad or misspelled dunder method name `___neg__`. (bad-dunder-name) | -14 | pass -15 | -16 | def ___neg__(self): # [bad-dunder-name] +17 | pass +18 | +19 | def ___neg__(self): # [bad-dunder-name] | ^^^^^^^^ PLW3201 -17 | # author likely accidentally added an additional `_` -18 | pass +20 | # author likely accidentally added an additional `_` +21 | pass | -bad_dunder_method_name.py:20:9: PLW3201 Bad or misspelled dunder method name `__inv__`. (bad-dunder-name) +bad_dunder_method_name.py:23:9: PLW3201 Bad or misspelled dunder method name `__inv__`. (bad-dunder-name) | -18 | pass -19 | -20 | def __inv__(self): # [bad-dunder-name] +21 | pass +22 | +23 | def __inv__(self): # [bad-dunder-name] | ^^^^^^^ PLW3201 -21 | # author likely meant to call the invert dunder method -22 | pass +24 | # author likely meant to call the invert dunder method +25 | pass |