Avoid refactoring x[:1]-like slices in RUF015 (#6150)

## Summary

Right now, `RUF015` will try to rewrite `x[:1]` as `[next(x)]`. This
isn't equivalent if `x`, for example, is empty, where slicing like
`x[:1]` is forgiving, but `next` raises `StopIteration`. For me this is
a little too much of a deviation to be comfortable with, and most of the
value in this rule is the `x[0]` to `next(x)` conversion anyway.

Closes https://github.com/astral-sh/ruff/issues/6148.
This commit is contained in:
Charlie Marsh 2023-07-28 09:38:13 -04:00 committed by GitHub
parent cd4147423c
commit 134d447d4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 180 additions and 514 deletions

View file

@ -2,21 +2,9 @@ x = range(10)
# RUF015
list(x)[0]
list(x)[:1]
list(x)[:1:1]
list(x)[:1:2]
tuple(x)[0]
tuple(x)[:1]
tuple(x)[:1:1]
tuple(x)[:1:2]
list(i for i in x)[0]
list(i for i in x)[:1]
list(i for i in x)[:1:1]
list(i for i in x)[:1:2]
[i for i in x][0]
[i for i in x][:1]
[i for i in x][:1:1]
[i for i in x][:1:2]
# OK (not indexing (solely) the first element)
list(x)
@ -29,6 +17,9 @@ list(x)[::]
[i for i in x]
[i for i in x][1]
[i for i in x][-1]
[i for i in x][:1]
[i for i in x][:1:1]
[i for i in x][:1:2]
[i for i in x][1:]
[i for i in x][:3:2]
[i for i in x][::2]

View file

@ -1,14 +1,13 @@
use std::borrow::Cow;
use num_bigint::BigInt;
use num_traits::{One, Zero};
use ruff_python_ast::{self as ast, Comprehension, Constant, Expr, Ranged};
use ruff_text_size::{TextRange, TextSize};
use num_traits::Zero;
use unicode_width::UnicodeWidthStr;
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Comprehension, Constant, Expr, Ranged};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::{TextRange, TextSize};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
@ -49,37 +48,20 @@ use crate::registry::AsRule;
#[violation]
pub(crate) struct UnnecessaryIterableAllocationForFirstElement {
iterable: String,
subscript_kind: HeadSubscriptKind,
}
impl AlwaysAutofixableViolation for UnnecessaryIterableAllocationForFirstElement {
#[derive_message_formats]
fn message(&self) -> String {
let UnnecessaryIterableAllocationForFirstElement {
iterable,
subscript_kind,
} = self;
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
let iterable = Self::truncate(iterable);
match subscript_kind {
HeadSubscriptKind::Index => {
format!("Prefer `next({iterable})` over single element slice")
}
HeadSubscriptKind::Slice => {
format!("Prefer `[next({iterable})]` over single element slice")
}
}
format!("Prefer `next({iterable})` over single element slice")
}
fn autofix_title(&self) -> String {
let UnnecessaryIterableAllocationForFirstElement {
iterable,
subscript_kind,
} = self;
let UnnecessaryIterableAllocationForFirstElement { iterable } = self;
let iterable = Self::truncate(iterable);
match subscript_kind {
HeadSubscriptKind::Index => format!("Replace with `next({iterable})`"),
HeadSubscriptKind::Slice => format!("Replace with `[next({iterable})]"),
}
format!("Replace with `next({iterable})`")
}
}
@ -106,9 +88,9 @@ pub(crate) fn unnecessary_iterable_allocation_for_first_element(
..
} = subscript;
let Some(subscript_kind) = classify_subscript(slice) else {
if !is_head_slice(slice) {
return;
};
}
let Some(target) = match_iteration_target(value, checker.semantic()) else {
return;
@ -123,72 +105,31 @@ pub(crate) fn unnecessary_iterable_allocation_for_first_element(
let mut diagnostic = Diagnostic::new(
UnnecessaryIterableAllocationForFirstElement {
iterable: iterable.to_string(),
subscript_kind,
},
*range,
);
if checker.patch(diagnostic.kind.rule()) {
let replacement = match subscript_kind {
HeadSubscriptKind::Index => format!("next({iterable})"),
HeadSubscriptKind::Slice => format!("[next({iterable})]"),
};
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(replacement, *range)));
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
format!("next({iterable})"),
*range,
)));
}
checker.diagnostics.push(diagnostic);
}
/// A subscript slice that represents the first element of a list.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum HeadSubscriptKind {
/// The subscript is an index (e.g., `[0]`).
Index,
/// The subscript is a slice (e.g., `[:1]`).
Slice,
}
/// Check that the slice [`Expr`] is functionally equivalent to slicing into the first element. The
/// first `bool` checks that the element is in fact first, the second checks if it's a slice or an
/// index.
fn classify_subscript(expr: &Expr) -> Option<HeadSubscriptKind> {
let result = match expr {
Expr::Constant(ast::ExprConstant {
value: Constant::Int(value),
..
}) if value.is_zero() => HeadSubscriptKind::Index,
Expr::Slice(ast::ExprSlice {
step, lower, upper, ..
}) => {
// Avoid, e.g., `list(...)[:2]`
let upper = upper.as_ref()?;
let upper = as_int(upper)?;
if !upper.is_one() {
return None;
}
// Avoid, e.g., `list(...)[2:]`.
if let Some(lower) = lower.as_ref() {
let lower = as_int(lower)?;
if !lower.is_zero() {
return None;
}
}
// Avoid, e.g., `list(...)[::-1]`
if let Some(step) = step.as_ref() {
let step = as_int(step)?;
if step < upper {
return None;
}
}
HeadSubscriptKind::Slice
}
_ => return None,
};
Some(result)
/// Check that the slice [`Expr`] is a slice of the first element (e.g., `x[0]`).
fn is_head_slice(expr: &Expr) -> bool {
if let Expr::Constant(ast::ExprConstant {
value: Constant::Int(value),
..
}) = expr
{
value.is_zero()
} else {
false
}
}
#[derive(Debug)]
@ -310,17 +251,3 @@ fn match_simple_comprehension(elt: &Expr, generators: &[Comprehension]) -> Optio
Some(generator.iter.range())
}
/// If an expression is a constant integer, returns the value of that integer; otherwise,
/// returns `None`.
fn as_int(expr: &Expr) -> Option<&BigInt> {
if let Expr::Constant(ast::ExprConstant {
value: Constant::Int(value),
..
}) = expr
{
Some(value)
} else {
None
}
}

