diff --git a/crates/ruff/resources/test/fixtures/ruff/RUF007.py b/crates/ruff/resources/test/fixtures/ruff/RUF007.py index 45f506b729..5b1fb84552 100644 --- a/crates/ruff/resources/test/fixtures/ruff/RUF007.py +++ b/crates/ruff/resources/test/fixtures/ruff/RUF007.py @@ -1,5 +1,6 @@ input = [1, 2, 3] otherInput = [2, 3, 4] +foo = [1, 2, 3, 4] # OK zip(input, otherInput) # different inputs @@ -8,6 +9,10 @@ zip(input, input[2:]) # not successive zip(input[:-1], input[2:]) # not successive list(zip(input, otherInput)) # nested call zip(input, input[1::2]) # not successive +zip(foo[:-1], foo[1:], foo, strict=False) # more than 2 inputs +zip(foo[:-1], foo[1:], foo, strict=True) # more than 2 inputs +zip(foo[:-1], foo[1:], strict=True) # use strict +zip(foo[:-1], foo[1:], strict=bool(foo)) # use strict # Errors zip(input, input[1:]) @@ -17,3 +22,4 @@ zip(input[1:], input[2:]) zip(input[1:-1], input[2:]) list(zip(input, input[1:])) list(zip(input[:-1], input[1:])) +zip(foo[:-1], foo[1:], strict=False) diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 7e2bea1009..69ae403192 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -2864,7 +2864,7 @@ where if self.settings.rules.enabled(Rule::PairwiseOverZipped) { if self.settings.target_version >= PythonVersion::Py310 { - ruff::rules::pairwise_over_zipped(self, func, args); + ruff::rules::pairwise_over_zipped(self, func, args, keywords); } } diff --git a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs index 651fdf693d..bd034b606c 100644 --- a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs +++ b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs @@ -1,5 +1,5 @@ use num_traits::ToPrimitive; -use rustpython_parser::ast::{Constant, Expr, ExprKind, Unaryop}; +use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, KeywordData, Unaryop}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -88,14 +88,53 @@ fn to_bound(expr: &Expr) -> Option { } /// RUF007 -pub fn pairwise_over_zipped(checker: &mut Checker, func: &Expr, args: &[Expr]) { +pub fn pairwise_over_zipped( + checker: &mut Checker, + func: &Expr, + args: &[Expr], + keywords: &[Keyword], +) { let ExprKind::Name { id, .. } = &func.node else { return; }; - if !(args.len() > 1 && id == "zip" && checker.ctx.is_builtin(id)) { + // Require exactly two positional arguments. + if args.len() != 2 { return; - }; + } + + // Allow `strict=False`, but no other keyword arguments. + if keywords.iter().any(|keyword| { + let KeywordData { + arg: Some(arg), + value, + } = &keyword.node else { + return true; + }; + if arg != "strict" { + return true; + } + if matches!( + value.node, + ExprKind::Constant { + value: Constant::Bool(false), + .. + } + ) { + return false; + } + true + }) { + return; + } + + // Require the function to be the builtin `zip`. + if id != "zip" { + return; + } + if !checker.ctx.is_builtin(id) { + return; + } // Allow the first argument to be a `Name` or `Subscript`. let Some(first_arg_info) = ({ diff --git a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__ruff_pairwise_over_zipped.snap b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__ruff_pairwise_over_zipped.snap index 944d3bb391..39972631af 100644 --- a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__ruff_pairwise_over_zipped.snap +++ b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__ruff_pairwise_over_zipped.snap @@ -2,71 +2,6 @@ source: crates/ruff/src/rules/ruff/mod.rs expression: diagnostics --- -- kind: - name: PairwiseOverZipped - body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" - suggestion: ~ - fixable: false - location: - row: 13 - column: 0 - end_location: - row: 13 - column: 3 - fix: ~ - parent: ~ -- kind: - name: PairwiseOverZipped - body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" - suggestion: ~ - fixable: false - location: - row: 14 - column: 0 - end_location: - row: 14 - column: 3 - fix: ~ - parent: ~ -- kind: - name: PairwiseOverZipped - body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" - suggestion: ~ - fixable: false - location: - row: 15 - column: 0 - end_location: - row: 15 - column: 3 - fix: ~ - parent: ~ -- kind: - name: PairwiseOverZipped - body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" - suggestion: ~ - fixable: false - location: - row: 16 - column: 0 - end_location: - row: 16 - column: 3 - fix: ~ - parent: ~ -- kind: - name: PairwiseOverZipped - body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" - suggestion: ~ - fixable: false - location: - row: 17 - column: 0 - end_location: - row: 17 - column: 3 - fix: ~ - parent: ~ - kind: name: PairwiseOverZipped body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" @@ -74,10 +9,10 @@ expression: diagnostics fixable: false location: row: 18 - column: 5 + column: 0 end_location: row: 18 - column: 8 + column: 3 fix: ~ parent: ~ - kind: @@ -87,10 +22,88 @@ expression: diagnostics fixable: false location: row: 19 - column: 5 + column: 0 end_location: row: 19 + column: 3 + fix: ~ + parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 20 + column: 0 + end_location: + row: 20 + column: 3 + fix: ~ + parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 21 + column: 0 + end_location: + row: 21 + column: 3 + fix: ~ + parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 22 + column: 0 + end_location: + row: 22 + column: 3 + fix: ~ + parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 23 + column: 5 + end_location: + row: 23 column: 8 fix: ~ parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 24 + column: 5 + end_location: + row: 24 + column: 8 + fix: ~ + parent: ~ +- kind: + name: PairwiseOverZipped + body: "Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs" + suggestion: ~ + fixable: false + location: + row: 25 + column: 0 + end_location: + row: 25 + column: 3 + fix: ~ + parent: ~