sift_client.pytest_plugin
¶
Sift pytest plugin: records each test as a step in a Sift test report.
Load it from a project's conftest.py::
pytest_plugins = ["sift_client.pytest_plugin"]
This module holds only the plugin's public surface: the catchable warnings,
the session-state globals a conftest may read, the fixtures a project can
request or override, and pytest's hook entry points. The implementation
(settings registry, step stacks, report construction, terminal formatting)
lives under sift_client._internal.pytest_plugin.
| CLASS | DESCRIPTION |
|---|---|
SiftPytestPluginWarning |
Base warning for issues raised by the Sift pytest plugin. |
SiftPytestStepDrainError |
Raised when mid-session drain fails, signaling a likely upstream invariant break. |
SiftPytestStepDrainWarning |
A step's |
| FUNCTION | DESCRIPTION |
|---|---|
client_has_connection |
Verify the |
report_context |
Lazy session-scoped Sift ReportContext. |
sift_client |
Default |
step |
Create an outer step for the function when the Sift gate is on. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
REPORT_CONTEXT |
TYPE:
|
SIFT_REPORT_ID_STASH_KEY |
|
SIFT_REPORT_URL_STASH_KEY |
|
SiftPytestPluginWarning
¶
Bases: SiftWarning
Base warning for issues raised by the Sift pytest plugin.
SiftPytestStepDrainError
¶
Bases: RuntimeError
Raised when mid-session drain fails, signaling a likely upstream invariant break.
SiftPytestStepDrainWarning
¶
Bases: SiftPytestPluginWarning
A step's __exit__ raised while the plugin was draining its stack.
Surfaced at module-teardown or session-end so the drain can continue and pytest test outcomes stay unaffected; the underlying exception is included in the message for debugging.
client_has_connection
¶
Verify the SiftClient can reach Sift via /ping.
Consulted at session start by report_context in online mode. A failed
ping aborts the session via pytest.exit. Override this fixture in your
conftest to use a
different reachability signal (e.g. a cached auth token) for environments
where pinging is the wrong check. Returns False in --sift-disabled
mode without constructing a client.
pytest_addoption
¶
Register every CLI flag and pytest ini key declared in PLUGIN_OPTIONS.
pytest_collection_modifyitems
¶
Stash each item's class chain + parametrize path and cluster siblings.
Sorts by (file_path, hierarchy_chain, parametrize_path) so sibling
items under a shared parent (package, module, class, or parametrize axis)
stay contiguous; otherwise a free function sorting between two class
methods would tear down + re-open the class step, producing duplicate
parents in the report tree.
pytest_configure
¶
Register the Sift gate markers and warn on unknown SIFT_* settings.
pytest_report_header
¶
Emit a session-start header with the SDK version and active mode.
Suppressed under -q (negative verbosity), matching how pytest hides its
own platform/plugin header.
pytest_runtest_makereport
¶
Capture per-phase reports and finalize step status after teardown.
Stashes both rep_<when> (the CallInfo, kept for pytest plugins that
expect that conventional attribute) and _sift_phase_<when> (a
SimpleNamespace(call, report) used by resolve_initial_status). The
collection-time skip path is strictly gated on _sift_step being unset
so it does not duplicate steps the fixture already created.
pytest_sessionfinish
¶
Drain any parent steps still open at session end (innermost first).
Wrapped so a failure in the inner drain does not prevent the outer one
from running. With module_substep removed, this is the sole place
where hierarchy parents close; they persist across all tests and only
drain when the session ends.
pytest_terminal_summary
¶
Emit a session-end Sift report summary, adapting per mode.
The printed panel is suppressed under -q, but programmatic side effects
(stashing the report ref for conftest.py, --sift-open-report) still run so
other plugins and CI steps can consume the result. The panel itself is
rendered by write_report_summary; this hook handles the side effects.
report_context
¶
report_context(
request: FixtureRequest, pytestconfig: Config
) -> Generator[ReportContext, None, None]
Lazy session-scoped Sift ReportContext.
The fixture is no longer autouse; it's instantiated on the first call
to request.getfixturevalue("report_context"), which today happens
inside the gated step, _hierarchy_parents, and
_parametrize_parents fixtures. If every test in the session is
excluded via the marker gate, this fixture is never resolved and no
ReportContext (or teardown subprocess) is created.
What gets yielded depends on the mode:
--sift-disabled: a realReportContextagainst a placeholderSiftClientwith_simulate=True. Every test-results write returns a synthesized response without contacting Sift; no log file is written; the replay subprocess never spawns. Test code that callsstep.measure(...)keeps working because bounds are evaluated as usual and routed through the simulate path.--sift-offline: a real ReportContext, but the session-start ping is skipped, all create/update calls go to the JSONL log file, and the import-test-result-log replay subprocess is not spawned at session end.- default (online): verify connectivity via
client_has_connectionbefore constructing the context. A failed ping aborts the session withpytest.exitand points at--sift-offlineand--sift-disabledas escape hatches.
The log-file destination is controlled by
--sift-log-file; defaults to a temp file when unset.
sift_client
¶
sift_client(pytestconfig: Config) -> SiftClient
Default SiftClient resolved from environment variables and ini keys.
Each credential is read from its environment variable first. The URIs
(SIFT_GRPC_URI, SIFT_REST_URI) additionally fall back to the
sift_grpc_uri / sift_rest_uri ini keys, since they are stable
per-org values that are safe to commit. SIFT_API_KEY is intentionally
env-only; use pytest-dotenv (already a project dependency) to load
it from a .env file kept out of version control.
Projects that need custom construction (TLS toggles, custom timeouts,
etc.) can override this fixture by defining their own sift_client
in their conftest.py; pytest fixture resolution prefers the local
definition.
In --sift-offline mode the missing-credential check is relaxed:
real env vars and ini values still win when set (so the client is
constructible against a real backend even though no calls are made), but
anything still missing is filled with a placeholder. In --sift-disabled
mode the credential resolution is skipped entirely and placeholders are
always used.
step
¶
step(
request: FixtureRequest,
pytestconfig: Config,
_parametrize_parents: None,
) -> Generator[NewStep | None, None, None]
Create an outer step for the function when the Sift gate is on.
Resolves the gate via gate_enabled: the sift_exclude marker forces off,
sift_include forces on, otherwise the sift_autouse ini default applies.
When on, requests the session report_context lazily; the first gated test
in the session triggers its creation, subsequent gated tests reuse it. In
--sift-disabled mode the report context is backed by a
SiftClient(_simulate=True) placeholder, so every write returns a
synthesized response without contacting Sift.