Keep the inserted block indented when the print call is not a bare name - #71
Open
dchaudhari7177 wants to merge 2 commits into
Open
Conversation
find_print only recognises a literal `print(...)` -- a Call whose func is a Name with id 'print'. Output reaches the mock through other forms too: `builtins.print(...)`, a local alias, or a method that prints internally (the report.print() in the issue). For those, find_print_location fell back to `(line_no, 0)`, so a multi-line block was written hard against the left margin even inside an indented function body, and the updated file no longer round-tripped. The fallback now uses the indentation of the source line instead of 0. That is the right answer whichever form the call took, since the block is inserted directly beneath that line -- and it needs no new special cases as more callable forms appear. Three regressions covering builtins.print, an alias and a method named print, plus controls that a bare print still takes the AST path and that an out-of-range line_no does not raise, since line_no is documented as possibly approximate. Closes pydantic#59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #59.
Diagnosis
find_printmatches only a literalprint(...)— anast.Callwhosefuncis aNamewith id'print'. When it finds nothing,find_print_locationfalls back to(line_no, 0), and that column becomes the indent of the inserted block.Output reaches the mock through forms that fall outside that match:
builtins.print(...)—funcis anAttributep = print; p(...)) —funcis aName, but not namedprintreport_default.print()in your exampleFor those, the multi-line block was written at column 0 inside an indented function body, producing a file that no longer round-trips. Reproduced with
line_length=30:That explains the "sometimes" in the title. I checked first, and a plain
print(...)indents correctly at top level, indef main(), inasync def main(), and nested inside anif— being async is not the trigger, and the same mis-indent happens in a sync function.Fix
The fallback uses the indentation of the source line rather than 0.
That is the correct column whichever form the call took, since the block is inserted directly beneath that line. I preferred it to teaching
find_printaboutAttributecalls: that would fixbuiltins.printandreport.print()but not the alias, and would need extending again for the next form. The AST path is unchanged and still takes precedence.Tests
Three regressions —
builtins.print, an alias, and a method namedprint— asserting column 4 rather than 0. Both controls matter:print(...)still resolves through the AST path to(2, 4)line_noreturns 0 without raising, since the docstring says the argument may be approximateRevert-verified: the three fail on a clean tree, the two controls pass on both.
Test results
The repo currently has 7 pre-existing failures on
main— the ruff 0.16 incompatibility from #69 (which my #70 addresses), plustest_insert_print_check_unchanged[hex_id].pytestalso cannot collecttests/test_update_examples_dir.pyorexample/test_example.pyat all on current pytest, which fails on a generator passed toparametrize.So rather than quote a total, I diffed the failure sets:
Same 12 failures before and after, byte for byte — nothing regressed, and I haven't claimed a green suite that isn't green.
AI disclosure
Written with Claude Code (Claude Opus 5): it found the
ast.Namerestriction, wrote the fix and the tests, and drafted this description. The reproduction across the four call forms, the revert check, and the before/after failure-set diff were run by hand.