mirror of
https://github.com/astral-sh/ruff.git
synced 2025-12-04 09:42:47 +00:00
Avoid A003 violations for explicitly overridden methods (#6076)
## Summary If a method is annotated with `@typing_extensions.override`, we should avoid flagging A003 on it. This isn't part of the standard library yet, but it's used to explicitly mark methods as overrides.
This commit is contained in:
parent
f5c69c1b34
commit
9171bd4c28
5 changed files with 65 additions and 3 deletions
|
|
@ -39,3 +39,15 @@ class CustomFilter(Filter):
|
||||||
|
|
||||||
def str(self) -> None:
|
def str(self) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
from typing_extensions import override
|
||||||
|
|
||||||
|
|
||||||
|
class MyClass:
|
||||||
|
@override
|
||||||
|
def str(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def int(self):
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -332,10 +332,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||||
}
|
}
|
||||||
if let ScopeKind::Class(class_def) = checker.semantic.scope().kind {
|
if let ScopeKind::Class(class_def) = checker.semantic.scope().kind {
|
||||||
if checker.enabled(Rule::BuiltinAttributeShadowing) {
|
if checker.enabled(Rule::BuiltinAttributeShadowing) {
|
||||||
flake8_builtins::rules::builtin_attribute_shadowing(
|
flake8_builtins::rules::builtin_method_shadowing(
|
||||||
checker,
|
checker,
|
||||||
class_def,
|
class_def,
|
||||||
name,
|
name,
|
||||||
|
decorator_list,
|
||||||
name.range(),
|
name.range(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
use rustpython_parser::ast;
|
use rustpython_parser::ast;
|
||||||
|
use rustpython_parser::ast::Decorator;
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
use ruff_diagnostics::Violation;
|
use ruff_diagnostics::Violation;
|
||||||
|
|
@ -10,7 +11,8 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::rules::flake8_builtins::helpers::shadows_builtin;
|
use crate::rules::flake8_builtins::helpers::shadows_builtin;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for any class attributes that use the same name as a builtin.
|
/// Checks for any class attributes or methods that use the same name as a
|
||||||
|
/// builtin.
|
||||||
///
|
///
|
||||||
/// ## Why is this bad?
|
/// ## Why is this bad?
|
||||||
/// Reusing a builtin name for the name of an attribute increases the
|
/// Reusing a builtin name for the name of an attribute increases the
|
||||||
|
|
@ -20,7 +22,9 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
|
||||||
///
|
///
|
||||||
/// Builtins can be marked as exceptions to this rule via the
|
/// Builtins can be marked as exceptions to this rule via the
|
||||||
/// [`flake8-builtins.builtins-ignorelist`] configuration option, or
|
/// [`flake8-builtins.builtins-ignorelist`] configuration option, or
|
||||||
/// converted to the appropriate dunder method.
|
/// converted to the appropriate dunder method. Methods decorated with
|
||||||
|
/// `@typing.override` or `@typing_extensions.override` are also
|
||||||
|
/// ignored.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
|
|
@ -81,12 +85,39 @@ pub(crate) fn builtin_attribute_shadowing(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
BuiltinAttributeShadowing {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
range,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A003
|
||||||
|
pub(crate) fn builtin_method_shadowing(
|
||||||
|
checker: &mut Checker,
|
||||||
|
class_def: &ast::StmtClassDef,
|
||||||
|
name: &str,
|
||||||
|
decorator_list: &[Decorator],
|
||||||
|
range: TextRange,
|
||||||
|
) {
|
||||||
|
if shadows_builtin(name, &checker.settings.flake8_builtins.builtins_ignorelist) {
|
||||||
// Ignore some standard-library methods. Ideally, we'd ignore all overridden methods, since
|
// Ignore some standard-library methods. Ideally, we'd ignore all overridden methods, since
|
||||||
// those should be flagged on the superclass, but that's more difficult.
|
// those should be flagged on the superclass, but that's more difficult.
|
||||||
if is_standard_library_override(name, class_def, checker.semantic()) {
|
if is_standard_library_override(name, class_def, checker.semantic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore explicit overrides.
|
||||||
|
if decorator_list.iter().any(|decorator| {
|
||||||
|
checker
|
||||||
|
.semantic()
|
||||||
|
.match_typing_expr(&decorator.expression, "override")
|
||||||
|
}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
BuiltinAttributeShadowing {
|
BuiltinAttributeShadowing {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -56,4 +56,13 @@ A003.py:40:9: A003 Class attribute `str` is shadowing a Python builtin
|
||||||
41 | ...
|
41 | ...
|
||||||
|
|
|
|
||||||
|
|
||||||
|
A003.py:52:9: A003 Class attribute `int` is shadowing a Python builtin
|
||||||
|
|
|
||||||
|
50 | pass
|
||||||
|
51 |
|
||||||
|
52 | def int(self):
|
||||||
|
| ^^^ A003
|
||||||
|
53 | pass
|
||||||
|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,13 @@ A003.py:40:9: A003 Class attribute `str` is shadowing a Python builtin
|
||||||
41 | ...
|
41 | ...
|
||||||
|
|
|
|
||||||
|
|
||||||
|
A003.py:52:9: A003 Class attribute `int` is shadowing a Python builtin
|
||||||
|
|
|
||||||
|
50 | pass
|
||||||
|
51 |
|
||||||
|
52 | def int(self):
|
||||||
|
| ^^^ A003
|
||||||
|
53 | pass
|
||||||
|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue