Skip to content

Commit 287eb80

Browse files
Accept unparenthesized exception groups in except clauses (#142)
PEP 758, accepted for Python 3.14, allows `except A, B:` and `except* A, B:` without parentheses when there is no `as` clause. The parser rejects both today, so a file using the new form fails to parse rather than producing a tree. `GenericList` already collapses a single element to itself and wraps the rest in a tuple, which is the shape CPython produces here, so this is one production per clause. The `as` form is untouched: PEP 758 keeps parentheses required there. python.rs is regenerated with lalrpop 0.20.0, the version that produced the file in tree. The diff is large because the state table renumbers.
1 parent 1834307 commit 287eb80

4 files changed

Lines changed: 9996 additions & 9432 deletions

File tree

parser/src/parser.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,24 @@ except OSError as e:
863863
insta::assert_debug_snapshot!(parse_ast);
864864
}
865865

866+
#[test]
867+
fn test_try_unparenthesized_except_group() {
868+
let parse_ast = ast::Suite::parse(
869+
r#"try:
870+
raise ValueError(1)
871+
except TypeError, OSError:
872+
print('caught')
873+
874+
try:
875+
raise ExceptionGroup('eg', [KeyError()])
876+
except* KeyError, IndexError:
877+
print('caught')"#,
878+
"<test>",
879+
)
880+
.unwrap();
881+
insta::assert_debug_snapshot!(parse_ast);
882+
}
883+
866884
#[test]
867885
fn test_try_star() {
868886
let parse_ast = ast::Suite::parse(

parser/src/python.lalrpop

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,8 @@ TryStatement: ast::Stmt = {
878878
};
879879

880880
ExceptStarClause: ast::ExceptHandler = {
881-
<location:@L> "except" "*" <typ:Test<"all">> ":" <body:Suite> => {
881+
// PEP 758 covers `except*` too.
882+
<location:@L> "except" "*" <typ:GenericList<Test<"all">>> ":" <body:Suite> => {
882883
let end_location = body.last().unwrap().end();
883884
ast::ExceptHandler::ExceptHandler(
884885
ast::ExceptHandlerExceptHandler {
@@ -904,7 +905,11 @@ ExceptStarClause: ast::ExceptHandler = {
904905

905906

906907
ExceptClause: ast::ExceptHandler = {
907-
<location:@L> "except" <typ:Test<"all">?> ":" <body:Suite> => {
908+
// PEP 758: several exception types without parentheses, as long as there
909+
// is no `as` clause. `GenericList` already collapses a single element to
910+
// itself and wraps the rest in a tuple, which is exactly the shape CPython
911+
// produces for `except A, B:`.
912+
<location:@L> "except" <typ:GenericList<Test<"all">>?> ":" <body:Suite> => {
908913
let end_location = body.last().unwrap().end();
909914
ast::ExceptHandler::ExceptHandler(
910915
ast::ExceptHandlerExceptHandler {

0 commit comments

Comments
 (0)