import itertools
import os
import pathlib
+import pkgutil
import re
import rlcompleter
import select
("from importlib import mac\t\n", "from importlib import machinery"),
("from importlib import res\t\n", "from importlib import resources"),
("from importlib.res\t import a\t\n", "from importlib.resources import abc"),
+ ("from __phello__ import s\t\n", "from __phello__ import spam"), # frozen module
)
for code, expected in cases:
with self.subTest(code=code):
self.assertEqual(output, expected)
def test_hardcoded_stdlib_submodules_not_proposed_if_local_import(self):
- with tempfile.TemporaryDirectory() as _dir:
+ with (tempfile.TemporaryDirectory() as _dir,
+ patch.object(sys, "modules", {})): # hide imported module
dir = pathlib.Path(_dir)
(dir / "collections").mkdir()
(dir / "collections" / "__init__.py").touch()
(dir / "collections" / "foo.py").touch()
- with patch.object(sys, "path", [dir, *sys.path]):
+ with patch.object(sys, "path", [_dir, *sys.path]):
events = code_to_events("import collections.\t\n")
reader = self.prepare_reader(events, namespace={})
output = reader.readline()
self.assertEqual(output, "import collections.foo")
+ def test_already_imported_stdlib_module_no_other_suggestions(self):
+ with (tempfile.TemporaryDirectory() as _dir,
+ patch.object(sys, "path", [_dir, *sys.path])):
+ dir = pathlib.Path(_dir)
+ (dir / "collections").mkdir()
+ (dir / "collections" / "__init__.py").touch()
+ (dir / "collections" / "foo.py").touch()
+
+ # collections found in dir, but was already imported
+ # from stdlib at startup -> suggest stdlib submodules only
+ events = code_to_events("import collections.\t\n")
+ reader = self.prepare_reader(events, namespace={})
+ output = reader.readline()
+ self.assertEqual(output, "import collections.abc")
+
+ def test_already_imported_custom_module_no_suggestions(self):
+ with (tempfile.TemporaryDirectory() as _dir1,
+ tempfile.TemporaryDirectory() as _dir2,
+ patch.object(sys, "path", [_dir2, _dir1, *sys.path])):
+ dir1 = pathlib.Path(_dir1)
+ (dir1 / "mymodule").mkdir()
+ (dir1 / "mymodule" / "__init__.py").touch()
+ (dir1 / "mymodule" / "foo.py").touch()
+ importlib.import_module("mymodule")
+
+ dir2 = pathlib.Path(_dir2)
+ (dir2 / "mymodule").mkdir()
+ (dir2 / "mymodule" / "__init__.py").touch()
+ (dir2 / "mymodule" / "bar.py").touch()
+ # Purge FileFinder cache after adding files
+ pkgutil.get_importer(_dir2).invalidate_caches()
+ # mymodule found in dir2 before dir1, but it was already imported
+ # from dir1 -> do not suggest dir2 submodules
+ events = code_to_events("import mymodule.\t\n")
+ reader = self.prepare_reader(events, namespace={})
+ output = reader.readline()
+ self.assertEqual(output, "import mymodule.")
+
+ del sys.modules["mymodule"]
+ # mymodule not imported anymore -> suggest dir2 submodules
+ events = code_to_events("import mymodule.\t\n")
+ reader = self.prepare_reader(events, namespace={})
+ output = reader.readline()
+ self.assertEqual(output, "import mymodule.bar")
+
+ def test_already_imported_custom_file_no_suggestions(self):
+ # Same as before, but mymodule from dir1 has no submodules
+ # -> propose nothing
+ with (tempfile.TemporaryDirectory() as _dir1,
+ tempfile.TemporaryDirectory() as _dir2,
+ patch.object(sys, "path", [_dir2, _dir1, *sys.path])):
+ dir1 = pathlib.Path(_dir1)
+ (dir1 / "mymodule").mkdir()
+ (dir1 / "mymodule.py").touch()
+ importlib.import_module("mymodule")
+
+ dir2 = pathlib.Path(_dir2)
+ (dir2 / "mymodule").mkdir()
+ (dir2 / "mymodule" / "__init__.py").touch()
+ (dir2 / "mymodule" / "bar.py").touch()
+ events = code_to_events("import mymodule.\t\n")
+ reader = self.prepare_reader(events, namespace={})
+ output = reader.readline()
+ self.assertEqual(output, "import mymodule.")
+ del sys.modules["mymodule"]
+
+ def test_already_imported_module_without_origin_or_spec(self):
+ with (tempfile.TemporaryDirectory() as _dir1,
+ patch.object(sys, "path", [_dir1, *sys.path])):
+ dir1 = pathlib.Path(_dir1)
+ for mod in ("no_origin", "not_has_location", "no_spec"):
+ (dir1 / mod).mkdir()
+ (dir1 / mod / "__init__.py").touch()
+ (dir1 / mod / "foo.py").touch()
+ module = importlib.import_module(mod)
+ assert module.__spec__
+ if mod == "no_origin":
+ module.__spec__.origin = None
+ elif mod == "not_has_location":
+ module.__spec__.has_location = False
+ else:
+ module.__spec__ = None
+ events = code_to_events(f"import {mod}.\t\n")
+ reader = self.prepare_reader(events, namespace={})
+ output = reader.readline()
+ self.assertEqual(output, f"import {mod}.")
+ del sys.modules[mod]
+
def test_get_path_and_prefix(self):
cases = (
('', ('', '')),