Skip to content

Commit f14fd5d

Browse files
authored
Fix exception handler parenthesis removal for Python 3.14+ (#23126)
Summary -- Fixes #23125. We were missing handling for starred elements within a tuple of exceptions. This produces valid syntax but changes the AST from a non-starred `except` handler to a starred `except` handler (which can be invalid if there are other non-starred handlers): ```diff try: ... -except (*exceptions, ValueError): ... +except *exceptions, ValueError: ... ``` Starred expressions in other positions are outright invalid: ```pycon >>> try: ... ... except Exception, *exceptions: ... ... File "<python-input-8>", line 2 except Exception, *exceptions: ... ^ SyntaxError: invalid syntax ``` We now preserve parentheses in these cases as well. Test Plan -- New tests derived from the issue
1 parent e84b0f4 commit f14fd5d

3 files changed

Lines changed: 74 additions & 1 deletion

File tree

crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/try.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,16 @@ def f():
203203
pass
204204
except* (BaseException, Exception, ValueError) as e:
205205
pass
206+
207+
208+
# Regression tests for https://github.com/astral-sh/ruff/issues/23125
209+
# Parentheses cannot be removed if any of the tuple elements is starred
210+
try:
211+
pass
212+
except (Exception, *exceptions):
213+
pass
214+
215+
try:
216+
pass
217+
except (*exceptions, Exception):
218+
pass

crates/ruff_python_formatter/src/other/except_handler_except_handler.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,30 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
7878
// except BaseException, Exception: # Ok
7979
// ...
8080
// ```
81+
//
82+
// Unless any component of the tuple is starred. This case is actually valid
83+
// syntax on its own but is parsed as `except*`, not a tuple with a starred
84+
// element:
85+
//
86+
// ```py
87+
// try:
88+
// ...
89+
// except *exceptions, BaseException:
90+
// ...
91+
// ```
92+
//
93+
// And this case is an outright `SyntaxError`:
94+
//
95+
// ```py
96+
// try:
97+
// ...
98+
// except BaseException, *exceptions: # SyntaxError
99+
// ...
100+
// ```
81101
Some(Expr::Tuple(tuple))
82102
if f.options().target_version() >= PythonVersion::PY314
83-
&& name.is_none() =>
103+
&& name.is_none()
104+
&& !tuple.iter().any(Expr::is_starred_expr) =>
84105
{
85106
write!(
86107
f,

crates/ruff_python_formatter/tests/snapshots/format@statement__try.py.snap

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,19 @@ try:
208208
pass
209209
except* (BaseException, Exception, ValueError) as e:
210210
pass
211+
212+
213+
# Regression tests for https://github.com/astral-sh/ruff/issues/23125
214+
# Parentheses cannot be removed if any of the tuple elements is starred
215+
try:
216+
pass
217+
except (Exception, *exceptions):
218+
pass
219+
220+
try:
221+
pass
222+
except (*exceptions, Exception):
223+
pass
211224
```
212225

213226
## Outputs
@@ -454,6 +467,19 @@ try:
454467
pass
455468
except* (BaseException, Exception, ValueError) as e:
456469
pass
470+
471+
472+
# Regression tests for https://github.com/astral-sh/ruff/issues/23125
473+
# Parentheses cannot be removed if any of the tuple elements is starred
474+
try:
475+
pass
476+
except (Exception, *exceptions):
477+
pass
478+
479+
try:
480+
pass
481+
except (*exceptions, Exception):
482+
pass
457483
```
458484

459485

@@ -727,6 +753,19 @@ try:
727753
pass
728754
except* (BaseException, Exception, ValueError) as e:
729755
pass
756+
757+
758+
# Regression tests for https://github.com/astral-sh/ruff/issues/23125
759+
# Parentheses cannot be removed if any of the tuple elements is starred
760+
try:
761+
pass
762+
except (Exception, *exceptions):
763+
pass
764+
765+
try:
766+
pass
767+
except (*exceptions, Exception):
768+
pass
730769
```
731770

732771

0 commit comments

Comments
 (0)