Do not derive rootdir from a non-regular config file - #14671
Open
apoorvdarshan wants to merge 2 commits into
Open
apoorvdarshan wants to merge 2 commits into
apoorvdarshan wants to merge 2 commits into
Conversation
When an explicitly given config file is not a regular file (e.g. --config-file=/dev/null to disable config file loading), do not use its parent directory as the rootdir. Previously rootdir became e.g. /dev, and the cache plugin emitted a confusing PytestCacheWarning when it failed to create /dev/.pytest_cache. Closes pytest-dev#11502
RonnyPfannschmidt
added a commit
to RonnyPfannschmidt/pytest
that referenced
this pull request
Jul 31, 2026
Consolidates three open reports that all bottom out in how an explicitly given config file is located and parsed. The preceding refactor turns each of them into a small change rather than another special case in a conditional. Custom TOML files read [pytest], not [tool.pytest] (pytest-dev#14705) [tool.pytest] is reserved for the project file. A TOML file passed via -c now reads its configuration from [pytest] directly, exactly like pytest.toml does. Previously any .toml that was not pytest.toml or .pytest.toml was parsed with pyproject.toml semantics, so the documented [pytest] table in a custom file was silently ignored. This is one entry in CONFIG_SUFFIXES. -c/--config-file validates its argument (pytest-dev#14716) Previously an invalid path either silently produced an empty configuration -- while still reporting `configfile:` in the header -- or crashed with a raw FileNotFoundError traceback, depending on its extension. Now a path that does not exist, a directory, and a regular file pytest has no loader for are each a UsageError. The supported extensions in the message are derived from CONFIG_SUFFIXES rather than restated in a separate constant. This is breaking for invocations that passed an unparsable file to -c and relied on it being ignored. The pytest-dev#14683 regression test did exactly that with a conftest.py and now uses a real config file; it passes --rootdir explicitly, so the config file was incidental to what it covers. The rootdir is not derived from a non-regular config file (pytest-dev#11502) --config-file=/dev/null is a common way to load no configuration at all. Deriving the rootdir from its parent made the rootdir /dev, and the cache plugin then warned on every run that it could not create /dev/.pytest_cache. Such a path says nothing about where the project lives, so fall back to the usual common-ancestor logic. The diagnoses come from pytest-dev#14707 (@DebadityaHait), pytest-dev#14723 (@wanxiankai) and pytest-dev#14671 (@apoorvdarshan); the implementations differ because the table-based dispatch makes each one smaller. Closes pytest-dev#14705 Closes pytest-dev#14716 Closes pytest-dev#11502 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
RonnyPfannschmidt
added a commit
to RonnyPfannschmidt/pytest
that referenced
this pull request
Jul 31, 2026
Consolidates three open reports that all bottom out in how an explicitly given config file is located and parsed. The preceding refactor turns each of them into a small change rather than another special case in a conditional. Custom TOML files read [pytest], not [tool.pytest] (pytest-dev#14705) [tool.pytest] is reserved for the project file. A TOML file passed via -c now reads its configuration from [pytest] directly, exactly like pytest.toml does. Previously any .toml that was not pytest.toml or .pytest.toml was parsed with pyproject.toml semantics, so the documented [pytest] table in a custom file was silently ignored. This is one entry in CONFIG_SUFFIXES. -c/--config-file validates its argument (pytest-dev#14716) Previously an invalid path either silently produced an empty configuration -- while still reporting `configfile:` in the header -- or crashed with a raw FileNotFoundError traceback, depending on its extension. Now a path that does not exist, a directory, and a regular file pytest has no loader for are each a UsageError. The supported extensions in the message are derived from CONFIG_SUFFIXES rather than restated in a separate constant. This is breaking for invocations that passed an unparsable file to -c and relied on it being ignored. The pytest-dev#14683 regression test did exactly that with a conftest.py and now uses a real config file; it passes --rootdir explicitly, so the config file was incidental to what it covers. The rootdir is not derived from a non-regular config file (pytest-dev#11502) --config-file=/dev/null is a common way to load no configuration at all. Deriving the rootdir from its parent made the rootdir /dev, and the cache plugin then warned on every run that it could not create /dev/.pytest_cache. Such a path says nothing about where the project lives, so fall back to the usual common-ancestor logic. The diagnoses come from pytest-dev#14707 (@DebadityaHait), pytest-dev#14723 (@wanxiankai) and pytest-dev#14671 (@apoorvdarshan); the implementations differ because the table-based dispatch makes each one smaller. Closes pytest-dev#14705 Closes pytest-dev#14716 Closes pytest-dev#11502 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
RonnyPfannschmidt
added a commit
to RonnyPfannschmidt/pytest
that referenced
this pull request
Aug 6, 2026
Consolidates three open reports that all bottom out in how an explicitly given config file is located and parsed. The preceding refactor turns each of them into a small change rather than another special case in a conditional. Custom TOML files also read [pytest] (pytest-dev#14705) pytest documents [pytest] as the table its own TOML configuration files use, but a TOML file passed via -c was parsed with pyproject.toml semantics, so a [pytest] table in it was silently ignored. Such files now read [pytest] as well, while the [tool.pytest]/[tool.pytest.ini_options] tables they were previously restricted to keep working -- writing both styles into one file is a UsageError. Suffix dispatch makes this one loader; pyproject.toml itself is unaffected, as name dispatch wins. -c/--config-file validates its argument (pytest-dev#14716) Previously an invalid path either silently produced an empty configuration -- while still reporting `configfile:` in the header -- or crashed with a raw FileNotFoundError traceback, depending on its extension. Now a path that does not exist, a directory, and a regular file pytest has no loader for are each a UsageError. The supported extensions in the message are derived from CONFIG_LOADERS_BY_SUFFIX rather than restated in a separate constant. This is breaking for invocations that passed an unparsable file to -c and relied on it being ignored. The pytest-dev#14683 regression test did exactly that with a conftest.py and now uses a real config file; it passes --rootdir explicitly, so the config file was incidental to what it covers. The rootdir is not derived from a non-regular config file (pytest-dev#11502) --config-file=/dev/null is a common way to load no configuration at all. Deriving the rootdir from its parent made the rootdir /dev, and the cache plugin then warned on every run that it could not create /dev/.pytest_cache. Such a path says nothing about where the project lives, so fall back to the usual common-ancestor logic. Whether a path is parsed and whether its directory decides the rootdir are kept separate: a loader runs whenever one matches the name or suffix, so a config file that happens to be a fifo is still read, and only a path with no loader *and* no chance of holding configuration -- a character device such as /dev/null -- means "no configuration" instead of an error. The diagnoses come from pytest-dev#14707 (@DebadityaHait), pytest-dev#14723 (@wanxiankai) and pytest-dev#14671 (@apoorvdarshan); the implementations differ because the table-based dispatch makes each one smaller. Closes pytest-dev#14705 Closes pytest-dev#14716 Closes pytest-dev#11502 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #11502
Problem
Passing a non-regular file as the config file — the common case being
--config-file=/dev/nullto deliberately disable config file loading — made pytest derive the rootdir from its parent directory. This resulted inrootdir: /dev, and the cache plugin then emitted a confusing warning on every run when it failed to create the cache directory there:Reproduced on current
main(9.2.0.dev) on macOS; same behavior as originally reported in #11502.Fix
In
determine_setup(), only derive the rootdir from the config file's parent directory when the given config file is a regular file. For non-regular files (character devices like/dev/null, FIFOs), fall back to the common-ancestor logic already used elsewhere in the function (with the existing filesystem-root guard). The explicitly given config file is still honored asinipath— only the rootdir derivation changes.With the fix,
pytest --config-file=/dev/nullrun from a project directory yieldsrootdir: <project dir>and no cache warning.Checklist
TestRootdir::test_explicit_config_file_non_regular_file, skipped on Windows).changelog/11502.bugfix.rst.AUTHORS.testing/test_config.py,testing/test_findpaths.py(278 passed) andtesting/test_cacheprovider.py(58 passed) locally; ruff check/format clean.AI disclosure
Per the project's AI/LLM-Assisted Contributions Policy: this fix was developed with the assistance of an AI tool (Claude Code). I have reviewed the change, reproduced the bug and verified the fix locally, and I take responsibility for the contribution and will respond to review feedback personally.