feat: add support for PEP758 (#1401)
Some checks are pending
CI / test (macos-latest, 3.10) (push) Waiting to run
CI / test (macos-latest, 3.11) (push) Waiting to run
CI / test (macos-latest, 3.12) (push) Waiting to run
CI / test (macos-latest, 3.13) (push) Waiting to run
CI / test (macos-latest, 3.13t) (push) Waiting to run
CI / test (macos-latest, 3.14) (push) Waiting to run
CI / test (macos-latest, 3.14t) (push) Waiting to run
CI / test (macos-latest, 3.9) (push) Waiting to run
CI / test (ubuntu-latest, 3.10) (push) Waiting to run
CI / test (ubuntu-latest, 3.11) (push) Waiting to run
CI / test (ubuntu-latest, 3.12) (push) Waiting to run
CI / test (ubuntu-latest, 3.13) (push) Waiting to run
CI / test (ubuntu-latest, 3.13t) (push) Waiting to run
CI / test (ubuntu-latest, 3.14) (push) Waiting to run
CI / test (ubuntu-latest, 3.14t) (push) Waiting to run
CI / test (ubuntu-latest, 3.9) (push) Waiting to run
CI / test (windows-latest, 3.10) (push) Waiting to run
CI / test (windows-latest, 3.11) (push) Waiting to run
CI / test (windows-latest, 3.12) (push) Waiting to run
CI / test (windows-latest, 3.13) (push) Waiting to run
CI / test (windows-latest, 3.13t) (push) Waiting to run
CI / test (windows-latest, 3.14) (push) Waiting to run
CI / test (windows-latest, 3.14t) (push) Waiting to run
CI / test (windows-latest, 3.9) (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / docs (push) Waiting to run
CI / Rust unit tests (push) Waiting to run
CI / Rustfmt (push) Waiting to run
CI / build (push) Waiting to run
pypi_upload / build (push) Waiting to run
pypi_upload / Upload wheels to pypi (push) Blocked by required conditions
GitHub Actions Security Analysis with zizmor 🌈 / zizmor latest via PyPI (push) Waiting to run

PEP758 removes the requirement for parentheses to surround exceptions
in except and except* expressions when 'as' is not present.

This pr implements support for parsing these types of statements
This commit is contained in:
martin 2025-09-09 11:16:49 -04:00 committed by GitHub
parent 48668dfabb
commit 3b5329aa20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 9 deletions

View file

@ -344,6 +344,34 @@ class TryTest(CSTNodeTest):
),
"code": "try: pass\nexcept foo()as bar: pass\n",
},
# PEP758 - Multiple exceptions with no parentheses
{
"node": cst.Try(
cst.SimpleStatementSuite((cst.Pass(),)),
handlers=[
cst.ExceptHandler(
cst.SimpleStatementSuite((cst.Pass(),)),
type=cst.Tuple(
elements=[
cst.Element(
value=cst.Name(
value="ValueError",
),
),
cst.Element(
value=cst.Name(
value="RuntimeError",
),
),
],
lpar=[],
rpar=[],
),
)
],
),
"code": "try: pass\nexcept ValueError, RuntimeError: pass\n",
},
)
)
def test_valid(self, **kwargs: Any) -> None:
@ -576,6 +604,38 @@ class TryStarTest(CSTNodeTest):
"parser": native_parse_statement,
"expected_position": CodeRange((1, 0), (5, 13)),
},
# PEP758 - Multiple exceptions with no parentheses
{
"node": cst.TryStar(
cst.SimpleStatementSuite((cst.Pass(),)),
handlers=[
cst.ExceptStarHandler(
cst.SimpleStatementSuite((cst.Pass(),)),
type=cst.Tuple(
elements=[
cst.Element(
value=cst.Name(
value="ValueError",
),
comma=cst.Comma(
whitespace_after=cst.SimpleWhitespace(" ")
),
),
cst.Element(
value=cst.Name(
value="RuntimeError",
),
),
],
lpar=[],
rpar=[],
),
)
],
),
"code": "try: pass\nexcept* ValueError, RuntimeError: pass\n",
"parser": native_parse_statement,
},
)
)
def test_valid(self, **kwargs: Any) -> None:

View file

@ -554,12 +554,21 @@ parser! {
}
// Except statement
rule except_block() -> ExceptHandler<'input, 'a>
= kw:lit("except") e:expression() a:(k:lit("as") n:name() {(k, n)})?
col:lit(":") b:block() {
make_except(kw, Some(e), a, col, b)
}
/ kw:lit("except") e:expression() other:(c:comma() ex:expression() {(c, ex)})+ tc:(c:comma())?
col:lit(":") b:block() {
let tuple = Expression::Tuple(Box::new(Tuple {
elements: comma_separate(expr_to_element(e), other.into_iter().map(|(comma, expr)| (comma, expr_to_element(expr))).collect(), tc),
lpar: vec![],
rpar: vec![],
}));
make_except(kw, Some(tuple), None, col, b)
}
/ kw:lit("except") col:lit(":") b:block() {
make_except(kw, None, None, col, b)
}
@ -569,6 +578,16 @@ parser! {
a:(k:lit("as") n:name() {(k, n)})? col:lit(":") b:block() {
make_except_star(kw, star, e, a, col, b)
}
/ kw:lit("except") star:lit("*") e:expression() other:(c:comma() ex:expression() {(c, ex)})+ tc:(c:comma())?
col:lit(":") b:block() {
let tuple = Expression::Tuple(Box::new(Tuple {
elements: comma_separate(expr_to_element(e), other.into_iter().map(|(comma, expr)| (comma, expr_to_element(expr))).collect(), tc),
lpar: vec![],
rpar: vec![],
}));
make_except_star(kw, star, tuple, None, col, b)
}
rule finally_block() -> Finally<'input, 'a>
= kw:lit("finally") col:lit(":") b:block() {
@ -1550,22 +1569,22 @@ parser! {
rule separated<El, Sep>(el: rule<El>, sep: rule<Sep>) -> (El, Vec<(Sep, El)>)
= e:el() rest:(s:sep() e:el() {(s, e)})* {(e, rest)}
rule traced<T>(e: rule<T>) -> T =
&(_* {
rule traced<T>(e: rule<T>) -> T =
&(_* {
#[cfg(feature = "trace")]
{
println!("[PEG_INPUT_START]");
println!("{}", input);
println!("[PEG_TRACE_START]");
}
})
e:e()? {?
})
e:e()? {?
#[cfg(feature = "trace")]
println!("[PEG_TRACE_STOP]");
e.ok_or("")
}
println!("[PEG_TRACE_STOP]");
e.ok_or("")
}
}
}
}
#[allow(clippy::too_many_arguments)]

View file

@ -69,3 +69,25 @@ except foo:
pass
#9
try:
pass
except (foo, bar):
pass
try:
pass
except foo, bar:
pass
try:
pass
except (foo, bar), baz:
pass
else:
pass
try:
pass
except* something, somethingelse:
pass