host.host¶
- otto.host.host.get_logging_command_output_enabled() bool¶
Return True if command-output logging is enabled on the active context.
-
class otto.host.host.ShellCommand(cmd: str, expects: tuple[str | Pattern[str], str] | list[tuple[str | Pattern[str], str]] | None =
None, timeout: float | None =None, log: bool | None =None)¶ Bases:
objectA command plus the per-command options that should be used to run it.
Fields left as
Noneinherit from the run-level kwargs onHost.run(). A scalarExpectvalue is accepted forexpectsfor ergonomics; it is normalized to a one-element list before execution.- expects : tuple[str | Pattern[str], str] | list[tuple[str | Pattern[str], str]] | None¶
Per-command expects.
Noneinherits the run-levelexpectsvalue.
- class otto.host.host.RunResult(status: Status, statuses: list[CommandStatus])¶
Bases:
objectUnified result of
Host.run()regardless of how many commands ran.statusesalways has one entry per issued command.statusis the aggregate:Status.Successwhen every entry is ok, otherwise the first non-ok status encountered (matching the old tuple-form semantics).- statuses : list[CommandStatus]¶
Per-command statuses in execution order.
- property only : CommandStatus¶
Return the sole
CommandStatuswhen exactly one command ran.Raises
ValueErrorotherwise — useful for single-command call sites that want to read fields directly without unpacking.
- class otto.host.host.Host(*args, **kwargs)¶
Bases:
Protocol- power_control : PowerController | None¶
Pluggable power backend, or None when this host can’t be power-controlled.
-
async run(cmds: str | ShellCommand | Sequence[str | ShellCommand], expects: tuple[str | Pattern[str], str] | list[tuple[str | Pattern[str], str]] | None =
None, timeout: float | None =None, log: bool =True, sudo: bool =False) RunResult¶
- async open_session(name: str) HostSession¶
- class otto.host.host.BaseHost¶
Bases:
ABC- power_control : PowerController | None¶
-
async switch_user(user: str =
'', password: str | None =None) None¶ Switch the persistent session to another user via
su.Default raises — only posix-shell hosts (via
PosixPrivilege) supportsu.
-
as_user(user: str =
'root', password: str | None =None)¶ Async context manager to run a block as user.
Default raises — only posix-shell hosts (via
PosixPrivilege) supportsu-based user switching.
- async interact() None¶
Open an interactive shell bridged to the local terminal.
Subclasses implement
_interactto do the actual protocol work. This wrapper exists so CLI and SDK callers have a single public entry point.stdin and stdout are bridged directly to the remote terminal and the session is recorded to the otto log. Press
Ctrl+]to disconnect locally without ending the remote session; typeexitorlogoutto end the session normally.
- async run(cmds: ~types.Annotated[str | ~otto.host.host.ShellCommand | ~collections.abc.Sequence[str | ~otto.host.host.ShellCommand], ~otto.utils.Arg(variadic=True, elem_type=str, name=None, help=Command(s) to run.)], expects: ~types.Annotated[tuple[str | ~re.Pattern[str], str] | list[tuple[str | ~re.Pattern[str], str]] | None, <otto.utils._Exclude object at 0x7fcc41e8fea0>] | None = None, timeout: ~types.Annotated[float | None, ~otto.utils.Opt(elem_type=None, name=None, help=Per-command/cumulative timeout (seconds).)] | None = None, log: ~typing.Annotated[bool, <otto.utils._Exclude object at 0x7fcc41e8fea0>] = True, sudo: bool = False) RunResult¶
Execute one or more commands on the host via the persistent shell session.
The session is stateful: working directory changes (
cd), exported environment variables, and other shell state persist between calls, just as they would in an interactive terminal.- Parameters:¶
cmds – A single command (
strorShellCommand) or a sequence of commands. Strings andShellCommandobjects may be mixed. For single-command calls, read the result viaresult.only(orresult.statuses[0]).expects – Default
(pattern, response)pair(s) for interactive prompts. Accepts a singleExpecttuple or a list of them. Each command inherits this value unless its ownShellCommand.expectsis set.timeout – For a single command, the per-command timeout. For a sequence, a cumulative timeout shared across all commands — each command receives the remaining budget; when exhausted, remaining commands are skipped with
Status.Error.ShellCommand.timeoutcaps the per-command value but is still bounded by the remaining budget.sudo – If
True, each command is rewritten through_elevatebefore execution. Hosts that do not support elevation (e.g. embedded/RTOS) raiseNotImplementedError— see_elevate.
- Returns:¶
RunResultwith the aggregateStatusand a list of per-commandCommandStatusentries.
See also
oneshot(): stateless, concurrent-safe alternative for one-off commands.
- async open_session(name: str) HostSession¶
- async stage() tuple[Status, str]¶
Stage every product onto this host (transfer/place, no install).
Iterates
productsin declaration order, returning the first non-ok(Status, str); an empty list is a successful no-op.
-
async install(stage_only: bool =
False) tuple[Status, str]¶ Stage, then install every product.
Calls
stage()first; returns early ifstage_onlyis set or the stage step failed. Otherwise installs each product in declaration order, short-circuiting on the first failure. Projects may override for cross-product ordering/dependencies.
- async uninstall() tuple[Status, str]¶
Uninstall every product (best-effort).
Attempts every product even if one fails, returning the first non-ok result seen (so cleanup is not abandoned halfway).
- async is_installed() bool¶
True iff there is at least one product and all report installed.
An empty
productslist is not installed (avoids the vacuous-truth surprise ofall([])).
- async is_uninstalled() bool¶
Inverse of
is_installed().
-
async power(state: Annotated[str | None, Arg(variadic=False, elem_type=None, name=None, help=None)] | None =
None) tuple[Status, str]¶ Power this host
'on'/'off', or toggle when state is None.Toggling reads the controller’s
status(); if the controller can’t report state, pass an explicitstate.
-
async reboot(hard: bool =
False, wait: bool =False, timeout: float =600.0) tuple[Status, str]¶ Reboot this host.
hard=False(default) issues the in-shell reboot command (_soft_reboot);hard=Truepower-cycles via thePowerController. When wait, block onwait_until_up()(up to timeout, default 10 minutes); if the host is still unreachable when timeout expires, the result is downgraded toFailed.
- async shutdown() tuple[Status, str]¶
Power this host off from its own shell (distinct from external
power('off')). Per-family override; default raises.
-
async is_reachable(timeout: float =
10.0) bool¶ Whether this host answers a lightweight connection probe.
Per-family override; default raises (no generic probe).
-
async wait_until_up(timeout: float, interval: float =
2.0) bool¶ Poll
is_reachable()until reachable or timeout. Returns success.
-
async wait_until_down(timeout: float, interval: float =
2.0) bool¶ Poll
is_reachable()until not reachable or timeout.
-
start_repeat(name: str, cmds: list[str] | str, interval: timedelta, times: int =
-1, duration: timedelta =datetime.timedelta(days=999999999, seconds=86399, microseconds=999999), until: datetime =datetime.datetime(9999, 12, 31, 23, 59, 59, 999999), on_result: Callable[[str, datetime, list[CommandStatus]], None] | None =None, max_history: int =1000) None¶
-
class otto.host.host.HostFilter(name=
'')¶ Bases:
FilterFilter log records based on whether command output logging is globally enabled.
-
class otto.host.host.SuppressCommandOutput(host: Host | None =
None)¶ Bases:
objectSuppress command/output logging for one host or globally.
On enter, the prior state is snapshotted; on exit it is restored. That makes nesting safe — an inner context cannot clobber an outer one — and makes concurrent per-host suppressions race-free, since each context only touches its own host’s
logattribute.The no-host (global) path mutates
log_command_outputon the activeOttoContextwhen one is present. When no context is active the call is a no-op (there is nothing to suppress). Prefer the per-host form when suppressing work that runs concurrently.