mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-27 18:36:35 +00:00
[flake8-bugbear] Skip B905 and B912 if <2 iterables and no starred arguments (#20998)
Closes #20997 This will _decrease_ the number of diagnostics emitted for [zip-without-explicit-strict (B905)](https://docs.astral.sh/ruff/rules/zip-without-explicit-strict/#zip-without-explicit-strict-b905), since previously it triggered on any `zip` call no matter the number of arguments. It may _increase_ the number of diagnostics for [map-without-explicit-strict (B912)](https://docs.astral.sh/ruff/rules/map-without-explicit-strict/#map-without-explicit-strict-b912) since it will now trigger on a single starred argument where before it would not. However, the latter rule is in `preview` so this is acceptable. Note - we do not need to make any changes to [batched-without-explicit-strict (B911)](https://docs.astral.sh/ruff/rules/batched-without-explicit-strict/#batched-without-explicit-strict-b911) since that just takes a single iterable. I am doing this in one PR rather than two because we should keep the behavior of these rules consistent with one another. For review: apologies for the unreadability of the snapshot for `B905`. Unfortunately I saw no way of keeping a small diff and a correct fixture (the fixture labeled a whole block as `# Error` whereas now several in the block became `# Ok`).Probably simplest to just view the actual snapshot - it's relatively small.
This commit is contained in:
parent
281ae8eb34
commit
d363d49ab7
6 changed files with 122 additions and 153 deletions
|
|
@ -1,12 +1,10 @@
|
|||
from itertools import count, cycle, repeat
|
||||
|
||||
# Errors
|
||||
zip()
|
||||
zip(range(3))
|
||||
zip("a", "b")
|
||||
zip("a", "b", *zip("c"))
|
||||
zip(zip("a"), strict=False)
|
||||
zip(zip("a", strict=True))
|
||||
zip(zip("a", "b"), strict=False)
|
||||
zip(zip("a", strict=True),"b")
|
||||
|
||||
# OK
|
||||
zip(range(3), strict=True)
|
||||
|
|
@ -27,3 +25,10 @@ zip([1, 2, 3], repeat(1, times=4))
|
|||
import builtins
|
||||
# Still an error even though it uses the qualified name
|
||||
builtins.zip([1, 2, 3])
|
||||
|
||||
# Regression https://github.com/astral-sh/ruff/issues/20997
|
||||
# Ok
|
||||
zip()
|
||||
zip(range(3))
|
||||
# Error
|
||||
zip(*lot_of_iterators)
|
||||
|
|
|
|||
|
|
@ -31,3 +31,6 @@ map(lambda x, y: x + y, [1, 2, 3], cycle([1, 2, 3]))
|
|||
map(lambda x, y: x + y, [1, 2, 3], repeat(1))
|
||||
map(lambda x, y: x + y, [1, 2, 3], repeat(1, times=None))
|
||||
map(lambda x, y: x + y, [1, 2, 3], count())
|
||||
|
||||
# Regression https://github.com/astral-sh/ruff/issues/20997
|
||||
map(f, *lots_of_iterators)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::rules::flake8_bugbear::helpers::any_infinite_iterables;
|
|||
use crate::{AlwaysFixableViolation, Applicability, Fix};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `map` calls without an explicit `strict` parameter when called with two or more iterables.
|
||||
/// Checks for `map` calls without an explicit `strict` parameter when called with two or more iterables, or any starred argument.
|
||||
///
|
||||
/// This rule applies to Python 3.14 and later, where `map` accepts a `strict` keyword
|
||||
/// argument. For details, see: [What’s New in Python 3.14](https://docs.python.org/dev/whatsnew/3.14.html).
|
||||
|
|
@ -62,7 +62,12 @@ pub(crate) fn map_without_explicit_strict(checker: &Checker, call: &ast::ExprCal
|
|||
|
||||
if semantic.match_builtin_expr(&call.func, "map")
|
||||
&& call.arguments.find_keyword("strict").is_none()
|
||||
&& call.arguments.args.len() >= 3 // function + at least 2 iterables
|
||||
&& (
|
||||
// at least 2 iterables (+ 1 function)
|
||||
call.arguments.args.len() >= 3
|
||||
// or a starred argument
|
||||
|| call.arguments.args.iter().any(ast::Expr::is_starred_expr)
|
||||
)
|
||||
&& !any_infinite_iterables(call.arguments.args.iter().skip(1), semantic)
|
||||
{
|
||||
checker
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::rules::flake8_bugbear::helpers::any_infinite_iterables;
|
|||
use crate::{AlwaysFixableViolation, Applicability, Fix};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `zip` calls without an explicit `strict` parameter.
|
||||
/// Checks for `zip` calls without an explicit `strict` parameter when called with two or more iterables, or any starred argument.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// By default, if the iterables passed to `zip` are of different lengths, the
|
||||
|
|
@ -58,6 +58,12 @@ pub(crate) fn zip_without_explicit_strict(checker: &Checker, call: &ast::ExprCal
|
|||
|
||||
if semantic.match_builtin_expr(&call.func, "zip")
|
||||
&& call.arguments.find_keyword("strict").is_none()
|
||||
&& (
|
||||
// at least 2 iterables
|
||||
call.arguments.args.len() >= 2
|
||||
// or a starred argument
|
||||
|| call.arguments.args.iter().any(ast::Expr::is_starred_expr)
|
||||
)
|
||||
&& !any_infinite_iterables(call.arguments.args.iter(), semantic)
|
||||
{
|
||||
checker
|
||||
|
|
|
|||
|
|
@ -1,204 +1,140 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||
assertion_line: 156
|
||||
---
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:4:1
|
||||
|
|
||||
3 | # Errors
|
||||
4 | zip()
|
||||
| ^^^^^
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
4 | zip("a", "b")
|
||||
| ^^^^^^^^^^^^^
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
1 | from itertools import count, cycle, repeat
|
||||
2 |
|
||||
3 | # Errors
|
||||
- zip()
|
||||
4 + zip(strict=False)
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
- zip("a", "b")
|
||||
4 + zip("a", "b", strict=False)
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:5:1
|
||||
|
|
||||
3 | # Errors
|
||||
4 | zip()
|
||||
5 | zip(range(3))
|
||||
| ^^^^^^^^^^^^^
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
4 | zip("a", "b")
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
2 |
|
||||
3 | # Errors
|
||||
4 | zip()
|
||||
- zip(range(3))
|
||||
5 + zip(range(3), strict=False)
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
4 | zip("a", "b")
|
||||
- zip("a", "b", *zip("c"))
|
||||
5 + zip("a", "b", *zip("c"), strict=False)
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
8 |
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:6:1
|
||||
--> B905.py:6:5
|
||||
|
|
||||
4 | zip()
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
| ^^^^^^^^^^^^^
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
4 | zip("a", "b")
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
| ^^^^^^^^^^^^^
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
3 | # Errors
|
||||
4 | zip()
|
||||
5 | zip(range(3))
|
||||
- zip("a", "b")
|
||||
6 + zip("a", "b", strict=False)
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
4 | zip("a", "b")
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
- zip(zip("a", "b"), strict=False)
|
||||
6 + zip(zip("a", "b", strict=False), strict=False)
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
8 |
|
||||
9 | # OK
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:7:1
|
||||
|
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
7 | zip(zip("a", strict=True),"b")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
8 |
|
||||
9 | # OK
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
4 | zip()
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
- zip("a", "b", *zip("c"))
|
||||
7 + zip("a", "b", *zip("c"), strict=False)
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
10 |
|
||||
4 | zip("a", "b")
|
||||
5 | zip("a", "b", *zip("c"))
|
||||
6 | zip(zip("a", "b"), strict=False)
|
||||
- zip(zip("a", strict=True),"b")
|
||||
7 + zip(zip("a", strict=True),"b", strict=False)
|
||||
8 |
|
||||
9 | # OK
|
||||
10 | zip(range(3), strict=True)
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:7:16
|
||||
|
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
| ^^^^^^^^
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
4 | zip()
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
- zip("a", "b", *zip("c"))
|
||||
7 + zip("a", "b", *zip("c", strict=False))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
10 |
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:8:5
|
||||
|
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
| ^^^^^^^^
|
||||
9 | zip(zip("a", strict=True))
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
5 | zip(range(3))
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
- zip(zip("a"), strict=False)
|
||||
8 + zip(zip("a", strict=False), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
10 |
|
||||
11 | # OK
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:9:1
|
||||
--> B905.py:22:1
|
||||
|
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
9 | zip(zip("a", strict=True))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
10 |
|
||||
11 | # OK
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
6 | zip("a", "b")
|
||||
7 | zip("a", "b", *zip("c"))
|
||||
8 | zip(zip("a"), strict=False)
|
||||
- zip(zip("a", strict=True))
|
||||
9 + zip(zip("a", strict=True), strict=False)
|
||||
10 |
|
||||
11 | # OK
|
||||
12 | zip(range(3), strict=True)
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:24:1
|
||||
|
|
||||
23 | # Errors (limited iterators).
|
||||
24 | zip([1, 2, 3], repeat(1, 1))
|
||||
21 | # Errors (limited iterators).
|
||||
22 | zip([1, 2, 3], repeat(1, 1))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
25 | zip([1, 2, 3], repeat(1, times=4))
|
||||
23 | zip([1, 2, 3], repeat(1, times=4))
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
21 | zip([1, 2, 3], repeat(1, times=None))
|
||||
22 |
|
||||
23 | # Errors (limited iterators).
|
||||
19 | zip([1, 2, 3], repeat(1, times=None))
|
||||
20 |
|
||||
21 | # Errors (limited iterators).
|
||||
- zip([1, 2, 3], repeat(1, 1))
|
||||
24 + zip([1, 2, 3], repeat(1, 1), strict=False)
|
||||
25 | zip([1, 2, 3], repeat(1, times=4))
|
||||
26 |
|
||||
27 | import builtins
|
||||
22 + zip([1, 2, 3], repeat(1, 1), strict=False)
|
||||
23 | zip([1, 2, 3], repeat(1, times=4))
|
||||
24 |
|
||||
25 | import builtins
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:25:1
|
||||
--> B905.py:23:1
|
||||
|
|
||||
23 | # Errors (limited iterators).
|
||||
24 | zip([1, 2, 3], repeat(1, 1))
|
||||
25 | zip([1, 2, 3], repeat(1, times=4))
|
||||
21 | # Errors (limited iterators).
|
||||
22 | zip([1, 2, 3], repeat(1, 1))
|
||||
23 | zip([1, 2, 3], repeat(1, times=4))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
26 |
|
||||
27 | import builtins
|
||||
24 |
|
||||
25 | import builtins
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
22 |
|
||||
23 | # Errors (limited iterators).
|
||||
24 | zip([1, 2, 3], repeat(1, 1))
|
||||
20 |
|
||||
21 | # Errors (limited iterators).
|
||||
22 | zip([1, 2, 3], repeat(1, 1))
|
||||
- zip([1, 2, 3], repeat(1, times=4))
|
||||
25 + zip([1, 2, 3], repeat(1, times=4), strict=False)
|
||||
26 |
|
||||
27 | import builtins
|
||||
28 | # Still an error even though it uses the qualified name
|
||||
23 + zip([1, 2, 3], repeat(1, times=4), strict=False)
|
||||
24 |
|
||||
25 | import builtins
|
||||
26 | # Still an error even though it uses the qualified name
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B905 [*] `zip()` without an explicit `strict=` parameter
|
||||
--> B905.py:29:1
|
||||
--> B905.py:34:1
|
||||
|
|
||||
27 | import builtins
|
||||
28 | # Still an error even though it uses the qualified name
|
||||
29 | builtins.zip([1, 2, 3])
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
32 | zip(range(3))
|
||||
33 | # Error
|
||||
34 | zip(*lot_of_iterators)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
26 |
|
||||
27 | import builtins
|
||||
28 | # Still an error even though it uses the qualified name
|
||||
- builtins.zip([1, 2, 3])
|
||||
29 + builtins.zip([1, 2, 3], strict=False)
|
||||
31 | zip()
|
||||
32 | zip(range(3))
|
||||
33 | # Error
|
||||
- zip(*lot_of_iterators)
|
||||
34 + zip(*lot_of_iterators, strict=False)
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
|
||||
assertion_line: 112
|
||||
---
|
||||
B912 [*] `map()` without an explicit `strict=` parameter
|
||||
--> B912.py:5:1
|
||||
|
|
@ -147,3 +146,18 @@ help: Add explicit value for parameter `strict=`
|
|||
19 | # OK
|
||||
20 | map(lambda x: x, [1, 2, 3], strict=True)
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
||||
B912 [*] `map()` without an explicit `strict=` parameter
|
||||
--> B912.py:36:1
|
||||
|
|
||||
35 | # Regression https://github.com/astral-sh/ruff/issues/20997
|
||||
36 | map(f, *lots_of_iterators)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: Add explicit value for parameter `strict=`
|
||||
33 | map(lambda x, y: x + y, [1, 2, 3], count())
|
||||
34 |
|
||||
35 | # Regression https://github.com/astral-sh/ruff/issues/20997
|
||||
- map(f, *lots_of_iterators)
|
||||
36 + map(f, *lots_of_iterators, strict=False)
|
||||
note: This is an unsafe fix and may change runtime behavior
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue