import subprocess
import sys
import tempfile
from pathlib import Path
from spotregen import make_sample_repo
tmp = tempfile.TemporaryDirectory()
root = make_sample_repo(Path(tmp.name) / "demo")
def spotregen(*args, drop=None):
"""Run `spotregen` in the sample repository; show the call and its output."""
done = subprocess.run(
[sys.executable, "-m", "spotregen", *args],
cwd=root,
capture_output=True,
text=True,
check=False,
)
print("$ spotregen", *args)
lines = (done.stdout + done.stderr).splitlines()
print("\n".join(x for x in lines if not (drop and drop in x)))
print(f"[exit {done.returncode}]")Check a repository
This tutorial runs the static check on a sample repository and breaks it in three ways. Every cell is live: it builds the repository in a temporary directory and calls the spotregen command line.
Definition 1 (The static check) spotregen check loads the whole regen/ tree, runs every check (architecture, each unit, each decision), prints one line per finding and a summary, and exits 1 if an error was found. It is deterministic and cheap, so it is the first step of make guard.
A clean repository
Example 1 (No findings)
spotregen("check")$ spotregen check
regen check: 1 units, 0 errors, 0 warnings
[exit 0]
The summary line is stable. A consistent repository prints nothing but the summary.
A forbidden import
Example 3 (ARCH01 and ARCH04: the architecture is violated) regen/architecture.toml allows app to import core and nothing else. A new module in core that imports app breaks the rule, and closes an import cycle as well.
(root / "src" / "samplepkg" / "core" / "bad.py").write_text("from samplepkg.app import main\n")
spotregen("check")$ spotregen check
ERROR ARCH01 src/samplepkg/core/bad.py: 'core' imports 'samplepkg.app', but architecture.toml allows only []
ERROR ARCH04 architecture.toml: new import cycle between 'app' and 'core' (not in known_cycles)
regen check: 1 units, 2 errors, 0 warnings
[exit 1]
Warnings and --strict
Example 4 (DEL03: a consumer that no longer references the unit) Warnings ask for attention. They fail the check only with --strict.
(root / "src" / "samplepkg" / "core" / "bad.py").unlink()
(root / "docs" / "guide.qmd").write_text("The guide no longer mentions the unit.\n")
spotregen("check")
spotregen("check", "--strict")$ spotregen check
WARNING DEL03 samplepkg.core.calc: consumer docs/guide.qmd no longer references the unit
regen check: 1 units, 0 errors, 1 warnings
[exit 0]
$ spotregen check --strict
WARNING DEL03 samplepkg.core.calc: consumer docs/guide.qmd no longer references the unit
regen check: 1 units, 0 errors, 1 warnings
[exit 1]
0 means no error (no finding at all with --strict), 1 means errors, 2 means that the spec itself is malformed: invalid TOML, a value outside a vocabulary or a missing regen/architecture.toml. See the schema page for every code.
(root / "regen" / "units" / "core.calc.toml").write_text("unit = [")
spotregen("check")$ spotregen check
spotregen: /private/var/folders/dw/pvtj6mt91znd0hftcztqb0k00000gn/T/tmpgu1h6b5f/demo/regen/units/core.calc.toml: invalid TOML (Invalid value (at end of document))
[exit 2]
Next: the deletion test.