plesty.lib.experiment.runs

How a run is named, laid out, found, and read back.

Experiment writes runs; this module is the other side — the one place that spells out the run-directory convention so viewers, analyzers, and command lines never re-derive it:

<run_root>/<name>_<YYYYmmdd-HHMMSS>/     # run id = experiment name + start time
├── plan.json                              # frozen schedule + config
├── journal.jsonl                          # events; run_started carries the data paths
├── records.jsonl                          # one line per completed step: its result
└── data/step_NNNN.npy                     # blobs the records reference, if any

Device-written blobs (spectrometer frames, camera images) never cross the network: they land on a shared disk under <data_dir>/<run_id>/raw, where data_dir is the share as the acquiring host sees it. A machine reading the run sees the same share under its own mount, so every path in a record is translated through the pair (data_dir, data_mount). Both come from one environment convention — PLESTY_DATA_DIR and PLESTY_DATA_MOUNT — and the run journals the spelling it was written with, so a viewer on any machine needs at most its own mount.

run = Run(latest_run("/mnt/share", name="pol_pl"))
run.config["powermeter"]          # the frozen configuration
run.status()["state"]             # "running" / "completed" / ...
run.local(record["data_file"])    # host path → path on this machine

Attributes

BLOB_SUBDIR

RECORDS_FILE

DATA_DIR_VAR

DATA_MOUNT_VAR

PLAN_FILE

JOURNAL_FILE

RAW_SUBDIR

RUN_ID_TIME_FORMAT

Classes

Run

Read access to one run directory: plan, journal, records, data paths.

Functions

run_id(→ str)

Return the run id for experiment name started at when (now by default).

parse_run_id(→ Optional[tuple[str, datetime.datetime]])

Split a run id into its experiment name and start time.

list_runs(→ list[pathlib.Path])

Return the run directories under run_root, oldest first.

latest_run(→ pathlib.Path)

Return the most recently started run under run_root.

host_join(→ str)

Join path parts in the spelling of root's operating system.

to_local(→ pathlib.Path)

Translate a path the acquiring host reported into this machine's mount.

Module Contents

plesty.lib.experiment.runs.BLOB_SUBDIR = 'data'
plesty.lib.experiment.runs.RECORDS_FILE = 'records.jsonl'
plesty.lib.experiment.runs.DATA_DIR_VAR = 'PLESTY_DATA_DIR'
plesty.lib.experiment.runs.DATA_MOUNT_VAR = 'PLESTY_DATA_MOUNT'
plesty.lib.experiment.runs.PLAN_FILE = 'plan.json'
plesty.lib.experiment.runs.JOURNAL_FILE = 'journal.jsonl'
plesty.lib.experiment.runs.RAW_SUBDIR = 'raw'
plesty.lib.experiment.runs.RUN_ID_TIME_FORMAT = '%Y%m%d-%H%M%S'
plesty.lib.experiment.runs.run_id(name: str, when: datetime.datetime | None = None) str

Return the run id for experiment name started at when (now by default).

Parameters:
  • name (str)

  • when (Optional[datetime.datetime])

Return type:

str

plesty.lib.experiment.runs.parse_run_id(text: str) tuple[str, datetime.datetime] | None

Split a run id into its experiment name and start time.

Parameters:

text (str) – A directory name.

Returns:

(name, started), or None when text is not a run id — the name may itself contain underscores, so the split is at the last one.

Return type:

Optional[tuple[str, datetime.datetime]]

plesty.lib.experiment.runs.list_runs(run_root: str | pathlib.Path, name: str | Sequence[str] | None = None) list[pathlib.Path]

Return the run directories under run_root, oldest first.

Parameters:
  • run_root (str | pathlib.Path) – The directory runs are created in.

  • name (Union[str, Sequence[str], None]) – Keep only runs of this experiment name (or any of several — an experiment that was renamed still owns its old runs). None keeps every run.

Return type:

list[pathlib.Path]

plesty.lib.experiment.runs.latest_run(run_root: str | pathlib.Path, name: str | Sequence[str] | None = None) pathlib.Path

Return the most recently started run under run_root.

Raises:

FileNotFoundError – If there is no such run yet — a viewer opened before its experiment is a mistake worth naming.

Parameters:
  • run_root (str | pathlib.Path)

  • name (Union[str, Sequence[str], None])

Return type:

pathlib.Path

plesty.lib.experiment.runs.host_join(root: str, *parts: str) str

Join path parts in the spelling of root’s operating system.

A data directory is spelled the way the acquiring host spells it, which is not necessarily this machine’s convention — G:\RAWDATA from a Linux viewer must still become G:\RAWDATA\run\raw.

Parameters:
  • root (str)

  • parts (str)

Return type:

str

plesty.lib.experiment.runs.to_local(host_path: str, data_dir: str, mount: str) pathlib.Path

Translate a path the acquiring host reported into this machine’s mount.

Parameters:
  • host_path (str) – The path as the acquiring host spelled it, e.g. G:\RAWDATA\pol_pl_20260805-091909\raw\frame.spe.

  • data_dir (str) – The shared root as that host sees it.

  • mount (str) – The same root as this machine sees it.

Raises:

ValueError – If host_path lies outside data_dir — a path from another rig or a stale configuration, which would otherwise resolve to a plausible-looking wrong file.

Return type:

pathlib.Path

class plesty.lib.experiment.runs.Run(run_dir: str | pathlib.Path, *, mount: str | None = None, data_dir: str | None = None, replay_rows: int = 0)

Read access to one run directory: plan, journal, records, data paths.

Nothing here writes. The plan is read once; the journal is replayed on each status() because a run under way keeps appending to it.

Attach to a run directory.

Parameters:
  • run_dir (str | pathlib.Path) – The run directory.

  • mount (Optional[str]) – This machine’s view of the shared data root; None takes PLESTY_DATA_MOUNT from the environment, then the mount journaled by the machine that ran the experiment (only when that directory exists here).

  • data_dir (Optional[str]) – The shared root as the acquiring host sees it — only for runs that did not record it themselves.

  • replay_rows (int) – How source() hands records out — 0 follows the run live, n rations a stored run n records per poll.

path
replay_rows = 0
_mount = None
_data_dir = None
_plan: plesty.lib.experiment.schedule.Plan | None = None
_started: dict[str, Any] | None = None
sources: list[Any] = []
property id: str

The run id (the directory name).

Return type:

str

property name: str | None

The experiment name the run id carries, if it parses as one.

Return type:

Optional[str]

property started: datetime.datetime | None

The start time the run id carries, if it parses as one.

Return type:

Optional[datetime.datetime]

property plan: plesty.lib.experiment.schedule.Plan

The frozen plan (loaded once).

Return type:

plesty.lib.experiment.schedule.Plan

property config: dict[str, Any]

The frozen configuration; {} when the plan is unreadable.

Return type:

dict[str, Any]

property journal: plesty.lib.experiment.journal.Journal

The run’s journal.

Return type:

plesty.lib.experiment.journal.Journal

status() dict[str, Any]

The run status by journal replay (see Journal.status()).

Return type:

dict[str, Any]

records() Iterable[dict[str, Any]]

Iterate the committed step records, oldest first.

Return type:

Iterable[dict[str, Any]]

_run_started() dict[str, Any]
Return type:

dict[str, Any]

property data_dir: str | None

The shared root as the acquiring host sees it.

Journaled by the run; falls back to the plan’s top-level data_dir for runs written before the journal carried it, then to the data_dir given at construction.

Return type:

Optional[str]

property raw_dir: str | None

Where the run’s device-written blobs went, in the host’s spelling.

Return type:

Optional[str]

property data_mount: str | None

The shared root as this machine sees it (see the class docstring).

Return type:

Optional[str]

local(host_path: str) pathlib.Path

Return host_path (as a record spells it) as a path on this machine.

Untranslated when the run has no data root or this machine has no mount for it — the case of a viewer on the acquiring host itself.

Parameters:

host_path (str)

Return type:

pathlib.Path

source(mapper: plesty.lib.monitor.sources.FrameMapper | None = None) plesty.lib.monitor.sources.RunSource | plesty.lib.monitor.sources.ReplaySource

Return a source over this run’s records — live or replayed.

A RunSource when replay_rows is 0, else a ReplaySource handing out that many records per poll. Every source made here is kept in sources.

Make one source per consumer: a source hands each record out once, so two views polling the same source would each see half the rows. The mapper is what they share.

Parameters:

mapper (Optional[plesty.lib.monitor.sources.FrameMapper])

Return type:

Union[plesty.lib.monitor.sources.RunSource, plesty.lib.monitor.sources.ReplaySource]

property exhausted: bool

Whether every source made here has handed out its last record.

Live sources never are (the next record may still be coming); a run without sources counts as exhausted so a watcher does not wait forever.

Return type:

bool

__repr__() str

Return Run('<path>').

Return type:

str