Skip to content

Commit

Permalink
[RUF007] - add autofix (zip-instead-of-pairwise)
Browse files Browse the repository at this point in the history
  • Loading branch information
diceroll123 committed Aug 5, 2024
1 parent 7a2c75e commit e3179c3
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 10 deletions.
2 changes: 1 addition & 1 deletion crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
if checker.enabled(Rule::ZipInsteadOfPairwise) {
if checker.settings.target_version >= PythonVersion::Py310 {
ruff::rules::zip_instead_of_pairwise(checker, func, args);
ruff::rules::zip_instead_of_pairwise(checker, call);
}
}
if checker.any_enabled(&[
Expand Down
40 changes: 32 additions & 8 deletions crates/ruff_linter/src/rules/ruff/rules/zip_instead_of_pairwise.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr, Int};
use ruff_python_ast::{self as ast, Arguments, Expr, Int};
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
use crate::{checkers::ast::Checker, importer::ImportRequest};

/// ## What it does
/// Checks for use of `zip()` to iterate over successive pairs of elements.
Expand Down Expand Up @@ -35,10 +35,15 @@ use crate::checkers::ast::Checker;
pub struct ZipInsteadOfPairwise;

impl Violation for ZipInsteadOfPairwise {
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
#[derive_message_formats]
fn message(&self) -> String {
format!("Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs")
}

fn fix_title(&self) -> Option<String> {
Some("Replace `zip()` with `itertools.pairwise()`".to_string())
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -95,9 +100,15 @@ fn match_slice_info(expr: &Expr) -> Option<SliceInfo> {
}

/// RUF007
pub(crate) fn zip_instead_of_pairwise(checker: &mut Checker, func: &Expr, args: &[Expr]) {
pub(crate) fn zip_instead_of_pairwise(checker: &mut Checker, call: &ast::ExprCall) {
let ast::ExprCall {
func,
arguments: Arguments { args, .. },
..
} = call;

// Require exactly two positional arguments.
let [first, second] = args else {
let [first, second] = args.as_ref() else {
return;
};

Expand Down Expand Up @@ -139,7 +150,20 @@ pub(crate) fn zip_instead_of_pairwise(checker: &mut Checker, func: &Expr, args:
return;
}

checker
.diagnostics
.push(Diagnostic::new(ZipInsteadOfPairwise, func.range()));
let mut diagnostic = Diagnostic::new(ZipInsteadOfPairwise, func.range());

if checker.settings.preview.is_enabled() {
diagnostic.try_set_fix(|| {
let (import_edit, binding) = checker.importer().get_or_import_symbol(
&ImportRequest::import("itertools", "pairwise"),
func.start(),
checker.semantic(),
)?;
let reference_edit =
Edit::range_replacement(format!("{binding}({})", first_arg_info.id), call.range());
Ok(Fix::unsafe_edits(import_edit, [reference_edit]))
});
}

checker.diagnostics.push(diagnostic);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ RUF007.py:16:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
17 | zip(input, input[1::1])
18 | zip(input[:-1], input[1:])
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
13 14 | zip(foo[:-1], foo[1:], foo, strict=True) # more than 2 inputs
14 15 |
15 16 | # Errors
16 |-zip(input, input[1:])
17 |+itertools.pairwise(input)
17 18 | zip(input, input[1::1])
18 19 | zip(input[:-1], input[1:])
19 20 | zip(input[1:], input[2:])

RUF007.py:17:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -19,6 +35,22 @@ RUF007.py:17:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
18 | zip(input[:-1], input[1:])
19 | zip(input[1:], input[2:])
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
14 15 |
15 16 | # Errors
16 17 | zip(input, input[1:])
17 |-zip(input, input[1::1])
18 |+itertools.pairwise(input)
18 19 | zip(input[:-1], input[1:])
19 20 | zip(input[1:], input[2:])
20 21 | zip(input[1:-1], input[2:])

RUF007.py:18:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -29,6 +61,22 @@ RUF007.py:18:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
19 | zip(input[1:], input[2:])
20 | zip(input[1:-1], input[2:])
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
15 16 | # Errors
16 17 | zip(input, input[1:])
17 18 | zip(input, input[1::1])
18 |-zip(input[:-1], input[1:])
19 |+itertools.pairwise(input)
19 20 | zip(input[1:], input[2:])
20 21 | zip(input[1:-1], input[2:])
21 22 | list(zip(input, input[1:]))

RUF007.py:19:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -39,6 +87,22 @@ RUF007.py:19:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
20 | zip(input[1:-1], input[2:])
21 | list(zip(input, input[1:]))
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
16 17 | zip(input, input[1:])
17 18 | zip(input, input[1::1])
18 19 | zip(input[:-1], input[1:])
19 |-zip(input[1:], input[2:])
20 |+itertools.pairwise(input)
20 21 | zip(input[1:-1], input[2:])
21 22 | list(zip(input, input[1:]))
22 23 | list(zip(input[:-1], input[1:]))

RUF007.py:20:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -49,6 +113,22 @@ RUF007.py:20:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
21 | list(zip(input, input[1:]))
22 | list(zip(input[:-1], input[1:]))
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
17 18 | zip(input, input[1::1])
18 19 | zip(input[:-1], input[1:])
19 20 | zip(input[1:], input[2:])
20 |-zip(input[1:-1], input[2:])
21 |+itertools.pairwise(input)
21 22 | list(zip(input, input[1:]))
22 23 | list(zip(input[:-1], input[1:]))
23 24 | zip(foo[:-1], foo[1:], strict=True)

RUF007.py:21:6: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -59,6 +139,22 @@ RUF007.py:21:6: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
22 | list(zip(input[:-1], input[1:]))
23 | zip(foo[:-1], foo[1:], strict=True)
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
18 19 | zip(input[:-1], input[1:])
19 20 | zip(input[1:], input[2:])
20 21 | zip(input[1:-1], input[2:])
21 |-list(zip(input, input[1:]))
22 |+list(itertools.pairwise(input))
22 23 | list(zip(input[:-1], input[1:]))
23 24 | zip(foo[:-1], foo[1:], strict=True)
24 25 | zip(foo[:-1], foo[1:], strict=False)

RUF007.py:22:6: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -69,6 +165,22 @@ RUF007.py:22:6: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
23 | zip(foo[:-1], foo[1:], strict=True)
24 | zip(foo[:-1], foo[1:], strict=False)
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
19 20 | zip(input[1:], input[2:])
20 21 | zip(input[1:-1], input[2:])
21 22 | list(zip(input, input[1:]))
22 |-list(zip(input[:-1], input[1:]))
23 |+list(itertools.pairwise(input))
23 24 | zip(foo[:-1], foo[1:], strict=True)
24 25 | zip(foo[:-1], foo[1:], strict=False)
25 26 | zip(foo[:-1], foo[1:], strict=bool(foo))

RUF007.py:23:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -79,6 +191,21 @@ RUF007.py:23:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
24 | zip(foo[:-1], foo[1:], strict=False)
25 | zip(foo[:-1], foo[1:], strict=bool(foo))
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
20 21 | zip(input[1:-1], input[2:])
21 22 | list(zip(input, input[1:]))
22 23 | list(zip(input[:-1], input[1:]))
23 |-zip(foo[:-1], foo[1:], strict=True)
24 |+itertools.pairwise(foo)
24 25 | zip(foo[:-1], foo[1:], strict=False)
25 26 | zip(foo[:-1], foo[1:], strict=bool(foo))

RUF007.py:24:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -88,6 +215,20 @@ RUF007.py:24:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
| ^^^ RUF007
25 | zip(foo[:-1], foo[1:], strict=bool(foo))
|
= help: Replace `zip()` with `itertools.pairwise()`

Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
21 22 | list(zip(input, input[1:]))
22 23 | list(zip(input[:-1], input[1:]))
23 24 | zip(foo[:-1], foo[1:], strict=True)
24 |-zip(foo[:-1], foo[1:], strict=False)
25 |+itertools.pairwise(foo)
25 26 | zip(foo[:-1], foo[1:], strict=bool(foo))

RUF007.py:25:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating over successive pairs
|
Expand All @@ -96,5 +237,16 @@ RUF007.py:25:1: RUF007 Prefer `itertools.pairwise()` over `zip()` when iterating
25 | zip(foo[:-1], foo[1:], strict=bool(foo))
| ^^^ RUF007
|
= help: Replace `zip()` with `itertools.pairwise()`


Unsafe fix
1 |+import itertools
1 2 | input = [1, 2, 3]
2 3 | otherInput = [2, 3, 4]
3 4 | foo = [1, 2, 3, 4]
--------------------------------------------------------------------------------
22 23 | list(zip(input[:-1], input[1:]))
23 24 | zip(foo[:-1], foo[1:], strict=True)
24 25 | zip(foo[:-1], foo[1:], strict=False)
25 |-zip(foo[:-1], foo[1:], strict=bool(foo))
26 |+itertools.pairwise(foo)

0 comments on commit e3179c3

Please sign in to comment.