main: only include package parents in collection tree for --pyargs collection arguments
(diff better viewed ignoring whitespace) In pytest<8, the collection tree for `pyargs` arguments in an invocation like this: pytest --collect-only --pyargs pyflakes.test.test_undefined_names looked like this: ``` <Package test> <Module test_undefined_names.py> <UnitTestCase Test> <TestCaseFunction test_annotationUndefined> ... snipped ... ``` The pytest 8 collection improvements changed it to this: ``` <Dir pytest> <Dir .tox> <Dir venv> <Dir lib> <Dir python3.11> <Dir site-packages> <Package pyflakes> <Package test> <Module test_undefined_names.py> <UnitTestCase Test> <TestCaseFunction test_annotationUndefined> ... snipped ... ``` Besides being egregious (and potentially even worse than the above, going all the way to the root, for system-installed packages, as is apparently common in CI), this also caused permission errors when trying to probe some of those intermediate directories. This change makes `--pyargs` arguments no longer try to add parent directories to the collection tree according to the `--confcutdir` like they're regular arguments. Instead, only add the parents that are in the import path. This now looks like this: ``` <Package .tox/venv/lib/python3.11/site-packages/pyflakes> <Package test> <Module test_undefined_names.py> <UnitTestCase Test> <TestCaseFunction test_annotationUndefined> ... snipped ... ``` Fix #11904.
This commit is contained in:
parent
f20e32c982
commit
31026a2df2
|
@ -0,0 +1,3 @@
|
|||
Fixed a regression in pytest 8.0.0 that would cause test collection to fail due to permission errors when using ``--pyargs``.
|
||||
|
||||
This change improves the collection tree for tests specified using ``--pyargs``, see :pull:`12043` for a comparison with pytest 8.0 and <8.
|
|
@ -846,6 +846,7 @@ class Session(nodes.Collector):
|
|||
|
||||
argpath = collection_argument.path
|
||||
names = collection_argument.parts
|
||||
module_name = collection_argument.module_name
|
||||
|
||||
# resolve_collection_argument() ensures this.
|
||||
if argpath.is_dir():
|
||||
|
@ -854,11 +855,20 @@ class Session(nodes.Collector):
|
|||
paths = [argpath]
|
||||
# Add relevant parents of the path, from the root, e.g.
|
||||
# /a/b/c.py -> [/, /a, /a/b, /a/b/c.py]
|
||||
# Paths outside of the confcutdir should not be considered.
|
||||
for path in argpath.parents:
|
||||
if not pm._is_in_confcutdir(path):
|
||||
break
|
||||
paths.insert(0, path)
|
||||
if module_name is None:
|
||||
# Paths outside of the confcutdir should not be considered.
|
||||
for path in argpath.parents:
|
||||
if not pm._is_in_confcutdir(path):
|
||||
break
|
||||
paths.insert(0, path)
|
||||
else:
|
||||
# For --pyargs arguments, only consider paths matching the module
|
||||
# name. Paths beyond the package hierarchy are not included.
|
||||
module_name_parts = module_name.split(".")
|
||||
for i, path in enumerate(argpath.parents, 2):
|
||||
if i > len(module_name_parts) or path.stem != module_name_parts[-i]:
|
||||
break
|
||||
paths.insert(0, path)
|
||||
|
||||
# Start going over the parts from the root, collecting each level
|
||||
# and discarding all nodes which don't match the level's part.
|
||||
|
|
|
@ -1787,3 +1787,48 @@ def test_collect_short_file_windows(pytester: Pytester) -> None:
|
|||
test_file.write_text("def test(): pass", encoding="UTF-8")
|
||||
result = pytester.runpytest(short_path)
|
||||
assert result.parseoutcomes() == {"passed": 1}
|
||||
|
||||
|
||||
def test_pyargs_collection_tree(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
|
||||
"""When using `--pyargs`, the collection tree of a pyargs collection
|
||||
argument should only include parents in the import path, not up to confcutdir.
|
||||
|
||||
Regression test for #11904.
|
||||
"""
|
||||
site_packages = pytester.path / "venv/lib/site-packages"
|
||||
site_packages.mkdir(parents=True)
|
||||
monkeypatch.syspath_prepend(site_packages)
|
||||
pytester.makepyfile(
|
||||
**{
|
||||
"venv/lib/site-packages/pkg/__init__.py": "",
|
||||
"venv/lib/site-packages/pkg/sub/__init__.py": "",
|
||||
"venv/lib/site-packages/pkg/sub/test_it.py": "def test(): pass",
|
||||
}
|
||||
)
|
||||
|
||||
result = pytester.runpytest("--pyargs", "--collect-only", "pkg.sub.test_it")
|
||||
assert result.ret == ExitCode.OK
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"<Package venv/lib/site-packages/pkg>",
|
||||
" <Package sub>",
|
||||
" <Module test_it.py>",
|
||||
" <Function test>",
|
||||
],
|
||||
consecutive=True,
|
||||
)
|
||||
|
||||
# Now with an unrelated rootdir with unrelated files.
|
||||
monkeypatch.chdir(tempfile.gettempdir())
|
||||
|
||||
result = pytester.runpytest("--pyargs", "--collect-only", "pkg.sub.test_it")
|
||||
assert result.ret == ExitCode.OK
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"<Package *pkg>",
|
||||
" <Package sub>",
|
||||
" <Module test_it.py>",
|
||||
" <Function test>",
|
||||
],
|
||||
consecutive=True,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue