|
18 | 18 | from _pytest.pathlib import get_extended_length_path_str
|
19 | 19 | from _pytest.pathlib import get_lock_path
|
20 | 20 | from _pytest.pathlib import import_path
|
| 21 | +from _pytest.pathlib import ImportMode |
21 | 22 | from _pytest.pathlib import ImportPathMismatchError
|
22 | 23 | from _pytest.pathlib import insert_missing_modules
|
23 | 24 | from _pytest.pathlib import maybe_delete_a_numbered_dir
|
@@ -585,6 +586,10 @@ def test_module_name_from_path(self, tmp_path: Path) -> None:
|
585 | 586 | result = module_name_from_path(Path("/home/foo/test_foo.py"), Path("/bar"))
|
586 | 587 | assert result == "home.foo.test_foo"
|
587 | 588 |
|
| 589 | + # Importing __init__.py files should return the package as module name. |
| 590 | + result = module_name_from_path(tmp_path / "src/app/__init__.py", tmp_path) |
| 591 | + assert result == "src.app" |
| 592 | + |
588 | 593 | def test_insert_missing_modules(
|
589 | 594 | self, monkeypatch: MonkeyPatch, tmp_path: Path
|
590 | 595 | ) -> None:
|
@@ -615,3 +620,43 @@ def test_parent_contains_child_module_attribute(
|
615 | 620 | assert sorted(modules) == ["xxx", "xxx.tests", "xxx.tests.foo"]
|
616 | 621 | assert modules["xxx"].tests is modules["xxx.tests"]
|
617 | 622 | assert modules["xxx.tests"].foo is modules["xxx.tests.foo"]
|
| 623 | + |
| 624 | + def test_importlib_package(self, monkeypatch: MonkeyPatch, tmp_path: Path): |
| 625 | + """ |
| 626 | + Importing a package using --importmode=importlib should not import the |
| 627 | + package's __init__.py file more than once (#11306). |
| 628 | + """ |
| 629 | + monkeypatch.chdir(tmp_path) |
| 630 | + monkeypatch.syspath_prepend(tmp_path) |
| 631 | + |
| 632 | + package_name = "importlib_import_package" |
| 633 | + tmp_path.joinpath(package_name).mkdir() |
| 634 | + init = tmp_path.joinpath(f"{package_name}/__init__.py") |
| 635 | + init.write_text( |
| 636 | + dedent( |
| 637 | + """ |
| 638 | + from .singleton import Singleton |
| 639 | +
|
| 640 | + instance = Singleton() |
| 641 | + """ |
| 642 | + ), |
| 643 | + encoding="ascii", |
| 644 | + ) |
| 645 | + singleton = tmp_path.joinpath(f"{package_name}/singleton.py") |
| 646 | + singleton.write_text( |
| 647 | + dedent( |
| 648 | + """ |
| 649 | + class Singleton: |
| 650 | + INSTANCES = [] |
| 651 | +
|
| 652 | + def __init__(self) -> None: |
| 653 | + self.INSTANCES.append(self) |
| 654 | + if len(self.INSTANCES) > 1: |
| 655 | + raise RuntimeError("Already initialized") |
| 656 | + """ |
| 657 | + ), |
| 658 | + encoding="ascii", |
| 659 | + ) |
| 660 | + |
| 661 | + mod = import_path(init, root=tmp_path, mode=ImportMode.importlib) |
| 662 | + assert len(mod.instance.INSTANCES) == 1 |
0 commit comments