diff --git a/AUTHORS b/AUTHORS index 27c0b3ac408..408ad6c063c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -302,6 +302,7 @@ Mark Abramowitz Mark Dickinson Mark Vong Marko Pacak +marko1olo Markus Unterwaditzer Martijn Faassen Martin Altmayer diff --git a/changelog/14514.bugfix.rst b/changelog/14514.bugfix.rst new file mode 100644 index 00000000000..071693b69cc --- /dev/null +++ b/changelog/14514.bugfix.rst @@ -0,0 +1 @@ +Fixed importlib-mode module names for dotted test filenames such as ``foo.test.py`` so they are imported as valid Python module names. diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index 291bdf4ecbf..a74508c72dc 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -931,6 +931,7 @@ def compute_module_name(root: Path, module_path: Path) -> str | None: return None if names[-1] == "__init__": names.pop() + names = [x.replace(".", "_") for x in names] return ".".join(names) diff --git a/testing/test_pathlib.py b/testing/test_pathlib.py index bd85b7e8fb4..4ad63fd8c8c 100644 --- a/testing/test_pathlib.py +++ b/testing/test_pathlib.py @@ -788,6 +788,41 @@ def test_resolve_pkg_root_and_module_name( "app.core.models", ) + def test_resolve_pkg_root_and_module_name_dotted_filename( + self, tmp_path: Path + ) -> None: + (tmp_path / "pkg").mkdir() + (tmp_path / "pkg/__init__.py").touch() + foo_test_py = tmp_path / "pkg/foo.test.py" + foo_test_py.touch() + + assert resolve_pkg_root_and_module_name(foo_test_py) == ( + tmp_path, + "pkg.foo_test", + ) + + def test_import_path_importlib_dotted_filename_in_package( + self, tmp_path: Path + ) -> None: + (tmp_path / "pkg").mkdir() + (tmp_path / "pkg/__init__.py").write_text("", encoding="ascii") + (tmp_path / "pkg/foo.py").write_text("value = 1\n", encoding="ascii") + foo_test_py = tmp_path / "pkg/foo.test.py" + foo_test_py.write_text( + "import pkg.foo\nimported_value = pkg.foo.value\n", + encoding="ascii", + ) + + mod = import_path( + foo_test_py, + mode="importlib", + root=tmp_path, + consider_namespace_packages=False, + ) + + assert mod.__name__ == "pkg.foo_test" + assert mod.imported_value == 1 + def test_insert_missing_modules( self, monkeypatch: MonkeyPatch, tmp_path: Path ) -> None: @@ -1733,6 +1768,9 @@ def test_compute_module_name(tmp_path: Path) -> None: compute_module_name(tmp_path, tmp_path / "src/app/bar/__init__.py") == "src.app.bar" ) + assert compute_module_name(tmp_path, tmp_path / "src/app/foo.test.py") == ( + "src.app.foo_test" + ) def validate_namespace_package(