Developer Onboarding¶
The front door for contributing to labgrid-plugins itself: clone the repo, install
the dev environment, learn the day-to-day nox loop, understand how the plugins register,
and add a driver, resource, or strategy. For the design and component model read
Architecture; for the bare lint/test/doc commands see Contributing.
Three different “onboardings” — don’t confuse them
This page — working inside the
labgrid-pluginspackage.Onboarding a Consumer Repo — wiring another repo onto the hardware-CI flow.
Onboarding a Lab Host — bringing hardware online to serve those consumers.
Prerequisites¶
Python 3.10+ and git.
uv (recommended) — the
noxautomation uses the uv backend.A C toolchain only if you need the
kuiperextra (it buildspytsk3for theKuiperDLDriver); everything else installs as pure Python.
Step 1 — clone and install¶
git clone https://github.com/tfcollins/labgrid-plugins.git
cd labgrid-plugins
pip install -e ".[dev,docs]" # editable install with dev + docs tooling
pip install -e ".[kuiper]" # optional: adds pytsk3 for KuiperDLDriver
Prefer an isolated environment:
uv venv venv --python 3.10 && source venv/bin/activate
uv pip install -e ".[dev,docs]"
Step 2 — the repo at a glance¶
The repository is more than the package — two sibling subprojects carry their own
toolchains and are not exercised by the top-level nox:
Path |
What lives there |
|---|---|
|
hardware control (power, shell, JTAG, TFTP, downloads, mass storage) |
|
passive config containers (outlets, device paths, release info) |
|
boot-workflow state machines (SoC, FPGA fabric, SelMap, RPi, SSH, TFTP) |
|
the |
|
hardware-CI helpers + the consumer |
|
sibling — Docker stack: coordinator, FastAPI bridge (own |
|
sibling — exporter YAML templates, |
|
package tests and this Sphinx documentation |
See Architecture “Directory Structure” for the file-level layout.
Step 3 — the development loop¶
nox (uv backend) is the canonical entry point:
nox # default sessions: lint, tests, docs (NOT typecheck)
nox -s lint # ruff check + format check
nox -s format # auto-fix: ruff format + ruff check --fix
nox -s tests # run pytest
nox -s tests -- -k test_name # a single test
nox -s docs # build the Sphinx docs
nox -s typecheck # opt-in: ty static check (baseline not yet clean)
Or run the tools directly: ruff check . --fix && ruff format . and pytest tests/.
Style: ruff with line length 100, double quotes, spaces, rules E/W/F/I/UP/B (E501
ignored). Types: ty intentionally ignores unresolved-attribute and
too-many-positional-arguments — labgrid injects binding attributes at bind time and
@step() mangles signatures, so don’t “fix” those by annotating bindings.
Step 4 — how the plugins register (read once)¶
This is the one piece of framework wiring you must understand.
Upstream labgrid has no entry-point auto-discovery (that was a fork-only feature). Registration happens by import side effect instead:
import adi_lg_pluginsrunsadi_lg_plugins/__init__.py, which imports thedrivers,resources, andstrategiessubpackages.Each subpackage
__init__imports its individual modules (a_MODULEStuple) so the@target_factory.reg_driver/@reg_resourcedecorators run and register the class by name. A module whose optional dependency is missing on this host logs a warning and is skipped rather than breaking the whole import.Therefore every labgrid env YAML that names an ADI component must carry
imports: [adi_lg_plugins](or the consuming process mustimport adi_lg_plugins).
The entry points in pyproject.toml are not discovery
[project.entry-points."labgrid.drivers"] (and .resources / .strategies) are
kept as a manifest/reference, but upstream labgrid never reads them. Adding an entry there
alone does not register a component — the module must be imported (step 2). The
fork-only never_retry strategy decorator is shimmed in
adi_lg_plugins/strategies/_compat.py.
Step 5 — add a component¶
For a new driver, resource, or strategy:
Create the class in the matching subdirectory, following the existing files — use
@attr.s(eq=False)and the registration decorator (@target_factory.reg_driverfor drivers and strategies,@target_factory.reg_resourcefor resources). See Architecture “Extensibility” for full templates.Wire it into discovery — add the module name to the subpackage’s
_MODULESimport list soimport adi_lg_pluginsregisters it (Step 4).Add the entry point in
pyproject.tomlunder the matching[project.entry-points."labgrid.*"]section (convention/manifest).Add tests in
tests/— and opt new unit tests into CI (next step) if they should run there.
Step 6 — testing¶
Two categories live in tests/:
Unit/integration — run without hardware (
test_cli.py,test_mcp.py,test_fabric_strat.py, …):pytest tests/.Hardware — marked
@pytest.mark.hardware; require--run-hardwareand a labgrid config via--lg-config. Some modules (test_soc_strat*.py,test_rpi_hw.py) are excluded from default collection inconftest.pybecause they crash without--lg-env.
CI (.github/workflows/tests.yml) runs a Python 3.10/3.11/3.12 matrix: nox -s lint
(blocking) → nox -s typecheck (continue-on-error / informational) → nox -s tests --
tests/test_cli.py tests/test_mcp.py. A new unit test must be added to that list to be
exercised by CI.
Step 7 — submit changes¶
Branch, make nox -s lint and nox -s tests green locally, then open a PR; CI re-runs
the same gates.
Note
The project’s license is unresolved — pyproject.toml declares LGPL-2.1-or-later
while LICENSE/README say Apache 2.0. Ask before adding license headers to new
files.
See also¶
Architecture — component model, bindings, lifecycle, extensibility.
Contributing — the condensed command reference.
Onboarding a Consumer Repo / Onboarding a Lab Host — the consumer- and lab-side onboarding flows.