From c9e9315725098dafa9a1ea3d3725a52811dca02e Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Mon, 13 May 2024 20:32:23 +0300 Subject: [PATCH] [8.2.x] python: add workaround for permission error crashes from non-selected directories --- changelog/12120.bugfix.rst | 1 + src/_pytest/python.py | 7 ++++++- testing/test_collection.py | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 changelog/12120.bugfix.rst diff --git a/changelog/12120.bugfix.rst b/changelog/12120.bugfix.rst new file mode 100644 index 00000000000..b1ca4913b37 --- /dev/null +++ b/changelog/12120.bugfix.rst @@ -0,0 +1 @@ +Fix `PermissionError` crashes arising from directories which are not selected on the command-line. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 5e059f2c4e6..41a2fe39af3 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -176,7 +176,12 @@ def pytest_collect_directory( path: Path, parent: nodes.Collector ) -> Optional[nodes.Collector]: pkginit = path / "__init__.py" - if pkginit.is_file(): + try: + has_pkginit = pkginit.is_file() + except PermissionError: + # See https://github.com/pytest-dev/pytest/issues/12120#issuecomment-2106349096. + return None + if has_pkginit: return Package.from_parent(parent, path=path) return None diff --git a/testing/test_collection.py b/testing/test_collection.py index 3f7a3d5351b..7f0790693a5 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -285,6 +285,23 @@ def test_testpaths_ini(self, pytester: Pytester, monkeypatch: MonkeyPatch) -> No items, reprec = pytester.inline_genitems() assert [x.name for x in items] == ["test_%s" % dirname] + def test_missing_permissions_on_unselected_directory_doesnt_crash( + self, pytester: Pytester + ) -> None: + """Regression test for #12120.""" + test = pytester.makepyfile(test="def test(): pass") + bad = pytester.mkdir("bad") + try: + bad.chmod(0) + + result = pytester.runpytest(test) + finally: + bad.chmod(750) + bad.rmdir() + + assert result.ret == ExitCode.OK + result.assert_outcomes(passed=1) + class TestCollectPluginHookRelay: def test_pytest_collect_file(self, pytester: Pytester) -> None: