Skip to content

Commit 68a4d98

Browse files
committed
Add regression test for pytest-dev#12112
1 parent f75dd87 commit 68a4d98

File tree

1 file changed

+65
-4
lines changed

1 file changed

+65
-4
lines changed

testing/test_pathlib.py

+65-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# mypy: allow-untyped-defs
22
import errno
3+
import importlib.abc
4+
import importlib.machinery
35
import os.path
46
from pathlib import Path
57
import pickle
@@ -10,6 +12,7 @@
1012
from typing import Any
1113
from typing import Generator
1214
from typing import Iterator
15+
from typing import Optional
1316
from typing import Tuple
1417
import unittest.mock
1518

@@ -1120,7 +1123,7 @@ class TestNamespacePackages:
11201123
"""Test import_path support when importing from properly namespace packages."""
11211124

11221125
def setup_directories(
1123-
self, tmp_path: Path, monkeypatch: MonkeyPatch, pytester: Pytester
1126+
self, tmp_path: Path, monkeypatch: Optional[MonkeyPatch], pytester: Pytester
11241127
) -> Tuple[Path, Path]:
11251128
# Set up a namespace package "com.company", containing
11261129
# two subpackages, "app" and "calc".
@@ -1149,9 +1152,9 @@ def setup_directories(
11491152
)
11501153
)
11511154
assert r.ret == 0
1152-
1153-
monkeypatch.syspath_prepend(tmp_path / "src/dist1")
1154-
monkeypatch.syspath_prepend(tmp_path / "src/dist2")
1155+
if monkeypatch is not None:
1156+
monkeypatch.syspath_prepend(tmp_path / "src/dist1")
1157+
monkeypatch.syspath_prepend(tmp_path / "src/dist2")
11551158
return models_py, algorithms_py
11561159

11571160
@pytest.mark.parametrize("import_mode", ["prepend", "append", "importlib"])
@@ -1235,3 +1238,61 @@ def test_incorrect_namespace_package(
12351238
tmp_path / "src/dist1/com/company",
12361239
"app.core.models",
12371240
)
1241+
1242+
def test_detect_meta_path(
1243+
self,
1244+
tmp_path: Path,
1245+
monkeypatch: MonkeyPatch,
1246+
pytester: Pytester,
1247+
) -> None:
1248+
"""
1249+
resolve_pkg_root_and_module_name() considers sys.meta_path when importing namespace packages.
1250+
1251+
Regression test for #12112.
1252+
"""
1253+
1254+
class CustomImporter(importlib.abc.MetaPathFinder):
1255+
"""
1256+
Imports the module name "com" as a namespace package.
1257+
1258+
This ensures our namespace detection considers sys.meta_path, which is important
1259+
to support all possible ways a module can be imported (for example editable installs).
1260+
"""
1261+
1262+
def find_spec(
1263+
self, name: str, path: Any = None, target: Any = None
1264+
) -> Optional[importlib.machinery.ModuleSpec]:
1265+
if name == "com":
1266+
spec = importlib.machinery.ModuleSpec("com", loader=None)
1267+
spec.submodule_search_locations = [str(com_root_2), str(com_root_1)]
1268+
return spec
1269+
return None
1270+
1271+
# Setup directories without configuring sys.path.
1272+
models_py, algorithms_py = self.setup_directories(
1273+
tmp_path, monkeypatch=None, pytester=pytester
1274+
)
1275+
com_root_1 = tmp_path / "src/dist1/com"
1276+
com_root_2 = tmp_path / "src/dist2/com"
1277+
1278+
# Because the namespace package is not setup correctly, we cannot resolve it as a namespace package.
1279+
pkg_root, module_name = resolve_pkg_root_and_module_name(
1280+
models_py, consider_namespace_packages=True
1281+
)
1282+
assert (pkg_root, module_name) == (
1283+
tmp_path / "src/dist1/com/company",
1284+
"app.core.models",
1285+
)
1286+
1287+
# Insert our custom importer, which will recognize the "com" directory as a namespace package.
1288+
new_meta_path = [CustomImporter(), *sys.meta_path]
1289+
monkeypatch.setattr(sys, "meta_path", new_meta_path)
1290+
1291+
# Now we should be able to resolve the path as namespace package.
1292+
pkg_root, module_name = resolve_pkg_root_and_module_name(
1293+
models_py, consider_namespace_packages=True
1294+
)
1295+
assert (pkg_root, module_name) == (
1296+
tmp_path / "src/dist1",
1297+
"com.company.app.core.models",
1298+
)

0 commit comments

Comments
 (0)