Plugin integration overview¶
A manifest is a small TOML file that teaches pytest-deck how to drive one pytest plugin. Each manifest becomes a switch in the dashboard’s sidebar. Turn the switch on, and the deck adds that plugin’s arguments to the next run.
Here is a complete manifest:
id = "randomly" # the entry-point name -p loads
label = "Shuffle (pytest-randomly)"
dist = "pytest-randomly" # the name you pip install (display only)
scope = "run"
Four lines is enough. With this file in place, the switch appears in the
sidebar, and turning it on adds -p randomly to the run.
Manifests come from two places, both loaded and validated by the same parser:
Curated manifests ship inside pytest-deck (
pytest_deck/manifests/*.toml). Seven ship today:pytest-cov,pytest-mpl,pytest-benchmark,pytest-metadata,pytest-mock,pytest-asyncio, andpytest-django. The plugins guide covers what each one does.User manifests live in your repo at
<rootdir>/.pytest-deck/plugins/*.toml. Drop one in and refresh the browser tab; it appears in the sidebar. See Writing your own manifest.
A manifest only becomes a switch if its plugin is actually installed. A switch for a missing plugin would fail the run, so the panel never offers one.
The three facets¶
Every manifest describes a plugin along three axes: how you control it, how its output comes back, and how that output is shown.
Control: the switch and its config¶
The identity and configuration half: id, label, dist, scope, an
optional [env] table, and typed [[fields]] that render as text inputs or
checkboxes. For example, typing web into coverage’s Source field compiles
the token --cov=web. Fields compile purely to a token list, never a shell
string.
A manifest can also declare a flags namespace, the command-line options that
belong to its plugin. Matching tokens from your ini addopts then ride along
whenever the switch is on. See Flags.
Transport: how output comes back¶
json_file/text_file: a file the plugin writes during the run and the deck reads once the child exits. Coverage uses this:--cov-report=json:{tmpdir}/cov.json. Available to any manifest.artifact_dir: a run-scoped directory of files the deck serves over HTTP, like pytest-mpl’s baseline and diff images. Curated only.fd3: no file at all. The payload rides the deck’s own structured-results channel, which is how pytest-metadata’s in-memory data gets out. Curated only.
Render: which panel lights up¶
json/text: generic surfaces available to any manifest. A JSON file shows as a foldable tree, a text file as plain preformatted text. This is how a user manifest for, say,pytest-json-reportgets its report on screen.First-party renderings: richer surfaces wired to specific curated plugins. Coverage’s total percentage, per-file source panel, and per-line hit/miss gutter; benchmark’s mean-time tree column and per-test stats table; metadata’s Environment section; pytest-mpl’s per-test Attachments pane (
render = "artifacts").
The user / curated boundary¶
A user manifest gets the switch, config fields, a flags namespace, and the
generic json / text renders. Every first-party pipeline ships with the
deck, end to end: the slimmers (deck-internal steps that shrink bulky output
to a summary), the fd3 transport, artifact_dir, and the custom panels.
A user manifest whose id matches a curated one replaces it. Your file
becomes the whole definition for that plugin: the curated fields, [env],
transport, and rich panel are gone. Whatever output you declare renders only
through the generic json or text surfaces.
In practice: a user manifest with a [transport] must declare
render = "json" or render = "text". One that omits the render, or
reaches for a first-party surface, is rejected at validation with the reason
printed.
Part of this is practical. Some plugins embed bulk per-line or per-sample data
in their output, and a generic json tree can’t usefully show that. Those
plugins need a curated manifest with a slimmer. See the
render size cap.
Trust model¶
Curated manifests are code the project ships, so the deck trusts them. A user manifest is TOML read from whatever repo is checked out, so the deck treats it as untrusted input. Argv is yours: a user manifest may compile any pytest tokens it likes, because you already run your own test code. The hard limits sit where a manifest could reach beyond the test run:
User manifests cannot set reserved environment variables. The
[env]table is applied to the run subprocess, and a few names would break the deck’s own machinery or redirect writes. The sharpest case isCOVERAGE_FILE: pytest-cov writes a data file to whatever path it names, so a hostile repo could aim it at a file like~/.bashrcand overwrite it. The full list is in the reference. Setting any of them rejects the whole manifest, with the reason printed.User manifests cannot declare the
artifact_dirtransport. Its root becomes a directory the deck serves over HTTP, which would let a manifest expose arbitrary files as URLs.User manifests cannot use the deck’s results channel (the
fd3transport). Only the deck’s own first-party records ride that channel.User manifests cannot borrow first-party renders, even by reusing a curated
idlikepytest_cov. Those panels make a claim (“this is your coverage”), and the deck won’t present a user-declared file as first-party data.
A user manifest that fails validation is skipped with a console warning naming the file and the reason. The rest still load.
Next steps¶
Writing your own manifest: the walkthrough.
Manifest reference: every key, with types and examples.
Example: the coverage manifest: the fullest curated manifest, annotated end to end.