API Reference — pytest Plugin¶
RAMPART's pytest integration. Activates automatically when installed.
_collection
¶
Result collection infrastructure for the pytest plugin.
Provides the ContextVar-based mechanism for collecting Result objects produced during test execution. The pytest plugin activates a collector per test; execution event handlers write into it automatically.
ResultCollectionHandler
¶
Bases: ExecutionEventHandler
Default ExecutionEventHandler installed on every BaseExecution.
Writes the Result into the active per-test collector on ON_POST_EXECUTE. No-op for all other events. No-op when no collector is active (safe to use outside pytest).
on_event
async
¶
Record result on post-execute. Ignore all other events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_data
|
ExecutionEventData
|
The event data. |
required |
Source code in rampart/pytest_plugin/_collection.py
ResultCollector
¶
record_result
¶
Record a Result into the active test's collector.
For building-block tests that construct Results manually rather than via Attacks. or Probes. factories. No-op when called outside a pytest test context (e.g., in library usage or scripts).
Re-exported from rampart at the top level — consumers import it as:
from rampart import record_result
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
Result
|
The result to record. |
required |
Source code in rampart/pytest_plugin/_collection.py
_session
¶
Session-scoped state for the RAMPART pytest plugin.
Accumulates Result objects, computes trial group aggregates, and builds the final TestRunReport.
RampartSession
¶
Session-scoped state for the RAMPART plugin.
Accumulates Result objects from all tests, stores trial group aggregates, tracks session duration, and builds the final TestRunReport. Holds configured sinks for report emission.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sinks
|
list[ReportSink]
|
Report sinks to emit to at session end. Defaults to an empty list (terminal-only output). |
None
|
Source code in rampart/pytest_plugin/_session.py
results_by_nodeid
property
¶
Read-only view of results grouped by pytest node ID.
is_emitted
property
¶
True once report emission has been attempted (idempotency guard).
incomplete_reasons
property
¶
The recorded reasons the run is incomplete (empty if complete).
trial_specs
property
¶
Read-only view of registered trial specs, keyed by clone node ID.
add_sinks
¶
Register additional sinks for report emission.
Called by the fixture-based bootstrap to add team-provided sinks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sinks
|
list[ReportSink]
|
Sinks to append. |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If any item does not satisfy ReportSink. |
Source code in rampart/pytest_plugin/_session.py
set_duration
¶
Set the total session duration.
Called by the plugin at session finish with the elapsed time since pytest_configure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration_seconds
|
float
|
Total wall-clock seconds. |
required |
Source code in rampart/pytest_plugin/_session.py
| Python | |
|---|---|
absorb
¶
Absorb results from a completed test's collector.
Tags each result with the short test name (extracted from the
node ID), the full node ID, its index within the test, and the
harm category from @pytest.mark.harm. The nodeid and index
give a total, deterministic ordering for the terminal summary and
report regardless of xdist worker completion order.
Results are shallow-copied before tagging to avoid mutating objects the test body may still reference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node
|
Item
|
The test item that just completed. |
required |
collector
|
ResultCollector
|
The test's result collector. |
required |
Source code in rampart/pytest_plugin/_session.py
record_trial_group
¶
Record aggregate statistics for a trial group.
Semantics:
- Any UNSAFE result across all trials -> group FAILS
- threshold is the minimum pass rate (SAFE / total).
e.g. 0.8 means at least 80% of runs must be SAFE.
- ERROR results count against the pass rate (they're not SAFE).
- Clones with zero results (skipped or crashed before producing
a Result) are tracked as no_result and count against
the pass rate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_nodeid
|
str
|
The original test's node ID. |
required |
clone_nodeids
|
Sequence[str]
|
Pytest node IDs of all clones in this trial group. |
required |
threshold
|
float
|
Minimum pass rate required. |
required |
Source code in rampart/pytest_plugin/_session.py
register_trial_spec
¶
Record trial metadata for a cloned item at collection time.
Called from pytest_collection_modifyitems whenever a
@pytest.mark.trial test is expanded into clones. Stores
the data needed for session-end aggregation in a form that
survives the xdist worker→controller boundary.
Identical re-registration (same key, same spec) is a no-op so that repeated collection passes (e.g., in workers and the controller) converge safely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clone_nodeid
|
str
|
Node ID of the cloned item. |
required |
base_nodeid
|
str
|
Node ID of the original (uncloned) item. |
required |
threshold
|
float
|
Pass-rate threshold from the trial marker. |
required |
Source code in rampart/pytest_plugin/_session.py
merge_trial_specs
¶
Merge trial specs received from an xdist worker payload.
Idempotent: re-merging identical specs is a no-op. Spec values from workers should match the controller's own collection because the same plugin code runs in every process; we merge defensively so the controller can aggregate correctly even when its own collection state is unavailable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trial_specs
|
Mapping[str, TrialSpec]
|
Specs keyed by clone node ID. |
required |
Source code in rampart/pytest_plugin/_session.py
merge_worker_results
¶
Merge an xdist worker's results into this session.
Extends both the flat _results list and the
_results_by_nodeid mapping. Invalidates any cached report
so the next build_report() reflects the merged data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
results_by_nodeid
|
dict[str, list[Result]]
|
Worker results grouped by pytest node ID. |
required |
Source code in rampart/pytest_plugin/_session.py
mark_emitted
¶
mark_incomplete
¶
Record that a worker failed to deliver complete results.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
str
|
A short human-readable explanation surfaced in the report metadata. |
required |
Source code in rampart/pytest_plugin/_session.py
| Python | |
|---|---|
set_report_metadata
¶
Attach run-level metadata that will appear on TestRunReport.
Used by the plugin to surface xdist run-mode information (active, worker count, dist mode). Subsequent calls merge into existing metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
dict[str, object]
|
Key/value pairs to attach. |
required |
Source code in rampart/pytest_plugin/_session.py
build_report
¶
Build a TestRunReport from all collected results.
The report is cached and reused on subsequent calls. The cache is invalidated when new results are absorbed or merged or when metadata is updated.
Results are sorted by (_pytest_nodeid, _rampart_result_index,
_rampart_source_worker) for a total, deterministic ordering across
xdist worker completion orders. _pytest_nodeid falls back to
_pytest_test_name and _rampart_source_worker is absent
(constant) outside xdist, so single-process ordering is unaffected.
These leading-underscore keys are RAMPART scheduling bookkeeping, namespaced to avoid colliding with user-supplied result metadata.
Returns:
| Name | Type | Description |
|---|---|---|
TestRunReport |
TestRunReport
|
Aggregated test run results. |
Source code in rampart/pytest_plugin/_session.py
Parallel Execution Hooks¶
When pytest-xdist is installed, the plugin registers pytest_testnodedown (as an optional hook) to merge worker results into the controller session. See Parallel Execution for the data flow and trust boundary.
_xdist
¶
xdist support for RAMPART's pytest plugin.
Provides serialization, deserialization, and controller-side merge
logic for running RAMPART under pytest-xdist. Workers serialize their
Result objects into config.workeroutput; the controller merges
worker payloads in pytest_testnodedown and emits a single unified
report at session end.
Trust boundary: worker payloads may contain attacker-controlled content (agent responses, payload text). Serialization is strictly JSON-safe primitives; deserialization validates schema version, enum values, and metadata depth; ANSI escapes are stripped from free text as defense-in-depth.
WorkerOutputError
¶
Bases: Exception
Base error for xdist worker output processing failures.
SchemaVersionError
¶
Bases: WorkerOutputError
Raised when a worker payload has missing or unknown schema version.
SizeLimitError
¶
Bases: WorkerOutputError
Raised when a worker payload exceeds the configured size cap.
is_xdist_worker
¶
Return True when this process is a pytest-xdist worker.
Detection is attribute-based; no xdist import required, so this function is safe to call when pytest-xdist is not installed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if running in an xdist worker process. |
Source code in rampart/pytest_plugin/_xdist.py
is_xdist_controller
¶
Return True when this process is the pytest-xdist controller.
The controller is the non-worker process that owns an active
distribution: a --dist mode other than "no" plus at least one
way of spawning execution endpoints (--numprocesses workers or
explicit --tx gateways). Keying off distribution rather than the
worker count alone keeps -d/--tx runs (no -n) on the
controller path while excluding a bare --dist with no endpoints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if running in the xdist controller process. |
Source code in rampart/pytest_plugin/_xdist.py
get_dist_mode
¶
Return the active --dist mode string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The dist mode (e.g., |
Source code in rampart/pytest_plugin/_xdist.py
| Python | |
|---|---|
get_worker_count
¶
Return the number of xdist workers configured.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
Number of workers (0 when xdist is not active). |
Source code in rampart/pytest_plugin/_xdist.py
serialize_worker_data
¶
Serialize a worker's RampartSession state for transport to the controller.
Produces a JSON-safe dict containing the schema version, the
package version (for cross-version diagnostics), the worker's
_results_by_nodeid mapping serialized to primitive types,
and trial specs registered during collection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
RampartSession
|
The worker's session state. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: A JSON-safe payload ready to write to
|
Source code in rampart/pytest_plugin/_xdist.py
deserialize_worker_data
¶
Deserialize a worker payload back into a results_by_nodeid mapping.
Performs strict schema validation: missing schema key, unknown
versions, and malformed enum values all raise WorkerOutputError
(or subclass). Caller should catch and mark the run incomplete
rather than letting the exception propagate to pytest.
Each result's metadata["_pytest_nodeid"] and
metadata["_rampart_result_index"] are set authoritatively from the
outer mapping key and list position so cross-worker ordering is total
and independent of any (untrusted) serialized values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
object
|
The deserialized JSON object from
|
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[Result]]
|
dict[str, list[Result]]: Results grouped by nodeid. |
Raises:
| Type | Description |
|---|---|
SchemaVersionError
|
Missing or unknown schema version. |
WorkerOutputError
|
Malformed payload (type errors, bad enums). |
Source code in rampart/pytest_plugin/_xdist.py
finalize_worker
¶
Serialize the worker's session state into config.workeroutput.
Called from pytest_sessionfinish on each xdist worker. The
worker skips sink emission entirely; the controller is responsible
for the final report.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
session
|
RampartSession
|
The worker's session state. |
required |
Raises:
| Type | Description |
|---|---|
SizeLimitError
|
If the serialized payload exceeds the
configured cap. The truncation marker is still written to
|
Source code in rampart/pytest_plugin/_xdist.py
handle_testnodedown
¶
Merge a finished worker's results into the controller session.
Called from pytest_testnodedown on the controller for each
worker that completes. Failures (missing payload, deserialization
errors, worker crashes) are recorded via mark_incomplete rather
than raised, so a single bad worker does not abort report emission.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
RampartSession
|
The controller's session state. |
required |
node
|
object
|
The xdist node object (has |
required |
error
|
object
|
The shutdown error from xdist, or None on clean exit. |
required |
Source code in rampart/pytest_plugin/_xdist.py
| Python | |
|---|---|
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | |
discover_sinks_from_conftest
¶
Discover rampart_sinks definitions from registered conftest modules.
Workers run the standard _rampart_sink_bootstrap fixture to
register sinks via pytest's fixture machinery. The controller has
no test execution, so fixtures do not run. This function scans
registered plugins for a module-level rampart_sinks attribute
and resolves it:
- If callable with zero arguments, invoke it and use the return.
- If a list, use it directly.
- Otherwise, log a warning and skip.
Sinks that depend on other fixtures cannot be discovered this way.
Such configurations should register sinks via the
pytest_rampart_sinks hook, which is resolved identically on the
controller and in every worker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Config
|
The pytest configuration object. |
required |
Returns:
| Type | Description |
|---|---|
list[ReportSink]
|
list[ReportSink]: Discovered sinks (may be empty). |