Preserve the magic trailing comma in --sort-reexports#2589
Preserve the magic trailing comma in --sort-reexports#2589dchaudhari7177 wants to merge 3 commits into
--sort-reexports#2589Conversation
--sort-reexports re-renders __all__ from the literal_eval'd value, and _format_collection collapses to a single line whenever the result fits in line_length. A trailing comma in the source was therefore dropped, against black's magic-trailing-comma rule that it asks for one element per line. Detect the trailing comma by tokenizing the literal, so a bracket or comma inside a string element, or a trailing comment, is not mistaken for the end of the literal, and force the vertical-hanging-indent branch when one is found. A one-element tuple is excluded: its trailing comma is required syntax rather than a formatting request, and black does not explode it either. Four existing reexport tests asserted the collapsed output for inputs that carry a magic trailing comma; their expected output is updated.
IndentationError is a subclass of SyntaxError, so catching both is redundant (DeepSource PYL-W0714).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2589 +/- ##
=======================================
Coverage 99.39% 99.39%
=======================================
Files 41 41
Lines 3147 3156 +9
Branches 680 681 +1
=======================================
+ Hits 3128 3137 +9
Misses 11 11
Partials 8 8 🚀 New features to boost your workflow:
|
DanielNoord
left a comment
There was a problem hiding this comment.
Can we fix this without touching the expected output for some of these tests? The expected output for some of those cases shouldn't change.
Per review: the magic-trailing-comma preservation should not change the established collapsed output of the import-focused reexport tests (test_reexport_multiline_import / _in_center / _long_rollback). Their __all__ trailing comma was incidental, not a deliberate magic comma, so drop it from those inputs — they keep asserting the original collapsed '__all__ = ["bar", "foo"]'. Only test_reexport_multiline (the deliberate multiline __all__) now demonstrates the preserved comma, alongside the dedicated new tests.
|
Good call — reverted the expected-output changes on the three import-focused tests ( Only |
DanielNoord
left a comment
There was a problem hiding this comment.
You are still changing expected outputs. Ideally, you should not need to touch any of the existing tests.
Summary
Closes #2578.
--sort-reexportsruns the__all__literal throughast.literal_evaland re-renders it, which loses the original formatting._format_collectionthen picks one line whenever the result fits withinline_length, so a trailing comma in the source was silently dropped:That trailing comma is black's magic trailing comma — a request for one element per line — so this preserves it.
#2582 covered the same issue and was withdrawn by its author; this is an independent implementation.
Implementation
_has_magic_trailing_commatokenizes the literal and checks whether the token before the closing bracket is a comma. Tokenizing rather than scanning text matters: a bracket or comma inside a string element ("b#)","a,") or a trailing comment would otherwise be mistaken for the end of the literal. There is a test for exactly that.When a magic trailing comma is found,
assignmentderives a config withline_length=0andinclude_trailing_comma=True, which forces the vertical-hanging-indent branch of_format_collection. This uses the existingConfig(config=..., ...)derivation pattern already used by_indented_config, and deliberately avoids changing the signature of the registered sort functions, sinceregister_typeis public API.One-element tuples are excluded.
__all__ = ("foo",)needs its comma to stay a tuple — that is syntax, not a formatting request, and black does not explode it either. Without this carve-out every single-export__all__would get exploded.Behaviour change to existing tests
Four existing tests asserted the current output and had to be updated:
test_reexport_multiline,test_reexport_multiline_import,test_reexport_multiline_in_center,test_reexport_multiline_long_rollback. Every one of them feeds in a literal that has a magic trailing comma and asserted it collapsed to a single line — i.e. they pinned the reported bug. Their inputs are unchanged; only the expected output now stays exploded.Worth a look during review, since it is the part that is a deliberate behaviour change rather than a fix. The two rollback/centre tests still pass, so the
reexport_rollbackseek logic is fine with multi-line output.test_reexport_list,test_reexport_setandtest_reexport_bareare untouched and still pass — none of them have a trailing comma, and the bare__all__ = 'foo', 'bar'form has no brackets so detection correctly ignores it.Tests
Four added: the magic comma is preserved; a literal without one still collapses; a one-element tuple is left alone; and the tokenizer-based detection is not fooled by strings or comments.
Revert-verified: with
literal.pyreverted, the two behaviour tests fail and the two control tests still pass.Local results (Windows, Python 3.12)
pytest tests/unit— 604 passed, 4 failed, 5 skipped. The same 4 fail on a clean tree (test_importable,test_windows_diff_too_large_misrepresentative_issue_1348,test_isort_supports_shared_profiles_issue_970,test_sort_configurable_sort_issue_1732); baseline is 600 passed.ruff check,ruff format --checkandmypy isort/literal.pyare all clean.