antithesis.catalog
This module gives read and write access to the assertion catalog: the set of assertion declarations in your code, whether or not they ever run.
It exists for local tooling rather than for Antithesis tests: enumerating
the test properties a source tree declares, comparing them against the ones
a local test run actually evaluated, failing CI when a change silently drops an
assertion, or checking an inventory of test properties into the repository.
Workloads use antithesis.assertions and antithesis.random instead and
never need this module.
On the Antithesis platform the catalog is produced at build time by the platform's instrumentor; this module is just that machinery, in case you need it:
scan_tree/scan_source/scan_astfind assertion declarations in source, with the same scanner the platform runs. Nothing is imported or executed.writeserializes entries as registration events.loadreads such a file back; it is what theANTITHESIS_ASSERTION_CATALOGenvironment variable resolution uses.load(write(entries))round-trips.registerdeclares entries to the active output handler at runtime, the way an instrumented process declares its catalog at startup.assertions()lists the catalog registered for this process, resolved throughANTITHESIS_ASSERTION_CATALOG. Outside an instrumented container that variable is normally unset and the result is empty -- usescan_treeon your source instead.
The scanner only catalogs what the platform would: calls to the assertion
functions of antithesis.assertions (under any import alias) with a literal
message. Assertions issued through your own wrappers, or with dynamically
built messages, are invisible to any static scan; declare those at runtime
with register (or antithesis.assertions.assert_raw), which works both
locally and on the platform.
A typical local workflow, with ANTITHESIS_SDK_LOCAL_OUTPUT set so
assertions are logged to a file:
python -m antithesis.catalog src/ -o catalog.json
ANTITHESIS_ASSERTION_CATALOG=catalog.json pytest
The output file then opens with one "hit": false line per declared
assertion, followed by the assertions the run actually evaluated
("hit": true) -- so the test properties your suite never exercised are
the messages with no "hit": true line. Equivalently, a harness can skip
the files entirely: call scan_tree at session start, register the
result, and join in memory.
One assertion declaration.
There is one per assertion call site the catalog knows about, whether or not that code ever runs: the catalog is a static property of the source, not of any particular execution.
The key under which Antithesis aggregates this assertion's evaluations
into one test property. Currently equal to message; treat it as opaque.
Which assertion function a declaration came from.
This is the typed form of the display_type field of serialized
assertion events; the enum value is that string, which is also how the
triage report labels the property. It is distinct from AssertType,
the three-way wire-level type, which cannot tell always from
always_or_unreachable, or reachable from unreachable, without
also consulting must_hit.
AssertType: The wire-level assertion type for this kind.
Where an assertion was declared.
For scanned entries, file is relative to the scanned root; for loaded
entries it is whatever the catalog file recorded. class_name is the
enclosing class (serialized as class, which Python reserves) and
function the enclosing function, or "" where there is none.
The assertion catalog registered for this process, resolved through
the ANTITHESIS_ASSERTION_CATALOG environment variable.
Inside an instrumented container this is the catalog the platform produced for this program. Outside one the variable is normally unset and the result is empty: the local catalog is whatever you scanned or loaded yourself. Reading it registers nothing and emits nothing.
Reads catalog entries back from a catalog file, or from a directory
the platform's instrumentor populated (such as the one
ANTITHESIS_ASSERTION_CATALOG points to inside a container).
Lines that do not parse as catalog entries are reported and skipped.
Raises FileNotFoundError if path does not exist or is a directory
in which no catalog can be located.
Declares catalog entries at runtime, emitting each one (with
"hit": false) through the active output handler.
This is how an instrumented process declares its catalog at startup, and it works the same on the platform and locally -- so it is the right tool for declaring assertions no static scan can see (wrapped call sites, messages drawn from a data table), as well as for harnesses that scan at session start instead of shipping a catalog file.
Entries are emitted unconditionally: registering the same entry twice writes two declaration lines. Consumers should treat declarations as a set keyed by message.
The assertion declarations in an already-parsed module.
relpath names the module in each entry's location.file and should be
relative to the scanned root.
The assertion declarations in one module's source text.
Raises SyntaxError if the source does not parse.
The assertion declarations under a source directory.
Scans every file iter_sources yields. Files that do not parse are
reported to stderr and skipped. Entries are in path order, so the
result is stable for a given tree.
Writes catalog entries to out (a path or a text file object) as JSON
lines. load reads it back.