[`flake8-builtins`] Skip lambda expressions in `builtin-argument-shadowing (A002)` (#14144)

Flake8-builtins provides two checks for arguments (really, parameters)
of a function shadowing builtins: A002 checks function definitions, and
A006 checks lambda expressions. This PR ensures that A002 is restricted
to functions rather than lambda expressions.

Closes #14135 .
This commit is contained in:
Dylan 2024-11-06 23:34:09 -06:00 committed by GitHub
parent 03a5788aa1
commit cb003ebe22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 34 additions and 32 deletions

View File

@ -10,6 +10,8 @@ async def func3(id, dir):
pass pass
# this is Ok for A002 (trigger A005 instead)
# https://github.com/astral-sh/ruff/issues/14135
map([], lambda float: ...) map([], lambda float: ...)
from typing import override, overload from typing import override, overload

View File

@ -3,3 +3,8 @@ lambda x, float, y: x + y
lambda min, max: min lambda min, max: min
lambda id: id lambda id: id
lambda dir: dir lambda dir: dir
# Ok for A006 - should trigger A002 instead
# https://github.com/astral-sh/ruff/issues/14135
def func1(str, /, type, *complex, Exception, **getattr):
pass

View File

@ -1,7 +1,7 @@
use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::Violation; use ruff_diagnostics::Violation;
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::Parameter; use ruff_python_ast::{Expr, Parameter};
use ruff_python_semantic::analyze::visibility::{is_overload, is_override}; use ruff_python_semantic::analyze::visibility::{is_overload, is_override};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
@ -58,7 +58,7 @@ impl Violation for BuiltinArgumentShadowing {
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
let BuiltinArgumentShadowing { name } = self; let BuiltinArgumentShadowing { name } = self;
format!("Argument `{name}` is shadowing a Python builtin") format!("Function argument `{name}` is shadowing a Python builtin")
} }
} }
@ -70,6 +70,15 @@ pub(crate) fn builtin_argument_shadowing(checker: &mut Checker, parameter: &Para
&checker.settings.flake8_builtins.builtins_ignorelist, &checker.settings.flake8_builtins.builtins_ignorelist,
checker.settings.target_version, checker.settings.target_version,
) { ) {
// Ignore parameters in lambda expressions.
// (That is the domain of A006.)
if checker
.semantic()
.current_expression()
.is_some_and(Expr::is_lambda_expr)
{
return;
}
// Ignore `@override` and `@overload` decorated functions. // Ignore `@override` and `@overload` decorated functions.
if checker if checker
.semantic() .semantic()

View File

@ -1,66 +1,58 @@
--- ---
source: crates/ruff_linter/src/rules/flake8_builtins/mod.rs source: crates/ruff_linter/src/rules/flake8_builtins/mod.rs
--- ---
A002.py:1:11: A002 Argument `str` is shadowing a Python builtin A002.py:1:11: A002 Function argument `str` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^ A002 | ^^^ A002
2 | pass 2 | pass
| |
A002.py:1:19: A002 Argument `type` is shadowing a Python builtin A002.py:1:19: A002 Function argument `type` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^ A002 | ^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:26: A002 Argument `complex` is shadowing a Python builtin A002.py:1:26: A002 Function argument `complex` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^ A002 | ^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:35: A002 Argument `Exception` is shadowing a Python builtin A002.py:1:35: A002 Function argument `Exception` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^^^ A002 | ^^^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:48: A002 Argument `getattr` is shadowing a Python builtin A002.py:1:48: A002 Function argument `getattr` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^ A002 | ^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:5:17: A002 Argument `bytes` is shadowing a Python builtin A002.py:5:17: A002 Function argument `bytes` is shadowing a Python builtin
| |
5 | async def func2(bytes): 5 | async def func2(bytes):
| ^^^^^ A002 | ^^^^^ A002
6 | pass 6 | pass
| |
A002.py:9:17: A002 Argument `id` is shadowing a Python builtin A002.py:9:17: A002 Function argument `id` is shadowing a Python builtin
| |
9 | async def func3(id, dir): 9 | async def func3(id, dir):
| ^^ A002 | ^^ A002
10 | pass 10 | pass
| |
A002.py:9:21: A002 Argument `dir` is shadowing a Python builtin A002.py:9:21: A002 Function argument `dir` is shadowing a Python builtin
| |
9 | async def func3(id, dir): 9 | async def func3(id, dir):
| ^^^ A002 | ^^^ A002
10 | pass 10 | pass
| |
A002.py:13:16: A002 Argument `float` is shadowing a Python builtin
|
13 | map([], lambda float: ...)
| ^^^^^ A002
14 |
15 | from typing import override, overload
|

View File

@ -1,52 +1,44 @@
--- ---
source: crates/ruff_linter/src/rules/flake8_builtins/mod.rs source: crates/ruff_linter/src/rules/flake8_builtins/mod.rs
--- ---
A002.py:1:11: A002 Argument `str` is shadowing a Python builtin A002.py:1:11: A002 Function argument `str` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^ A002 | ^^^ A002
2 | pass 2 | pass
| |
A002.py:1:19: A002 Argument `type` is shadowing a Python builtin A002.py:1:19: A002 Function argument `type` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^ A002 | ^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:26: A002 Argument `complex` is shadowing a Python builtin A002.py:1:26: A002 Function argument `complex` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^ A002 | ^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:35: A002 Argument `Exception` is shadowing a Python builtin A002.py:1:35: A002 Function argument `Exception` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^^^ A002 | ^^^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:1:48: A002 Argument `getattr` is shadowing a Python builtin A002.py:1:48: A002 Function argument `getattr` is shadowing a Python builtin
| |
1 | def func1(str, /, type, *complex, Exception, **getattr): 1 | def func1(str, /, type, *complex, Exception, **getattr):
| ^^^^^^^ A002 | ^^^^^^^ A002
2 | pass 2 | pass
| |
A002.py:5:17: A002 Argument `bytes` is shadowing a Python builtin A002.py:5:17: A002 Function argument `bytes` is shadowing a Python builtin
| |
5 | async def func2(bytes): 5 | async def func2(bytes):
| ^^^^^ A002 | ^^^^^ A002
6 | pass 6 | pass
| |
A002.py:13:16: A002 Argument `float` is shadowing a Python builtin
|
13 | map([], lambda float: ...)
| ^^^^^ A002
14 |
15 | from typing import override, overload
|

View File

@ -61,4 +61,6 @@ A006.py:5:8: A006 Lambda argument `dir` is shadowing a Python builtin
4 | lambda id: id 4 | lambda id: id
5 | lambda dir: dir 5 | lambda dir: dir
| ^^^ A006 | ^^^ A006
6 |
7 | # Ok for A006 - should trigger A002 instead
| |