Skip to content

Commit 2be73e9

Browse files
authored
[flake8-bugbear] Mark B905 and B912 fixes as unsafe (#20695)
Resolves #20694 This PR updates the `zip_without_explicit_strict` and `map_without_explicit_strict` rules so their fixes are always marked unsafe, following Brent's guidance that adding `strict=False` can silently preserve buggy behaviour when inputs differ. The fix safety docs now spell out that reasoning, the applicability drops to `Unsafe`, and the snapshots were refreshed so Ruff clearly warns users before applying the edit.
1 parent 7a347c4 commit 2be73e9

File tree

4 files changed

+29
-28
lines changed

4 files changed

+29
-28
lines changed

crates/ruff_linter/src/rules/flake8_bugbear/rules/map_without_explicit_strict.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ use crate::{AlwaysFixableViolation, Applicability, Fix};
3434
/// ```
3535
///
3636
/// ## Fix safety
37-
/// This rule's fix is marked as unsafe for `map` calls that contain
38-
/// `**kwargs`, as adding a `strict` keyword argument to such a call may lead
39-
/// to a duplicate keyword argument error.
37+
/// This rule's fix is marked as unsafe. While adding `strict=False` preserves
38+
/// the runtime behavior, it can obscure situations where the iterables are of
39+
/// unequal length. Ruff prefers to alert users so they can choose the intended
40+
/// behavior themselves.
4041
///
4142
/// ## References
4243
/// - [Python documentation: `map`](https://docs.python.org/3/library/functions.html#map)
@@ -73,17 +74,7 @@ pub(crate) fn map_without_explicit_strict(checker: &Checker, call: &ast::ExprCal
7374
checker.comment_ranges(),
7475
checker.locator().contents(),
7576
),
76-
// If the function call contains `**kwargs`, mark the fix as unsafe.
77-
if call
78-
.arguments
79-
.keywords
80-
.iter()
81-
.any(|keyword| keyword.arg.is_none())
82-
{
83-
Applicability::Unsafe
84-
} else {
85-
Applicability::Safe
86-
},
77+
Applicability::Unsafe,
8778
));
8879
}
8980
}

crates/ruff_linter/src/rules/flake8_bugbear/rules/zip_without_explicit_strict.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ use crate::{AlwaysFixableViolation, Applicability, Fix};
3131
/// ```
3232
///
3333
/// ## Fix safety
34-
/// This rule's fix is marked as unsafe for `zip` calls that contain
35-
/// `**kwargs`, as adding a `strict` keyword argument to such a call may lead
36-
/// to a duplicate keyword argument error.
34+
/// This rule's fix is marked as unsafe. While adding `strict=False` preserves
35+
/// the runtime behavior, it can obscure situations where the iterables are of
36+
/// unequal length. Ruff prefers to alert users so they can choose the intended
37+
/// behavior themselves.
3738
///
3839
/// ## References
3940
/// - [Python documentation: `zip`](https://docs.python.org/3/library/functions.html#zip)
@@ -68,17 +69,7 @@ pub(crate) fn zip_without_explicit_strict(checker: &Checker, call: &ast::ExprCal
6869
checker.comment_ranges(),
6970
checker.locator().contents(),
7071
),
71-
// If the function call contains `**kwargs`, mark the fix as unsafe.
72-
if call
73-
.arguments
74-
.keywords
75-
.iter()
76-
.any(|keyword| keyword.arg.is_none())
77-
{
78-
Applicability::Unsafe
79-
} else {
80-
Applicability::Safe
81-
},
72+
Applicability::Unsafe,
8273
));
8374
}
8475
}

crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B905.py.snap

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
3+
assertion_line: 156
34
---
45
B905 [*] `zip()` without an explicit `strict=` parameter
56
--> B905.py:4:1
@@ -19,6 +20,7 @@ help: Add explicit value for parameter `strict=`
1920
5 | zip(range(3))
2021
6 | zip("a", "b")
2122
7 | zip("a", "b", *zip("c"))
23+
note: This is an unsafe fix and may change runtime behavior
2224

2325
B905 [*] `zip()` without an explicit `strict=` parameter
2426
--> B905.py:5:1
@@ -39,6 +41,7 @@ help: Add explicit value for parameter `strict=`
3941
6 | zip("a", "b")
4042
7 | zip("a", "b", *zip("c"))
4143
8 | zip(zip("a"), strict=False)
44+
note: This is an unsafe fix and may change runtime behavior
4245

4346
B905 [*] `zip()` without an explicit `strict=` parameter
4447
--> B905.py:6:1
@@ -59,6 +62,7 @@ help: Add explicit value for parameter `strict=`
5962
7 | zip("a", "b", *zip("c"))
6063
8 | zip(zip("a"), strict=False)
6164
9 | zip(zip("a", strict=True))
65+
note: This is an unsafe fix and may change runtime behavior
6266

6367
B905 [*] `zip()` without an explicit `strict=` parameter
6468
--> B905.py:7:1
@@ -79,6 +83,7 @@ help: Add explicit value for parameter `strict=`
7983
8 | zip(zip("a"), strict=False)
8084
9 | zip(zip("a", strict=True))
8185
10 |
86+
note: This is an unsafe fix and may change runtime behavior
8287