View file

@ -6,8 +6,8 @@ RUF015.py:4:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
3 | # RUF015
4 | list(x)[0]
| ^^^^^^^^^^ RUF015
5 | list(x)[:1]
6 | list(x)[:1:1]
5 | tuple(x)[0]
6 | list(i for i in x)[0]
|
= help: Replace with `next(iter(x))`
@ -17,490 +17,238 @@ RUF015.py:4:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
3 3 | # RUF015
4 |-list(x)[0]
4 |+next(iter(x))
5 5 | list(x)[:1]
6 6 | list(x)[:1:1]
7 7 | list(x)[:1:2]
5 5 | tuple(x)[0]
6 6 | list(i for i in x)[0]
7 7 | [i for i in x][0]
RUF015.py:5:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
RUF015.py:5:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
|
3 | # RUF015
4 | list(x)[0]
5 | list(x)[:1]
5 | tuple(x)[0]
| ^^^^^^^^^^^ RUF015
6 | list(x)[:1:1]
7 | list(x)[:1:2]
6 | list(i for i in x)[0]
7 | [i for i in x][0]
|
= help: Replace with `[next(iter(x))]
= help: Replace with `next(iter(x))`
Suggested fix
2 2 |
3 3 | # RUF015
4 4 | list(x)[0]
5 |-list(x)[:1]
5 |+[next(iter(x))]
6 6 | list(x)[:1:1]
7 7 | list(x)[:1:2]
8 8 | tuple(x)[0]
5 |-tuple(x)[0]
5 |+next(iter(x))
6 6 | list(i for i in x)[0]
7 7 | [i for i in x][0]
8 8 |
RUF015.py:6:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
RUF015.py:6:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
|
4 | list(x)[0]
5 | list(x)[:1]
6 | list(x)[:1:1]
| ^^^^^^^^^^^^^ RUF015
7 | list(x)[:1:2]
8 | tuple(x)[0]
5 | tuple(x)[0]
6 | list(i for i in x)[0]
| ^^^^^^^^^^^^^^^^^^^^^ RUF015
7 | [i for i in x][0]
|
= help: Replace with `[next(iter(x))]
= help: Replace with `next(iter(x))`
Suggested fix
3 3 | # RUF015
4 4 | list(x)[0]
5 5 | list(x)[:1]
6 |-list(x)[:1:1]
6 |+[next(iter(x))]
7 7 | list(x)[:1:2]
8 8 | tuple(x)[0]
9 9 | tuple(x)[:1]
5 5 | tuple(x)[0]
6 |-list(i for i in x)[0]
6 |+next(iter(x))
7 7 | [i for i in x][0]
8 8 |
9 9 | # OK (not indexing (solely) the first element)
RUF015.py:7:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
RUF015.py:7:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
|
5 | list(x)[:1]
6 | list(x)[:1:1]
7 | list(x)[:1:2]
| ^^^^^^^^^^^^^ RUF015
8 | tuple(x)[0]
9 | tuple(x)[:1]
5 | tuple(x)[0]
6 | list(i for i in x)[0]
7 | [i for i in x][0]
| ^^^^^^^^^^^^^^^^^ RUF015
8 |
9 | # OK (not indexing (solely) the first element)
|
= help: Replace with `[next(iter(x))]
= help: Replace with `next(iter(x))`
Suggested fix
4 4 | list(x)[0]
5 5 | list(x)[:1]
6 6 | list(x)[:1:1]
7 |-list(x)[:1:2]
7 |+[next(iter(x))]
8 8 | tuple(x)[0]
9 9 | tuple(x)[:1]
10 10 | tuple(x)[:1:1]
5 5 | tuple(x)[0]
6 6 | list(i for i in x)[0]
7 |-[i for i in x][0]
7 |+next(iter(x))
8 8 |
9 9 | # OK (not indexing (solely) the first element)
10 10 | list(x)
RUF015.py:8:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
RUF015.py:29:1: RUF015 [*] Prefer `next(i + 1 for i in x)` over single element slice
|
6 | list(x)[:1:1]
7 | list(x)[:1:2]
8 | tuple(x)[0]
| ^^^^^^^^^^^ RUF015
9 | tuple(x)[:1]
10 | tuple(x)[:1:1]
|
= help: Replace with `next(iter(x))`
Suggested fix
5 5 | list(x)[:1]
6 6 | list(x)[:1:1]
7 7 | list(x)[:1:2]
8 |-tuple(x)[0]
8 |+next(iter(x))
9 9 | tuple(x)[:1]
10 10 | tuple(x)[:1:1]
11 11 | tuple(x)[:1:2]
RUF015.py:9:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
7 | list(x)[:1:2]
8 | tuple(x)[0]
9 | tuple(x)[:1]
| ^^^^^^^^^^^^ RUF015
10 | tuple(x)[:1:1]
11 | tuple(x)[:1:2]
|
= help: Replace with `[next(iter(x))]
Suggested fix
6 6 | list(x)[:1:1]
7 7 | list(x)[:1:2]
8 8 | tuple(x)[0]
9 |-tuple(x)[:1]
9 |+[next(iter(x))]
10 10 | tuple(x)[:1:1]
11 11 | tuple(x)[:1:2]
12 12 | list(i for i in x)[0]
RUF015.py:10:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
8 | tuple(x)[0]
9 | tuple(x)[:1]
10 | tuple(x)[:1:1]
| ^^^^^^^^^^^^^^ RUF015
11 | tuple(x)[:1:2]
12 | list(i for i in x)[0]
|
= help: Replace with `[next(iter(x))]
Suggested fix
7 7 | list(x)[:1:2]
8 8 | tuple(x)[0]
9 9 | tuple(x)[:1]
10 |-tuple(x)[:1:1]
10 |+[next(iter(x))]
11 11 | tuple(x)[:1:2]
12 12 | list(i for i in x)[0]
13 13 | list(i for i in x)[:1]
RUF015.py:11:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
9 | tuple(x)[:1]
10 | tuple(x)[:1:1]
11 | tuple(x)[:1:2]
| ^^^^^^^^^^^^^^ RUF015
12 | list(i for i in x)[0]
13 | list(i for i in x)[:1]
|
= help: Replace with `[next(iter(x))]
Suggested fix
8 8 | tuple(x)[0]
9 9 | tuple(x)[:1]
10 10 | tuple(x)[:1:1]
11 |-tuple(x)[:1:2]
11 |+[next(iter(x))]
12 12 | list(i for i in x)[0]
13 13 | list(i for i in x)[:1]
14 14 | list(i for i in x)[:1:1]
RUF015.py:12:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
|
10 | tuple(x)[:1:1]
11 | tuple(x)[:1:2]
12 | list(i for i in x)[0]
28 | # RUF015 (doesn't mirror the underlying list)
29 | [i + 1 for i in x][0]
| ^^^^^^^^^^^^^^^^^^^^^ RUF015
13 | list(i for i in x)[:1]
14 | list(i for i in x)[:1:1]
|
= help: Replace with `next(iter(x))`
Suggested fix
9 9 | tuple(x)[:1]
10 10 | tuple(x)[:1:1]
11 11 | tuple(x)[:1:2]
12 |-list(i for i in x)[0]
12 |+next(iter(x))
13 13 | list(i for i in x)[:1]
14 14 | list(i for i in x)[:1:1]
15 15 | list(i for i in x)[:1:2]
RUF015.py:13:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
11 | tuple(x)[:1:2]
12 | list(i for i in x)[0]
13 | list(i for i in x)[:1]
| ^^^^^^^^^^^^^^^^^^^^^^ RUF015
14 | list(i for i in x)[:1:1]
15 | list(i for i in x)[:1:2]
|
= help: Replace with `[next(iter(x))]
Suggested fix
10 10 | tuple(x)[:1:1]
11 11 | tuple(x)[:1:2]
12 12 | list(i for i in x)[0]
13 |-list(i for i in x)[:1]
13 |+[next(iter(x))]
14 14 | list(i for i in x)[:1:1]
15 15 | list(i for i in x)[:1:2]
16 16 | [i for i in x][0]
RUF015.py:14:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
12 | list(i for i in x)[0]
13 | list(i for i in x)[:1]
14 | list(i for i in x)[:1:1]
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF015
15 | list(i for i in x)[:1:2]
16 | [i for i in x][0]
|
= help: Replace with `[next(iter(x))]
Suggested fix
11 11 | tuple(x)[:1:2]
12 12 | list(i for i in x)[0]
13 13 | list(i for i in x)[:1]
14 |-list(i for i in x)[:1:1]
14 |+[next(iter(x))]
15 15 | list(i for i in x)[:1:2]
16 16 | [i for i in x][0]
17 17 | [i for i in x][:1]
RUF015.py:15:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
13 | list(i for i in x)[:1]
14 | list(i for i in x)[:1:1]
15 | list(i for i in x)[:1:2]
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF015
16 | [i for i in x][0]
17 | [i for i in x][:1]
|
= help: Replace with `[next(iter(x))]
Suggested fix
12 12 | list(i for i in x)[0]
13 13 | list(i for i in x)[:1]
14 14 | list(i for i in x)[:1:1]
15 |-list(i for i in x)[:1:2]
15 |+[next(iter(x))]
16 16 | [i for i in x][0]
17 17 | [i for i in x][:1]
18 18 | [i for i in x][:1:1]
RUF015.py:16:1: RUF015 [*] Prefer `next(iter(x))` over single element slice
|
14 | list(i for i in x)[:1:1]
15 | list(i for i in x)[:1:2]
16 | [i for i in x][0]
| ^^^^^^^^^^^^^^^^^ RUF015
17 | [i for i in x][:1]
18 | [i for i in x][:1:1]
|
= help: Replace with `next(iter(x))`
Suggested fix
13 13 | list(i for i in x)[:1]
14 14 | list(i for i in x)[:1:1]
15 15 | list(i for i in x)[:1:2]
16 |-[i for i in x][0]
16 |+next(iter(x))
17 17 | [i for i in x][:1]
18 18 | [i for i in x][:1:1]
19 19 | [i for i in x][:1:2]
RUF015.py:17:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
15 | list(i for i in x)[:1:2]
16 | [i for i in x][0]
17 | [i for i in x][:1]
| ^^^^^^^^^^^^^^^^^^ RUF015
18 | [i for i in x][:1:1]
19 | [i for i in x][:1:2]
|
= help: Replace with `[next(iter(x))]
Suggested fix
14 14 | list(i for i in x)[:1:1]
15 15 | list(i for i in x)[:1:2]
16 16 | [i for i in x][0]
17 |-[i for i in x][:1]
17 |+[next(iter(x))]
18 18 | [i for i in x][:1:1]
19 19 | [i for i in x][:1:2]
20 20 |
RUF015.py:18:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
16 | [i for i in x][0]
17 | [i for i in x][:1]
18 | [i for i in x][:1:1]
| ^^^^^^^^^^^^^^^^^^^^ RUF015
19 | [i for i in x][:1:2]
|
= help: Replace with `[next(iter(x))]
Suggested fix
15 15 | list(i for i in x)[:1:2]
16 16 | [i for i in x][0]
17 17 | [i for i in x][:1]
18 |-[i for i in x][:1:1]
18 |+[next(iter(x))]
19 19 | [i for i in x][:1:2]
20 20 |
21 21 | # OK (not indexing (solely) the first element)
RUF015.py:19:1: RUF015 [*] Prefer `[next(iter(x))]` over single element slice
|
17 | [i for i in x][:1]
18 | [i for i in x][:1:1]
19 | [i for i in x][:1:2]
| ^^^^^^^^^^^^^^^^^^^^ RUF015
20 |
21 | # OK (not indexing (solely) the first element)
|
= help: Replace with `[next(iter(x))]
Suggested fix
16 16 | [i for i in x][0]
17 17 | [i for i in x][:1]
18 18 | [i for i in x][:1:1]
19 |-[i for i in x][:1:2]
19 |+[next(iter(x))]
20 20 |
21 21 | # OK (not indexing (solely) the first element)
22 22 | list(x)
RUF015.py:38:1: RUF015 [*] Prefer `next(i + 1 for i in x)` over single element slice
|
37 | # RUF015 (doesn't mirror the underlying list)
38 | [i + 1 for i in x][0]
| ^^^^^^^^^^^^^^^^^^^^^ RUF015
39 | [i for i in x if i > 5][0]
40 | [(i, i + 1) for i in x][0]
30 | [i for i in x if i > 5][0]
31 | [(i, i + 1) for i in x][0]
|
= help: Replace with `next(i + 1 for i in x)`
Suggested fix
35 35 | [i for i in x][::]
36 36 |
37 37 | # RUF015 (doesn't mirror the underlying list)
38 |-[i + 1 for i in x][0]
38 |+next(i + 1 for i in x)
39 39 | [i for i in x if i > 5][0]
40 40 | [(i, i + 1) for i in x][0]
41 41 |
26 26 | [i for i in x][::]
27 27 |
28 28 | # RUF015 (doesn't mirror the underlying list)
29 |-[i + 1 for i in x][0]
29 |+next(i + 1 for i in x)
30 30 | [i for i in x if i > 5][0]
31 31 | [(i, i + 1) for i in x][0]
32 32 |
RUF015.py:39:1: RUF015 [*] Prefer `next(i for i in x if i > 5)` over single element slice
RUF015.py:30:1: RUF015 [*] Prefer `next(i for i in x if i > 5)` over single element slice
|
37 | # RUF015 (doesn't mirror the underlying list)
38 | [i + 1 for i in x][0]
39 | [i for i in x if i > 5][0]
28 | # RUF015 (doesn't mirror the underlying list)
29 | [i + 1 for i in x][0]
30 | [i for i in x if i > 5][0]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF015
40 | [(i, i + 1) for i in x][0]
31 | [(i, i + 1) for i in x][0]
|
= help: Replace with `next(i for i in x if i > 5)`
Suggested fix
36 36 |
37 37 | # RUF015 (doesn't mirror the underlying list)
38 38 | [i + 1 for i in x][0]
39 |-[i for i in x if i > 5][0]
39 |+next(i for i in x if i > 5)
40 40 | [(i, i + 1) for i in x][0]
41 41 |
42 42 | # RUF015 (multiple generators)
27 27 |
28 28 | # RUF015 (doesn't mirror the underlying list)
29 29 | [i + 1 for i in x][0]
30 |-[i for i in x if i > 5][0]
30 |+next(i for i in x if i > 5)
31 31 | [(i, i + 1) for i in x][0]
32 32 |
33 33 | # RUF015 (multiple generators)
RUF015.py:40:1: RUF015 [*] Prefer `next((i, i + 1) for i in x)` over single element slice
RUF015.py:31:1: RUF015 [*] Prefer `next((i, i + 1) for i in x)` over single element slice
|
38 | [i + 1 for i in x][0]
39 | [i for i in x if i > 5][0]
40 | [(i, i + 1) for i in x][0]
29 | [i + 1 for i in x][0]
30 | [i for i in x if i > 5][0]
31 | [(i, i + 1) for i in x][0]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF015
41 |
42 | # RUF015 (multiple generators)
32 |
33 | # RUF015 (multiple generators)
|
= help: Replace with `next((i, i + 1) for i in x)`
Suggested fix
37 37 | # RUF015 (doesn't mirror the underlying list)
38 38 | [i + 1 for i in x][0]
39 39 | [i for i in x if i > 5][0]
40 |-[(i, i + 1) for i in x][0]
40 |+next((i, i + 1) for i in x)
41 41 |
42 42 | # RUF015 (multiple generators)
43 43 | y = range(10)
28 28 | # RUF015 (doesn't mirror the underlying list)
29 29 | [i + 1 for i in x][0]
30 30 | [i for i in x if i > 5][0]
31 |-[(i, i + 1) for i in x][0]
31 |+next((i, i + 1) for i in x)
32 32 |
33 33 | # RUF015 (multiple generators)
34 34 | y = range(10)
RUF015.py:44:1: RUF015 [*] Prefer `next(i + j for i in x for j in y)` over single element slice
RUF015.py:35:1: RUF015 [*] Prefer `next(i + j for i in x for j in y)` over single element slice
|
42 | # RUF015 (multiple generators)
43 | y = range(10)
44 | [i + j for i in x for j in y][0]
33 | # RUF015 (multiple generators)
34 | y = range(10)
35 | [i + j for i in x for j in y][0]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF015
45 |
46 | # RUF015
36 |
37 | # RUF015
|
= help: Replace with `next(i + j for i in x for j in y)`
Suggested fix
41 41 |
42 42 | # RUF015 (multiple generators)
43 43 | y = range(10)
44 |-[i + j for i in x for j in y][0]
44 |+next(i + j for i in x for j in y)
45 45 |
46 46 | # RUF015
47 47 | list(range(10))[0]
32 32 |
33 33 | # RUF015 (multiple generators)
34 34 | y = range(10)
35 |-[i + j for i in x for j in y][0]
35 |+next(i + j for i in x for j in y)
36 36 |
37 37 | # RUF015
38 38 | list(range(10))[0]
RUF015.py:47:1: RUF015 [*] Prefer `next(iter(range(10)))` over single element slice
RUF015.py:38:1: RUF015 [*] Prefer `next(iter(range(10)))` over single element slice
|
46 | # RUF015
47 | list(range(10))[0]
37 | # RUF015
38 | list(range(10))[0]
| ^^^^^^^^^^^^^^^^^^ RUF015
48 | list(x.y)[0]
49 | list(x["y"])[0]
39 | list(x.y)[0]
40 | list(x["y"])[0]
|
= help: Replace with `next(iter(range(10)))`
Suggested fix
44 44 | [i + j for i in x for j in y][0]
45 45 |
46 46 | # RUF015
47 |-list(range(10))[0]
47 |+next(iter(range(10)))
48 48 | list(x.y)[0]
49 49 | list(x["y"])[0]
50 50 |
35 35 | [i + j for i in x for j in y][0]
36 36 |
37 37 | # RUF015
38 |-list(range(10))[0]
38 |+next(iter(range(10)))
39 39 | list(x.y)[0]
40 40 | list(x["y"])[0]
41 41 |
RUF015.py:48:1: RUF015 [*] Prefer `next(iter(x.y))` over single element slice
RUF015.py:39:1: RUF015 [*] Prefer `next(iter(x.y))` over single element slice
|
46 | # RUF015
47 | list(range(10))[0]
48 | list(x.y)[0]
37 | # RUF015
38 | list(range(10))[0]
39 | list(x.y)[0]
| ^^^^^^^^^^^^ RUF015
49 | list(x["y"])[0]
40 | list(x["y"])[0]
|
= help: Replace with `next(iter(x.y))`
Suggested fix
45 45 |
46 46 | # RUF015
47 47 | list(range(10))[0]
48 |-list(x.y)[0]
48 |+next(iter(x.y))
49 49 | list(x["y"])[0]
50 50 |
51 51 | # RUF015 (multi-line)
36 36 |
37 37 | # RUF015
38 38 | list(range(10))[0]
39 |-list(x.y)[0]
39 |+next(iter(x.y))
40 40 | list(x["y"])[0]
41 41 |
42 42 | # RUF015 (multi-line)
RUF015.py:49:1: RUF015 [*] Prefer `next(iter(x["y"]))` over single element slice
RUF015.py:40:1: RUF015 [*] Prefer `next(iter(x["y"]))` over single element slice
|
47 | list(range(10))[0]
48 | list(x.y)[0]
49 | list(x["y"])[0]
38 | list(range(10))[0]
39 | list(x.y)[0]
40 | list(x["y"])[0]
| ^^^^^^^^^^^^^^^ RUF015
50 |
51 | # RUF015 (multi-line)
41 |
42 | # RUF015 (multi-line)
|
= help: Replace with `next(iter(x["y"]))`
Suggested fix
46 46 | # RUF015
47 47 | list(range(10))[0]
48 48 | list(x.y)[0]
49 |-list(x["y"])[0]
49 |+next(iter(x["y"]))
50 50 |
51 51 | # RUF015 (multi-line)
52 52 | revision_heads_map_ast = [
37 37 | # RUF015
38 38 | list(range(10))[0]
39 39 | list(x.y)[0]
40 |-list(x["y"])[0]
40 |+next(iter(x["y"]))
41 41 |
42 42 | # RUF015 (multi-line)
43 43 | revision_heads_map_ast = [
RUF015.py:52:26: RUF015 [*] Prefer `next(...)` over single element slice
RUF015.py:43:26: RUF015 [*] Prefer `next(...)` over single element slice
|
51 | # RUF015 (multi-line)
52 | revision_heads_map_ast = [
42 | # RUF015 (multi-line)
43 | revision_heads_map_ast = [
| __________________________^
53 | | a
54 | | for a in revision_heads_map_ast_obj.body
55 | | if isinstance(a, ast.Assign) and a.targets[0].id == "REVISION_HEADS_MAP"
56 | | ][0]
44 | | a
45 | | for a in revision_heads_map_ast_obj.body
46 | | if isinstance(a, ast.Assign) and a.targets[0].id == "REVISION_HEADS_MAP"
47 | | ][0]
| |____^ RUF015
|
= help: Replace with `next(...)`
Suggested fix
49 49 | list(x["y"])[0]
50 50 |
51 51 | # RUF015 (multi-line)
52 |-revision_heads_map_ast = [
52 |+revision_heads_map_ast = next(
53 53 | a
54 54 | for a in revision_heads_map_ast_obj.body
55 55 | if isinstance(a, ast.Assign) and a.targets[0].id == "REVISION_HEADS_MAP"
56 |-][0]
56 |+)
40 40 | list(x["y"])[0]
41 41 |
42 42 | # RUF015 (multi-line)
43 |-revision_heads_map_ast = [
43 |+revision_heads_map_ast = next(
44 44 | a
45 45 | for a in revision_heads_map_ast_obj.body
46 46 | if isinstance(a, ast.Assign) and a.targets[0].id == "REVISION_HEADS_MAP"
47 |-][0]
47 |+)