Use structured types for C417 comprehension target (#7190)

Rather than manually joining the arguments as a comma-separated string,
and treating that comma-separated string as a name.
This commit is contained in:
Charlie Marsh 2023-09-06 15:20:04 +02:00 committed by GitHub
parent 5b31524920
commit eab85aea1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 94 deletions

View file

@ -11,6 +11,7 @@ map(lambda _: 3.0, nums)
_ = "".join(map(lambda x: x in nums and "1" or "0", range(123))) _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
all(map(lambda v: isinstance(v, dict), nums)) all(map(lambda v: isinstance(v, dict), nums))
filter(func, map(lambda v: v, nums)) filter(func, map(lambda v: v, nums))
list(map(lambda x, y: x * y, nums))
# When inside f-string, then the fix should be surrounded by whitespace # When inside f-string, then the fix should be surrounded by whitespace
_ = f"{set(map(lambda x: x % 2 == 0, nums))}" _ = f"{set(map(lambda x: x % 2 == 0, nums))}"

View file

@ -957,11 +957,29 @@ pub(crate) fn fix_unnecessary_map(
_ => bail!("Expected a call or lambda"), _ => bail!("Expected a call or lambda"),
}; };
// Format the lambda arguments as a comma-separated list. // Format the lambda target.
let mut args_str = lambda.params.params.iter().map(|f| f.name.value).join(", "); let target = match lambda.params.params.as_slice() {
if args_str.is_empty() { // Ex) `lambda: x`
args_str = "_".to_string(); [] => AssignTargetExpression::Name(Box::new(Name {
} value: "_",
lpar: vec![],
rpar: vec![],
})),
// Ex) `lambda x: y`
[param] => AssignTargetExpression::Name(Box::new(param.name.clone())),
// Ex) `lambda x, y: z`
params => AssignTargetExpression::Tuple(Box::new(Tuple {
elements: params
.iter()
.map(|param| Element::Simple {
value: Expression::Name(Box::new(param.name.clone())),
comma: None,
})
.collect(),
lpar: vec![],
rpar: vec![],
})),
};
// Parenthesize the iterator, if necessary, as in: // Parenthesize the iterator, if necessary, as in:
// ```python // ```python
@ -978,11 +996,7 @@ pub(crate) fn fix_unnecessary_map(
}; };
let compfor = Box::new(CompFor { let compfor = Box::new(CompFor {
target: AssignTargetExpression::Name(Box::new(Name { target,
value: args_str.as_str(),
lpar: vec![],
rpar: vec![],
})),
iter, iter,
ifs: vec![], ifs: vec![],
inner_for_in: None, inner_for_in: None,

View file

@ -187,7 +187,7 @@ C417.py:11:13: C417 [*] Unnecessary `map` usage (rewrite using a generator expre
11 |+_ = "".join((x in nums and "1" or "0" for x in range(123))) 11 |+_ = "".join((x in nums and "1" or "0" for x in range(123)))
12 12 | all(map(lambda v: isinstance(v, dict), nums)) 12 12 | all(map(lambda v: isinstance(v, dict), nums))
13 13 | filter(func, map(lambda v: v, nums)) 13 13 | filter(func, map(lambda v: v, nums))
14 14 | 14 14 | list(map(lambda x, y: x * y, nums))
C417.py:12:5: C417 [*] Unnecessary `map` usage (rewrite using a generator expression) C417.py:12:5: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
| |
@ -196,6 +196,7 @@ C417.py:12:5: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
12 | all(map(lambda v: isinstance(v, dict), nums)) 12 | all(map(lambda v: isinstance(v, dict), nums))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
13 | filter(func, map(lambda v: v, nums)) 13 | filter(func, map(lambda v: v, nums))
14 | list(map(lambda x, y: x * y, nums))
| |
= help: Replace `map` with a generator expression = help: Replace `map` with a generator expression
@ -206,8 +207,8 @@ C417.py:12:5: C417 [*] Unnecessary `map` usage (rewrite using a generator expres
12 |-all(map(lambda v: isinstance(v, dict), nums)) 12 |-all(map(lambda v: isinstance(v, dict), nums))
12 |+all((isinstance(v, dict) for v in nums)) 12 |+all((isinstance(v, dict) for v in nums))
13 13 | filter(func, map(lambda v: v, nums)) 13 13 | filter(func, map(lambda v: v, nums))
14 14 | 14 14 | list(map(lambda x, y: x * y, nums))
15 15 | # When inside f-string, then the fix should be surrounded by whitespace 15 15 |
C417.py:13:14: C417 [*] Unnecessary `map` usage (rewrite using a generator expression) C417.py:13:14: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
| |
@ -215,8 +216,7 @@ C417.py:13:14: C417 [*] Unnecessary `map` usage (rewrite using a generator expre
12 | all(map(lambda v: isinstance(v, dict), nums)) 12 | all(map(lambda v: isinstance(v, dict), nums))
13 | filter(func, map(lambda v: v, nums)) 13 | filter(func, map(lambda v: v, nums))
| ^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^ C417
14 | 14 | list(map(lambda x, y: x * y, nums))
15 | # When inside f-string, then the fix should be surrounded by whitespace
| |
= help: Replace `map` with a generator expression = help: Replace `map` with a generator expression
@ -226,121 +226,142 @@ C417.py:13:14: C417 [*] Unnecessary `map` usage (rewrite using a generator expre
12 12 | all(map(lambda v: isinstance(v, dict), nums)) 12 12 | all(map(lambda v: isinstance(v, dict), nums))
13 |-filter(func, map(lambda v: v, nums)) 13 |-filter(func, map(lambda v: v, nums))
13 |+filter(func, (v for v in nums)) 13 |+filter(func, (v for v in nums))
14 14 | 14 14 | list(map(lambda x, y: x * y, nums))
15 15 | # When inside f-string, then the fix should be surrounded by whitespace 15 15 |
16 16 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}" 16 16 | # When inside f-string, then the fix should be surrounded by whitespace
C417.py:16:8: C417 [*] Unnecessary `map` usage (rewrite using a `set` comprehension) C417.py:14:1: C417 [*] Unnecessary `map` usage (rewrite using a `list` comprehension)
| |
15 | # When inside f-string, then the fix should be surrounded by whitespace 12 | all(map(lambda v: isinstance(v, dict), nums))
16 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}" 13 | filter(func, map(lambda v: v, nums))
14 | list(map(lambda x, y: x * y, nums))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
15 |
16 | # When inside f-string, then the fix should be surrounded by whitespace
|
= help: Replace `map` with a `list` comprehension
Suggested fix
11 11 | _ = "".join(map(lambda x: x in nums and "1" or "0", range(123)))
12 12 | all(map(lambda v: isinstance(v, dict), nums))
13 13 | filter(func, map(lambda v: v, nums))
14 |-list(map(lambda x, y: x * y, nums))
14 |+[x * y for x, y in nums]
15 15 |
16 16 | # When inside f-string, then the fix should be surrounded by whitespace
17 17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
C417.py:17:8: C417 [*] Unnecessary `map` usage (rewrite using a `set` comprehension)
|
16 | # When inside f-string, then the fix should be surrounded by whitespace
17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
17 | _ = f"{dict(map(lambda v: (v, v**2), nums))}" 18 | _ = f"{dict(map(lambda v: (v, v**2), nums))}"
| |
= help: Replace `map` with a `set` comprehension = help: Replace `map` with a `set` comprehension
Suggested fix Suggested fix
13 13 | filter(func, map(lambda v: v, nums)) 14 14 | list(map(lambda x, y: x * y, nums))
14 14 | 15 15 |
15 15 | # When inside f-string, then the fix should be surrounded by whitespace 16 16 | # When inside f-string, then the fix should be surrounded by whitespace
16 |-_ = f"{set(map(lambda x: x % 2 == 0, nums))}" 17 |-_ = f"{set(map(lambda x: x % 2 == 0, nums))}"
16 |+_ = f"{ {x % 2 == 0 for x in nums} }" 17 |+_ = f"{ {x % 2 == 0 for x in nums} }"
17 17 | _ = f"{dict(map(lambda v: (v, v**2), nums))}" 18 18 | _ = f"{dict(map(lambda v: (v, v**2), nums))}"
18 18 | 19 19 |
19 19 | # False negatives. 20 20 | # False negatives.
C417.py:17:8: C417 [*] Unnecessary `map` usage (rewrite using a `dict` comprehension) C417.py:18:8: C417 [*] Unnecessary `map` usage (rewrite using a `dict` comprehension)
| |
15 | # When inside f-string, then the fix should be surrounded by whitespace 16 | # When inside f-string, then the fix should be surrounded by whitespace
16 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}" 17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
17 | _ = f"{dict(map(lambda v: (v, v**2), nums))}" 18 | _ = f"{dict(map(lambda v: (v, v**2), nums))}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
18 | 19 |
19 | # False negatives. 20 | # False negatives.
| |
= help: Replace `map` with a `dict` comprehension = help: Replace `map` with a `dict` comprehension
Suggested fix Suggested fix
14 14 | 15 15 |
15 15 | # When inside f-string, then the fix should be surrounded by whitespace 16 16 | # When inside f-string, then the fix should be surrounded by whitespace
16 16 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}" 17 17 | _ = f"{set(map(lambda x: x % 2 == 0, nums))}"
17 |-_ = f"{dict(map(lambda v: (v, v**2), nums))}" 18 |-_ = f"{dict(map(lambda v: (v, v**2), nums))}"
17 |+_ = f"{ {v: v**2 for v in nums} }" 18 |+_ = f"{ {v: v**2 for v in nums} }"
18 18 | 19 19 |
19 19 | # False negatives. 20 20 | # False negatives.
20 20 | map(lambda x=2, y=1: x + y, nums, nums) 21 21 | map(lambda x=2, y=1: x + y, nums, nums)
C417.py:35:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression) C417.py:36:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
| |
34 | # Error: the `x` is overridden by the inner lambda. 35 | # Error: the `x` is overridden by the inner lambda.
35 | map(lambda x: lambda x: x, range(4)) 36 | map(lambda x: lambda x: x, range(4))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
36 | 37 |
37 | # Ok because of the default parameters, and variadic arguments. 38 | # Ok because of the default parameters, and variadic arguments.
| |
= help: Replace `map` with a generator expression = help: Replace `map` with a generator expression
Suggested fix Suggested fix
32 32 | map(lambda x: lambda: x, range(4)) 33 33 | map(lambda x: lambda: x, range(4))
33 33 | 34 34 |
34 34 | # Error: the `x` is overridden by the inner lambda. 35 35 | # Error: the `x` is overridden by the inner lambda.
35 |-map(lambda x: lambda x: x, range(4)) 36 |-map(lambda x: lambda x: x, range(4))
35 |+(lambda x: x for x in range(4)) 36 |+(lambda x: x for x in range(4))
36 36 | 37 37 |
37 37 | # Ok because of the default parameters, and variadic arguments. 38 38 | # Ok because of the default parameters, and variadic arguments.
38 38 | map(lambda x=1: x, nums) 39 39 | map(lambda x=1: x, nums)
C417.py:46:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
|
45 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
46 | map(lambda x: x, y if y else z)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
47 | map(lambda x: x, (y if y else z))
48 | map(lambda x: x, (x, y, z))
|
= help: Replace `map` with a generator expression
Suggested fix
43 43 | dict(map(lambda k, v: (k, v), keys, values))
44 44 |
45 45 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
46 |-map(lambda x: x, y if y else z)
46 |+(x for x in (y if y else z))
47 47 | map(lambda x: x, (y if y else z))
48 48 | map(lambda x: x, (x, y, z))
C417.py:47:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression) C417.py:47:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
| |
45 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
46 | map(lambda x: x, y if y else z) 47 | map(lambda x: x, y if y else z)
47 | map(lambda x: x, (y if y else z)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 48 | map(lambda x: x, (y if y else z))
48 | map(lambda x: x, (x, y, z)) 49 | map(lambda x: x, (x, y, z))
| |
= help: Replace `map` with a generator expression = help: Replace `map` with a generator expression
Suggested fix Suggested fix
44 44 | 44 44 | dict(map(lambda k, v: (k, v), keys, values))
45 45 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121 45 45 |
46 46 | map(lambda x: x, y if y else z) 46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
47 |-map(lambda x: x, (y if y else z)) 47 |-map(lambda x: x, y if y else z)
47 |+(x for x in (y if y else z)) 47 |+(x for x in (y if y else z))
48 48 | map(lambda x: x, (x, y, z)) 48 48 | map(lambda x: x, (y if y else z))
49 49 | map(lambda x: x, (x, y, z))
C417.py:48:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression) C417.py:48:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
| |
46 | map(lambda x: x, y if y else z) 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
47 | map(lambda x: x, (y if y else z)) 47 | map(lambda x: x, y if y else z)
48 | map(lambda x: x, (x, y, z)) 48 | map(lambda x: x, (y if y else z))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
49 | map(lambda x: x, (x, y, z))
|
= help: Replace `map` with a generator expression
Suggested fix
45 45 |
46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
47 47 | map(lambda x: x, y if y else z)
48 |-map(lambda x: x, (y if y else z))
48 |+(x for x in (y if y else z))
49 49 | map(lambda x: x, (x, y, z))
C417.py:49:1: C417 [*] Unnecessary `map` usage (rewrite using a generator expression)
|
47 | map(lambda x: x, y if y else z)
48 | map(lambda x: x, (y if y else z))
49 | map(lambda x: x, (x, y, z))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ C417
| |
= help: Replace `map` with a generator expression = help: Replace `map` with a generator expression
Suggested fix Suggested fix
45 45 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121 46 46 | # Regression test for: https://github.com/astral-sh/ruff/issues/7121
46 46 | map(lambda x: x, y if y else z) 47 47 | map(lambda x: x, y if y else z)
47 47 | map(lambda x: x, (y if y else z)) 48 48 | map(lambda x: x, (y if y else z))
48 |-map(lambda x: x, (x, y, z)) 49 |-map(lambda x: x, (x, y, z))
48 |+(x for x in (x, y, z)) 49 |+(x for x in (x, y, z))