From 82cfa21bd9a706d6c06aa46410a5daba320fc91b Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Fri, 1 Mar 2024 11:59:26 +0200 Subject: [PATCH] main: add `module_name` to `CollectionArgument` This is available when the argument is a `--pyargs` argument (resolved from a python module path). Will be used in an upcoming commit. --- src/_pytest/main.py | 19 ++++++++++++++----- testing/test_main.py | 11 +++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index b815bc9dbd4..298f2b270ac 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -957,17 +957,18 @@ def genitems( node.ihook.pytest_collectreport(report=rep) -def search_pypath(module_name: str) -> str: - """Search sys.path for the given a dotted module name, and return its file system path.""" +def search_pypath(module_name: str) -> Optional[str]: + """Search sys.path for the given a dotted module name, and return its file + system path if found.""" try: spec = importlib.util.find_spec(module_name) # AttributeError: looks like package module, but actually filename # ImportError: module does not exist # ValueError: not a module name except (AttributeError, ImportError, ValueError): - return module_name + return None if spec is None or spec.origin is None or spec.origin == "namespace": - return module_name + return None elif spec.submodule_search_locations: return os.path.dirname(spec.origin) else: @@ -980,6 +981,7 @@ class CollectionArgument: path: Path parts: Sequence[str] + module_name: Optional[str] def resolve_collection_argument( @@ -997,6 +999,7 @@ def resolve_collection_argument( CollectionArgument( path=Path("/full/path/to/pkg/tests/test_foo.py"), parts=["TestClass", "test_foo"], + module_name=None, ) When as_pypath is True, expects that the command-line argument actually contains @@ -1010,6 +1013,7 @@ def resolve_collection_argument( CollectionArgument( path=Path("/home/u/myvenv/lib/site-packages/pkg/tests/test_foo.py"), parts=["TestClass", "test_foo"], + module_name="pkg.tests.test_foo", ) If the path doesn't exist, raise UsageError. @@ -1019,8 +1023,12 @@ def resolve_collection_argument( strpath, *parts = base.split("::") if parts: parts[-1] = f"{parts[-1]}{squacket}{rest}" + module_name = None if as_pypath: - strpath = search_pypath(strpath) + pyarg_strpath = search_pypath(strpath) + if pyarg_strpath is not None: + module_name = strpath + strpath = pyarg_strpath fspath = invocation_path / strpath fspath = absolutepath(fspath) if not safe_exists(fspath): @@ -1040,4 +1048,5 @@ def resolve_collection_argument( return CollectionArgument( path=fspath, parts=parts, + module_name=module_name, ) diff --git a/testing/test_main.py b/testing/test_main.py index d940dc51829..345aa1e62cf 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -139,24 +139,28 @@ def test_file(self, invocation_path: Path) -> None: ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=[], + module_name=None, ) assert resolve_collection_argument( invocation_path, "src/pkg/test.py::" ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=[""], + module_name=None, ) assert resolve_collection_argument( invocation_path, "src/pkg/test.py::foo::bar" ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=["foo", "bar"], + module_name=None, ) assert resolve_collection_argument( invocation_path, "src/pkg/test.py::foo::bar::" ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=["foo", "bar", ""], + module_name=None, ) def test_dir(self, invocation_path: Path) -> None: @@ -166,6 +170,7 @@ def test_dir(self, invocation_path: Path) -> None: ) == CollectionArgument( path=invocation_path / "src/pkg", parts=[], + module_name=None, ) with pytest.raises( @@ -185,18 +190,21 @@ def test_pypath(self, invocation_path: Path) -> None: ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=[], + module_name="pkg.test", ) assert resolve_collection_argument( invocation_path, "pkg.test::foo::bar", as_pypath=True ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=["foo", "bar"], + module_name="pkg.test", ) assert resolve_collection_argument( invocation_path, "pkg", as_pypath=True ) == CollectionArgument( path=invocation_path / "src/pkg", parts=[], + module_name="pkg", ) with pytest.raises( @@ -212,6 +220,7 @@ def test_parametrized_name_with_colons(self, invocation_path: Path) -> None: ) == CollectionArgument( path=invocation_path / "src/pkg/test.py", parts=["test[a::b]"], + module_name=None, ) def test_does_not_exist(self, invocation_path: Path) -> None: @@ -237,6 +246,7 @@ def test_absolute_paths_are_resolved_correctly(self, invocation_path: Path) -> N ) == CollectionArgument( path=Path(os.path.abspath("src")), parts=[], + module_name=None, ) # ensure full paths given in the command-line without the drive letter resolve @@ -247,6 +257,7 @@ def test_absolute_paths_are_resolved_correctly(self, invocation_path: Path) -> N ) == CollectionArgument( path=Path(os.path.abspath("src")), parts=[], + module_name=None, )