Repository navigation
pip install -e ".[dev]" produces an environment where pytest cannot start #110
Description
Activity
- addedP0-criticalBlocks everything; safety or correctness landmineBlocks everything; safety or correctness landminetestingTest suite, CI, coverageTest suite, CI, coverage
on Aug 17, 2026 - added a parent issue
on Aug 17, 2026 New evidence from PR #129: unbounded dependency pins make CI fail with no code change.
While landing #109, CI failed on
Lint with blackwith "19 files would be reformatted" — none of which the PR touched.Cause:
pyproject.toml:86,135declared"black>=21.0"with no upper bound, sopip install -e ".[dev,...]"resolved black 26.5.1, whose new stable style reformats 19 existing files..pre-commit-config.yamlseparately pinsrev: 25.1.0. Local pre-commit and CI were therefore running different formatters, and CI could turn red spontaneously whenever black published a release.Reproduced exactly by installing 26.5.1 locally:
19 files would be reformatted, 276 files would be left unchanged.Fixed in #129 by pinning
black==25.1.0; python_version >= "3.9"and running lint once on ubuntu/3.11. The tree passes cleanly under 25.1.0, so no files needed reformatting.Still outstanding for this issue — the same unbounded pattern applies to the other linters, and they carry identical drift risk:
pyproject.toml:87,136 "flake8>=3.8" pyproject.toml:88,137 "mypy>=0.812"- Pin
flake8andmypyto versions the tree currently passes under - Consider pinning or constraining the runtime deps too — 6 of the 127 failures in Fix the 127 test failures and 8 collection errors that CI never sees #114 are
TypeError: __init__() missing 1 required keyword-only argument: response, which isgoogleapiclientchanging under an unpinned requirement. Same root cause, different package.
This is worth treating as part of this issue's "reproducible dev-env bootstrap" AC: an environment is not reproducible if
pip install -e ".[dev]"resolves differently today than yesterday.- Pin
Dependabot alert #1 — caused by the black pin in #129
black==25.1.0(pinned in PR #129 to stop CI drift) falls inside a high-severity advisory range:black >= 24.3.0, < 26.3.1 Arbitrary file writes from unsanitized user input in cache file nameFull disclosure: the previous unbounded
black>=21.0would have resolved to 26.5.1, which is patched. So the pin fixed a CI-determinism problem and introduced a (low-practical-risk) advisory. Both facts belong on the record.Practical risk
The vector is a cache filename derived from untrusted input. black here runs over the project's own source, in CI and pre-commit, with no attacker-controlled paths. Real exposure is close to nil — but the alert stays red until resolved, and "red alerts we have decided to ignore" is exactly the habit this repo is trying to break.
The awkward part
The patched line (>=26.3.1) requires Python >=3.10, and the CI matrix still includes 3.8 and 3.9. So a straight bump is impossible without one of:
(a) Raise the floor. Drop 3.8/3.9 and set
requires-python = ">=3.10"— already an AC of this issue, and both are long EOL (3.8 Oct 2024, 3.9 Oct 2025). Then pinblack==26.5.1and reformat the 19 files it restyles in one dedicated commit.(b) Environment markers —
black==26.5.1; python_version >= "3.10"plus an older pin below. Then two formatters disagree, which is the original bug in a new costume. Not recommended.(c) Stop installing black per-matrix-entry. #129 already gated lint steps to ubuntu/3.11 only; the logical next step is moving linting into its own job with its own pinned toolchain, so formatter version stops being coupled to the Python support matrix. Cleanest fix, and it makes (a) independent rather than a prerequisite.
Recommendation
Do (c), then (a). Together they clear this alert, remove the 3.8/3.9 EOL exposure, and decouple lint tooling from the runtime support matrix — the underlying design problem, not the black version.
The same unbounded-pin risk still applies to
flake8>=3.8andmypy>=0.812(pyproject.toml:87-88,136-137) and to unpinned runtime deps — 6 of the 127 failures in #114 aregoogleapiclientchanging under an unpinned requirement.Correction: the
addoptspremise in this issue does not describemasterFound while fixing #130. Two claims here need amending, and one acceptance-criteria item is now done.
1. The quoted
addoptswas never live onmasterThis issue opens with:
pyproject.toml:189hard-requires xdist:addopts = "-v --tb=short --strict-markers -n 4 --dist loadfile"That line is from the closed epic branch, not
master. Onmasterata9393b7,pyproject.toml'saddoptswas-v --tb=short— no-n, no--dist.More importantly, it did not matter what it said.
pytest.inisat in the repo root with the section header[tool:pytest], which is valid only insetup.cfg. pytest still selectedpytest.inias its config file, and having selected one it stops searching — sopyproject.toml's[tool.pytest.ini_options]was never read. Onmaster,addoptsfrom either file was inert:$ pytest tests/unit/ --co 2>&1 | grep configfile configfile: pytest.ini $ pytest --markers | grep -c '^@pytest.mark.real_world' 0So
pip install -e ".[dev]"did not fail withunrecognized arguments: -n --dist loadfileonmaster— that reproduces only wherepytest.iniis absent. Any statement about "the addopts" needs to name which config was live. Full analysis in #130.The underlying dependency point still stands and is now recorded in
pyproject.toml:pytest-xdistis in[test], not[dev], so-nmust not be added toaddoptswithout moving it first. There is a comment aboveaddoptssaying so.2.
scikit-learndoes not cause collection errorssklearn-> 2 further failuresNot at collection time. Every
sklearnimport undertests/is inside a function body (test_notebook_magic_real.py:450,test_decorator_real.py:463-467,reference_workflows/kubernetes_workflows.py:68-70), so it is never executed during collection. Withnumpyandpandasinstalled and nothing else, collection is clean:$ pytest tests/ -m "not real_world" --co -q -o addopts= | tail -1 1275/1665 tests collected (390 deselected) # 0 errorssklearnmay still be needed to run those tests; it is not needed to collect them.3. Two acceptance-criteria items are done (in #130's PR)
-
tests/real_world/test_container_registry_comprehensive.py:571syntax error fixed. The backslash was inside an f-string expression, aSyntaxErroron every Python before 3.12 whilerequires-pythonsays>=3.8. Thesplit()is now hoisted out. An AST parse over all oftests/andclustrix/confirms it was the only such error in the tree. -
numpyandpandasadded to the[dev]extra. These were the real cause of the collection errors. Onmastera clean[dev]install gave 6 collection errors; it now gives 0.
Still open here:
pytest-xdistplacement, therequires-pythonfloor, the bootstrap command, and the CI job that installs only[dev]and asserts collection succeeds.The verification command in this issue's "Verification" section now passes:
$ python -m venv /tmp/fresh && /tmp/fresh/bin/pip install -e ".[dev]" $ /tmp/fresh/bin/pytest tests/ --collect-only -q 2>&1 | tail -1 1670 tests collected # 0 errors-
- added 4 commits that reference this issue
on Aug 17, 2026 Closed — the environment starts pytest
$ pytest --collect-only -q 1677 tests collected, 0 errorsEach named cause is gone:
addoptscarries no-n, so xdist is not required to start;requires-python = ">=3.10"(pyproject.toml:19,setup.py:31) with a CI matrix of 3.10/3.11/3.12;[dev]declares numpy, pandas, scikit-learn, ipywidgets, ipython and pytest-timeout; the file carrying the f-stringSyntaxErrorno longer exists.fast_ci.yml:47installs only.[dev]and runs the suite green.The one item not done is a
make devbootstrap. There is no Makefile, andCONTRIBUTING.mddocuments the pip command instead — a documentation nicety rather than the defect this issue describes.
Part of #108 · Phase 0 · Blocks all measurement.
Problem
The documented setup produces an environment in which pytest cannot start.
pyproject.toml:189hard-requires xdist:but
pytest-xdistis in the[test]extra, not[dev]. So after the documentedpip install -e ".[dev]":Separately, on this machine no interpreter can import
paramiko— a hard runtime dependency — across anaconda base, homebrew, system, and mambaforge. There is no project venv.import clustrixfails everywhere, which is why every coverage figure in issues #61/#86/#98-#106 is unverifiable.Undeclared test dependencies cause 6 collection errors on a clean
[dev]install:numpy->tests/test_decorator_real.py,tests/comprehensive/test_{edge_cases,failure_recovery,performance_benchmarks,serialization}_real.pypandas-> the samecomprehensive/filessklearn-> 2 further failuresAnd one error is unfixable by installation:
tests/real_world/test_container_registry_comprehensive.py:571—SyntaxError: f-string expression part cannot include a backslash. This blocks collection of the whole run on Python <=3.11 even under-m "not real_world".Also in scope
requires-python = ">=3.8"(pyproject.toml:14,setup.py:32). Python 3.8 and 3.9 are both past end-of-life. The f-string bug above is precisely a <=3.11 issue.Acceptance criteria
pip install -e ".[dev]"on a clean machine yields an environment wherepyteststarts and collects with zero errors.[dev]includes everythingaddoptsand the tests require:pytest-xdist,numpy,pandas,scikit-learn(or the tests needing them are moved behind an extra and marked).tests/real_world/test_container_registry_comprehensive.py:571syntax error fixed.requires-pythonraised to a supported floor (>=3.10 recommended); CI matrix updated to match.make devor equivalent) that a new contributor can run start to finish.[dev]on a clean runner and asserts collection succeeds — so this cannot regress.Verification