[`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_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Arguments, Expr}; use ruff_python_ast::{self as ast, Arguments, Expr};
@ -6,6 +6,7 @@ use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::fix::edits::add_argument;
/// ## What it does /// ## What it does
/// Checks for `zip` calls without an explicit `strict` parameter. /// Checks for `zip` calls without an explicit `strict` parameter.
@ -28,16 +29,25 @@ use crate::checkers::ast::Checker;
/// zip(a, b, strict=True) /// 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 /// ## References
/// - [Python documentation: `zip`](https://docs.python.org/3/library/functions.html#zip) /// - [Python documentation: `zip`](https://docs.python.org/3/library/functions.html#zip)
#[violation] #[violation]
pub struct ZipWithoutExplicitStrict; pub struct ZipWithoutExplicitStrict;
impl Violation for ZipWithoutExplicitStrict { impl AlwaysFixableViolation for ZipWithoutExplicitStrict {
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
format!("`zip()` without an explicit `strict=` parameter") format!("`zip()` without an explicit `strict=` parameter")
} }
fn fix_title(&self) -> String {
"Add explicit `strict=False`".to_string()
}
} }
/// B905 /// B905
@ -52,9 +62,27 @@ pub(crate) fn zip_without_explicit_strict(checker: &mut Checker, call: &ast::Exp
.iter() .iter()
.any(|arg| is_infinite_iterator(arg, checker.semantic())) .any(|arg| is_infinite_iterator(arg, checker.semantic()))
{ {
checker let mut diagnostic = Diagnostic::new(ZipWithoutExplicitStrict, call.range());
.diagnostics diagnostic.set_fix(Fix::applicable_edit(
.push(Diagnostic::new(ZipWithoutExplicitStrict, call.range())); 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 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 3 | # Errors
4 | zip() 4 | zip()
@ -9,8 +9,19 @@ B905.py:4:1: B905 `zip()` without an explicit `strict=` parameter
5 | zip(range(3)) 5 | zip(range(3))
6 | zip("a", "b") 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 3 | # Errors
4 | zip() 4 | zip()
@ -19,8 +30,19 @@ B905.py:5:1: B905 `zip()` without an explicit `strict=` parameter
6 | zip("a", "b") 6 | zip("a", "b")
7 | zip("a", "b", *zip("c")) 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() 4 | zip()
5 | zip(range(3)) 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")) 7 | zip("a", "b", *zip("c"))
8 | zip(zip("a"), strict=False) 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)) 5 | zip(range(3))
6 | zip("a", "b") 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) 8 | zip(zip("a"), strict=False)
9 | zip(zip("a", strict=True)) 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)) 5 | zip(range(3))
6 | zip("a", "b") 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) 8 | zip(zip("a"), strict=False)
9 | zip(zip("a", strict=True)) 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") 6 | zip("a", "b")
7 | zip("a", "b", *zip("c")) 7 | zip("a", "b", *zip("c"))
@ -58,8 +113,19 @@ B905.py:8:5: B905 `zip()` without an explicit `strict=` parameter
| ^^^^^^^^ B905 | ^^^^^^^^ B905
9 | zip(zip("a", strict=True)) 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")) 7 | zip("a", "b", *zip("c"))
8 | zip(zip("a"), strict=False) 8 | zip(zip("a"), strict=False)
@ -68,21 +134,49 @@ B905.py:9:1: B905 `zip()` without an explicit `strict=` parameter
10 | 10 |
11 | # OK 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). 23 | # Errors (limited iterators).
24 | zip([1, 2, 3], repeat(1, 1)) 24 | zip([1, 2, 3], repeat(1, 1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B905 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B905
25 | zip([1, 2, 3], repeat(1, times=4)) 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). 23 | # Errors (limited iterators).
24 | zip([1, 2, 3], repeat(1, 1)) 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))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ B905 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)