mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
[pep8-naming
] Ignore @override
methods (N803
) (#15954)
## Summary Resolves #15925. `N803` now checks for functions instead of parameters. In preview mode, if a method is decorated with `@override` and the current scope is that of a class, it will be ignored. ## Test Plan `cargo nextest run` and `cargo insta test`.
This commit is contained in:
parent
5852217198
commit
82cb8675dd
8 changed files with 162 additions and 28 deletions
|
@ -9,3 +9,21 @@ class Class:
|
|||
|
||||
def func(_, setUp):
|
||||
return _, setUp
|
||||
|
||||
|
||||
from typing import override
|
||||
|
||||
class Extended(Class):
|
||||
@override
|
||||
def method(self, _, a, A): ...
|
||||
|
||||
|
||||
@override # Incorrect usage
|
||||
def func(_, a, A): ...
|
||||
|
||||
|
||||
func = lambda _, a, A: ...
|
||||
|
||||
|
||||
class Extended(Class):
|
||||
method = override(lambda self, _, a, A: ...) # Incorrect usage
|
||||
|
|
|
@ -1746,9 +1746,12 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
ruff::rules::parenthesize_chained_logical_operators(checker, bool_op);
|
||||
}
|
||||
}
|
||||
Expr::Lambda(lambda_expr) => {
|
||||
Expr::Lambda(lambda) => {
|
||||
if checker.enabled(Rule::ReimplementedOperator) {
|
||||
refurb::rules::reimplemented_operator(checker, &lambda_expr.into());
|
||||
refurb::rules::reimplemented_operator(checker, &lambda.into());
|
||||
}
|
||||
if checker.enabled(Rule::InvalidArgumentName) {
|
||||
pep8_naming::rules::invalid_argument_name_lambda(checker, lambda);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -3,7 +3,7 @@ use ruff_text_size::Ranged;
|
|||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::rules::{flake8_builtins, pep8_naming, pycodestyle};
|
||||
use crate::rules::{flake8_builtins, pycodestyle};
|
||||
|
||||
/// Run lint rules over a [`Parameter`] syntax node.
|
||||
pub(crate) fn parameter(parameter: &Parameter, checker: &mut Checker) {
|
||||
|
@ -14,15 +14,6 @@ pub(crate) fn parameter(parameter: &Parameter, checker: &mut Checker) {
|
|||
parameter.name.range(),
|
||||
);
|
||||
}
|
||||
if checker.enabled(Rule::InvalidArgumentName) {
|
||||
if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name(
|
||||
¶meter.name,
|
||||
parameter,
|
||||
&checker.settings.pep8_naming.ignore_names,
|
||||
) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::BuiltinArgumentShadowing) {
|
||||
flake8_builtins::rules::builtin_argument_shadowing(checker, parameter);
|
||||
}
|
||||
|
|
|
@ -379,6 +379,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::NonPEP695GenericFunction) {
|
||||
pyupgrade::rules::non_pep695_generic_function(checker, function_def);
|
||||
}
|
||||
if checker.enabled(Rule::InvalidArgumentName) {
|
||||
pep8_naming::rules::invalid_argument_name_function(checker, function_def);
|
||||
}
|
||||
}
|
||||
Stmt::Return(_) => {
|
||||
if checker.enabled(Rule::ReturnOutsideFunction) {
|
||||
|
|
|
@ -14,6 +14,7 @@ mod tests {
|
|||
use crate::registry::Rule;
|
||||
use crate::rules::pep8_naming::settings::IgnoreNames;
|
||||
use crate::rules::{flake8_import_conventions, pep8_naming};
|
||||
use crate::settings::types::PreviewMode;
|
||||
use crate::test::test_path;
|
||||
use crate::{assert_messages, settings};
|
||||
|
||||
|
@ -88,6 +89,24 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(Rule::InvalidArgumentName, Path::new("N803.py"))]
|
||||
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!(
|
||||
"preview__{}_{}",
|
||||
rule_code.noqa_code(),
|
||||
path.to_string_lossy()
|
||||
);
|
||||
let diagnostics = test_path(
|
||||
Path::new("pep8_naming").join(path).as_path(),
|
||||
&settings::LinterSettings {
|
||||
preview: PreviewMode::Enabled,
|
||||
..settings::LinterSettings::for_rule(rule_code)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn camelcase_imported_as_incorrect_convention() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use ruff_python_ast::Parameter;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::{ExprLambda, Parameters, StmtFunctionDef};
|
||||
use ruff_python_semantic::analyze::visibility::is_override;
|
||||
use ruff_python_semantic::ScopeKind;
|
||||
use ruff_python_stdlib::str;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::rules::pep8_naming::settings::IgnoreNames;
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for argument names that do not follow the `snake_case` convention.
|
||||
|
@ -22,6 +23,8 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
|
|||
/// > mixedCase is allowed only in contexts where that’s already the
|
||||
/// > prevailing style (e.g. threading.py), to retain backwards compatibility.
|
||||
///
|
||||
/// In [preview], overridden methods are ignored.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def my_function(A, myArg):
|
||||
|
@ -35,6 +38,7 @@ use crate::rules::pep8_naming::settings::IgnoreNames;
|
|||
/// ```
|
||||
///
|
||||
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments
|
||||
/// [preview]: https://docs.astral.sh/ruff/preview/
|
||||
#[derive(ViolationMetadata)]
|
||||
pub(crate) struct InvalidArgumentName {
|
||||
name: String,
|
||||
|
@ -49,22 +53,54 @@ impl Violation for InvalidArgumentName {
|
|||
}
|
||||
|
||||
/// N803
|
||||
pub(crate) fn invalid_argument_name(
|
||||
name: &str,
|
||||
parameter: &Parameter,
|
||||
ignore_names: &IgnoreNames,
|
||||
) -> Option<Diagnostic> {
|
||||
if !str::is_lowercase(name) {
|
||||
// Ignore any explicitly-allowed names.
|
||||
if ignore_names.matches(name) {
|
||||
return None;
|
||||
pub(crate) fn invalid_argument_name_function(
|
||||
checker: &mut Checker,
|
||||
function_def: &StmtFunctionDef,
|
||||
) {
|
||||
let semantic = checker.semantic();
|
||||
let scope = semantic.current_scope();
|
||||
|
||||
if checker.settings.preview.is_enabled()
|
||||
&& matches!(scope.kind, ScopeKind::Class(_))
|
||||
&& is_override(&function_def.decorator_list, semantic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
invalid_argument_name(checker, &function_def.parameters);
|
||||
}
|
||||
|
||||
/// N803
|
||||
pub(crate) fn invalid_argument_name_lambda(checker: &mut Checker, lambda: &ExprLambda) {
|
||||
let Some(parameters) = &lambda.parameters else {
|
||||
return;
|
||||
};
|
||||
|
||||
invalid_argument_name(checker, parameters);
|
||||
}
|
||||
|
||||
/// N803
|
||||
fn invalid_argument_name(checker: &mut Checker, parameters: &Parameters) {
|
||||
let ignore_names = &checker.settings.pep8_naming.ignore_names;
|
||||
|
||||
for parameter in parameters {
|
||||
let name = parameter.name().as_str();
|
||||
|
||||
if str::is_lowercase(name) {
|
||||
continue;
|
||||
}
|
||||
return Some(Diagnostic::new(
|
||||
|
||||
if ignore_names.matches(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let diagnostic = Diagnostic::new(
|
||||
InvalidArgumentName {
|
||||
name: name.to_string(),
|
||||
},
|
||||
parameter.range(),
|
||||
));
|
||||
);
|
||||
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
N803.py:1:16: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
|
@ -16,3 +15,31 @@ N803.py:6:28: N803 Argument name `A` should be lowercase
|
|||
| ^ N803
|
||||
7 | return _, a, A
|
||||
|
|
||||
|
||||
N803.py:18:28: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
16 | class Extended(Class):
|
||||
17 | @override
|
||||
18 | def method(self, _, a, A): ...
|
||||
| ^ N803
|
||||
|
|
||||
|
||||
N803.py:22:16: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
21 | @override # Incorrect usage
|
||||
22 | def func(_, a, A): ...
|
||||
| ^ N803
|
||||
|
|
||||
|
||||
N803.py:25:21: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
25 | func = lambda _, a, A: ...
|
||||
| ^ N803
|
||||
|
|
||||
|
||||
N803.py:29:42: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
28 | class Extended(Class):
|
||||
29 | method = override(lambda self, _, a, A: ...) # Incorrect usage
|
||||
| ^ N803
|
||||
|
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
|
||||
---
|
||||
N803.py:1:16: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
1 | def func(_, a, A):
|
||||
| ^ N803
|
||||
2 | return _, a, A
|
||||
|
|
||||
|
||||
N803.py:6:28: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
5 | class Class:
|
||||
6 | def method(self, _, a, A):
|
||||
| ^ N803
|
||||
7 | return _, a, A
|
||||
|
|
||||
|
||||
N803.py:22:16: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
21 | @override # Incorrect usage
|
||||
22 | def func(_, a, A): ...
|
||||
| ^ N803
|
||||
|
|
||||
|
||||
N803.py:25:21: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
25 | func = lambda _, a, A: ...
|
||||
| ^ N803
|
||||
|
|
||||
|
||||
N803.py:29:42: N803 Argument name `A` should be lowercase
|
||||
|
|
||||
28 | class Extended(Class):
|
||||
29 | method = override(lambda self, _, a, A: ...) # Incorrect usage
|
||||
| ^ N803
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue