diff --git a/libcst/codemod/commands/tests/test_remove_unused_imports.py b/libcst/codemod/commands/tests/test_remove_unused_imports.py index d7b369ed9..2c8175607 100644 --- a/libcst/codemod/commands/tests/test_remove_unused_imports.py +++ b/libcst/codemod/commands/tests/test_remove_unused_imports.py @@ -83,3 +83,10 @@ def test_access_in_assignment(self) -> None: b(0)[x] = False """ self.assertCodemod(before, before) + + def test_no_formatting_if_no_unused_imports(self) -> None: + before = """ + from m import (a, b,) + a(b, 'look at these ugly quotes') + """ + self.assertCodemod(before, before) diff --git a/libcst/codemod/visitors/_remove_imports.py b/libcst/codemod/visitors/_remove_imports.py index 8c3dc9f85..318372d8d 100644 --- a/libcst/codemod/visitors/_remove_imports.py +++ b/libcst/codemod/visitors/_remove_imports.py @@ -343,17 +343,22 @@ def leave_Import( names_to_keep.append(import_alias) continue + # no changes + if names_to_keep == original_node.names: + return updated_node + # Now, either remove this statement or remove the imports we are # deleting from this statement. if len(names_to_keep) == 0: return cst.RemoveFromParent() - else: + + if names_to_keep[-1] != original_node.names[-1]: # Remove trailing comma in order to not mess up import statements. names_to_keep = [ *names_to_keep[:-1], names_to_keep[-1].with_changes(comma=cst.MaybeSentinel.DEFAULT), ] - return updated_node.with_changes(names=names_to_keep) + return updated_node.with_changes(names=names_to_keep) def leave_ImportFrom( self, original_node: cst.ImportFrom, updated_node: cst.ImportFrom @@ -399,14 +404,19 @@ def leave_ImportFrom( names_to_keep.append(import_alias) continue + # no changes + if names_to_keep == names: + return updated_node + # Now, either remove this statement or remove the imports we are # deleting from this statement. if len(names_to_keep) == 0: return cst.RemoveFromParent() - else: + + if names_to_keep[-1] != names[-1]: # Remove trailing comma in order to not mess up import statements. names_to_keep = [ *names_to_keep[:-1], names_to_keep[-1].with_changes(comma=cst.MaybeSentinel.DEFAULT), ] - return updated_node.with_changes(names=names_to_keep) + return updated_node.with_changes(names=names_to_keep) diff --git a/libcst/codemod/visitors/tests/test_remove_imports.py b/libcst/codemod/visitors/tests/test_remove_imports.py index 21932b65e..d8d0e1863 100644 --- a/libcst/codemod/visitors/tests/test_remove_imports.py +++ b/libcst/codemod/visitors/tests/test_remove_imports.py @@ -797,3 +797,17 @@ def visit_ImportFrom(self, node: cst.ImportFrom) -> None: after, RemoveImportTransformer(CodemodContext()).transform_module(module).code, ) + + def test_remove_comma(self) -> None: + """ + Trailing commas should be removed if and only if the last alias is removed. + """ + before = """ + from m import (a, b,) + import x, y + """ + after = """ + from m import (b,) + import x + """ + self.assertCodemod(before, after, [("m", "a", None), ("y", None, None)])