Skip to content

Commit

Permalink
[flake8-bugbear] Add fix for zip-without-explicit-strict (B905) (
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja authored Dec 18, 2023
1 parent 0bf7683 commit a751429
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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};
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.
Expand All @@ -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
Expand All @@ -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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
---
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()
| ^^^^^ B905
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()
Expand All @@ -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`

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
B905.py:6:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
4 | zip()
5 | zip(range(3))
Expand All @@ -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`

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
B905.py:7:1: B905 [*] `zip()` without an explicit `strict=` parameter
|
5 | zip(range(3))
6 | zip("a", "b")
Expand All @@ -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")
Expand All @@ -49,17 +93,39 @@ 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`

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
B905.py:8:5: B905 [*] `zip()` without an explicit `strict=` parameter
|
6 | zip("a", "b")
7 | zip("a", "b", *zip("c"))
8 | zip(zip("a"), strict=False)
| ^^^^^^^^ 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)
Expand All @@ -68,21 +134,49 @@ B905.py:9:1: B905 `zip()` without an explicit `strict=` parameter
10 |
11 | # OK
|
= help: Add explicit `strict=False`

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
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)


0 comments on commit a751429

Please sign in to comment.