Run it
With the three demo servers running and their addresses in .env (see
The Rig):
$ uv run python -m plesty.demo_pow_pl
… Run experiment_20260925-181144: 92 step(s), run dir …/plesty-tutorial/data/runs/experiment_20260925-181144
… Setup: connecting devices
… Preflight hwp @ tcp://localhost:5552: ok (SIM-APT (S/N: 55123456, firmware: 1.0.0))
… Preflight spec @ tcp://localhost:5553: ok (Mock LightField Spectrometer (no hardware))
… Preflight pm @ tcp://localhost:5551: ok (THORLABS,PM100D,MOCK0001,1.0.0)
… Step 1/92 hwp[000.00] (measure_row)
… Step 1/92 done in 0.0 s
…
The run goes into runs/ under the shared data disk — LOCAL_DATA in .env,
which a run other than --dry-run refuses to start without. Its folder:
runs/experiment_20260925-181144/
├── plan.json the plan, and the settings it was built from
├── journal.jsonl what happened, one event per line
├── records.jsonl what each finished step returned: 91 rows, then the analysis
├── raw/spec/ the 91 spectra, written there by the spectrometer
└── analysis/ what the analysis step saved — see Analyze
Stop it and continue
Press Ctrl-C — here at row 64 of 91:
… Step 64/92 done in 0.1 s
… Run experiment_20260925-181144 canceled; resume with run(resume='experiment_20260925-181144').
… Teardown: disconnecting devices
Continue it with the same command line and the run's id:
$ uv run python -m plesty.demo_pow_pl --resume experiment_20260925-181144
… Resuming run experiment_20260925-181144: 64/92 steps already completed.
… Preflight hwp @ tcp://localhost:5552: ok (SIM-APT (S/N: 55123456, firmware: 1.0.0))
…
… Step 65/92 hwp[128.00] (measure_row)
…
… Run experiment_20260925-181144 completed (92 steps) in 1.9 s.
The run's journal now reads run_canceled, then run_completed, and its
records hold each row once. Continuing rebuilds the plan and compares it with
the saved one, so a run whose settings were edited in between is refused
rather than stitched together. The instruments are disconnected at the end
however the run stops.
A run can also be paused, stopped or aborted from outside — by PLESTY Bench's
buttons, or by a script calling plesty.lib.experiment.control on the run's
folder (see Data Flow).
The command ends the way the run's journal does, so a script that started it can tell (plesty-lib 0.6.1 and newer):
| Exit code | The run |
|---|---|
0 |
completed |
130 |
was interrupted with Ctrl-C or canceled — continue it with --resume |
1 |
was aborted — continue it with --resume |
Read it back
Run reads a run's folder from any program, on any PC that sees the disk, and
run.local() turns a row's data_file into a path on this PC:
from pathlib import Path
from plesty.lib.experiment import Run, latest_run
run = Run(latest_run(Path.home() / "plesty-tutorial/data/runs", name="experiment"))
print(run.status()["state"]) # completed
row = next(run.records())
print(row["hwp_deg"], row["power_w"]) # 0.0 6.112988e-06
print(run.local(row["data_file"])) # …/runs/experiment_20260925-181144/raw/spec/mock_….spe
Next: Analyze.