diff --git a/CHANGELOG.md b/CHANGELOG.md index ff6f27ed8..8fe9aa442 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # **Upcoming release** -- ... +- #811 Preserve still-used imports when moving globals with filtered import cleanup # Release 1.15.0 diff --git a/rope/refactor/importutils/actions.py b/rope/refactor/importutils/actions.py index 47e6e8c7f..37d345360 100644 --- a/rope/refactor/importutils/actions.py +++ b/rope/refactor/importutils/actions.py @@ -175,6 +175,11 @@ def visitFromImport(self, import_stmt, import_info): ): if import_info.is_star_import(): return True + if import_stmt.readonly: + return not self.import_info.is_star_import() and all( + pair in import_info.names_and_aliases + for pair in self.import_info.names_and_aliases + ) if self.import_info.is_star_import(): import_stmt.import_info = self.import_info return True diff --git a/ropetest/refactor/importutilstest.py b/ropetest/refactor/importutilstest.py index a2ebd49d1..a9a482a86 100644 --- a/ropetest/refactor/importutilstest.py +++ b/ropetest/refactor/importutilstest.py @@ -1948,6 +1948,30 @@ def import_filter(import_stmt): return import_filter + def test_filtered_duplicate_removal_preserves_distinct_from_imports(self): + for imported in ("mod3", "mod3 as other", "*"): + with self.subTest(imported=imported): + source = "from pkg2 import mod2\nfrom pkg2 import " + imported + "\n" + self.mod.write(source) + pymod = self.project.get_pymodule(self.mod) + module_imports = self.import_tools.module_imports( + pymod, self._line_filter(2) + ) + module_imports.remove_duplicates() + self.assertEqual(source, module_imports.get_changed_source()) + + def test_filtered_duplicate_removal_still_removes_covered_imports(self): + for imported in ("mod2", "mod2, mod3", "*"): + with self.subTest(imported=imported): + expected = "from pkg2 import " + imported + "\n" + self.mod.write(expected + "from pkg2 import mod2\n") + pymod = self.project.get_pymodule(self.mod) + module_imports = self.import_tools.module_imports( + pymod, self._line_filter(2) + ) + module_imports.remove_duplicates() + self.assertEqual(expected, module_imports.get_changed_source()) + def test_filtered_expand_stars(self): self.pkg1.get_child("__init__.py").write("var1 = 1\n") self.pkg2.get_child("__init__.py").write("var2 = 1\n") diff --git a/ropetest/refactor/movetest.py b/ropetest/refactor/movetest.py index 90f235d32..deb511ba3 100644 --- a/ropetest/refactor/movetest.py +++ b/ropetest/refactor/movetest.py @@ -73,6 +73,29 @@ def test_move_constant(self) -> None: self.assertEqual("", self.origin_module.read()) self.assertEqual("foo = 123\n", self.destination_module.read()) + def test_move_constant_preserves_used_module_alias(self) -> None: + self.project.prefs["prefer_module_from_imports"] = True + self.mod4.write("def keep():\n return 1\n\nvalue = 2\n") + self.mod5.write("def existing():\n return 3\n") + self.mod3.write( + "from pkg import mod5\n" + "from pkg import mod4 as utils_module\n" + "\n" + "def run():\n" + " return mod5.existing(), utils_module.keep(), utils_module.value\n" + ) + self._move(self.mod4, self.mod4.read().index("value"), self.mod5) + self.assertEqual( + "from pkg import mod5\n" + "from pkg import mod4 as utils_module\n" + "\n" + "def run():\n" + " return mod5.existing(), utils_module.keep(), mod5.value\n", + self.mod3.read(), + ) + self.assertEqual("def keep():\n return 1\n\n", self.mod4.read()) + self.assertIn("value = 2\n", self.mod5.read()) + def test_move_constant_2(self) -> None: self.origin_module.write("bar = 321\nfoo = 123\n") self._move(self.origin_module, self.origin_module.read().index("foo") + 1, self.destination_module)