[`flake8-bugbear`] Add fix for `zip-without-explicit-strict` (`B905`) (#9176)

This commit is contained in:
Shantanu 2023-12-18 08:34:53 -08:00 committed by GitHub
parent 0bf7683a3f
commit a7514295c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 136 additions and 14 deletions

View File

@ -1,4 +1,4 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr};
@ -6,6 +6,7 @@ use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::fix::edits::add_argument;
/// ## What it does
/// Checks for `zip` calls without an explicit `strict` parameter.
@ -28,16 +29,25 @@ use crate::checkers::ast::Checker;
/// zip(a, b, strict=True)
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe for `zip` calls that contain
/// `**kwargs`, as adding a `check` keyword argument to such a call may lead
/// to a duplicate keyword argument error.
///
/// ## References
/// - [Python documentation: `zip`](https://docs.python.org/3/library/functions.html#zip)
#[violation]
pub struct ZipWithoutExplicitStrict;
impl Violation for ZipWithoutExplicitStrict {
impl AlwaysFixableViolation for ZipWithoutExplicitStrict {
#[derive_message_formats]
fn message(&self) -> String {
format!("`zip()` without an explicit `strict=` parameter")
}
fn fix_title(&self) -> String {
"Add explicit `strict=False`".to_string()
}
}
/// B905
@ -52,9 +62,27 @@ pub(crate) fn zip_without_explicit_strict(checker: &mut Checker, call: &ast::Exp
.iter()
.any(|arg| is_infinite_iterator(arg, checker.semantic()))
{
checker
.diagnostics
.push(Diagnostic::new(ZipWithoutExplicitStrict, call.range()));
let mut diagnostic = Diagnostic::new(ZipWithoutExplicitStrict, call.range());
diagnostic.set_fix(Fix::applicable_edit(
add_argument(
"strict=False",
&call.arguments,
checker.indexer().comment_ranges(),
checker.locator().contents(),
),
// If the function call contains `**kwargs`, mark the fix as unsafe.
if call
.arguments
.keywords
.iter()
.any(|keyword| keyword.arg.is_none())
{
Applicability::Unsafe
} else {
Applicability::Safe
},
));
checker.diagnostics.push(diagnostic);
}
}
}

View File

