Skip to content

Commit 86c3aab

Browse files
[8.1.x] Do not import duplicated modules with --importmode=importlib (#12077)
Co-authored-by: Bruno Oliveira <[email protected]>
1 parent 5b82b0c commit 86c3aab

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

changelog/11475.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed regression where ``--importmode=importlib`` would import non-test modules more than once.

src/_pytest/pathlib.py

+4
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,10 @@ def import_path(
539539
except CouldNotResolvePathError:
540540
pass
541541
else:
542+
# If the given module name is already in sys.modules, do not import it again.
543+
with contextlib.suppress(KeyError):
544+
return sys.modules[module_name]
545+
542546
mod = _import_module_using_spec(
543547
module_name, path, pkg_root, insert_modules=False
544548
)

testing/test_pathlib.py

+71
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,12 @@ class Data:
587587
assert data.value == "foo"
588588
assert data.__module__ == "_src.tests.test_dataclass"
589589

590+
# Ensure we do not import the same module again (#11475).
591+
module2 = import_path(
592+
fn, mode="importlib", root=tmp_path, consider_namespace_packages=ns_param
593+
)
594+
assert module is module2
595+
590596
def test_importmode_importlib_with_pickle(
591597
self, tmp_path: Path, ns_param: bool
592598
) -> None:
@@ -616,6 +622,12 @@ def round_trip():
616622
action = round_trip()
617623
assert action() == 42
618624

625+
# Ensure we do not import the same module again (#11475).
626+
module2 = import_path(
627+
fn, mode="importlib", root=tmp_path, consider_namespace_packages=ns_param
628+
)
629+
assert module is module2
630+
619631
def test_importmode_importlib_with_pickle_separate_modules(
620632
self, tmp_path: Path, ns_param: bool
621633
) -> None:
@@ -816,6 +828,14 @@ def __init__(self) -> None:
816828
consider_namespace_packages=ns_param,
817829
)
818830
assert len(mod.instance.INSTANCES) == 1
831+
# Ensure we do not import the same module again (#11475).
832+
mod2 = import_path(
833+
init,
834+
root=tmp_path,
835+
mode=ImportMode.importlib,
836+
consider_namespace_packages=ns_param,
837+
)
838+
assert mod is mod2
819839

820840
def test_importlib_root_is_package(self, pytester: Pytester) -> None:
821841
"""
@@ -942,6 +962,15 @@ def test_import_using_normal_mechanism_first(
942962
assert mod.__name__ == "app.core"
943963
assert mod.__file__ and Path(mod.__file__) == core_py
944964

965+
# Ensure we do not import the same module again (#11475).
966+
mod2 = import_path(
967+
core_py,
968+
mode="importlib",
969+
root=pytester.path,
970+
consider_namespace_packages=ns_param,
971+
)
972+
assert mod is mod2
973+
945974
# tests are not reachable from sys.path, so they are imported as a standalone modules.
946975
# Instead of '.tests.a.test_core', we import as "_tests.a.test_core" because
947976
# importlib considers module names starting with '.' to be local imports.
@@ -952,6 +981,16 @@ def test_import_using_normal_mechanism_first(
952981
consider_namespace_packages=ns_param,
953982
)
954983
assert mod.__name__ == "_tests.a.test_core"
984+
985+
# Ensure we do not import the same module again (#11475).
986+
mod2 = import_path(
987+
test_path1,
988+
mode="importlib",
989+
root=pytester.path,
990+
consider_namespace_packages=ns_param,
991+
)
992+
assert mod is mod2
993+
955994
mod = import_path(
956995
test_path2,
957996
mode="importlib",
@@ -960,6 +999,15 @@ def test_import_using_normal_mechanism_first(
960999
)
9611000
assert mod.__name__ == "_tests.b.test_core"
9621001

1002+
# Ensure we do not import the same module again (#11475).
1003+
mod2 = import_path(
1004+
test_path2,
1005+
mode="importlib",
1006+
root=pytester.path,
1007+
consider_namespace_packages=ns_param,
1008+
)
1009+
assert mod is mod2
1010+
9631011
def test_import_using_normal_mechanism_first_integration(
9641012
self, monkeypatch: MonkeyPatch, pytester: Pytester, ns_param: bool
9651013
) -> None:
@@ -1021,6 +1069,14 @@ def test_import_path_imports_correct_file(
10211069
assert mod.__file__ and Path(mod.__file__) == x_in_sub_folder
10221070
assert mod.X == "a/b/x"
10231071

1072+
mod2 = import_path(
1073+
x_in_sub_folder,
1074+
mode=ImportMode.importlib,
1075+
root=pytester.path,
1076+
consider_namespace_packages=ns_param,
1077+
)
1078+
assert mod is mod2
1079+
10241080
# Attempt to import root 'x.py'.
10251081
with pytest.raises(AssertionError, match="x at root"):
10261082
_ = import_path(
@@ -1124,6 +1180,12 @@ def test_resolve_pkg_root_and_module_name_ns_multiple_levels(
11241180
assert mod.__name__ == "com.company.app.core.models"
11251181
assert mod.__file__ == str(models_py)
11261182

1183+
# Ensure we do not import the same module again (#11475).
1184+
mod2 = import_path(
1185+
models_py, mode=import_mode, root=tmp_path, consider_namespace_packages=True
1186+
)
1187+
assert mod is mod2
1188+
11271189
pkg_root, module_name = resolve_pkg_root_and_module_name(
11281190
algorithms_py, consider_namespace_packages=True
11291191
)
@@ -1141,6 +1203,15 @@ def test_resolve_pkg_root_and_module_name_ns_multiple_levels(
11411203
assert mod.__name__ == "com.company.calc.algo.algorithms"
11421204
assert mod.__file__ == str(algorithms_py)
11431205

1206+
# Ensure we do not import the same module again (#11475).
1207+
mod2 = import_path(
1208+
algorithms_py,
1209+
mode=import_mode,
1210+
root=tmp_path,
1211+
consider_namespace_packages=True,
1212+
)
1213+
assert mod is mod2
1214+
11441215
@pytest.mark.parametrize("import_mode", ["prepend", "append", "importlib"])
11451216
def test_incorrect_namespace_package(
11461217
self,

0 commit comments

Comments
 (0)