plesty.server.presenter.bench
The local bench: one object that composes the model and the services.
Bench is what the CLI and the GUI talk to. It owns a Home, a
Fleet, and the four services, and answers the operator’s questions
— what is declared, what is installed, what is running — and carries out
the operator’s intents — install, start, stop, field-test, bring the fleet
up. Anything that takes longer than a request/reply (an install, a field
test) it starts as a job by re-invoking plesty-server _job … through the
detached launcher (Bench.install(), Bench.field_test()); the
synchronous twins (install_now(), field_test_now()) are what
those jobs run.
Attributes
Exceptions
An operation could not be carried out as asked. |
Classes
Where a command for one device runs: which interpreter, in which directory. |
|
The agent this process is serving, and what it takes to stop it. |
|
What the operator sees about one device instance. |
|
What a declaration form can offer for a package's source. |
|
One installed version of a module, as Hub ▸ Installed modules… lists it. |
|
The local bench. |
Functions
|
The |
|
A setup entry as the bench serving it declares it: without the run keys. |
|
What an experiment's declaration sets for one device of its setup, by stem. |
|
text with each |
|
Refuse a configuration a run would refuse: one that is not a YAML mapping. |
|
The configuration a started run froze into its plan; |
|
What a run's Source cell says: the version that measured it. |
|
A distribution name as PyPI compares them: case and |
|
Order runs with the ones not yet started on top, the newest created first. |
|
Why a device in this state cannot be controlled, or |
|
Each |
|
An ISO timestamp as an aware |
|
Whether ref names a release ( |
|
A declaration standing in for a bare module install. |
|
Rebuild one device of the node host from its |
|
A status from a node's JSON, keeping only the fields this version knows. |
|
|
|
What a fleet is called: its file's name without |
|
Whether one and other name the same file, however each is spelled. |
|
Module Contents
- plesty.server.presenter.bench.Say
- plesty.server.presenter.bench.SERVE_TIMEOUT_MS = 600000
- plesty.server.presenter.bench.SHARE_CHECK_DIR = '.plesty-share-check'
- plesty.server.presenter.bench._RUN_KEYS = ('host_name', 'data_dir')
- plesty.server.presenter.bench._setup_entries(checkout: pathlib.Path) dict[str, dict[str, Any]]
The
devices:of the module’ssetup.yamlas written; empty when unreadable.Kept whole, for the bench serving a device to declare it by; the run-side reading of the same file is
plesty.lib.experiment.Setup.- Parameters:
checkout (pathlib.Path)
- Return type:
dict[str, dict[str, Any]]
- plesty.server.presenter.bench._served_entry(entry: collections.abc.Mapping[str, Any], located: collections.abc.Mapping[str, str] | None = None) dict[str, Any]
A setup entry as the bench serving it declares it: without the run keys.
Where the device writes is not added: the bench that starts it gives that from its own share and folder (
Bench.device_env()).A
${VARIABLE}in itsargsis the variable’s value, as a bench’s fields in the same file are (#43): a device that follows the runs —--replay-run-root ${LOCAL_DATA}/pol-pl— is told the folder this machine’s.envnames, not one written into the file for every machine.- Parameters:
entry (collections.abc.Mapping[str, Any]) – The device’s
setup.yamlentry.located (collections.abc.Mapping[str, str] | None) – The variables, as the experiment’s environment has them.
- Raises:
BenchError – When an argument names a variable that is not set.
- Return type:
dict[str, Any]
- plesty.server.presenter.bench.DEVICE_ENV_SEPARATOR = '__'
- plesty.server.presenter.bench._device_env(env: collections.abc.Mapping[str, str], stem: str) dict[str, str]
What an experiment’s declaration sets for one device of its setup, by stem.
<STEM>__<NAME>in the declaration’senvisNAMEfor the device whose stem is STEM (spec→SPEC, as inSPEC_ADDRESS), when this experiment serves it — and only then (#43). The welcome’s demo used to write its spectrometer’s folders into that device’s own.env, which every later experiment serving aspecinherited.- Parameters:
env (collections.abc.Mapping[str, str])
stem (str)
- Return type:
dict[str, str]
- plesty.server.presenter.bench._VARIABLE
- plesty.server.presenter.bench._expanded(text: str, located: collections.abc.Mapping[str, str]) str
text with each
${NAME}replaced by its value in located.- Parameters:
text (str)
located (collections.abc.Mapping[str, str])
- Return type:
str
- plesty.server.presenter.bench._check_config(name: str, text: str) None
Refuse a configuration a run would refuse: one that is not a YAML mapping.
- Raises:
BenchError – Naming what is wrong with it.
- Parameters:
name (str)
text (str)
- Return type:
None
- plesty.server.presenter.bench._planned_config(run_dir: pathlib.Path) dict[str, Any] | None
The configuration a started run froze into its plan;
Nonewhen it has none.- Parameters:
run_dir (pathlib.Path)
- Return type:
dict[str, Any] | None
- plesty.server.presenter.bench.UNKNOWN_SOURCE = 'unknown — the run recorded no version'
- plesty.server.presenter.bench._run_source(status: dict[str, Any], package: str, installed: str) str
What a run’s Source cell says: the version that measured it.
- Parameters:
status (dict[str, Any]) – The run’s status, with the
provenanceits start journaled.package (str) – The experiment’s distribution.
installed (str) – The current install’s line (
Bench.experiment_source()).
- Returns:
<package>==<version>from the run’s own provenance once it has started; the current install marked as what it will run on while it waits;UNKNOWN_SOURCEfor a started run that recorded none.- Return type:
str
- plesty.server.presenter.bench._canonical(name: str) str
A distribution name as PyPI compares them: case and
_/./-alike.- Parameters:
name (str)
- Return type:
str
- plesty.server.presenter.bench._waiting_runs_first(rows: list[dict[str, Any]]) list[dict[str, Any]]
Order runs with the ones not yet started on top, the newest created first.
A created run has no start time, so by name alone it lands wherever its name happens to sort. Put at the bottom, under every measurement, the run just created was out of sight, and creating it read as having failed — an operator duplicated a run three times and saw none of them (#31). The run just created is the one the next Run is meant for, so it leads.
- Parameters:
rows (list[dict[str, Any]]) – The runs, newest first by name.
- Returns:
The same rows, reordered.
- Return type:
list[dict[str, Any]]
- plesty.server.presenter.bench.control_blocked(status: plesty.server.model.ProcessStatus) str | None
Why a device in this state cannot be controlled, or
Nonewhen it can.Pure, and taking the status rather than a name, so the window can decide whether to enable Control… from the state it already painted — a check that probed a server on every table refresh would be a round trip per device per tick, on the GUI thread.
Controls need a server that answers: the panel reads the device’s schema over the wire, and a stopped server has nothing to read it from.
- Parameters:
status (plesty.server.model.ProcessStatus) – The server’s observed state.
- Returns:
The reason a tooltip shows, or
None.- Return type:
str | None
- exception plesty.server.presenter.bench.BenchError
Bases:
RuntimeErrorAn operation could not be carried out as asked.
Initialize self. See help(type(self)) for accurate signature.
- plesty.server.presenter.bench.TERMINAL_KIND = 'cmd'
- plesty.server.presenter.bench.LAST_OPERATOR_FILE = 'last-operator.txt'
- plesty.server.presenter.bench.WELCOME_SEEN_FILE = 'welcome-seen'
- plesty.server.presenter.bench.DEMO: dict[str, str]
- plesty.server.presenter.bench.TRAFFIC_LINES = 2000
- class plesty.server.presenter.bench.VenvContext
Where a command for one device runs: which interpreter, in which directory.
- Variables:
name – The device instance.
python – The interpreter of the environment serving it.
cwd – The directory a command runs in — the checkout for a git install, the device’s run directory for a release.
installed – The installation this describes.
- name: str
- python: pathlib.Path
- cwd: pathlib.Path
- installed: plesty.server.model.InstalledVersion
- property scripts: pathlib.Path
The environment’s executables —
plesty,pytest,python.- Return type:
pathlib.Path
- property label: str
One line naming what commands here will run against.
- Return type:
str
- path_env() dict[str, str]
PATHwith this environment first, so its console scripts win.- Return type:
dict[str, str]
- class plesty.server.presenter.bench.AgentHandle
The agent this process is serving, and what it takes to stop it.
- Variables:
service – The agent answering requests.
thread – The daemon thread it serves on.
stop – Set to end the serve loop at its next poll.
settings – What it was started with — a later edit to
agent.yamldoes not move a bound socket.
- service: plesty.server.services.Agent
- thread: threading.Thread
- stop: threading.Event
- settings: plesty.server.model.AgentSettings
- class plesty.server.presenter.bench.DeviceView
What the operator sees about one device instance.
- Variables:
spec – The fleet declaration.
installed – The installed version that serves it, or
None.status – The server’s observed state.
field_test_blocked – Why a field test cannot run, or
Nonewhen it can.control_blocked – Why its controls cannot be opened, or
None.info – The package-level record (repository, project page, latest release).
host – The node this device runs on, empty for this bench’s own. What the Host column shows, and what decides whether an action is carried out here or relayed.
fleet – The fleet of this bench that declares it; empty for a node’s.
- installed: plesty.server.model.InstalledVersion | None
- field_test_blocked: str | None = None
- control_blocked: str | None = None
- info: plesty.server.model.PackageInfo | None = None
- host: str = ''
- fleet: str = ''
- property name: str
The instance name.
- Return type:
str
- property remote: bool
Whether this device runs on a node rather than on this bench.
- Return type:
bool
- property source: str
the requirement plus the commit for a checkout.
- Type:
One line
- Return type:
str
- class plesty.server.presenter.bench.SourceOptions
What a declaration form can offer for a package’s source.
- Variables:
versions – Release versions known for the package: every release on PyPI newest first once fetched, then what this bench installed and the catalogue’s.
refs – Git refs known for it (installed checkouts, the repository’s tags once fetched, the usual branches). A tag whose release is in versions is left to the release source.
git_urls – Repository URLs known for it.
- versions: tuple[str, Ellipsis] = ()
- refs: tuple[str, Ellipsis] = ()
- git_urls: tuple[str, Ellipsis] = ()
- class plesty.server.presenter.bench.InstalledModule
One installed version of a module, as Hub ▸ Installed modules… lists it.
- Variables:
installed – The inventory record.
kind –
deviceorexperiment— what the module says it is, else what this bench declares it as;""when neither says.used_by – The declarations this version serves. While there is one, it is not uninstalled.
- installed: plesty.server.model.InstalledVersion
- kind: str = ''
- used_by: tuple[str, Ellipsis] = ()
- class plesty.server.presenter.bench.Bench(home: plesty.server.model.Home, fleet: plesty.server.model.Fleet | None = None, manager: plesty.server.model.DeviceManager | None = None, installer: plesty.server.services.Installer | None = None, jobs: plesty.server.services.JobRunner | None = None, supervisor: plesty.server.services.Supervisor | None = None, say: Say | None = None, connect_node: Any | None = None)
The local bench.
Compose a bench.
- Parameters:
home (plesty.server.model.Home) – The bench home.
fleet (plesty.server.model.Fleet | None) – The fleet file, or
Nonefor a bench with no declarations (instances are then declared throughdeclare()).manager (plesty.server.model.DeviceManager | None) – Installed-version inventory; default on home.
installer (plesty.server.services.Installer | None) – Environment creator; default on home and manager.
jobs (plesty.server.services.JobRunner | None) – Job runner; default on home.
supervisor (plesty.server.services.Supervisor | None) – Server supervisor; default on home.
say (Say | None) – Where progress lines go; default: stderr.
connect_node (Any | None) – Builds the client for a peer; injected by the tests, which reach a fake agent rather than a bench on a network.
- home
- fleet
- manager
- installer
- jobs
- supervisor
- _agent: AgentHandle | None = None
- _nodes: plesty.server.services.Nodes | None = None
- _connect_node = None
- view: frozenset[str] | None = None
- node_view: frozenset[str] | None = None
- _fleet_cache: dict[pathlib.Path, tuple[int, plesty.server.model.Fleet]]
- _current_stamp: int | None
- _run_roots: dict[str, tuple[tuple[str, Ellipsis], str]]
- _published: dict[str, tuple[tuple[str, Ellipsis], tuple[str, Ellipsis]]]
- _released_jobs: set[str]
- classmethod open(home: str | os.PathLike[str] | None = None, fleet_path: str | os.PathLike[str] | None = None, say: Say | None = None) Bench
Build a bench from the environment: the home, and the fleet file it finds.
- Parameters:
home (str | os.PathLike[str] | None) – Explicit home directory (
--home); else the default.fleet_path (str | os.PathLike[str] | None) – Explicit fleet file (
-f); else./fleet.yaml, then<home>/fleet.yaml, then the fleet used last, then<home>/fleets/default.yaml— created empty if missing.say (Say | None) – Progress sink.
- Return type:
- say(line: str) None
Emit a progress line.
- Parameters:
line (str)
- Return type:
None
- say_to(say: Say) None
Send progress lines to say from now on.
The console does this at start-up. Without it these lines go to stderr, which a windowed process on Windows discards outright — so “port 5551 is in use — moving to 5553” was written to nowhere while the fleet file was quietly edited.
- Parameters:
say (Say)
- Return type:
None
- spec(name: str) plesty.server.model.DeviceSpec
The declaration of name, in the current fleet or any other of this bench.
- Raises:
BenchError – When no fleet declares it.
- Parameters:
name (str)
- Return type:
- fleet_files() list[pathlib.Path]
Every fleet this bench has:
<home>/fleets/*.yaml, and the current file.- Return type:
list[pathlib.Path]
- fleets() dict[str, plesty.server.model.Fleet]
Every fleet this bench has, by name, each as its file says now.
Read from disk each time — a file only when it changed since — so what the agent declares shows in the console without a restart (#18). A file that does not read is said and left out.
- Return type:
dict[str, plesty.server.model.Fleet]
- fleet_of(name: str) str | None
The fleet that declares device name, or
None.- Parameters:
name (str)
- Return type:
str | None
- shown_fleets() dict[str, plesty.server.model.Fleet]
The fleets the console shows: every one, or those in
view.- Return type:
dict[str, plesty.server.model.Fleet]
- new_fleet(name: str) pathlib.Path
Create the empty fleet name beside this bench’s others; returns its file.
The current fleet stays current: a client creates a fleet to declare into it (
declare --fleet NAME), not to move the bench onto it.- Raises:
BenchError – When the name is unusable or the fleet exists.
- Parameters:
name (str)
- Return type:
pathlib.Path
- fleet_rows() list[dict[str, Any]]
Every fleet:
name,path,devices(a count) andcurrent.- Return type:
list[dict[str, Any]]
- fleet_file(fleet: str | None) pathlib.Path
The file of the fleet called fleet, or of the current one.
- Raises:
BenchError – When this bench has no fleet of that name.
- Parameters:
fleet (str | None)
- Return type:
pathlib.Path
- _edit_fleet(path: pathlib.Path, change: collections.abc.Callable[[plesty.server.model.Fleet], plesty.server.model.Fleet]) plesty.server.model.Fleet
Re-read the fleet at path, make change, write it back; returns the result.
Never written from what was read earlier: the agent and the console are two writers of the same file, and a write from a stale copy undid what the other had just declared (#18).
- Raises:
BenchError – When path is an experiment’s setup, which the bench reads and never writes (#48).
- Parameters:
path (pathlib.Path)
change (collections.abc.Callable[[plesty.server.model.Fleet], plesty.server.model.Fleet])
- Return type:
- _check_free(name: str, fleet_path: pathlib.Path) None
Refuse name when another fleet of this bench already declares it.
A name keys the run directory, the log and the process record, so two fleets declaring it would share all three.
- Parameters:
name (str)
fleet_path (pathlib.Path)
- Return type:
None
- declare(spec: plesty.server.model.DeviceSpec, save: bool = True, fleet: str | None = None) plesty.server.model.DeviceSpec
Add or replace spec, allocating a port when it names none.
- Parameters:
spec (plesty.server.model.DeviceSpec) – The declaration.
save (bool) – Write the fleet file back (creating one when there is none).
fleet (str | None) – The fleet to declare it in; the one that already declares it, else the current one, by default.
- Raises:
BenchError – When another fleet declares the name, or fleet is not one.
- Return type:
- forget(name: str, save: bool = True) None
Remove name from the fleet that declares it (no error when absent).
- Parameters:
name (str)
save (bool)
- Return type:
None
- _save_fleet() pathlib.Path
Write the current fleet back, to
<home>/fleets/default.yamlwhen it has no file.A declaration that is not on disk is invisible to the jobs the console starts — they are separate processes that read the fleet file. So a bench that declares a device gets a fleet file, whether or not anyone asked for one.
- Return type:
pathlib.Path
- remove(name: str) bool
Drop name from the fleet, stopping its server first;
Truewhen one was stopped.The environment stays installed (another instance may use it); the
.envstays too, in case the device is declared again.- Parameters:
name (str)
- Return type:
bool
- rename(old: str, new: str) plesty.server.model.DeviceSpec
Declare old under new, moving with it what the name keys on disk.
A device name is not a label: it names the working directory the server runs in — which holds its
.envand the logs plesty-lib writes there — and its own server log. Removing the device and declaring it again is what an operator does today to fix a typo, and it loses both. So the rename moves them.The server has to be stopped first: its process record, the port it bound and the directory it has open are all keyed by the name it was started under.
- Parameters:
old (str) – The declared name.
new (str) – The name to give it; unchanged when equal to old.
- Returns:
The renamed declaration.
- Raises:
BenchError – When old is not declared, its server still runs, the new name is unusable, or something already holds it.
- Return type:
- set_autostart(name: str, flag: bool) plesty.server.model.DeviceSpec
Include name in (or drop it from) the working fleet; persists to the fleet file.
- Parameters:
name (str)
flag (bool)
- Return type:
- property working: list[plesty.server.model.DeviceSpec]
the declared devices marked
autostart.- Type:
The working fleet
- Return type:
- save_fleet_as(path: str | os.PathLike[str], names: collections.abc.Sequence[str] | None = None) pathlib.Path
Write the working fleet (or names) to path as a new fleet file; returns it.
The file is portable: it carries the declarations, not this bench’s
home. Every device written is markedautostart— it is the fleet of that file. The declared experiments go with it: an experiment has no autostart to set and is part of what this bench is set up to do.- Parameters:
path (str | os.PathLike[str])
names (collections.abc.Sequence[str] | None)
- Return type:
pathlib.Path
- create_fleet(path: str | os.PathLike[str]) plesty.server.model.Fleet
Write an empty fleet file at path and make it the current one.
- Raises:
BenchError – When path already exists.
- Parameters:
path (str | os.PathLike[str])
- Return type:
- load_fleet(path: str | os.PathLike[str]) plesty.server.model.Fleet
Replace the declarations with the fleet file at path (the home stays).
Nothing is stopped: the console loads the remembered fleet at start-up and the servers it finds running are the ones it is there to supervise. Swapping one fleet for another is
open_fleet().- Parameters:
path (str | os.PathLike[str])
- Return type:
- open_fleet(path: str | os.PathLike[str], create: bool = False) plesty.server.model.Fleet
Stop what this bench has running, then adopt the fleet file at path.
Replacing the declarations alone left the servers of the old fleet running with no way to reach them: the console is filled from the fleet, so they dropped out of the table while their PIDs, launch records and TCP ports lived on — and a device of the same name in the newly opened fleet then could not bind. Everything with a launch record is stopped, the working fleet and hand-started devices alike;
running()names them beforehand, for the operator to confirm.The new file is read before anything is stopped, so a path that is not a fleet costs nothing: the running servers are still there to go back to.
- Parameters:
path (str | os.PathLike[str]) – The fleet file to adopt.
create (bool) – Write an empty fleet file at path first (New fleet) instead of reading an existing one.
- Raises:
BenchError – When create is set and path already exists.
FleetError – When path is not a readable fleet document.
- Return type:
- remember_fleet() None
Note the current fleet file as the one to reopen next time (console start-up).
- Return type:
None
- fleet_text() str
The current fleet as YAML text (what the fleet-file editor shows).
- Return type:
str
- replace_fleet_text(text: str) plesty.server.model.Fleet
Validate text as a fleet file, write it to the fleet path and adopt it.
- Raises:
FleetError – When the text is not a valid fleet document.
- Parameters:
text (str)
- Return type:
- env_file(name: str) pathlib.Path
The device’s
.envfile:<home>/run/<name>/.env.- Parameters:
name (str)
- Return type:
pathlib.Path
- read_env_text(name: str) str
The
.envtext of name (empty when there is none).- Parameters:
name (str)
- Return type:
str
- write_env_text(name: str, text: str) pathlib.Path
Write the
.envof name; returns the path.- Parameters:
name (str)
text (str)
- Return type:
pathlib.Path
- process_env(spec: plesty.server.model.DeviceSpec) dict[str, str]
The environment a server or field test of spec runs with.
The bench’s own environment, then
device_env().- Parameters:
- Return type:
dict[str, str]
- device_env(spec: plesty.server.model.DeviceSpec) dict[str, str]
What the bench sets for spec on top of its own environment.
Where it writes — the bench data path as
DEVICE_DATA_ROOTand itsdata_dirunder it asDEVICE_DATA_PATH— then the device’s.envfile, then the fleet’senv:(explicit in the declaration, so it wins). A run serving the device overrides the folder the same way.- Parameters:
- Return type:
dict[str, str]
- venv_context(name: str) VenvContext
The interpreter and directory a command for name would run in.
- Raises:
BenchError – When nothing is installed for name.
- Parameters:
name (str)
- Return type:
- run_in_venv(name: str, line: str) plesty.server.model.Job
Run the command line against the environment installed for name.
The point is the interpreter.
plesty check,plesty initandplesty field-testhave to run against the venv that serves the device, which until now meant finding that path by hand in a system terminal and leaving the console to use it. The venv’s script directory goes first onPATH, soplesty,pythonandpytestare that environment’s.It is not a shell: the line is split into an argument list and handed to the process, so there is no pipe, no redirection and no glob. What it buys is the right interpreter, not a second way to compose shell.
- Raises:
BenchError – When nothing is installed for name, the line is empty, or it cannot be split into arguments.
- Parameters:
name (str)
line (str)
- Return type:
- experiments() list[plesty.server.model.ExperimentSpec]
Every declared experiment, in file order.
- Return type:
- experiment(name: str) plesty.server.model.ExperimentSpec
The declaration of experiment name.
- Raises:
BenchError – When it is not declared.
- Parameters:
name (str)
- Return type:
- declare_experiment(spec: plesty.server.model.ExperimentSpec, save: bool = True) plesty.server.model.ExperimentSpec
Add or replace an experiment declaration; returns it.
- Parameters:
spec (plesty.server.model.ExperimentSpec) – The declaration.
save (bool) – Write the fleet file, when there is one.
- Raises:
BenchError – When a device, or another fleet, already holds that name.
- Return type:
- forget_experiment(name: str, save: bool = True) None
Drop experiment name from the fleet, leaving its runs on disk.
The runs are the measurement and outlive the declaration: removing them is
purge()’s business and is asked for separately.- Parameters:
name (str) – The declared name.
save (bool) – Write the fleet file, when there is one.
- Return type:
None
- experiment_context(name: str) VenvContext
The interpreter and checkout a run of name would use.
- Raises:
BenchError – When nothing is installed, or the module was installed from a release — an experiment’s configuration lives in its repository, so a release install has nothing to run against.
- Parameters:
name (str)
- Return type:
- experiment_env(name: str) dict[str, str]
The environment a run of name would get.
The bench’s own, then the checkout’s
.env, then what the fleet declares — so pointing one experiment at a different stage is an edit to the declaration and not to the module’s deployment file.- Parameters:
name (str)
- Return type:
dict[str, str]
- unset_reasons(name: str, missing: collections.abc.Sequence[str]) list[str]
Why the bench could not give a run each of missing — what to set so it can.
Where this machine sees the shared disk comes from the bench without an address in the module’s setup, and each device’s address from the bench serving it, so a missing one is a setting missing there — a bench’s data, a device the setup does not list — or a variable the checkout’s
.envdoes not set, and the message names that.- Parameters:
name (str)
missing (collections.abc.Sequence[str])
- Return type:
list[str]
- local_endpoint() str
Where this bench’s own agent listens — the bench a device’s
localhost is.- Return type:
str
- static _setup(checkout: pathlib.Path) Any
The module’s
setup.yaml(aplesty.lib.experiment.Setup).Empty when it is missing or broken: a broken setup is reported where it is edited, not here, and a run still starts with the addresses and paths its
.envgives it.- Parameters:
checkout (pathlib.Path)
- Return type:
Any
- experiment_manifest(name: str) plesty.server.model.ExperimentManifest
Ask the module of name what it takes.
Read from the module every time rather than cached in the fleet: a declaration carrying a copy of the contract would be a second thing to keep in step, and an updated module would leave it stale.
- Raises:
BenchError – When nothing is installed, or the module publishes no manifest.
- Parameters:
name (str)
- Return type:
- experiment_devices(name: str, config: str) list[str] | None
The devices of name’s setup a run of config uses;
Nonefor all.Asked of a module whose manifest says it chooses (plesty-lib#62): one module may measure in place with a few devices or navigate with more on another bench, and serving the others would start instruments no step touches.
- Raises:
BenchError – When the module could not say.
- Parameters:
name (str)
config (str)
- Return type:
list[str] | None
- experiment_config_file(name: str, config: str | None = None) pathlib.Path
The configuration file a run of name would read — or config, one of its others.
- Parameters:
name (str) – The declared experiment.
config (str | None) – A configuration file relative to the checkout (
config/demo.yaml); the declared one whenNone.
- Raises:
BenchError – When config names a file outside the checkout.
- Return type:
pathlib.Path
- experiment_source(name: str) str
One line naming what a run of name would execute.
The same line the device table carries, for the same reason: a run is only reproducible if what produced it can be named, and a declaration alone does not say which version answered. Reads the install rather than the declaration, so a checkout shows the commit it is on.
- Parameters:
name (str) – The declared experiment.
- Returns:
plesty-pol-pl==0.1.0 (abc1234), or the requirement marked(not installed)when nothing is installed for it yet.- Return type:
str
- experiment_configs(name: str) list[str]
The configuration files name’s checkout offers, declared one first.
A module ships its
config/in the repository rather than in the wheel, so what a run may be given is whatever is in the checkout — a measured configuration and a demo one beside it, say. Reading the directory is the only way to know: nothing declares the alternatives, and a bench that offered only the declared file would hide them.- Parameters:
name (str) – The declared experiment.
- Returns:
Paths relative to the checkout (
config/default.yaml). The declared configuration leads and is always present, even when the checkout has yet to be made, so the caller always has something to offer.- Return type:
list[str]
- experiment_config_copy(name: str, config: str | None = None) pathlib.Path
Where this bench keeps its own copy of a configuration file of name.
Configuring an experiment never writes the module’s files — they change only through its repository — so what the operator saves goes here, under the experiment’s folder in the bench home (
<home>/run/<name>/config/demo.yaml), and new runs start from it.- Raises:
BenchError – When config names a file outside the checkout.
- Parameters:
name (str)
config (str | None)
- Return type:
pathlib.Path
- experiment_config_path(name: str, config: str | None = None) pathlib.Path
The file new runs of name take config from: the bench’s copy, else the module’s.
- Parameters:
name (str)
config (str | None)
- Return type:
pathlib.Path
- read_experiment_config(name: str, config: str | None = None) str
The configuration’s text — the declared one, or config; empty when absent.
The bench’s own copy when it has saved one, else the module’s file.
- Parameters:
name (str)
config (str | None)
- Return type:
str
- write_experiment_config(name: str, text: str, config: str | None = None) pathlib.Path
Save the configuration of name — or config, one of its others; returns where.
Written to the bench’s copy (
experiment_config_copy()), never to the module’s file, which is left as its repository has it.- Raises:
BenchError – When the text is not a YAML mapping, or cannot be written. A run refuses a configuration it cannot parse, and refusing it here costs nothing started.
- Parameters:
name (str)
text (str)
config (str | None)
- Return type:
pathlib.Path
- read_run_config(name: str, run_id: str) dict[str, Any]
What the run run_id of name is configured with, and whether it may change.
A run created here has its own copy (
RUN_CONFIG_FILE), and that is what it is started with. A run that has started was planned from its configuration, which its plan keeps; one created before runs had copies still names the module’s file.- Returns:
text, the configuration;config, the module’s file it came from;path, where it is read;frozen, whether the run has started and the configuration can no longer change.- Raises:
BenchError – When there is no such run.
- Parameters:
name (str)
run_id (str)
- Return type:
dict[str, Any]
- write_run_config(name: str, run_id: str, text: str, config: str) pathlib.Path
Configure the run run_id of name alone, before it has started.
The run’s own copy is replaced; the module’s files, and every other run, are left as they are.
- Parameters:
name (str) – The declared experiment.
run_id (str) – The run.
text (str) – The configuration it is to be run with.
config (str) – The module’s file it was taken from (
config/demo.yaml).
- Returns:
The run’s configuration file.
- Raises:
BenchError – When there is no such run, it has started, or the text is not a YAML mapping.
- Return type:
pathlib.Path
- experiment_setup_file(name: str) pathlib.Path
The
setup.yamlthe module of name ships at its root — which may be missing.- Raises:
BenchError – When nothing is installed to look in.
- Parameters:
name (str)
- Return type:
pathlib.Path
- experiment_dotenv(name: str) dict[str, str]
The values the checkout’s
.envholds — where its setup’s variables are set.- Raises:
BenchError – When nothing is installed to look in.
- Parameters:
name (str)
- Return type:
dict[str, str]
- write_experiment_setup(name: str, text: str | None, values: collections.abc.Mapping[str, str] | None = None) pathlib.Path
Replace the module’s
setup.yamlwith text, and set values in its.env.The setup names the variables, the
.envholds their values: a bench edited by value is saved as both (plesty.lib.experiment.setup.split_benches()).- Parameters:
name (str) – The experiment.
text (str | None) – The setup’s new text;
Noneleaves it as it is.values (collections.abc.Mapping[str, str] | None) – Variable → value for
.env; the rest of it is kept.
- Raises:
BenchError – When the text is not a setup — refused here rather than when a run reads it — or a file cannot be written.
- Return type:
pathlib.Path
- experiment_run_root(name: str) pathlib.Path
Where the runs of name land: its root on the shared disk, else this bench’s home.
With the module’s setup saying where this machine sees the shared data disk (
PLESTY_DATA), runs go to the root the module declares there —pol-pl→/mnt/plesty/pol-pl— the folder every bench sees, so a device on any of them can write into a run. Without one, or for a module that cannot say, they stay under this bench’s home.- Parameters:
name (str)
- Return type:
pathlib.Path
- _declared_run_root(name: str) str | None
The run root the module of name declares;
Nonewhen it cannot be read.- Parameters:
name (str)
- Return type:
str | None
- experiment_runs(name: str) list[pathlib.Path]
The run directories of name, newest first.
- Parameters:
name (str)
- Return type:
list[pathlib.Path]
- experiment_run(name: str, run_id: str | None = None) pathlib.Path | None
The run directory run_id names, or the newest run of name.
- Parameters:
name (str)
run_id (str | None)
- Return type:
pathlib.Path | None
- experiment_status(name: str, run_id: str | None = None) dict[str, Any]
What a run of name is doing, read from its run directory.
Nothing is asked of the run: the journal, the plan and the progress file are this bench’s own files, so a refresh costs a directory read and cannot disturb a measurement.
- Returns:
The journal’s status, with
run(the run id, orNonewhen there is none yet),totalsteps,step(what the step in flight last reported) andasked(what the run is currently being asked for).- Parameters:
name (str)
run_id (str | None)
- Return type:
dict[str, Any]
- serve_experiment_devices(name: str, devices: collections.abc.Sequence[str] | None = None) tuple[dict[str, str], list[str]]
Have each device of name’s setup running on its bench; the run’s addresses.
The module’s
setup.yamlsays which bench each device runs on (host_name); that bench declares it when it lacks it, starts it on a port of its own choosing, and says the port. This bench serves its own devices itself and asks another bench through its agent — the link Server ▸ Benches drives it by — so a run is only ever told an address a server is listening on. A device whose<DEVICE>_ADDRESSis set by hand, in the checkout’s.envor the declaration, is left alone: whoever set it said where the device is.- Parameters:
name (str) – The declared experiment.
devices (collections.abc.Sequence[str] | None) – Only these devices of the setup — the ones the run’s configuration uses (
experiment_devices());Nonefor all.
- Returns:
<DEVICE>_ADDRESSfor every device served, and the devices this call started — the run’s to stop when it ends (release_experiment_devices()); one already running was someone else’s and is left to them.- Raises:
BenchError – When a bench could not be asked, or could not serve a device.
- Return type:
tuple[dict[str, str], list[str]]
- release_experiment_devices(name: str, devices: collections.abc.Sequence[str]) list[str]
Stop devices of name’s setup, each on its bench: a run’s, once it has ended.
The devices a run started (
serve_experiment_devices()) are its own, and are stopped however it ended — completed, stopped, aborted or killed. A device that is not running any more is passed over, and one that cannot be stopped is reported, not raised: the run is over either way.- Parameters:
name (str) – The declared experiment.
devices (collections.abc.Sequence[str]) – The devices to stop, as its setup names them.
- Returns:
The devices stopped.
- Return type:
list[str]
- _bench_link(bench: Any) plesty.server.services.NodeLink
A link to the agent of bench, a bench of an experiment’s setup.
- Parameters:
bench (Any)
- Return type:
- serve(name: str, entry: collections.abc.Mapping[str, Any]) tuple[plesty.server.model.ProcessStatus, bool]
Have name running on this bench, declared from a
setup.yamlentry.An entry naming no port leaves this bench to pick one (
declare()). The experiment’s setup holds its devices’ settings, so a device this bench already declares is declared again from the entry when the two differ — keeping the port this bench gave it, unless the entry names one — and a server running with the old settings is restarted. A name declared for another package is refused rather than started under a name the experiment means differently.- Parameters:
name (str) – The device, as the experiment’s setup names it.
entry (collections.abc.Mapping[str, Any]) – Its entry, as
_served_entry()makes it.
- Returns:
The server’s status, and whether this call started it.
- Raises:
BenchError – When the name is declared for another package, or the server did not come up.
- Return type:
tuple[plesty.server.model.ProcessStatus, bool]
- _serve_on(bench: Any, device: str, entry: collections.abc.Mapping[str, Any]) tuple[int, bool]
Have the bench bench of a setup serve device; its port, and whether it started it.
- Raises:
BenchError – When the bench did not answer, refused, or said no port.
- Parameters:
bench (Any)
device (str)
entry (collections.abc.Mapping[str, Any])
- Return type:
tuple[int, bool]
Prove every bench of name’s setup sees the one shared disk this bench sees.
Each bench says where it sees the disk (its
data) and devices write there by paths relative to it, so a bench pointed at another folder writes data no one reads. This bench writes a probe under its owndata; every other bench, through its agent, reads it under its own and writes a reply, which this bench reads back — so each bench is shown to see the same folder, and to be able to write to it. The files are removed afterwards.- Parameters:
name (str) – The declared experiment.
devices (collections.abc.Sequence[str] | None) – Only the benches serving these devices — the ones the run’s configuration uses;
Nonefor every bench.
- Returns:
The benches checked.
- Raises:
BenchError – When a bench does not see the disk this bench does, or could not be asked.
- Return type:
list[str]
- next_run_id(name: str, when: Any = None) str
Propose a name for the next run of name:
<experiment>-<date>-<idx>.The date makes a run findable by when it was measured and the index orders the runs within a day, which is how an operator refers to them out loud. It is only a proposal — whoever creates the run can call it whatever they like.
- Parameters:
name (str) – The declared experiment.
when (Any) – The day to number within; today by default.
- Returns:
A run id no run of this experiment is using.
- Return type:
str
- _taken_run_names(name: str) set[str]
The run names name cannot give a run: the ones on disk, and the ones runs have had.
A deleted run leaves its job and its log behind, and handing its name to another run makes that log look like the new run’s — which is exactly how a fresh run comes to show a finished one’s output.
- Parameters:
name (str)
- Return type:
set[str]
- rename_experiment_run(name: str, run_id: str, new_name: str) dict[str, Any]
Give a run of name that has not started another name (#27).
A typo, or a name chosen before the sample was settled, would otherwise cost deleting the run and configuring it again.
- Parameters:
name (str) – The declared experiment.
run_id (str) – The run’s name now.
new_name (str) – What to call it.
- Returns:
A row for the run table, under the new name.
- Raises:
BenchError – If there is no such run, it has started, or the new name is unusable or taken.
- Return type:
dict[str, Any]
- create_experiment_run(name: str, run_id: str | None = None, config: str | None = None, copy_of: str | None = None, text: str | None = None, operator: str = '', note: str = '') dict[str, Any]
Name a run of name and record what it will be run with, without starting it.
Creating and starting are separate on purpose: a measurement takes hours and touches the rig, so there is value in seeing the name, the configuration and the plan sitting in the table before anything moves. The run gets its own copy of its configuration (
RUN_CONFIG_FILE), so configuring it later changes it alone.- Parameters:
name (str) – The declared experiment.
run_id (str | None) – What to call it; the proposal of
next_run_id()by default.config (str | None) – Configuration file for this run, relative to the checkout; the declared one by default.
copy_of (str | None) – The run this one repeats, when it is a duplicate. Recorded so the table can keep the copy beside its original instead of sorting it to the top, where the two are read apart.
text (str | None) – The run’s configuration; the text of config by default.
operator (str) – Who measures it (#40), kept with the run and proposed for the next one on this bench.
note (str) – Why — the run’s first note, in its
notes.txt.
- Returns:
A row for the run table.
- Raises:
BenchError – If the name is unusable or already taken.
- Return type:
dict[str, Any]
- last_operator() str
Who created the last run on this bench;
""before the first (#40).- Return type:
str
- run_notes(name: str, run_id: str) list[dict[str, str]]
The notes of one run, oldest first; none when it has none (#40).
- Parameters:
name (str)
run_id (str)
- Return type:
list[dict[str, str]]
- add_run_note(name: str, run_id: str, text: str, by: str) list[dict[str, str]]
Add a note to a run, open or ended; returns its notes, oldest first (#40).
- Raises:
BenchError – When there is no such run, or the note is empty.
- Parameters:
name (str)
run_id (str)
text (str)
by (str)
- Return type:
list[dict[str, str]]
- duplicate_experiment_run(name: str, run_id: str, into: str | None = None) dict
Create a run that repeats run_id — same experiment, same configuration.
Repeating a measurement is the ordinary thing to want: the same dot again tomorrow, the same sweep after realigning. The configuration is taken from the run itself — its own copy, or what it froze into its plan — not from the module’s file, which may have been edited since.
- Parameters:
name (str) – The declared experiment.
run_id (str) – The run to repeat.
into (str | None) – What to call the new run; the next proposal by default.
- Returns:
A row for the run table.
- Raises:
BenchError – If the run is not there, or the new name is taken.
- Return type:
dict
- delete_experiment_run(name: str, run_id: str) str
Delete one run of name — its directory and everything in it.
This throws away a measurement, so it refuses a run that is still going: what is on disk then is half a run whose process is still writing to it.
- Parameters:
name (str) – The declared experiment.
run_id (str) – The run to delete.
- Returns:
The run id deleted.
- Raises:
BenchError – If there is no such run, it is still going, or the directory cannot be removed.
- Return type:
str
- experiment_rows(name: str) list[dict[str, Any]]
Every run of name, newest first, as the run table shows them.
An experiment that has never run still gets one row. It is declared and ready, which is a state worth seeing — a table that listed only runs would make a newly added experiment invisible until someone started it.
- Parameters:
name (str) – The experiment.
- Returns:
One
{"name", "status"}per run, or a single not-started row.- Return type:
list[dict[str, Any]]
- release_lost_run_devices(name: str) list[str]
Stop the devices a run of name started, when its job died before it could.
The job that runs a module stops the devices the run started once the module ends; killed itself, it stops nothing, and they stayed up with no run to use them. The newest ended run job of name says which they were. A device is stopped only while the server running now is the one that run started — up before the job ended — so one started since, by anyone, is left alone. Once per job: the refresh asks again.
- Returns:
The devices stopped.
- Parameters:
name (str)
- Return type:
list[str]
- read_run(run_dir: str | pathlib.Path) dict[str, Any]
Read a run directory that is not one of this bench’s own.
A run carries everything needed to read it — the plan it was given, the journal of what happened, the records, and the versions that produced it — so a run measured on another bench, or restored from a backup, is openable here without declaring the experiment it came from.
- Parameters:
run_dir (str | pathlib.Path) – The directory to read.
- Returns:
A row for the run table, its
nametaken from the run’s own provenance where it records one.- Raises:
ExperimentError – If the directory is not a run.
- Return type:
dict[str, Any]
- experiment_records(name: str, run_id: str | None = None) list[dict[str, Any]]
The committed step records of a run of name, oldest of the tail first.
- Parameters:
name (str)
run_id (str | None)
- Return type:
list[dict[str, Any]]
- experiment_jobs(name: str) list[plesty.server.model.Job]
Every run job recorded for name, newest first.
- Parameters:
name (str)
- Return type:
list[plesty.server.model.Job]
- running_experiment(name: str) plesty.server.model.Job | None
The run job of name that is still going, if one is.
- Parameters:
name (str)
- Return type:
plesty.server.model.Job | None
- start_experiment(name: str, resume: str | None = None, start: str | None = None) plesty.server.model.Job
Start a run of name, or continue resume; returns the job.
The run is a detached job like any other, so closing the console does not stop the measurement. Before it starts, the module’s required environment is checked against what the run would actually get: a missing address is worth refusing here rather than aborting a plan part-way through.
- Parameters:
name (str) – The declared experiment.
resume (str | None) – Run id to continue, or
Nonefor a new run.start (str | None) – Run id created beforehand to start under that name, so the run an operator named is the directory the data lands in. Needs a module whose plesty-lib understands
--run-id.
- Raises:
BenchError – When one is already running, the resumed run is not there, or the environment the module requires is incomplete.
- Return type:
- ask_experiment(name: str, run_id: str | None = None, **changes: Any) dict[str, Any]
Ask a run of name for something, and return what it now asks for.
- Raises:
BenchError – When there is no run to ask.
- Parameters:
name (str)
run_id (str | None)
changes (Any)
- Return type:
dict[str, Any]
- pause_experiment(name: str, run_id: str | None = None) dict[str, Any]
Ask a run to hold before its next step.
The rig stays connected and the instruments keep their positions — that is the difference from stopping and resuming, which releases the rig and pays a reconnect and a preflight to come back.
- Parameters:
name (str)
run_id (str | None)
- Return type:
dict[str, Any]
- resume_experiment(name: str, run_id: str | None = None) dict[str, Any]
Let a held run go on.
- Parameters:
name (str)
run_id (str | None)
- Return type:
dict[str, Any]
- stop_experiment(name: str, run_id: str | None = None, reason: str = '') dict[str, Any]
Ask a run to finish the step in flight and then stop.
Nothing is lost and nothing is redone: the step commits and the journal records where to resume from. On a long exposure this takes as long as the exposure —
abort_experiment()is the one that does not wait.- Parameters:
name (str)
run_id (str | None)
reason (str)
- Return type:
dict[str, Any]
- abort_experiment(name: str, run_id: str | None = None, reason: str = '') dict[str, Any]
Ask a run to stop without finishing the step in flight.
The instruments are released at once; the interrupted step never committed, so resuming runs it again.
- Parameters:
name (str)
run_id (str | None)
reason (str)
- Return type:
dict[str, Any]
- report_experiment(name: str, text: str, run_id: str | None = None) dict[str, Any]
Record something on a running measurement, where it happened.
- Raises:
BenchError – When there is no run, or the text is empty.
- Parameters:
name (str)
text (str)
run_id (str | None)
- Return type:
dict[str, Any]
- kill_experiment(name: str) bool
Kill the run job of name outright;
Truewhen one was running.The last resort, for a run that has stopped reading its control file. It leaves no
run_canceledin the journal, so the resume point is the last step that committed and the one in flight is lost. Killing the job also kills the step that stops the run’s devices when it ends, so they are stopped here instead.- Parameters:
name (str)
- Return type:
bool
- experiment_site_packages(name: str) list[pathlib.Path]
Where the environment of name’s module keeps its packages — to load its viewer from.
An experiment is installed in an environment of its own, and its viewer (plesty-lib’s viewer contract,
plesty.lib.monitor.load_viz()) imports the module and what it depends on. Those directories, put behind this console’s own on its import path, make the viewer importable here without installing anything:plestyis a namespace package, so the module’s part of it joins the console’s.- Raises:
BenchError – When nothing is installed, or the environment is not of this console’s Python — its compiled packages would not load.
- Parameters:
name (str)
- Return type:
list[pathlib.Path]
- experiment_viewer(name: str, run_id: str | None = None) plesty.server.model.Job
Open the module’s own viewer on a run of name; returns the job.
The panels are built from the experiment’s dependencies, which this console’s environment does not have — so the viewer runs in the module’s environment, as its own process, rather than inside the console.
- Raises:
BenchError – When the module ships no viewer, or there is no run.
- Parameters:
name (str)
run_id (str | None)
- Return type:
- agent_settings() plesty.server.model.AgentSettings
How this bench’s agent binds and whom it answers (
<home>/agent.yaml).- Return type:
- save_agent_settings(settings: plesty.server.model.AgentSettings) plesty.server.model.AgentSettings
Write settings for the next start; returns them.
A running agent is not re-bound underneath its clients — the endpoint and the token are what they connected with. The console says so and the operator restarts it.
A share or bench folder that changed is checked first: the share is mounted and this bench can write in its folder, created when missing. One left as it was is not, so the token can still be changed while the shared disk is away.
- Raises:
FleetError – When the settings would not bind, or the new share and folder are not a place this bench can write.
- Parameters:
settings (plesty.server.model.AgentSettings)
- Return type:
- property agent_running: bool
Whether this process is serving the agent right now.
- Return type:
bool
- agent_state() str
One line for the status bar: where the agent listens, and whether it checks a token.
Never the token itself — the value belongs on the clipboard and in the client’s environment, not in a window anyone can read over a shoulder.
- Return type:
str
- start_agent(settings: plesty.server.model.AgentSettings | None = None) plesty.server.model.AgentSettings
Serve plesty-bench clients from this process; returns the settings used.
The console is the long-running process a lab PC already has open, so the agent is served on a thread of it — the same way
fleet run --agentdoes — rather than by a second process to supervise.- Raises:
BenchError – When the agent is already running here.
FleetError – When the settings would not bind.
- Parameters:
settings (plesty.server.model.AgentSettings | None)
- Return type:
- stop_agent() bool
Stop the agent served here;
Falsewhen none was.Clients in the middle of a command are not waited for: the socket is closed on the next poll, and an
execthat was running finishes against a bench that no longer answers. Stopping is the operator saying the bench is no longer offered.- Return type:
bool
- property is_master: bool
Whether this bench drives others (
role: masterinagent.yaml).- Return type:
bool
- peers() list[plesty.server.model.Peer]
The nodes this bench declares, empty when it is not a master.
Read on demand rather than at
open(), so a list that cannot be parsed is a message on a console that opened rather than a console that did not.- Raises:
FleetError – When
peers.yamlis malformed.- Return type:
list[plesty.server.model.Peer]
- save_peers(peers: list[plesty.server.model.Peer]) list[plesty.server.model.Peer]
Write the node list and reconnect what changed; returns it.
- Raises:
FleetError – When a peer is incomplete or two share a name.
- Parameters:
peers (list[plesty.server.model.Peer])
- Return type:
list[plesty.server.model.Peer]
- property nodes: plesty.server.services.Nodes
The links to the declared nodes, built on first use.
- Return type:
- refresh_nodes() plesty.server.services.Nodes
Make the links match what
peers.yamldeclares; returns them.- Raises:
FleetError – When
peers.yamlis malformed.- Return type:
- node_link(host: str) plesty.server.services.NodeLink
The link to the node host, against the list as it is declared now.
Every act on a node goes through here rather than through whatever the last refresh happened to build: a bench added in the dialog is acted on without waiting for the table’s next tick, and one removed there is not acted on at all.
- Raises:
NodeError – When no such node is declared.
FleetError – When
peers.yamlis malformed.
- Parameters:
host (str)
- Return type:
- node_device_handle(host: str, name: str) Any
A control handle on a device of the node host.
The agent relays to the device’s own server, so this is what a control panel drives — the same object
plesty-bench controlbuilds.- Raises:
NodeError – When no such node is declared.
- Parameters:
host (str)
name (str)
- Return type:
Any
- catalogue(index_url: str | None = None) plesty.server.services.Catalogue
The hub catalogue (the fleet’s
index_urlwhen it names one).The instance is kept, and with it the entries it has fetched: one request then answers every filter keystroke. It is rebuilt only when the index it is bound to is no longer the wanted one — which opening another fleet can change. Asking the hub again for the same index is
Catalogue.entries()withrefresh, not a new instance.- Parameters:
index_url (str | None)
- Return type:
- install_entry(entry: plesty.server.model.CatalogueEntry, version: str | None = None, ref: str | None = None, repository: bool = False) plesty.server.model.Job
Install a catalogue module onto this bench as a job; nothing is declared.
The catalogue is a market place: it puts modules on the bench, and the fleet then declares device instances of what is on it. Which is why this touches no fleet file and needs none.
- Parameters:
entry (plesty.server.model.CatalogueEntry) – The catalogue module.
version (str | None) – Release to install;
Nonetakes the newest release.ref (str | None) – Ref for a repository install;
Nonetakes the entry’s latest tag, and no tag means the default branch.repository (bool) – Install the repository instead of a release.
- Raises:
BenchError – When the entry is not an installable device.
- Return type:
- module_release(package: str) str | None
The newest release of package on PyPI, or
None— one network call.What the console asks before it offers a source: a release install needs nothing but
uv, a repository install needs git.- Parameters:
package (str)
- Return type:
str | None
- module_releases(package: str) tuple[str, Ellipsis]
Every release of package on PyPI, newest first — one network call.
- Parameters:
package (str)
- Return type:
tuple[str, Ellipsis]
- module_tags(url: str) tuple[str, Ellipsis]
The release tags of the repository at url, newest first — one
git ls-remote.None without git on this bench: git is installed for an install that needs it, not to fill a drop-down.
- Parameters:
url (str)
- Return type:
tuple[str, Ellipsis]
- source_options(package: str, fetch: bool = False) SourceOptions
Versions, refs and repository URLs the bench knows for package.
Reads the inventory and the fleet; the catalogue only when it has already been fetched — unless fetch is set, which asks the hub, PyPI for every release and the repository for its tags (network calls: callers on a GUI thread make them on a worker).
- Parameters:
package (str)
fetch (bool)
- Return type:
- seed_env(name: str, installed: plesty.server.model.InstalledVersion | None = None) pathlib.Path | None
Bring the device’s
.envin line with the module’s.env.example.On the first install the example is copied verbatim — comments and all — as the
.env(an empty or missing file counts as “first”). On a later install of another version or ref, keys the new example has and the.envlacks are appended together with the example’s own comment lines above them; the operator’s values are never touched. A checkout’s own.env.exampleis used; a PyPI install (no repository on disk) gets the generic example shipped with plesty-server.- Returns:
The written path, or
Nonewhen nothing had to change.- Parameters:
name (str)
installed (plesty.server.model.InstalledVersion | None)
- Return type:
pathlib.Path | None
- env_example(name: str, installed: plesty.server.model.InstalledVersion | None = None) str
The
.env.exampletext that applies to device name.A checkout’s own file first; for a release install (no repository on disk) the file is fetched from the module’s repository as the catalogue names it — the wheel does not carry it; and the generic example shipped with plesty-server when neither is reachable.
- Parameters:
name (str)
installed (plesty.server.model.InstalledVersion | None)
- Return type:
str
- _remote_env_example(package: str) str | None
.env.examplefrom the module’s repository (GitLab raw URL), orNone.The repository comes from the package record; the catalogue is asked only when the bench has never learned it.
- Parameters:
package (str)
- Return type:
str | None
- _startable_port(spec: plesty.server.model.DeviceSpec) plesty.server.model.DeviceSpec
spec with a port nothing else is holding; declares the choice.
A port the bench allocated is not a promise it can keep against another process on the machine — a second bench allocates from the same range, and a server left over from an earlier start holds what it holds. When it is taken the device cannot serve a client there whatever we do, so it moves and the fleet file records where it went.
A port the declaration names —
--tcp-portinargs, or an env value the device itself reads — is a different thing: that number is passed to the device, an operator chose it, and moving it silently would start the server somewhere its own arguments deny. That clash is reported instead.A device of an experiment’s setup gets its port for this bench only, in memory: the setup is the experiment’s file, and written back it lost its comments and gained this bench’s ports (#48).
- Parameters:
- Return type:
- _claim_port(spec: plesty.server.model.DeviceSpec) plesty.server.model.DeviceSpec
Declare spec on its port — in its fleet file, or in memory for a setup.
- Parameters:
- Return type:
- _with_port(spec: plesty.server.model.DeviceSpec) plesty.server.model.DeviceSpec
Give spec a port of its own unless it asked for one.
- Parameters:
- Return type:
- installed(name: str) plesty.server.model.InstalledVersion | None
The installed version serving name, or
None.- Parameters:
name (str)
- Return type:
- require_installed(name: str) plesty.server.model.InstalledVersion
Like
installed()but raisesBenchErrorwhen absent.- Parameters:
name (str)
- Return type:
- status(name: str, probe: bool = True) plesty.server.model.ProcessStatus
The server state of name.
- Parameters:
name (str)
probe (bool)
- Return type:
- device(name: str, probe: bool = True) DeviceView
Declaration, installation and state of name in one view.
- Parameters:
name (str)
probe (bool)
- Return type:
- devices(probe: bool = True, nodes: bool = False) list[DeviceView]
Every device the shown fleets declare (
view), in fleet order.- Parameters:
probe (bool) – Ask each local server for its state rather than reporting the process record alone.
nodes (bool) – Append the devices of the shown nodes (
node_view) — what the console asks for and the CLI does not, since a command line is aimed at one bench and says which with-b.
- Return type:
list[DeviceView]
- node_devices(hosts: collections.abc.Collection[str] | None = None) list[DeviceView]
Every device of every declared node, one round trip per node.
A node that does not answer contributes no rows and a line through
say()— its devices are not gone, they are out of reach, and the distinction belongs in the status bar rather than in a table that quietly shortens.- Parameters:
hosts (collections.abc.Collection[str] | None) – Only these nodes, by name;
Noneasks every one. A node left out is not asked at all.- Return type:
list[DeviceView]
- log(name: str, lines: int = 50) str
The tail of the server log of name.
- Parameters:
name (str)
lines (int)
- Return type:
str
- clear_log(name: str) int
Empty the server log of name; returns the bytes discarded.
A device server’s log is append-only for the life of the bench, so a module worked on for a week is read through a month of older runs. This is what gives an operator a clean slate before reproducing something.
The Traffic tab is read back out of this same log, so clearing it clears the traffic history with it — they are one file, and a caller that only wanted one of them would be surprised by the other.
- Parameters:
name (str) – The device whose log to clear.
- Returns:
How many bytes were dropped.
- Return type:
int
- traffic(name: str, lines: int = TRAFFIC_LINES) list[plesty.server.model.TrafficRecord]
What the server of name served, newest last.
Read from the same log tail the Log tab shows, so it costs one file read and nothing on the wire. Records are sparse in it — one per request among the server’s ordinary lines — so this reads a longer tail than the log view does to fill a useful pane.
An empty list means one of two things the caller cannot tell apart here: a server that has served nothing, or one on a plesty-lib too old to write records at all. The view says so.
- Parameters:
name (str)
lines (int)
- Return type:
- reports(name: str) list[plesty.server.model.FieldTestReport]
Published field-test reports of name (git installs only).
- Parameters:
name (str)
- Return type:
- install_now(name: str, force: bool = False, job_id: str | None = None) plesty.server.model.InstalledVersion
Install what name declares, in the foreground; returns the record.
- Parameters:
name (str)
force (bool)
job_id (str | None)
- Return type:
- update_now(name: str, ref: str | None = None, job_id: str | None = None) plesty.server.model.InstalledVersion
Update the environment of name in the foreground.
A git checkout moves to ref (default: its recorded ref) and re-syncs; a PyPI install is reinstalled. The declaration follows a new ref.
- Parameters:
name (str)
ref (str | None)
job_id (str | None)
- Return type:
- install(name: str, force: bool = False) plesty.server.model.Job
Install what the device name declares, as a job; returns it at once.
- Parameters:
name (str)
force (bool)
- Return type:
- install_module(package: str, version: str | None = None, git: str | None = None, ref: str | None = None, force: bool = False) plesty.server.model.Job
Install a module onto the bench as a job — no device, no fleet.
The environment is keyed by the package, never by a device name, so installing one is a market-place act: it stocks the bench, and a declaration later picks from what is in stock.
- Parameters:
package (str) – Distribution name (
plesty-pm100d).version (str | None) – Release to install;
Nonetakes the newest.git (str | None) – Repository to install from instead of a release.
ref (str | None) – Branch, tag or commit for git.
force (bool) – Reinstall even when it is already on the bench.
- Return type:
- welcome_due() bool
Whether the welcome opens by itself: the first start of a bench that holds nothing.
Once only —
welcome_seen()records it — and never on a bench that already has a module, a device or an experiment: that bench was set up.- Return type:
bool
- welcome_seen() None
Record that the welcome was offered, so it does not open by itself again.
- Return type:
None
- install_demo() plesty.server.model.Job
Install the demo experiment from its repository, as a job (
DEMO).Only the experiment: its
setup.yamlnames the demo devices — the stage in its simulator and the spectrometer replaying measured spectra — and the run installs and starts them itself, on this bench, as it does for any experiment.- Return type:
- set_up_demo(operator: str) dict[str, Any]
Declare the demo experiment, unless it is, and create its first run.
- Returns:
The run’s row, as
create_experiment_run()gives it.- Parameters:
operator (str)
- Return type:
dict[str, Any]
- local_module(folder: str | os.PathLike[str]) plesty.server.services.LocalModule
What the repository at folder is, read from its
pyproject.toml.- Raises:
BenchError – When it is not a device or experiment module.
- Parameters:
folder (str | os.PathLike[str])
- Return type:
- local_branches(folder: str | os.PathLike[str]) tuple[list[str], str]
The branches of the repository at folder, and the one it is on.
- Parameters:
folder (str | os.PathLike[str])
- Return type:
tuple[list[str], str]
- load_module(folder: str | os.PathLike[str], ref: str | None = None) plesty.server.model.Job
Load the repository at folder onto the bench, where it lives, as a job.
What it is is read first, so a folder that is not a module is refused here rather than in a job log. The job checks out ref when it names another branch, makes the folder’s
.venvonly when there is none, then records it (load_module_now()).- Parameters:
folder (str | os.PathLike[str])
ref (str | None)
- Return type:
- load_module_now(folder: str | os.PathLike[str], ref: str | None = None) plesty.server.model.InstalledVersion
Load the repository at folder in the foreground; returns the record.
See
plesty.server.services.Installer.load_local(): the folder stays where it is, and<home>/packages/<package>/records its path, what the module is, its branch, version and commit.- Parameters:
folder (str | os.PathLike[str])
ref (str | None)
- Return type:
- loaded_modules() list[plesty.server.model.InstalledVersion]
Every local repository loaded onto this bench, newest first.
- Return type:
- installed_experiments(loaded: bool = False) tuple[str, Ellipsis]
The packages installed from PyPI or git that may be experiments.
A package the module itself calls a device (
[tool.plesty] module_type), or one this bench declares as a device, is not: a run installs its devices here too, and they are not experiments to create a run of. One whose kind is unknown is offered — the module says what it is only once it is asked.- Parameters:
loaded (bool) – Also offer a package that is only loaded from a folder on this machine. Create run offers those as themselves; Add experiment… has no other list to find them in.
- Return type:
tuple[str, Ellipsis]
- installed_devices() tuple[str, Ellipsis]
The installed packages that may be devices: what Add device… offers.
The mirror of
installed_experiments(). A package the module itself calls an experiment, or one this bench declares as an experiment, is not offered; one whose kind is unknown is.- Return type:
tuple[str, Ellipsis]
- install_module_now(package: str, version: str | None = None, git: str | None = None, ref: str | None = None, force: bool = False, job_id: str | None = None) plesty.server.model.InstalledVersion
Install a module in the foreground; returns the record.
- Parameters:
package (str)
version (str | None)
git (str | None)
ref (str | None)
force (bool)
job_id (str | None)
- Return type:
- learn_repository(package: str) str
Make sure the bench knows where package lives; returns the URL or
"".The release→tag fallback can only reach a repository the package record names, and a bench that has never seen the module names none — which is exactly the first install of a young module, the case the fallback exists for. The hub is what knows: one lookup, best effort, remembered so it is not asked twice. A bench that cannot reach it simply keeps the release failure it would have had anyway.
- Parameters:
package (str)
- Return type:
str
- update(name: str, ref: str | None = None) plesty.server.model.Job
Update name as a job; returns it at once.
- Parameters:
name (str)
ref (str | None)
- Return type:
- uninstall(name: str) bool
Stop name if it runs and remove its environment;
Truewhen one was removed.- Parameters:
name (str)
- Return type:
bool
- installed_modules() list[InstalledModule]
Every installed version of every module, by name, with what declares it.
A module installed from the Hub and never declared is listed too: it is on the bench, and this is where it is seen and removed.
- Return type:
list[InstalledModule]
- uninstall_module(package: str, slot: str) bool
Remove one installed version of package;
Truewhen an environment was removed.A loaded folder is only forgotten: it is the developer’s repository, not the bench’s.
- Raises:
BenchError – When it is not installed, or a declaration uses it — removing it would leave that declaration with nothing to run.
- Parameters:
package (str)
slot (str)
- Return type:
bool
- start(name: str, wait: bool = True, timeout: float | None = None) plesty.server.model.ProcessStatus
Start the server of name (installing first when nothing serves it).
- Raises:
BenchError – When it is not installed and cannot be, or the launch fails.
- Parameters:
name (str)
wait (bool)
timeout (float | None)
- Return type:
- stop(name: str, timeout: float | None = None) bool
Stop the server of name;
Truewhen a process was stopped.A stop that killed the server before its shutdown ran is reported through
say: the device was never closed and may still hold the instrument, which is what refuses the next start. Nothing observable survives the stop — the record and the exit code are both cleared — so this is the only moment it can be said.- Parameters:
name (str)
timeout (float | None)
- Return type:
bool
- restart(name: str, wait: bool = True) plesty.server.model.ProcessStatus
Stop (if running) and start the server of name.
- Parameters:
name (str)
wait (bool)
- Return type:
- node_status(host: str, name: str) plesty.server.model.ProcessStatus
The state of name on the node host.
- Raises:
NodeError – When the node did not answer, or knows no such device.
- Parameters:
host (str)
name (str)
- Return type:
- node_start(host: str, name: str) plesty.server.model.ProcessStatus
Start name on the node host; returns its state afterwards.
- Raises:
NodeError – When the node did not answer or refused.
- Parameters:
host (str)
name (str)
- Return type:
- node_stop(host: str, name: str) plesty.server.model.ProcessStatus
Stop name on the node host; returns its state afterwards.
- Raises:
NodeError – When the node did not answer or refused.
- Parameters:
host (str)
name (str)
- Return type:
- node_restart(host: str, name: str) plesty.server.model.ProcessStatus
Restart name on the node host; returns its state afterwards.
- Raises:
NodeError – When the node did not answer or refused.
- Parameters:
host (str)
name (str)
- Return type:
- node_install(host: str, name: str, force: bool = False) str
Install name on the node host; returns the job id it started.
Started and left to run: the install happens in the node’s own home and is followed there. This console shows no Jobs tab for a device it does not host, so what comes back is the identifier to ask about, and the state the next refresh reports.
- Raises:
NodeError – When the node did not answer or refused.
- Parameters:
host (str)
name (str)
force (bool)
- Return type:
str
- node_update(host: str, name: str, ref: str | None = None) str
Update name on the node host; returns the job id it started.
- Raises:
NodeError – When the node did not answer or refused.
- Parameters:
host (str)
name (str)
ref (str | None)
- Return type:
str
- fleet_on_nodes(verb: str) None
Run
fleet uporfleet downon every declared node.A master brings a rig up, and the rig is every bench the console shows — bringing up only the devices that happen to be on this machine is half a rig. Each node is asked for its own working fleet rather than told which devices to start: what is in it is that bench’s declaration, and the checkbox that sets it is on that bench’s own table.
A node that refuses costs a line and not the others: one bench being unreachable must not leave the rest of the rig down.
- Parameters:
verb (str) –
upordown.- Return type:
None
- up(names: collections.abc.Sequence[str] | None = None, install: bool = True, wait: bool = True, nodes: bool = False) list[plesty.server.model.ProcessStatus]
Install (unless install is off) and start the autostart devices, or names.
A device that is already running is left alone. Returns one status per device, in fleet order.
- Parameters:
names (collections.abc.Sequence[str] | None)
install (bool)
wait (bool)
nodes (bool)
- Return type:
- down(names: collections.abc.Sequence[str] | None = None, nodes: bool = False) list[str]
Stop everything running (or names); returns the names stopped.
fleet upstarts the working fleet, sodownstarts there — but a device declaredautostart: falseand started by hand is running all the same, and stopping only the working fleet left it up and called the bench down. Anything with a launch record is included.- Parameters:
names (collections.abc.Sequence[str] | None)
nodes (bool)
- Return type:
list[str]
- stoppable() list[str]
Every name
down()would reach, running or not.Names that only have a launch record are included: stopping needs the record, not the declaration.
- Return type:
list[str]
- running() list[str]
The names of the device servers alive right now, in fleet order.
What
down()would actually stop — the working fleet and anything started by hand — so a caller can name them before stopping them.- Return type:
list[str]
- orphans() list[str]
Servers alive on this bench that none of its fleets declares.
A fleet opened in place of the one that started them — a stale default after a crash — drops them out of the table while they keep their ports and the instruments’ sessions. Named, they can be stopped (#24).
- Return type:
list[str]
- run(stop: threading.Event, names: collections.abc.Sequence[str] | None = None, interval: float = 5.0, max_sweeps: int | None = None, leave_running: bool = False, max_backoff: float = 60.0) int
Bring the fleet up and keep it up until stop is set (headless bench mode).
Every interval seconds each device is inspected; one found
exitedis started again, after a backoff that doubles per consecutive crash (capped at max_backoff) and resets once it has answered a probe. Devices stopped on purpose (no record) are left alone: the loop keeps up what it started, it does not fight the operator.- Parameters:
stop (threading.Event) – Set to end the loop.
names (collections.abc.Sequence[str] | None) – Devices to keep up; default: the autostart ones.
interval (float) – Seconds between sweeps.
max_sweeps (int | None) – Stop after this many sweeps (tests).
leave_running (bool) – Do not bring the servers down when the loop ends.
max_backoff (float) – Longest wait before a restart.
- Returns:
The number of restarts performed.
- Return type:
int
- field_test_now(name: str, run: plesty.server.model.FieldTestRun, say: Say | None = None) int
Run the field test of name in the foreground; returns the script’s exit code.
Host tier: the server is stopped for the run and relaunched afterwards exactly as it was (unless
run.keep_server). Client tier: the server is started when it is not up, and the address defaults to it.- Raises:
BenchError – When name is not a git install with that tier’s script.
- Parameters:
name (str)
say (Say | None)
- Return type:
int
- field_test_options(name: str, tier: str = 'host') dict[str, list[str]]
What the device’s field-test script accepts, from its
--help.- Returns:
{"options": [...], "gates": [...]}— the long options and the gate choices (the standard gates when the script does not list them); both empty when the script cannot be asked.- Parameters:
name (str)
tier (str)
- Return type:
dict[str, list[str]]
- control_availability(name: str) str | None
Why the controls of name cannot be opened, or
Nonewhen they can.- Parameters:
name (str) – The instance name.
- Returns:
The reason, or
None.- Return type:
str | None
- device_link(name: str) plesty.server.services.DeviceLink
Return a handle on the running server of name.
The link is not connected: it opens on its first call, on whichever thread makes it, which is how a panel keeps its socket to itself.
- Parameters:
name (str) – The instance name.
- Returns:
The handle a
DevicePaneldrives.- Raises:
BenchError – When the device is not in a state to be controlled; the message is
control_availability()’s reason.- Return type:
- field_test_availability(name: str, tier: str = 'host') str | None
Why the field test of name cannot run, or
Nonewhen it can.The reason is what a tooltip shows: not installed, a release install (no repository on disk), or a checkout without the tier’s script.
- Parameters:
name (str)
tier (str)
- Return type:
str | None
- field_test(name: str, run: plesty.server.model.FieldTestRun) plesty.server.model.Job
Run the field test of name as a job; returns it at once.
- Parameters:
name (str)
- Return type:
- _field_test_command(run: plesty.server.model.FieldTestRun, spec: plesty.server.model.DeviceSpec, python: pathlib.Path, checkout: pathlib.Path) list[str]
- Parameters:
python (pathlib.Path)
checkout (pathlib.Path)
- Return type:
list[str]
- static _script_help(python: pathlib.Path, script: pathlib.Path) str
The
--helptext of a field-test script (""when it cannot be asked).- Parameters:
python (pathlib.Path)
script (pathlib.Path)
- Return type:
str
- classmethod _script_options(python: pathlib.Path, script: pathlib.Path) set[str] | None
The options a field-test script accepts, read from its
--help.Scaffolds differ between SDK releases (
--addressnow,--port/--mockbefore); asking the script is cheaper than guessing wrong.Nonewhen it cannot be asked (the current scaffold is assumed).- Parameters:
python (pathlib.Path)
script (pathlib.Path)
- Return type:
set[str] | None
- job(job_id: str) plesty.server.model.Job | None
The job job_id, up to date, or
None.- Parameters:
job_id (str)
- Return type:
plesty.server.model.Job | None
- job_list(name: str | None = None, kind: str | None = None) list[plesty.server.model.Job]
Jobs on record, newest first.
- Parameters:
name (str | None)
kind (str | None)
- Return type:
list[plesty.server.model.Job]
- job_log(job_id: str, offset: int = 0) tuple[str, int]
Job log from byte offset; returns text and the next offset.
- Parameters:
job_id (str)
offset (int)
- Return type:
tuple[str, int]
- job_log_end(job_id: str) tuple[str, int, int]
The end of a job’s log: text, the byte it starts at, the byte it ends at.
- Parameters:
job_id (str)
- Return type:
tuple[str, int, int]
- job_log_before(job_id: str, end: int) tuple[str, int]
The part of a job’s log before byte end: text and the byte it starts at.
- Parameters:
job_id (str)
end (int)
- Return type:
tuple[str, int]
- run_kept_log(name: str, run_id: str) pathlib.Path | None
The log run run_id of name keeps in its own directory, if any (#33).
What the console shows when this bench has no job for the run: one measured before an uninstall emptied the home, or on another bench.
- Parameters:
name (str)
run_id (str)
- Return type:
pathlib.Path | None
- log_from(path: str | pathlib.Path, offset: int = 0) tuple[str, int]
The log at path from byte offset: text and the next offset.
- Parameters:
path (str | pathlib.Path)
offset (int)
- Return type:
tuple[str, int]
- log_end(path: str | pathlib.Path) tuple[str, int, int]
The end of the log at path: text, the byte it starts at, the byte it ends at.
- Parameters:
path (str | pathlib.Path)
- Return type:
tuple[str, int, int]
- log_before(path: str | pathlib.Path, end: int) tuple[str, int]
The part of the log at path before byte end: text and the byte it starts at.
- Parameters:
path (str | pathlib.Path)
end (int)
- Return type:
tuple[str, int]
- cancel(job_id: str) bool
Cancel a running job.
- Parameters:
job_id (str)
- Return type:
bool
- _job(name: str, kind: str, argv: list[str], detail: dict[str, object] | None = None, fleet_needed: bool = True) plesty.server.model.Job
Start
plesty-server _job <argv>against this bench as a job.- Raises:
BenchError – When the job reads declarations this bench has not written anywhere — a job is another process, and it opens the fleet file.
- Parameters:
name (str)
kind (str)
argv (list[str])
detail (dict[str, object] | None)
fleet_needed (bool)
- Return type:
- _job_command(*argv: str) list[str]
plesty-server _job <argv>on this bench: this program, this home and fleet file.- Parameters:
argv (str)
- Return type:
list[str]
- plesty.server.presenter.bench._example_blocks(template: str) dict[str, str]
Each
KEY=line of an example with the comment lines directly above it, keyed by KEY.- Parameters:
template (str)
- Return type:
dict[str, str]
- plesty.server.presenter.bench._moment(stamp: str | None) datetime.datetime | None
An ISO timestamp as an aware
datetime;Nonewhen absent or unreadable.- Parameters:
stamp (str | None)
- Return type:
datetime.datetime | None
- plesty.server.presenter.bench.release_tag(ref: str) bool
Whether ref names a release (
v0.3.1) rather than a branch.- Parameters:
ref (str) – A git ref as the inventory or the catalogue reports it.
- Return type:
bool
- plesty.server.presenter.bench.module_spec(package: str, version: str | None = None, git: str | None = None, ref: str | None = None, path: str | None = None) plesty.server.model.DeviceSpec
A declaration standing in for a bare module install.
The installer works from a
DeviceSpecbecause a device install is the common case; an environment is keyed by(package, version),(package, ref)or a local folder either way, so the name is only along for the ride and the package’s own is the honest one.- Parameters:
package (str)
version (str | None)
git (str | None)
ref (str | None)
path (str | None)
- Return type:
- plesty.server.presenter.bench.FIELD_TEST_ELSEWHERE = 'it runs on {host} — field-test it from that bench'
- plesty.server.presenter.bench._node_view(host: str, entry: dict[str, Any]) DeviceView | None
Rebuild one device of the node host from its
list --jsonentry.The node answers in the same document the local
list --jsonprints, so a row is the sameDeviceViewthe local devices make — carrying which bench it came from, and nothing else different.- Returns:
The view, or
Nonewhen the entry is not one this version reads — a node on an older or newer plesty-server costs its row and not the table.- Parameters:
host (str)
entry (dict[str, Any])
- Return type:
DeviceView | None
- plesty.server.presenter.bench._node_status(name: str, raw: dict[str, Any]) plesty.server.model.ProcessStatus
A status from a node’s JSON, keeping only the fields this version knows.
- Parameters:
name (str)
raw (dict[str, Any])
- Return type:
- plesty.server.presenter.bench._stderr(line: str) None
- Parameters:
line (str)
- Return type:
None
- plesty.server.presenter.bench.fleet_name(path: pathlib.Path) str
What a fleet is called: its file’s name without
.yaml(fleets/default.yaml).- Parameters:
path (pathlib.Path)
- Return type:
str
- plesty.server.presenter.bench._same_file(one: pathlib.Path, other: pathlib.Path) bool
Whether one and other name the same file, however each is spelled.
- Parameters:
one (pathlib.Path)
other (pathlib.Path)
- Return type:
bool
- plesty.server.presenter.bench._now() str
- Return type:
str