scripts/tests/reproduction_utils/test_remove_import.py
scripts/tests/reproduction_utils/test_remove_import.pyBrowse 41 files
1,408 tokens
5,288 bytes
Token encoding: o200k_base
Snapshot a9fb1c3
← Back to SKILL.md
1import subprocess2import sys3from pathlib import Path4 5import pytest6 7sys.path.insert(0, str(Path(__file__).resolve().parents[2]))8 9import mechanical_refactor_reproduction_utils as rr10from mechanical_refactor_reproduction_utils import (11 Repro,12 _def_span,13 _find_class,14 _find_def,15 _replace_span,16 _slice_span,17 dedent,18 exec_command,19 git_add_and_commit,20 verify_mechanical_refactor,21)22from reproduction_testlib import _apply, _commit, _git, _write # noqa: F40123 24# --- remove_import -------------------------------------------------------------25 26 27def test_remove_import_scoped_leaves_module_level_same_text(tmp_path: Path) -> None:28 """Scoped to a function, it removes the local import but not a same-text module-level29 one (e.g. a TYPE_CHECKING guard), and drops the import's trailing blank line."""30 (tmp_path / "m.py").write_text(31 "from typing import TYPE_CHECKING\n"32 "\n"33 "if TYPE_CHECKING:\n"34 " from pkg.mod import Thing\n"35 "\n"36 "def caller(self):\n"37 " from pkg.mod import Thing\n"38 "\n"39 " return Thing.go(self.x)\n"40 )41 r = Repro("b", "t").remove_import(42 "m.py", "from pkg.mod import Thing", in_function="caller"43 )44 _apply(r, tmp_path)45 out = (tmp_path / "m.py").read_text()46 assert out.count("from pkg.mod import Thing") == 147 assert "if TYPE_CHECKING:\n from pkg.mod import Thing" in out48 assert "def caller(self):\n return Thing.go(self.x)\n" in out49 50 51def test_remove_import_removes_every_occurrence_in_scope(tmp_path: Path) -> None:52 """All matching local imports in the function are removed, not just the first."""53 (tmp_path / "m.py").write_text(54 "def caller(self):\n"55 " from pkg import M\n"56 "\n"57 " M.a(self.x)\n"58 " if cond:\n"59 " from pkg import M\n"60 "\n"61 " M.b(self.y)\n"62 )63 r = Repro("b", "t").remove_import("m.py", "from pkg import M", in_function="caller")64 _apply(r, tmp_path)65 assert "from pkg import M" not in (tmp_path / "m.py").read_text()66 67 68# --- remove_imported_name ------------------------------------------------------69 70 71# --- adversarial audit: import primitives ----------------------------------------72 73 74def test_remove_import_unscoped_removes_module_level_import_and_blank(75 tmp_path: Path,76) -> None:77 """Without in_function the matching module-level import and its trailing blank go."""78 (tmp_path / "m.py").write_text("import os\nfrom pkg import Thing\n\nx = Thing\n")79 r = Repro("b", "t").remove_import("m.py", "from pkg import Thing")80 _apply(r, tmp_path)81 assert (tmp_path / "m.py").read_text() == "import os\nx = Thing\n"82 83 84def test_remove_import_keeps_a_code_line_directly_after_the_import(85 tmp_path: Path,86) -> None:87 """Only a blank line after the import is absorbed; a code line stays untouched."""88 (tmp_path / "m.py").write_text("import os\nx = 1\n")89 r = Repro("b", "t").remove_import("m.py", "import os")90 _apply(r, tmp_path)91 assert (tmp_path / "m.py").read_text() == "x = 1\n"92 93 94def test_remove_import_asserts_when_text_absent(tmp_path: Path) -> None:95 """Removing an import text that matches nothing fails loudly."""96 (tmp_path / "m.py").write_text("import os\n")97 r = Repro("b", "t").remove_import("m.py", "from pkg import Q")98 with pytest.raises(AssertionError):99 _apply(r, tmp_path)100 101 102def test_remove_import_asserts_when_scope_function_missing(tmp_path: Path) -> None:103 """Scoping to a function that does not exist fails loudly."""104 (tmp_path / "m.py").write_text("def f():\n import os\n")105 r = Repro("b", "t").remove_import("m.py", "import os", in_function="nope")106 with pytest.raises(AssertionError):107 _apply(r, tmp_path)108 109 110def test_remove_import_leaves_other_statements_on_a_semicolon_line(111 tmp_path: Path,112) -> None:113 """Removing 'import os' from a semicolon-joined line must keep 'import sys'."""114 (tmp_path / "m.py").write_text("import os; import sys\nprint(sys.path)\n")115 r = Repro("b", "t").remove_import("m.py", "import os")116 _apply(r, tmp_path)117 out = (tmp_path / "m.py").read_text()118 assert "import sys" in out and "print(sys.path)" in out119 120 121def test_remove_import_trailing_on_a_semicolon_line_leaves_no_dangling_separator(122 tmp_path: Path,123) -> None:124 """Removing the trailing import on a semicolon-joined line drops the dangling ';' too125 (a trailing space may remain for the formatter to strip, but the separator is gone).126 """127 (tmp_path / "m.py").write_text("import sys; import os\nprint(sys.path)\n")128 r = Repro("b", "t").remove_import("m.py", "import os")129 _apply(r, tmp_path)130 out = (tmp_path / "m.py").read_text()131 assert ";" not in out132 assert "import os" not in out133 assert "import sys" in out and "print(sys.path)" in out134 135 136def test_remove_import_does_not_overmatch_a_submodule_import(tmp_path: Path) -> None:137 """Removing 'import os' must not also remove 'import os.path'."""138 (tmp_path / "m.py").write_text("import os\nimport os.path\nprint(os.path.sep)\n")139 r = Repro("b", "t").remove_import("m.py", "import os")140 _apply(r, tmp_path)141 assert "import os.path\n" in (tmp_path / "m.py").read_text()142