diff --git a/libcst/_nodes/tests/test_try.py b/libcst/_nodes/tests/test_try.py index c5ae2462..8c96f060 100644 --- a/libcst/_nodes/tests/test_try.py +++ b/libcst/_nodes/tests/test_try.py @@ -372,6 +372,60 @@ class TryTest(CSTNodeTest): ), "code": "try: pass\nexcept ValueError, RuntimeError: pass\n", }, + # Whitespace before the colon without an as name + { + "node": cst.Try( + cst.SimpleStatementSuite((cst.Pass(),)), + handlers=( + cst.ExceptHandler( + cst.SimpleStatementSuite((cst.Pass(),)), + type=cst.Name("Exception"), + whitespace_before_colon=cst.SimpleWhitespace(" "), + ), + ), + ), + "code": "try: pass\nexcept Exception : pass\n", + "parser": parse_statement, + }, + # Whitespace before the colon after a parenthesized tuple + { + "node": cst.Try( + cst.SimpleStatementSuite((cst.Pass(),)), + handlers=( + cst.ExceptHandler( + cst.SimpleStatementSuite((cst.Pass(),)), + type=cst.Tuple( + [ + cst.Element( + cst.Name("IOError"), + comma=cst.Comma( + whitespace_after=cst.SimpleWhitespace(" ") + ), + ), + cst.Element(cst.Name("ImportError")), + ] + ), + whitespace_before_colon=cst.SimpleWhitespace(" "), + ), + ), + ), + "code": "try: pass\nexcept (IOError, ImportError) : pass\n", + "parser": parse_statement, + }, + # A bare except keeps its space in whitespace_after_except + { + "node": cst.Try( + cst.SimpleStatementSuite((cst.Pass(),)), + handlers=( + cst.ExceptHandler( + cst.SimpleStatementSuite((cst.Pass(),)), + whitespace_after_except=cst.SimpleWhitespace(" "), + ), + ), + ), + "code": "try: pass\nexcept : pass\n", + "parser": parse_statement, + }, ) ) def test_valid(self, **kwargs: Any) -> None: @@ -636,6 +690,46 @@ class TryStarTest(CSTNodeTest): "code": "try: pass\nexcept* ValueError, RuntimeError: pass\n", "parser": native_parse_statement, }, + # Whitespace before the colon without an as name + { + "node": cst.TryStar( + cst.SimpleStatementSuite((cst.Pass(),)), + handlers=( + cst.ExceptStarHandler( + cst.SimpleStatementSuite((cst.Pass(),)), + type=cst.Name("Exception"), + whitespace_before_colon=cst.SimpleWhitespace(" "), + ), + ), + ), + "code": "try: pass\nexcept* Exception : pass\n", + "parser": native_parse_statement, + }, + # Whitespace before the colon after a parenthesized tuple + { + "node": cst.TryStar( + cst.SimpleStatementSuite((cst.Pass(),)), + handlers=( + cst.ExceptStarHandler( + cst.SimpleStatementSuite((cst.Pass(),)), + type=cst.Tuple( + [ + cst.Element( + cst.Name("IOError"), + comma=cst.Comma( + whitespace_after=cst.SimpleWhitespace(" ") + ), + ), + cst.Element(cst.Name("ImportError")), + ] + ), + whitespace_before_colon=cst.SimpleWhitespace(" "), + ), + ), + ), + "code": "try: pass\nexcept* (IOError, ImportError) : pass\n", + "parser": native_parse_statement, + }, ) ) def test_valid(self, **kwargs: Any) -> None: diff --git a/native/libcst/src/nodes/statement.rs b/native/libcst/src/nodes/statement.rs index 8ed32a6b..ec39cce1 100644 --- a/native/libcst/src/nodes/statement.rs +++ b/native/libcst/src/nodes/statement.rs @@ -2100,14 +2100,12 @@ impl<'r, 'a> Inflate<'a> for DeflatedExceptHandler<'r, 'a> { let r#type = self.r#type.inflate(config)?; let name = self.name.inflate(config)?; - let whitespace_before_colon = if name.is_some() { - parse_simple_whitespace( - config, - &mut (*self.colon_tok).whitespace_before.borrow_mut(), - )? - } else { - Default::default() - }; + // In a bare `except :`, whitespace_after_except has already consumed this + // whitespace, so it parses as empty here. + let whitespace_before_colon = parse_simple_whitespace( + config, + &mut (*self.colon_tok).whitespace_before.borrow_mut(), + )?; let body = self.body.inflate(config)?; Ok(Self::Inflated { @@ -2172,11 +2170,8 @@ impl<'r, 'a> Inflate<'a> for DeflatedExceptStarHandler<'r, 'a> { let r#type = self.r#type.inflate(config)?; let name = self.name.inflate(config)?; - let whitespace_before_colon = if name.is_some() { - parse_simple_whitespace(config, &mut self.colon_tok.whitespace_before.borrow_mut())? - } else { - Default::default() - }; + let whitespace_before_colon = + parse_simple_whitespace(config, &mut self.colon_tok.whitespace_before.borrow_mut())?; let body = self.body.inflate(config)?; Ok(Self::Inflated { diff --git a/native/libcst/tests/fixtures/starry_tries.py b/native/libcst/tests/fixtures/starry_tries.py index 2749a031..51f7927d 100644 --- a/native/libcst/tests/fixtures/starry_tries.py +++ b/native/libcst/tests/fixtures/starry_tries.py @@ -30,6 +30,17 @@ finally: pass +try: + pass +except* foo : + pass +except* (foo, bar) : + pass +except* foo, bar : + pass +except* foo as bar : + pass + try: diff --git a/native/libcst/tests/fixtures/terrible_tries.py b/native/libcst/tests/fixtures/terrible_tries.py index eb5429cc..aa11052c 100644 --- a/native/libcst/tests/fixtures/terrible_tries.py +++ b/native/libcst/tests/fixtures/terrible_tries.py @@ -75,6 +75,19 @@ except (foo, bar): pass +try: + pass +except foo : + pass +except (foo, bar) : + pass +except foo, bar : + pass +except foo as bar : + pass +except : + pass + try: pass except foo, bar: