Skip to content

Commit d724b61

Browse files
committed
Add support for star-unpacking of comprehensions
1 parent f8df8ea commit d724b61

11 files changed

Lines changed: 455 additions & 221 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[
2+
{
3+
"target_version": "3.15"
4+
}
5+
]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[*x for x in y]
2+
3+
[
4+
* # comment between * and x
5+
x
6+
for x in y
7+
]
8+
9+
[
10+
*values
11+
for values in some_really_long_collection_name_that_should_force_wrapping
12+
]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
source: crates/ruff_python_formatter/tests/fixtures.rs
3+
---
4+
## Input
5+
```python
6+
[*x for x in y]
7+
8+
[
9+
* # comment between * and x
10+
x
11+
for x in y
12+
]
13+
14+
[
15+
*values
16+
for values in some_really_long_collection_name_that_should_force_wrapping
17+
]
18+
```
19+
20+
## Outputs
21+
### Output 1
22+
```
23+
indent-style = space
24+
line-width = 88
25+
indent-width = 4
26+
quote-style = Double
27+
line-ending = LineFeed
28+
magic-trailing-comma = Respect
29+
docstring-code = Disabled
30+
docstring-code-line-width = "dynamic"
31+
preview = Disabled
32+
target_version = 3.15
33+
source_type = Python
34+
```
35+
36+
```python
37+
[*x for x in y]
38+
39+
[
40+
# comment between * and x
41+
*x
42+
for x in y
43+
]
44+
45+
[*values for values in some_really_long_collection_name_that_should_force_wrapping]
46+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# parse_options: {"target-version": "3.14"}
2+
[*x for x in y]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# parse_options: {"target-version": "3.15"}
2+
[*x for x in y]
3+
[*factor.dims for factor in bases]

crates/ruff_python_parser/resources/invalid/expressions/list/comprehension.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# Iterable unpacking not allowed
2-
[*x for x in y]
3-
41
# Invalid target
52
[x for 1 in y]
63
[x for 'a' in y]
@@ -17,4 +14,4 @@
1714
[x for x in data if *y]
1815
[x for x in data if yield y]
1916
[x for x in data if yield from y]
20-
[x for x in data if lambda y: y]
17+
[x for x in data if lambda y: y]

crates/ruff_python_parser/src/error.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,28 @@ pub enum UnsupportedSyntaxErrorKind {
837837
/// [PEP 646]: https://peps.python.org/pep-0646/#change-2-args-as-a-typevartuple
838838
StarAnnotation,
839839

840+
/// Represents the use of iterable unpacking inside a list comprehension
841+
/// before Python 3.15.
842+
///
843+
/// ## Examples
844+
///
845+
/// Before Python 3.15, list comprehensions could not use iterable
846+
/// unpacking in their element expression:
847+
///
848+
/// ```python
849+
/// [*x for x in y] # SyntaxError
850+
/// ```
851+
///
852+
/// Starting with Python 3.15, [PEP 798] allows iterable unpacking within
853+
/// list comprehensions:
854+
///
855+
/// ```python
856+
/// [*x for x in y]
857+
/// ```
858+
///
859+
/// [PEP 798]: https://peps.python.org/pep-0798/
860+
IterableUnpackingInListComprehension,
861+
840862
/// Represents the use of tuple unpacking in a `for` statement iterator clause before Python
841863
/// 3.9.
842864
///
@@ -979,6 +1001,9 @@ impl Display for UnsupportedSyntaxError {
9791001
"Cannot use star expression in index"
9801002
}
9811003
UnsupportedSyntaxErrorKind::StarAnnotation => "Cannot use star annotation",
1004+
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension => {
1005+
"Cannot use iterable unpacking in a list comprehension"
1006+
}
9821007
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
9831008
"Cannot use iterable unpacking in `for` statements"
9841009
}
@@ -1051,6 +1076,9 @@ impl UnsupportedSyntaxErrorKind {
10511076
Change::Added(PythonVersion::PY311)
10521077
}
10531078
UnsupportedSyntaxErrorKind::StarAnnotation => Change::Added(PythonVersion::PY311),
1079+
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension => {
1080+
Change::Added(PythonVersion::PY315)
1081+
}
10541082
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
10551083
Change::Added(PythonVersion::PY39)
10561084
}

crates/ruff_python_parser/src/parser/expression.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,9 +1990,9 @@ impl<'src> Parser<'src> {
19901990
// Parenthesized starred expression isn't allowed either but that is
19911991
// handled by the `parse_parenthesized_expression` method.
19921992
if first_element.is_unparenthesized_starred_expr() {
1993-
self.add_error(
1994-
ParseErrorType::IterableUnpackingInComprehension,
1995-
&first_element,
1993+
self.add_unsupported_syntax_error(
1994+
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension,
1995+
first_element.range(),
19961996
);
19971997
}
19981998

0 commit comments

Comments
 (0)