Skip to content

Commit f9b2b50

Browse files
author
simonbreidenbach
committed
Load initial conftest when an option value is an existing file path (#13913)
Since the switch to intermixed argument parsing (115b870), the *value* of a command line option that is a path to an existing file (e.g. ``--write-idents idents.txt``) ends up among the positional arguments during pre-parsing. _set_initial_conftests() then treated it as a test path anchor. Because the anchor was a file, the ``test*`` sub-directory discovery was skipped, and since the anchor list was non-empty the invocation-directory fallback was skipped too. As a result a conftest.py that registers the option (typically living under a ``test*`` directory) was not loaded as an initial conftest, so the option was reported as "unrecognized". Resolve file anchors to their containing directory (via _get_directory) so both the conftest loading and the ``test*`` sub-directory discovery consider the right location. Fixes #13913.
1 parent efc0134 commit f9b2b50

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

changelog/13913.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a regression where a conftest.py that registers command line options was sometimes not loaded as an initial conftest. This happened when a command line option's value was the path of an existing file (e.g. ``pytest --write-idents idents.txt``): due to intermixed argument parsing the value ended up among the positional arguments during pre-parsing and was treated as a test path, which suppressed the conftest discovery and made the option report as "unrecognized".

src/_pytest/config/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,10 +650,17 @@ def _set_initial_conftests(
650650
if not safe_exists(anchor):
651651
continue
652652

653+
# With intermixed argument parsing, the path *value* of a command
654+
# line option (e.g. ``--write-idents idents.txt``) can end up among
655+
# the positional arguments. Such a file anchor must not prevent the
656+
# conftest discovery for its directory (and its ``test*``
657+
# sub-directories), otherwise conftests that register the option are
658+
# not loaded as initial conftests and the option becomes
659+
# "unrecognized" (#13913). Resolve file anchors to their directory.
660+
anchor = self._get_directory(anchor)
653661
anchors.append(anchor)
654662
# Let's also consider test* subdirs.
655-
if anchor.is_dir():
656-
anchors.extend(x for x in anchor.glob("test*") if x.is_dir())
663+
anchors.extend(x for x in anchor.glob("test*") if x.is_dir())
657664
if not anchors:
658665
anchors.append(invocation_dir)
659666
anchors.extend(x for x in invocation_dir.glob("test*") if x.is_dir())

testing/test_conftest.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,36 @@ def test_it(request):
462462
result.assert_outcomes(passed=1)
463463

464464

465+
def test_initial_conftest_loaded_when_option_value_is_existing_file(
466+
pytester: Pytester,
467+
) -> None:
468+
"""An initial conftest registering a command line option is still loaded
469+
when the option's value happens to be the path of an existing file.
470+
471+
With intermixed argument parsing, such a value ends up among the
472+
positional arguments during pre-parsing and used to be treated as a test
473+
path anchor, which suppressed the ``test*`` conftest discovery and left
474+
the option "unrecognized". Regression test for #13913.
475+
"""
476+
pytester.makepyfile(
477+
**{
478+
"tests/conftest.py": """
479+
def pytest_addoption(parser):
480+
parser.addoption("--write-idents", action="store", default=None)
481+
""",
482+
"test_it.py": """
483+
def test_it(request):
484+
assert request.config.getoption("--write-idents") == "idents.txt"
485+
""",
486+
}
487+
)
488+
# The option value is a path to an existing file on disk.
489+
pytester.makefile(".txt", idents="")
490+
result = pytester.runpytest("--write-idents", "idents.txt")
491+
assert result.ret == ExitCode.OK
492+
result.assert_outcomes(passed=1)
493+
494+
465495
def test_conftest_import_order(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
466496
ct1 = pytester.makeconftest("")
467497
sub = pytester.mkdir("sub")

0 commit comments

Comments
 (0)