Skip to content

Fix rootdir with explicit config and test paths - #14579

Closed
hariharan077 wants to merge 1 commit into
pytest-dev:mainfrom
hariharan077:fix-rootdir-explicit-config
Closed

hariharan077 wants to merge 1 commit into
pytest-dev:mainfrom
hariharan077:fix-rootdir-explicit-config

Conversation

@hariharan077

@hariharan077 hariharan077 commented Jun 9, 2026 •

Copy link
Copy Markdown

Fixes #9703.

Summary

  • When -c/--config-file is used with explicit existing test paths, determine rootdir from the common ancestor of the config file directory and those paths.
  • Preserve the existing behavior where -c without test paths uses the config file directory as rootdir.
  • Add regression coverage for the -c config/pytest.ini tests/... node ID case, including the autouse fixture leakage shape from the original issue.
  • Update the rootdir docs and add a changelog fragment.

Verification

  • Reproduced the issue locally before the fix: pytest -c config/pytest.ini -s -v test/test_file1.py test/test_file2.py produced config::test_in_file1 / config::test_in_file2 node IDs.
  • Confirmed the new regression tests failed before the production change.
  • .venv/bin/python -m pytest testing/test_config.py::TestRootdir::test_explicit_config_file_uses_args_for_rootdir testing/test_config.py::TestRootdir::test_explicit_config_file_uses_args_for_nodeids
  • .venv/bin/python -m pytest testing/test_config.py::TestRootdir testing/test_findpaths.py
  • .venv/bin/python -m pytest testing/test_config.py testing/test_collection.py
  • .venv/bin/python -m pytest (4096 passed, 121 skipped, 12 xfailed, 1 xpassed)
  • .venv/bin/tox -e linting
  • .venv/bin/pre-commit run --files src/_pytest/config/findpaths.py testing/test_config.py doc/en/reference/customize.rst AUTHORS changelog/9703.bugfix.rst
  • .venv/bin/towncrier build --draft --version 9.1.0
  • git diff --check

@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Jun 9, 2026
@hariharan077
hariharan077 marked this pull request as ready for review June 9, 2026 09:17
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Jul 31, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Jul 31, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@hariharan077
hariharan077 force-pushed the fix-rootdir-explicit-config branch from 8065b8f to f0a18a3 Compare August 21, 2026 18:30
@RonnyPfannschmidt

Copy link
Copy Markdown
Member

closing as superseded by #14837 which manages some edge cases more correct
thanks for providing an example

RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Sep 15, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

This is a breaking change: it alters documented behaviour, so
doc/en/reference/customize.rst is updated along with it, and the changelog
entries are filed as breaking rather than as bugfixes.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Sep 23, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

This is a breaking change: it alters documented behaviour, so
doc/en/reference/customize.rst is updated along with it, and the changelog
entries are filed as breaking rather than as bugfixes.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Oct 4, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

This is a breaking change: it alters documented behaviour, so
doc/en/reference/customize.rst is updated along with it, and the changelog
entries are filed as breaking rather than as bugfixes.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Oct 11, 2026
Passing -c/--config-file set the rootdir to the config file's parent
directory. A config kept in a subdirectory -- the common `-c config/pytest.ini`
layout -- therefore moved the rootdir into that subdirectory, which broke
conftest discovery and node ids: conftests collected an empty path prefix, so
same-named fixtures from sibling directories shadowed each other and node ids
came out as `config::test2` instead of `tests/tests2/test2.py::test2`.

The config file's location is evidence about where the project lives, not a
decision on its own. Take the common ancestor of the config file's directory
and the collected test paths instead, falling back to the invocation directory
in place of the test paths when none were given. If the two live in unrelated
trees the ancestor degrades to the filesystem root, in which case the config
file's directory is kept, as before.

This covers cases neither of the two open proposals handled alone:

  scenario                                     before      pytest-dev#14454   pytest-dev#14579   now
  -c config/pytest.ini (no args)               config/     ok       config/  ok
  -c config/pytest.ini tests/                  config/     ok       ok       ok
  sibling config, invoked from a subdirectory  config/     sub/     ok       ok
  unrelated working directory                  config/     unrel.   ok       ok

pytest-dev#14454 (@EternalRights) found the root cause and drove the design discussion;
its `invocation_dir` rule is right for the no-args case but follows the working
directory even when that is unrelated to the project. pytest-dev#14579 (@hariharan077)
contributed the common-ancestor form, which is most of the answer but leaves
the no-args case unfixed. Neither is needed once the ancestor also considers
the invocation directory, and no ambiguity warning is required because the
ancestor is derived rather than guessed.

This is a breaking change: it alters documented behaviour, so
doc/en/reference/customize.rst is updated along with it, and the changelog
entries are filed as breaking rather than as bugfixes.

Closes pytest-dev#13246
Closes pytest-dev#9703

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided (automation) changelog entry is part of PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scopes of several files are merged when specifying a config using -c

2 participants