Skip to content

Commit 55a227d

Browse files
Python: fix ChangeImport leaving stray leading newline when import is the only statement (#7433)
When `ChangeImport` replaced the only statement in a file, the scheduled `AddImport` pass ran against an empty statement list and fell through to the "inserting after existing imports" branch, prefixing the new import with `\n` and producing `\nfrom collections.abc import Callable\n`. Handle the empty-statement-list case explicitly: the new import becomes the sole statement with empty prefix; the trailing newline stays in `cu.eof`.
1 parent f17ba12 commit 55a227d

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

rewrite-python/rewrite/src/rewrite/python/add_import.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,13 @@ def _add_import(self, cu: CompilationUnit) -> CompilationUnit:
260260
break # Stop after we've passed the import section
261261

262262
# Insert the new import at the padding level
263-
if insert_idx == 0 and padded_stmts:
263+
if not padded_stmts:
264+
# Empty file (e.g., a prior remove-import emptied the statement
265+
# list). The new import becomes the sole statement with empty
266+
# prefix; any trailing newline lives in cu.eof.
267+
new_padded = JRightPadded(new_import.replace(prefix=Space.EMPTY), Space.EMPTY, Markers.EMPTY)
268+
padded_stmts.append(new_padded)
269+
elif insert_idx == 0:
264270
first = padded_stmts[0]
265271
first_prefix = first.element.prefix
266272
if first_prefix.whitespace and first_prefix.whitespace.startswith('\n'):

rewrite-python/rewrite/tests/recipes/test_change_import.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ def test_change_from_import_module_and_name(self):
4646
)
4747
)
4848

49+
def test_change_import_only_statement(self):
50+
"""Import is the only statement in the file — no leading newline in output."""
51+
spec = RecipeSpec(recipe=ChangeImport(
52+
old_module='typing',
53+
old_name='Callable',
54+
new_module='collections.abc',
55+
))
56+
spec.rewrite_run(
57+
python(
58+
"from typing import Callable\n",
59+
"from collections.abc import Callable\n",
60+
)
61+
)
62+
4963
def test_change_direct_import(self):
5064
"""Change: import os -> import pathlib"""
5165
spec = RecipeSpec(recipe=ChangeImport(

0 commit comments

Comments
 (0)