Repository navigation
pytest.ini is dead config that silently shadows pyproject.toml (--strict-markers, testpaths, markers all inert) #130
Copy link
Copy link
Closed
Labels
P1-highRequired for production readinessRequired for production readinessbugtestingTest suite, CI, coverageTest suite, CI, coverage
Description
Part of #108 · Phase 1 · Discovered while red-teaming #109.
Problem
pytest.ini uses the section header [tool:pytest]. That header is only valid in setup.cfg. In a file named pytest.ini, pytest requires [pytest].
pytest still selects the file as its config — and having selected it, stops looking, so pyproject.toml's [tool.pytest.ini_options] is never read.
Verified:
$ pytest tests/unit/test_billable_safety.py --co
rootdir: /Users/jmanning/clustrix
configfile: pytest.ini <- not pyproject.toml
$ pytest --markers | grep -cE "^@pytest.mark.(expensive|real_world|dartmouth_network)"
0 <- no project markers registered at all
$ pytest <file with @pytest.mark.definitely_not_registered_xyz> --co -q
1 test collected <- --strict-markers is NOT active
Everything currently inert
Both files declare these; neither takes effect:
| Setting | Intended | Actual |
|---|---|---|
addopts (-v --tb=short --strict-markers, and -n 4 --dist loadfile in pyproject) |
applied to every run | ignored |
testpaths |
limit collection to tests |
ignored — bare pytest collects the whole repo |
markers (13 of them) |
registered | none registered |
filterwarnings |
suppress paramiko/crypto noise | ignored |
--strict-markers |
typo in a marker = error | inert |
Why this matters beyond tidiness
- It invalidates a premise of several other issues. pip install -e ".[dev]" produces an environment where pytest cannot start #110 reports that
pip install -e ".[dev]"cannot start pytest becauseaddoptsrequires xdist. That is true only on branches wherepytest.iniis absent — the epic branch deleted it. Onmaster,addoptsnever applies. Any statement about "the addopts" needs to say which config was live. - Marker-based safety is illusory. tests/integration/ is unmarked, so the documented unit-test command provisions billable AWS EKS clusters #109's gate deliberately does not rely on markers, which turns out to have been necessary: applying
pytest.mark.expensivetoday producesPytestUnknownMarkWarning, not a usable selector. --strict-markersbeing inert hides typos.scripts/test_discovery.py(on the closed epic branch) found 1,532 marker-hygiene issues that a live--strict-markerswould have caught at source.
Fix — needs care, do not just flip it
The obvious change ([tool:pytest] → [pytest], or delete pytest.ini so pyproject wins) will activate --strict-markers, testpaths, and possibly -n 4. Any test using an unregistered mark then becomes a hard error, and there are 1,532 known marker issues. Sequence it:
- Decide on ONE config source. Recommendation: delete
pytest.ini, keeppyproject.toml(it has the fuller marker list — 13 vs 10 — and is the modern convention). - Before activating, inventory every mark actually used:
grep -rhoE "@pytest\.mark\.[a-z_]+" tests/ | sort -uand reconcile against the registered list. - Confirm
pytest-xdistis installed whereveraddoptswill now apply (ties to pip install -e ".[dev]" produces an environment where pytest cannot start #110). - Verify
testpathsactivation does not pulltests/real_world/into default runs. - Land
--strict-markerslast, once the marker inventory is clean. - Add a test asserting
Config.inifileis the expected file, so a future stray config file cannot silently shadow it again.
Verification
pytest --co -q tests/unit/ 2>&1 | grep -i configfile
pytest --markers | grep -cE "^@pytest.mark."Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P1-highRequired for production readinessRequired for production readinessbugtestingTest suite, CI, coverageTest suite, CI, coverage
Activity
Issue #130: Add handoff plan for the pytest config-shadowing fix
jeremymanning commentedon Aug 17, 2026
Handoff plan written —
notes/handoff_130_pytest_config.md(commitde09f1a)A fresh session can pick this up cold. Everything in it was verified on
masterata9393b7; every fact carries the command that established it.Naively fixing this breaks bare
pytestoutright. Verified:Cause:
master's pyproject setstestpaths = ["tests/unit", "tests/integration"], and pytest populatesconfig.argsfrom testpaths when no paths are given on the command line. The #109 guard inspectsconfig.args, so the moment pyproject becomes live, every bare run aborts.This is a trap I created in #109 and it must be defused first. The clean fix — verified — is to key the guard off
config.invocation_params.args(what the user actually typed) instead:config.argsconfig.invocation_params.argspytest(testpaths live)['tests/unit', 'tests/integration']pytest tests/unit/['tests/unit/']['tests/unit/', ...flags]Corrections to this issue's original body
master(real_world,slow,unit,integration), not 13. The longer list I cited was from the closed epic branch.pytest.inideclares 14.master's pyprojectaddoptsis just-v --tb=short— no-n 4. So activating pyproject does not require xdist here. The xdist problem is specific to the epic branch, which deletespytest.ini. pip install -e ".[dev]" produces an environment where pytest cannot start #110 needs the same correction.Measured marker gap (the thing that gates
--strict-markers)real_worlddartmouth_networkslowexpensiveperformanceintegrationcleanuptest_kubernetes_performance_benchmarks.py:1038, likely a typoPlan shape
6 steps, one commit each, verification commands after every one:
invocation_params.args) — must be firstpytest.ini, settestpaths = ["tests"]cleanup--strict-markerslastscripts/pre_push_check.py, then correct pip install -e ".[dev]" produces an environment where pytest cannot start #110,MIGRATION.md:80,.claude/commands/testing/prime.md:95The regression test uses
pytestconfig.inipathandgetini("markers"); both were verified against pytest 8.4.2 in the broken and fixed states, so the snippet is known-working rather than assumed. It fails today and passes after Step 2 — write it first and watch it fail.jeremymanning commentedon Aug 17, 2026
Fixed in #134 (branch
fix/130-pytest-config). Before/after evidence below; the issue closes when that PR merges.Before —
master@a9393b7After
Checklist from this issue
pytest.ini, keptpyproject.tomlexpensive,dartmouth_network,performance; removed the single deadcleanuppytest-xdistis installed whereveraddoptsapplies — not needed:master'saddoptshas no-n. A comment aboveaddoptsnow records that adding one requires moving xdist from[test]into[dev]first (pip install -e ".[dev]" produces an environment where pytest cannot start #110)testpathsactivation does not pulltests/real_world/into default runs — it does collect them (testpaths = ["tests"]), which is correct and matches the previous no-config behaviour. Nothing runs them by default: CI usespytest tests/unit/ -m "not real_world", andscripts/pre_push_check.pynow does the same, which it previously did not--strict-markerslast — Step 4, after the marker inventory was cleantests/unit/test_pytest_config.py, four assertions, all failing onmasterTwo corrections to this issue's own text
"13 markers" / "1,532 marker issues."
pytest.inideclared 10 markers andpyproject.toml4. The suite uses 7 distinct non-builtin markers across 253 applications. The 1,532 figure came fromscripts/test_discovery.pyon the closed epic branch and does not correspond to anything measurable onmaster.The landmine was not in the issue. Deleting
pytest.inialone breakspytestentirely, becausetestpathsthen feedsconfig.argsand the #109 guard refuses the run. That had to be fixed first, in its own commit. Details in #134 and innotes/handoff_130_pytest_config.md.Found along the way
SyntaxError(fatal on Python <3.12 whilerequires-pythonis>=3.8) plus undeclarednumpy/pandas. Fixed here, since Step 4's gate is "0 errors".scripts/pre_push_check.pycannot exit 0 for unrelated reasons, and never could — filed as pre_push_check.py can never pass: 92 flake8 findings, incl. a real f-string bug in test_direct_gpu_detection.py #133, which also documents a real f-string bug intests/integration/test_direct_gpu_detection.py.addoptspremise and itssklearnclaim are both wrong; corrected there.Issue #130: Close the guard bypasses red-teaming found, and fix my ow…
Issue #130: Revert the fast_ci.yml change; the diagnosis was wrong
Issue #130: pytest.ini was dead config shadowing pyproject.toml (#134)
Update notes for handoff to a fresh session (#136)