check_test_layout¶
rhiza_hooks.check_test_layout
¶
Check that the test layout mirrors the source layout.
Enforces a strict test/source parity so tests are easy to locate and no test drifts loose from what it covers:
- every source module
<src>/…/xyz.pyhas a test file<tests>/…/test_xyz.py(nested packages are mirrored); - every top-level
class Ain a source module has a matchingTestAclass in that test file; - no test file lacks a corresponding source module (no orphan test files);
- no
Test*class lacks a corresponding source class (no orphan test classes).
The reverse direction is the one that pays for itself: a renamed or retired module leaves its tests behind, and those tests keep passing against nothing.
__init__.py and conftest.py are ignored on both sides, and the
tests/benchmarks/ and tests/stress/ trees are exempt entirely — those
hold benchmarks and stress tests that need not mirror a source module. Test
functions are unconstrained — the rules bind files and classes only.
Repositories that deliberately organise tests by behaviour rather than 1:1
mirroring (and guarantee per-module coverage another way, e.g. a 100% coverage
gate) can opt out via a [tool.check_test_layout] table in pyproject.toml::
[tool.check_test_layout]
enforce = false
reason = "Tests are grouped by behaviour; coverage is enforced by pytest."
enforce = false requires a non-empty reason so the deviation is always
documented — an undocumented opt-out is indistinguishable from neglect. The same
table accepts exempt_dirs = [...] to extend the built-in benchmarks/stress
exemptions when parity is enforced, and exempt_files = [...] to exempt
individual test files by their path relative to the tests root — for a single
loose file, exempt_dirs cannot express it, since its first path component is
the file itself and exempting that reads as a directory that does not exist.
The configuration lives in pyproject.toml rather than under .rhiza/
deliberately: the layout it describes is a property of the Python project, not of
the template that syncs its infrastructure, and a repo that is not rhiza-managed
must still be able to configure this hook.
Exit codes
0 - the layout is clean, or parity is intentionally not enforced 1 - violations were found (every one is listed), or the opt-out is misconfigured
check(src, tests, config=None)
¶
Return a list of layout violations (empty when the layout is clean).
The two directions are independent passes — see :func:_forward_violations
and :func:_orphan_violations — and this is their concatenation, forward
first so a missing test file is reported before its knock-on orphans.
Source code in rhiza_hooks/check_test_layout.py
main(argv=None)
¶
Run the hook and return a process exit code.
--src/--tests/--config are resolved against the current working
directory (pre-commit runs hooks from the repository root); the defaults are
anchored to the repository root itself, so the hook also behaves when invoked
from a subdirectory by hand.