8388
B905 [*] `zip()` without an explicit `strict=` parameter
8489
--> B905.py:7:16
@@ -99,6 +104,7 @@ help: Add explicit value for parameter `strict=`
99104
8 | zip(zip("a"), strict=False)
100105
9 | zip(zip("a", strict=True))
101106
10 |
107+
note: This is an unsafe fix and may change runtime behavior
102108

103109
B905 [*] `zip()` without an explicit `strict=` parameter
104110
--> B905.py:8:5
@@ -118,6 +124,7 @@ help: Add explicit value for parameter `strict=`
118124
9 | zip(zip("a", strict=True))
119125
10 |
120126
11 | # OK
127+
note: This is an unsafe fix and may change runtime behavior
121128

122129
B905 [*] `zip()` without an explicit `strict=` parameter
123130
--> B905.py:9:1
@@ -138,6 +145,7 @@ help: Add explicit value for parameter `strict=`
138145
10 |
139146
11 | # OK
140147
12 | zip(range(3), strict=True)
148+
note: This is an unsafe fix and may change runtime behavior
141149

142150
B905 [*] `zip()` without an explicit `strict=` parameter
143151
--> B905.py:24:1
@@ -156,6 +164,7 @@ help: Add explicit value for parameter `strict=`
156164
25 | zip([1, 2, 3], repeat(1, times=4))
157165
26 |
158166
27 | import builtins
167+
note: This is an unsafe fix and may change runtime behavior
159168

160169
B905 [*] `zip()` without an explicit `strict=` parameter
161170
--> B905.py:25:1
@@ -176,6 +185,7 @@ help: Add explicit value for parameter `strict=`
176185
26 |
177186
27 | import builtins
178187
28 | # Still an error even though it uses the qualified name
188+
note: This is an unsafe fix and may change runtime behavior
179189

180190
B905 [*] `zip()` without an explicit `strict=` parameter
181191
--> B905.py:29:1
@@ -191,3 +201,4 @@ help: Add explicit value for parameter `strict=`
191201
28 | # Still an error even though it uses the qualified name
192202
- builtins.zip([1, 2, 3])
193203
29 + builtins.zip([1, 2, 3], strict=False)
204+
note: This is an unsafe fix and may change runtime behavior

crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__preview__B912_B912.py.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
3+
assertion_line: 112
34
---
45
B912 [*] `map()` without an explicit `strict=` parameter
56
--> B912.py:5:1
@@ -20,6 +21,7 @@ help: Add explicit value for parameter `strict=`
2021
6 | map(lambda x, y, z: x + y + z, [1, 2, 3], [4, 5, 6], [7, 8, 9])
2122
7 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9]))
2223
8 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9]), strict=False)
24+
note: This is an unsafe fix and may change runtime behavior
2325

2426
B912 [*] `map()` without an explicit `strict=` parameter
2527
--> B912.py:6:1
@@ -40,6 +42,7 @@ help: Add explicit value for parameter `strict=`
4042
7 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9]))
4143
8 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9]), strict=False)
4244
9 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9], strict=True))
45+
note: This is an unsafe fix and may change runtime behavior
4346

4447
B912 [*] `map()` without an explicit `strict=` parameter
4548
--> B912.py:7:1
@@ -61,6 +64,7 @@ help: Add explicit value for parameter `strict=`
6164
9 | map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6], *map(lambda x: x, [7, 8, 9], strict=True))
6265
10 |
6366
11 | # Errors (limited iterators).
67+
note: This is an unsafe fix and may change runtime behavior
6468

6569
B912 [*] `map()` without an explicit `strict=` parameter
6670
--> B912.py:9:1
@@ -81,6 +85,7 @@ help: Add explicit value for parameter `strict=`
8185
10 |
8286
11 | # Errors (limited iterators).
8387
12 | map(lambda x, y: x + y, [1, 2, 3], repeat(1, 1))
88+
note: This is an unsafe fix and may change runtime behavior
8489

8590
B912 [*] `map()` without an explicit `strict=` parameter
8691
--> B912.py:12:1
@@ -99,6 +104,7 @@ help: Add explicit value for parameter `strict=`
99104
13 | map(lambda x, y: x + y, [1, 2, 3], repeat(1, times=4))
100105
14 |
101106
15 | import builtins
107+
note: This is an unsafe fix and may change runtime behavior
102108

103109
B912 [*] `map()` without an explicit `strict=` parameter
104110
--> B912.py:13:1
@@ -119,6 +125,7 @@ help: Add explicit value for parameter `strict=`
119125
14 |
120126
15 | import builtins
121127
16 | # Still an error even though it uses the qualified name
128+
note: This is an unsafe fix and may change runtime behavior
122129

123130
B912 [*] `map()` without an explicit `strict=` parameter
124131
--> B912.py:17:1
@@ -139,3 +146,4 @@ help: Add explicit value for parameter `strict=`
139146
18 |
140147
19 | # OK
141148
20 | map(lambda x: x, [1, 2, 3], strict=True)
149+
note: This is an unsafe fix and may change runtime behavior

0 commit comments

Comments
 (0)