Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"target_version": "3.15"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[*x for x in y]

[
* # comment between * and x
x
for x in y
]

[
*values
for values in some_really_long_collection_name_that_should_force_wrapping
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
---
## Input
```python
[*x for x in y]

[
* # comment between * and x
x
for x in y
]

[
*values
for values in some_really_long_collection_name_that_should_force_wrapping
]
```

## Outputs
### Output 1
```
indent-style = space
line-width = 88
indent-width = 4
quote-style = Double
line-ending = LineFeed
magic-trailing-comma = Respect
docstring-code = Disabled
docstring-code-line-width = "dynamic"
preview = Disabled
target_version = 3.15
source_type = Python
```

```python
[*x for x in y]

[
# comment between * and x
*x
for x in y
]

[*values for values in some_really_long_collection_name_that_should_force_wrapping]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: {"target-version": "3.14"}
[*x for x in y]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# parse_options: {"target-version": "3.15"}
[*x for x in y]
[*factor.dims for factor in bases]
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# Iterable unpacking not allowed
[*x for x in y]

# Invalid target
[x for 1 in y]
[x for 'a' in y]
Expand All @@ -12,9 +9,14 @@
[x for x in yield y]
[x for x in yield from y]
[x for x in lambda y: y]
[**x for x in [{1: 2}]]
[*x, for x in y]
[*x, *y for x in y]

# Invalid if
[x for x in data if *y]
[x for x in data if yield y]
[x for x in data if yield from y]
[x for x in data if lambda y: y]
[x for x in data if lambda y: y]
[*x if x else y for x in z]
[x if x else *y for x in z]
28 changes: 28 additions & 0 deletions crates/ruff_python_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,28 @@ pub enum UnsupportedSyntaxErrorKind {
/// [PEP 646]: https://peps.python.org/pep-0646/#change-2-args-as-a-typevartuple
StarAnnotation,

/// Represents the use of iterable unpacking inside a list comprehension
/// before Python 3.15.
///
/// ## Examples
///
/// Before Python 3.15, list comprehensions could not use iterable
/// unpacking in their element expression:
///
/// ```python
/// [*x for x in y] # SyntaxError
/// ```
///
/// Starting with Python 3.15, [PEP 798] allows iterable unpacking within
/// list comprehensions:
///
/// ```python
/// [*x for x in y]
/// ```
///
/// [PEP 798]: https://peps.python.org/pep-0798/
IterableUnpackingInListComprehension,

/// Represents the use of tuple unpacking in a `for` statement iterator clause before Python
/// 3.9.
///
Expand Down Expand Up @@ -979,6 +1001,9 @@ impl Display for UnsupportedSyntaxError {
"Cannot use star expression in index"
}
UnsupportedSyntaxErrorKind::StarAnnotation => "Cannot use star annotation",
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension => {
"Cannot use iterable unpacking in a list comprehension"
}
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
"Cannot use iterable unpacking in `for` statements"
}
Expand Down Expand Up @@ -1051,6 +1076,9 @@ impl UnsupportedSyntaxErrorKind {
Change::Added(PythonVersion::PY311)
}
UnsupportedSyntaxErrorKind::StarAnnotation => Change::Added(PythonVersion::PY311),
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension => {
Change::Added(PythonVersion::PY315)
}
UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
Change::Added(PythonVersion::PY39)
}
Expand Down
15 changes: 12 additions & 3 deletions crates/ruff_python_parser/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1989,10 +1989,19 @@ impl<'src> Parser<'src> {
TokenKind::Async | TokenKind::For => {
// Parenthesized starred expression isn't allowed either but that is
// handled by the `parse_parenthesized_expression` method.

// test_ok starred_list_comp_py315
// # parse_options: {"target-version": "3.15"}
// [*x for x in y]
// [*factor.dims for factor in bases]

// test_err starred_list_comp_py314
// # parse_options: {"target-version": "3.14"}
// [*x for x in y]
if first_element.is_unparenthesized_starred_expr() {
self.add_error(
ParseErrorType::IterableUnpackingInComprehension,
&first_element,
self.add_unsupported_syntax_error(
UnsupportedSyntaxErrorKind::IterableUnpackingInListComprehension,
first_element.range(),
);
}

Expand Down
Loading
Loading