@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
---
B905.py:4:1: B905 `zip()` without an explicit `strict=` parameter
B905.py:4:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
3 | # Errors
4 | zip()
@ -9,8 +9,19 @@ B905.py:4:1: B905 `zip()` without an explicit `strict=` parameter
5 | zip(range(3))
6 | zip("a", "b")
|
= help: Add explicit `strict=False`
B905.py:5:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
1 1 | from itertools import count, cycle, repeat
2 2 |
3 3 | # Errors
4 |-zip()
4 |+zip(strict=False)
5 5 | zip(range(3))
6 6 | zip("a", "b")
7 7 | zip("a", "b", *zip("c"))
B905.py:5:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
3 | # Errors
4 | zip()
@ -19,8 +30,19 @@ B905.py:5:1: B905 `zip()` without an explicit `strict=` parameter
6 | zip("a", "b")
7 | zip("a", "b", *zip("c"))
|
= help: Add explicit `strict=False`
B905.py:6:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
2 2 |
3 3 | # Errors
4 4 | zip()
5 |-zip(range(3))
5 |+zip(range(3), strict=False)
6 6 | zip("a", "b")
7 7 | zip("a", "b", *zip("c"))
8 8 | zip(zip("a"), strict=False)
B905.py:6:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
4 | zip()
5 | zip(range(3))
@ -29,8 +51,19 @@ B905.py:6:1: B905 `zip()` without an explicit `strict=` parameter
7 | zip("a", "b", *zip("c"))
8 | zip(zip("a"), strict=False)
|
= help: Add explicit `strict=False`
B905.py:7:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
3 3 | # Errors
4 4 | zip()
5 5 | zip(range(3))
6 |-zip("a", "b")
6 |+zip("a", "b", strict=False)
7 7 | zip("a", "b", *zip("c"))
8 8 | zip(zip("a"), strict=False)
9 9 | zip(zip("a", strict=True))
B905.py:7:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
5 | zip(range(3))
6 | zip("a", "b")
@ -39,8 +72,19 @@ B905.py:7:1: B905 `zip()` without an explicit `strict=` parameter
8 | zip(zip("a"), strict=False)
9 | zip(zip("a", strict=True))
|
= help: Add explicit `strict=False`
B905.py:7:16: B905 `zip()` without an explicit `strict=` parameter
Safe fix
4 4 | zip()
5 5 | zip(range(3))
6 6 | zip("a", "b")
7 |-zip("a", "b", *zip("c"))
7 |+zip("a", "b", *zip("c"), strict=False)
8 8 | zip(zip("a"), strict=False)
9 9 | zip(zip("a", strict=True))
10 10 |
B905.py:7:16: B905 [*] `zip()` without an explicit `strict=` parameter
|
5 | zip(range(3))
6 | zip("a", "b")
@ -49,8 +93,19 @@ B905.py:7:16: B905 `zip()` without an explicit `strict=` parameter
8 | zip(zip("a"), strict=False)
9 | zip(zip("a", strict=True))
|
= help: Add explicit `strict=False`
B905.py:8:5: B905 `zip()` without an explicit `strict=` parameter
Safe fix
4 4 | zip()
5 5 | zip(range(3))
6 6 | zip("a", "b")
7 |-zip("a", "b", *zip("c"))
7 |+zip("a", "b", *zip("c", strict=False))
8 8 | zip(zip("a"), strict=False)
9 9 | zip(zip("a", strict=True))
10 10 |
B905.py:8:5: B905 [*] `zip()` without an explicit `strict=` parameter
|
6 | zip("a", "b")
7 | zip("a", "b", *zip("c"))
@ -58,8 +113,19 @@ B905.py:8:5: B905 `zip()` without an explicit `strict=` parameter
| ^^^^^^^^ B905
9 | zip(zip("a", strict=True))
|
= help: Add explicit `strict=False`
B905.py:9:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
5 5 | zip(range(3))
6 6 | zip("a", "b")
7 7 | zip("a", "b", *zip("c"))
8 |-zip(zip("a"), strict=False)
8 |+zip(zip("a", strict=False), strict=False)
9 9 | zip(zip("a", strict=True))
10 10 |
11 11 | # OK
B905.py:9:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
7 | zip("a", "b", *zip("c"))
8 | zip(zip("a"), strict=False)
@ -68,21 +134,49 @@ B905.py:9:1: B905 `zip()` without an explicit `strict=` parameter
10 |
11 | # OK
|
= help: Add explicit `strict=False`
B905.py:24:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
6 6 | zip("a", "b")
7 7 | zip("a", "b", *zip("c"))
8 8 | zip(zip("a"), strict=False)
9 |-zip(zip("a", strict=True))
9 |+zip(zip("a", strict=True), strict=False)
10 10 |
11 11 | # OK
12 12 | zip(range(3), strict=True)
B905.py:24:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
23 | # Errors (limited iterators).
24 | zip([1, 2, 3], repeat(1, 1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B905
25 | zip([1, 2, 3], repeat(1, times=4))
|
= help: Add explicit `strict=False`
B905.py:25:1: B905 `zip()` without an explicit `strict=` parameter
Safe fix
21 21 | zip([1, 2, 3], repeat(1, times=None))
22 22 |
23 23 | # Errors (limited iterators).
24 |-zip([1, 2, 3], repeat(1, 1))
24 |+zip([1, 2, 3], repeat(1, 1), strict=False)
25 25 | zip([1, 2, 3], repeat(1, times=4))
B905.py:25:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
23 | # Errors (limited iterators).
24 | zip([1, 2, 3], repeat(1, 1))
25 | zip([1, 2, 3], repeat(1, times=4))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B905
|
= help: Add explicit `strict=False`
Safe fix
22 22 |
23 23 | # Errors (limited iterators).
24 24 | zip([1, 2, 3], repeat(1, 1))
25 |-zip([1, 2, 3], repeat(1, times=4))
25 |+zip([1, 2, 3], repeat(1, times=4), strict=False)