models.settings¶
Pydantic boundary specs for .otto/settings.toml and the OTTO_* env.
These validate the settings dict (extra='forbid') and build the unchanged
runtime objects (DockerSettings/DockerImage/DockerCompose frozen
dataclasses, OsProfile, the reservation backend) via to_runtime() — the
same two-type split the option/host specs use.
Leaf isolation: this module must NOT import from otto.configmodule at module
top — doing so triggers configmodule/__init__’s app bootstrap. Runtime types
from configmodule.repo are imported lazily inside to_runtime() and under
TYPE_CHECKING for annotations only.
- class otto.models.settings.DockerImageSpec(*, name: str, dockerfile: ~pathlib.Path, context: ~pathlib.Path, target: str | None = None, build_args: dict[str, ~typing.Any] = <factory>)¶
Bases:
OttoModelBoundary spec for a
[[docker.images]]entry insettings.toml.Validates the image name, Dockerfile path, build context, optional build stage target, and
build_argsdict (scalar TOML values are accepted and stringified). Builds aDockerImageruntime dataclass viato_runtime(), withbuild_argsnormalised to a sorted, frozen tuple-of-pairs for hashability.- to_runtime() DockerImage¶
Build the
DockerImageruntime dataclass from the validated spec fields.
-
class otto.models.settings.DockerComposeSpec(*, path: Path, default_host: str | None =
None, services: tuple[str, ...] =())¶ Bases:
OttoModelBoundary spec for a
[[docker.composes]]entry insettings.toml.Validates the Compose file path, an optional default service host name, and the list of services within the Compose project. Builds a
DockerComposeruntime dataclass viato_runtime().- to_runtime() DockerCompose¶
Build the
DockerComposeruntime dataclass from the validated spec fields.
- class otto.models.settings.DockerSettingsSpec(*, registry_url: str = 'docker.io', images: list[~otto.models.settings.DockerImageSpec] = <factory>, composes: list[~otto.models.settings.DockerComposeSpec] = <factory>)¶
Bases:
OttoModelBoundary spec for the
[docker]section ofsettings.toml.Validates the Docker registry URL and the lists of image and Compose specs. Builds a
DockerSettingsruntime dataclass (with images and composes as frozen tuples) viato_runtime().- images : list[DockerImageSpec]¶
- composes : list[DockerComposeSpec]¶
- to_runtime() DockerSettings¶
Build the
DockerSettingsruntime dataclass from the validated spec fields.
- class otto.models.settings.OsProfileSpec(*, base: str, **extra_data: Any)¶
Bases:
OttoModelA named
[os_profiles.<name>]bundle: abasehost-class plus raw default field values.extra='allow'collects the non-basekeys; the per-field typo guard runs later, inregister_os_profile(against the base class’s slots), so the bundle stays raw here exactly as ahosts.jsonentry would be.
-
class otto.models.settings.ReservationConfigSpec(*, backend: str =
'none', url: str | None =None, **extra_data: Any)¶ Bases:
OttoModelThe otto-owned
[reservations]envelope:backend+ optionalurl.extra='allow'keeps the backend-specific[reservations.<backend>]sub-table open — otto-core cannot type a third-party backend’s kwargs.
- class otto.models.settings.LoggingConfigSpec(*, capture: list[str] = <factory>)¶
Bases:
OttoModelBoundary spec for the
[logging]section ofsettings.toml.capturelists top-level logger prefixes whoselogging.getLogger(__name__)records otto should route into its sinks (in addition to the package prefixes auto-derived from a repo’sinit/libs). Defaults to an empty list.
-
class otto.models.settings.LabConfigSpec(*, backend: str =
'json', **extra_data: Any)¶ Bases:
OttoModelThe otto-owned
[lab]envelope: which host-sourcebackendto use.extra='allow'keeps the backend-specific[lab.<backend>]sub-table open — otto-core cannot type a third-party backend’s kwargs. Defaults to the built-in"json"backend so repos with no[lab]block behave exactly as before.
-
class otto.models.settings.ReservationEntry(*, user: str, resources: list[str], expires: datetime | None =
None)¶ Bases:
OttoModelA single reservation record: the holder, the reserved resource names, and an optional expiry.
The
expiresfield accepts an ISO-8601 string from JSON (including trailingZ) and normalises it to a timezone-awaredatetimevia_normalize_expires.
- class otto.models.settings.ReservationFile(*, version: ~typing.Literal[1], reservations: list[~otto.models.settings.ReservationEntry] = <factory>)¶
Bases:
OttoModelThe
version: 1JSON reservation file the built-in JSON backend reads.- version : Literal[1]¶
- reservations : list[ReservationEntry]¶
- class otto.models.settings.SettingsModel(*, name: str, version: str, lab_data_type: str = 'json', coverage: dict[str, ~typing.Any] = <factory>, labs: list[~pathlib.Path] = <factory>, valid_labs: list[str] = <factory>, libs: list[~pathlib.Path] = <factory>, tests: list[~pathlib.Path] = <factory>, init: list[str] = <factory>, host_preferences: dict[str, dict[str, ~typing.Any]] = <factory>, os_profiles: dict[str, ~otto.models.settings.OsProfileSpec] = <factory>, docker: ~otto.models.settings.DockerSettingsSpec = DockerSettingsSpec(registry_url='docker.io', images=[], composes=[]), lab: ~otto.models.settings.LabConfigSpec = LabConfigSpec(backend='json'), logging: ~otto.models.settings.LoggingConfigSpec = LoggingConfigSpec(capture=[]), reservations: ~otto.models.settings.ReservationConfigSpec = ReservationConfigSpec(backend='none', url=None))¶
Bases:
OttoModelBoundary model for a repo’s
.otto/settings.toml(post${sut_dir}expansion).extra='forbid'turns a typo’d top-level key into an error.- os_profiles : dict[str, OsProfileSpec]¶
- docker : DockerSettingsSpec¶
- lab : LabConfigSpec¶
- logging : LoggingConfigSpec¶
- reservations : ReservationConfigSpec¶
- class otto.models.settings.OttoEnvSettings¶
Bases:
BaseSettingsTyped view of the
OTTO_*environment surface; single source of truth for otto’s env vars.The six CLI-option vars are read by Typer’s
envvar=at parse time; this model documents the whole surface and is the reader for the non-CLI reads: sut_dirs, field_default, compose_suffix, and the completion-cache xdir.sut_dirs existence-checking is done by
configmodule.env.load_otto_envso a missing dir raisesFileNotFoundError(not a wrapped ValidationError).