diff --git a/changelog/10169.bugfix.rst b/changelog/10169.bugfix.rst new file mode 100644 index 000000000..cbf3516a9 --- /dev/null +++ b/changelog/10169.bugfix.rst @@ -0,0 +1 @@ +Fix bug where very long option names could cause pytest to break with ``OSError: [Errno 36] File name too long`` on some systems. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 25cf75e98..74905ff4c 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -556,19 +556,13 @@ class PytestPluginManager(PluginManager): path = path[:i] anchor = absolutepath(current / path) - # On Python 3.7 on Windows, anchor.exists() might raise - # if the anchor contains glob characters (for example "*//tests"), specially - # in the case of the 'testpaths' ini option. - # Using an explicit version check to remove this code later once - # Python 3.7 is dropped. - if sys.version_info[:2] == (3, 7): - try: - anchor_exists = anchor.exists() - except OSError: # pragma: no cover - anchor_exists = False - else: + # Ensure we do not break if what appears to be an anchor + # is in fact a very long option (#10169). + try: anchor_exists = anchor.exists() - if anchor_exists: # We found some file object. + except OSError: # pragma: no cover + anchor_exists = False + if anchor_exists: self._try_load_conftest(anchor, namespace.importmode, rootpath) foundanchor = True if not foundanchor: diff --git a/testing/test_collection.py b/testing/test_collection.py index f78ae7bea..bbcb358b6 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1254,7 +1254,7 @@ def test_initial_conftests_with_testpaths(pytester: Pytester) -> None: textwrap.dedent( """ def pytest_sessionstart(session): - raise Exception("pytest_sessionstart hook is successfully run") + raise Exception("pytest_sessionstart hook successfully run") """ ) ) @@ -1266,10 +1266,29 @@ def test_initial_conftests_with_testpaths(pytester: Pytester) -> None: ) result = pytester.runpytest() result.stdout.fnmatch_lines( - "INTERNALERROR* Exception: pytest_sessionstart hook is successfully run" + "INTERNALERROR* Exception: pytest_sessionstart hook successfully run" ) +def test_large_option_breaks_initial_conftests(pytester: Pytester) -> None: + """Long option values do not break initial conftests handling (#10169).""" + option_value = "x" * 1024 * 1000 + pytester.makeconftest( + """ + def pytest_addoption(parser): + parser.addoption("--xx", default=None) + """ + ) + pytester.makepyfile( + f""" + def test_foo(request): + assert request.config.getoption("xx") == {option_value!r} + """ + ) + result = pytester.runpytest(f"--xx={option_value}") + assert result.ret == 0 + + def test_collect_symlink_file_arg(pytester: Pytester) -> None: """Collect a direct symlink works even if it does not match python_files (#4325).""" real = pytester.makepyfile(