Skip to content

Preserve whitespace before : in except handlers without as - #1473

Open
Thanatos9404 wants to merge 1 commit into
Instagram:mainfrom
Thanatos9404:fix-except-whitespace-before-colon
Open

Thanatos9404 wants to merge 1 commit into
Instagram:mainfrom
Thanatos9404:fix-except-whitespace-before-colon

Conversation

@Thanatos9404

Copy link
Copy Markdown

Summary

Fixes #1457.

The native parser only read the whitespace before the colon of an except or except* handler when the handler had an as name. Without one, whitespace_before_colon was left at its default and the whitespace was dropped, so except A : came back as except A:. The ExceptHandler and ExceptStarHandler nodes already have the field and emit it in codegen, so the fix is only in the two Inflate impls in native/libcst/src/nodes/statement.rs: always parse whitespace_before_colon from the colon token.

A bare except : parses the same as before (whitespace_after_except=" ", whitespace_before_colon=""). The whitespace after except and before : is the same token whitespace there, and whitespace_after_except consumes it first, so it is not duplicated. There is a test for that case.

Test Plan

New tests:

  • native/libcst/tests/fixtures/terrible_tries.py and starry_tries.py: whitespace before : after a name, a parenthesized tuple, an unparenthesized tuple (PEP 758) and an as name, plus a bare except :. Both parser_roundtrip.rs and libcst/tests/test_roundtrip.py round-trip these fixtures.
  • libcst/_nodes/tests/test_try.py: parse and codegen cases checking that whitespace_before_colon is populated for except Exception : and except (IOError, ImportError) :, the same two for except*, and that a bare except : still parses as before.

On main plus only the new tests, the four new whitespace cases and both fixture round trips fail (except foo : comes back as except foo:); the bare except : case passes. With the fix (Ubuntu 24.04 on WSL2, Python 3.10, debug build) these pass:

  • uv run poe test
  • pyre check
  • cargo test --manifest-path=native/Cargo.toml, with and without --no-default-features
  • cargo fmt --all --manifest-path=native/Cargo.toml -- --check
  • cargo clippy --manifest-path=native/Cargo.toml --all-targets --all-features (no new warnings)
  • flake8 and ufmt check on test_try.py, scripts/check_copyright.py

The native parser only read the whitespace before the colon of an
ExceptHandler or ExceptStarHandler when the handler had an `as` name.
Without a name that whitespace was not stored anywhere, so `except A :`
and `except* A :` came back as `except A:` and `except* A:` after a
parse and codegen round trip.

Always parse whitespace_before_colon from the colon token. A bare
`except :` is unchanged: its whitespace is shared with the colon token
and is still consumed first by whitespace_after_except.

Add round-trip fixtures for both handler types, and node tests that
check whitespace_before_colon is populated when there is no name.

Fixes Instagram#1457
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LibCST drops whitespace before : in except / except* handlers without as

1 participant