Fix handling recursive symlinks
When pytest was run on a directory containing a recursive symlink it failed
with ELOOP as the library was not able to determine the type of the
direntry:
src/_pytest/main.py:685: in collect
if not direntry.is_file():
E OSError: [Errno 40] Too many levels of symbolic links: '/home/florian/proj/pytest/tests/recursive'
This is fixed by handling ELOOP and other errors in the visit function in
pathlib.py, so the entries whose is_file() call raises an OSError with the
pre-defined list of error numbers will be exluded from the result.
The _ignore_errors function was copied from Lib/pathlib.py of cpython 3.9.
Fixes #7951
This commit is contained in:
@@ -1404,3 +1404,17 @@ def test_does_not_crash_on_error_from_decorated_function(testdir: Testdir) -> No
|
||||
result = testdir.runpytest()
|
||||
# Not INTERNAL_ERROR
|
||||
assert result.ret == ExitCode.INTERRUPTED
|
||||
|
||||
|
||||
def test_does_not_crash_on_recursive_symlink(testdir: Testdir) -> None:
|
||||
"""Regression test for an issue around recursive symlinks (#7951)."""
|
||||
symlink_or_skip("recursive", testdir.tmpdir.join("recursive"))
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo(): assert True
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
|
||||
assert result.ret == ExitCode.OK
|
||||
assert result.parseoutcomes() == {"passed": 1}
|
||||
|
||||
@@ -17,6 +17,8 @@ from _pytest.pathlib import import_path
|
||||
from _pytest.pathlib import ImportPathMismatchError
|
||||
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
||||
from _pytest.pathlib import resolve_package_path
|
||||
from _pytest.pathlib import symlink_or_skip
|
||||
from _pytest.pathlib import visit
|
||||
|
||||
|
||||
class TestFNMatcherPort:
|
||||
@@ -401,3 +403,14 @@ def test_commonpath() -> None:
|
||||
assert commonpath(subpath, path) == path
|
||||
assert commonpath(Path(str(path) + "suffix"), path) == path.parent
|
||||
assert commonpath(path, path.parent.parent) == path.parent.parent
|
||||
|
||||
|
||||
def test_visit_ignores_errors(tmpdir) -> None:
|
||||
symlink_or_skip("recursive", tmpdir.join("recursive"))
|
||||
tmpdir.join("foo").write_binary(b"")
|
||||
tmpdir.join("bar").write_binary(b"")
|
||||
|
||||
assert [entry.name for entry in visit(tmpdir, recurse=lambda entry: False)] == [
|
||||
"bar",
|
||||
"foo",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user