On this page
The pytest11 entry point: hook ordering that binds the floor before conftest import, marker registration, and the autouse cwd and push-guard fixtures.
#python.src.stricttest.plugin
#python.src.stricttest.plugin
The pytest plugin entry point (pytest11).
Installing stricttest IS adoption. Every hook below binds unconditionally once the project's safety keys validate; there is no opt-in switch and no runtime degradation path -- a project either declares its stance and gets the floor, or the session aborts.
Ordering matters and is deliberate:
pytest_load_initial_conftests-- the earliest hook that already has a
parsed ini file. Validation, the TMPDIR refusal, the env-poisoning floor and the socket guard all bind HERE, before any conftest module is imported. A conftest that reads HOME at import time therefore sees the throwaway one.
pytest_configure-- marker registration and a second TMPDIR check now
that --basetemp is fully resolved.
pytest_collection_modifyitems/pytest_xdist_node_collection_finished
-- the bare-run threshold, once the selected test count is known.
#settings
def settings() -> SettingsThe resolved settings for this session (raises if not yet configured).
#pytest_addoption
def pytest_addoption(parser)#pytest_load_initial_conftests
def pytest_load_initial_conftests(early_config, parser, args)Bind the whole floor before any conftest module is imported.
#pytest_configure
def pytest_configure(config)#pytest_unconfigure
def pytest_unconfigure(config)Tear down the throwaway env directory for this process.
#pytest_collection_modifyitems
def pytest_collection_modifyitems(config, items)Refuse a bare full-ish run outside the sandbox.
trylast so this runs AFTER pytest's own -k / -m deselection, which mutates items in place -- the count then reflects the SELECTED tests, so a -k slice of a big file stays under the threshold and runs bare instead of being refused on the pre-deselection total.
Enforcement is split by execution topology:
- Single process (no xdist):
itemsis the full set here -- enforce. - xdist worker (
PYTEST_XDIST_WORKERset): a shard; defer to the
controller so the error surfaces once, not once per worker.
- xdist controller (
numprocessesset):itemsis empty here because
workers do the collecting -- defer to pytest_xdist_node_collection_finished which sees the real count.
#pytest_xdist_node_collection_finished
def pytest_xdist_node_collection_finished(node, ids)xdist controller: enforce the threshold once collection lands.
The controller does not collect items itself; each worker reports its collected ids here. All workers collect the same full set, so the first report carries the true test count -- enforce on it.
optionalhook so the plugin loads cleanly in projects without xdist.
#_stricttest_chdir_into_tmp
def _stricttest_chdir_into_tmp(request, tmp_path, monkeypatch)Autouse: never let a test run with the process cwd at the real repo.
A test whose process cwd is the real repo can make every unanchored git command (status/commit/push, file generation, scaffolding) operate on the development repo. Chdir-ing each test into its own tmp_path makes implicit repo-cwd reliance a visible failure instead of silent real-repo pollution. Fixtures that chdir into their own tmp_path (the same tmp_path object) compose cleanly -- they land in the same directory. Tests that genuinely need the repo cwd must anchor explicitly, or opt out with @pytest.mark.repo_cwd.
#_stricttest_guard_nonlocal_push
def _stricttest_guard_nonlocal_push()Autouse guard: block any real git push to a non-local remote.