Fix import_path for packages (#11390)
For packages, `import_path` receives the path to the package's `__init__.py` file, however module names (as they live in `sys.modules`) should not include the `__init__` part. For example, `app/core/__init__.py` should be imported as `app.core`, not as `app.core.__init__`. Fix #11306
This commit is contained in:
parent
8032d21271
commit
194a782e38
|
@ -0,0 +1 @@
|
|||
Fixed bug using ``--importmode=importlib`` which would cause package ``__init__.py`` files to be imported more than once in some cases.
|
|
@ -623,6 +623,10 @@ def module_name_from_path(path: Path, root: Path) -> str:
|
|||
# Use the parts for the relative path to the root path.
|
||||
path_parts = relative_path.parts
|
||||
|
||||
# Module name for packages do not contain the __init__ file.
|
||||
if path_parts[-1] == "__init__":
|
||||
path_parts = path_parts[:-1]
|
||||
|
||||
return ".".join(path_parts)
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ from _pytest.pathlib import fnmatch_ex
|
|||
from _pytest.pathlib import get_extended_length_path_str
|
||||
from _pytest.pathlib import get_lock_path
|
||||
from _pytest.pathlib import import_path
|
||||
from _pytest.pathlib import ImportMode
|
||||
from _pytest.pathlib import ImportPathMismatchError
|
||||
from _pytest.pathlib import insert_missing_modules
|
||||
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
||||
|
@ -585,6 +586,10 @@ class TestImportLibMode:
|
|||
result = module_name_from_path(Path("/home/foo/test_foo.py"), Path("/bar"))
|
||||
assert result == "home.foo.test_foo"
|
||||
|
||||
# Importing __init__.py files should return the package as module name.
|
||||
result = module_name_from_path(tmp_path / "src/app/__init__.py", tmp_path)
|
||||
assert result == "src.app"
|
||||
|
||||
def test_insert_missing_modules(
|
||||
self, monkeypatch: MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
|
@ -615,3 +620,43 @@ class TestImportLibMode:
|
|||
assert sorted(modules) == ["xxx", "xxx.tests", "xxx.tests.foo"]
|
||||
assert modules["xxx"].tests is modules["xxx.tests"]
|
||||
assert modules["xxx.tests"].foo is modules["xxx.tests.foo"]
|
||||
|
||||
def test_importlib_package(self, monkeypatch: MonkeyPatch, tmp_path: Path):
|
||||
"""
|
||||
Importing a package using --importmode=importlib should not import the
|
||||
package's __init__.py file more than once (#11306).
|
||||
"""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.syspath_prepend(tmp_path)
|
||||
|
||||
package_name = "importlib_import_package"
|
||||
tmp_path.joinpath(package_name).mkdir()
|
||||
init = tmp_path.joinpath(f"{package_name}/__init__.py")
|
||||
init.write_text(
|
||||
dedent(
|
||||
"""
|
||||
from .singleton import Singleton
|
||||
|
||||
instance = Singleton()
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
singleton = tmp_path.joinpath(f"{package_name}/singleton.py")
|
||||
singleton.write_text(
|
||||
dedent(
|
||||
"""
|
||||
class Singleton:
|
||||
INSTANCES = []
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.INSTANCES.append(self)
|
||||
if len(self.INSTANCES) > 1:
|
||||
raise RuntimeError("Already initialized")
|
||||
"""
|
||||
),
|
||||
encoding="ascii",
|
||||
)
|
||||
|
||||
mod = import_path(init, root=tmp_path, mode=ImportMode.importlib)
|
||||
assert len(mod.instance.INSTANCES) == 1
|
||||
|
|
Loading…
Reference in New Issue