exlab_wizard.config.models#

Pydantic models that mirror config.yaml. Backend Spec §9.

These models are the typed schema for the on-disk config.yaml. The loader (exlab_wizard.config.loader) parses YAML into a plain dict, hands it to Config.model_validate, and converts any Pydantic ValidationError into a ConfigError at the boundary; nothing here raises ConfigError directly except for cases that need a custom message before the model layer sees the input (for instance the password-key rejection in RsyncSshTransport).

Style: - model_config = ConfigDict(extra="forbid", str_strip_whitespace=True) on

every model so unknown keys raise a clear validation error.

  • StrEnum values are accepted in either string or enum form; Pydantic v2 lax mode coerces raw strings to enum members, and the spec stores the string value verbatim on dump (via StrEnum.value or explicit field_serializer).

  • All cross-field invariants from §9 are encoded as ``model_validator``s.

Classes

BandwidthConfig(**data)

bandwidth: sub-block on a transport.

BandwidthWindow(**data)

One {days, from, to} window.

Config(**data)

Top-level config.yaml model.

EquipmentConfig(**data)

One equipment: list entry.

LIMSConfig(**data)

lims: block.

LoggingConfig(**data)

logging: block.

NASCleanupConfig(**data)

nas_cleanup: block.

OperatorsConfig(**data)

operators: block.

OrchestratorConfig(**data)

orchestrator: block.

OrchestratorStagingCleanup(**data)

orchestrator.staging_cleanup: sub-block.

OrchestratorStagingTransport(**data)

orchestrator_staging_transport: -- staging hop only.

PathsConfig(**data)

paths: block.

PluginsConfig(**data)

plugins: block.

READMEConfig(**data)

readme: block.

READMEDefaultField(**data)

One operator-defined extra README field.

RcloneTransport(**data)

transport: block when type == 'rclone'.

RsyncSshTransport(**data)

transport: block when type == 'rsync_ssh'.

SyncConfig(**data)

sync: block.

ValidatorConfig(**data)

validator: block.

class exlab_wizard.config.models.BandwidthConfig(**data)[source]#

Bases: BaseModel

bandwidth: sub-block on a transport.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

schedule: list[BandwidthWindow]#
upload_mbps: float | None#
class exlab_wizard.config.models.BandwidthWindow(**data)[source]#

Bases: BaseModel

One {days, from, to} window. Backend Spec §9.

Parameters:

data (Any)

days: list[BandwidthDay]#
from_: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'populate_by_name': True, 'str_strip_whitespace': True, 'validate_by_alias': True, 'validate_by_name': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to: str#
class exlab_wizard.config.models.Config(**data)[source]#

Bases: BaseModel

Top-level config.yaml model. Mirrors §9 verbatim.

Parameters:

data (Any)

equipment: list[EquipmentConfig]#
lims: LIMSConfig#
logging: LoggingConfig#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

nas_cleanup: NASCleanupConfig#
operators: OperatorsConfig#
orchestrator: OrchestratorConfig#
paths: PathsConfig#
plugins: PluginsConfig#
readme: READMEConfig#
sync: SyncConfig#
validator: ValidatorConfig#
class exlab_wizard.config.models.EquipmentConfig(**data)[source]#

Bases: BaseModel

One equipment: list entry. Backend Spec §9.

Parameters:

data (Any)

completeness_signal: CompletenessSignal#
id: str#
label: str#
local_root: str#
manifest_filename: str | None#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

nas_root: str#
orchestrator_staging_transport: OrchestratorStagingTransport | None#
sentinel_filename: str | None#
transport: Annotated[RcloneTransport | RsyncSshTransport, FieldInfo(annotation=NoneType, required=True, discriminator='type')]#
class exlab_wizard.config.models.LIMSConfig(**data)[source]#

Bases: BaseModel

lims: block. Read-only LIMS endpoint plus offline catalogue path.

Parameters:

data (Any)

cache_ttl_hours: int#
email: str#
endpoint: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

offline_catalogue_path: str#
class exlab_wizard.config.models.LoggingConfig(**data)[source]#

Bases: BaseModel

logging: block. Central app-log rotation + level.

Parameters:

data (Any)

central_log_keep: int#
central_log_max_mb: int#
level: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class exlab_wizard.config.models.NASCleanupConfig(**data)[source]#

Bases: BaseModel

nas_cleanup: block. Local-copy retention after NAS verify.

Parameters:

data (Any)

enabled: bool#
min_age_hours: int#
min_verify_passes: int#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

retain_cache: bool#
class exlab_wizard.config.models.OperatorsConfig(**data)[source]#

Bases: BaseModel

operators: block. Optional case-sensitive allowlist.

Parameters:

data (Any)

allowlist: list[str]#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class exlab_wizard.config.models.OrchestratorConfig(**data)[source]#

Bases: BaseModel

orchestrator: block. Backend Spec §9, §13.

Parameters:

data (Any)

enabled: bool#
label: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

staging_cleanup: OrchestratorStagingCleanup#
staging_root: str#
class exlab_wizard.config.models.OrchestratorStagingCleanup(**data)[source]#

Bases: BaseModel

orchestrator.staging_cleanup: sub-block. Backend Spec §13.7.

Parameters:

data (Any)

mode: StagingCleanupMode#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

retain_hours: int#
class exlab_wizard.config.models.OrchestratorStagingTransport(**data)[source]#

Bases: BaseModel

orchestrator_staging_transport: – staging hop only. Backend Spec §13.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

mount_point: str#
staging_subpath: str#
type: OrchestratorTransportType#
class exlab_wizard.config.models.PathsConfig(**data)[source]#

Bases: BaseModel

paths: block. Templates / plugins / equipment-first local root.

Parameters:

data (Any)

local_root: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

plugin_dir: str#
templates_dir: str#
class exlab_wizard.config.models.PluginsConfig(**data)[source]#

Bases: BaseModel

plugins: block. Master opt-in for network-declaring plugins.

Parameters:

data (Any)

allow_network: bool#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class exlab_wizard.config.models.READMEConfig(**data)[source]#

Bases: BaseModel

readme: block. Lab-policy fields layered on top of the core set.

Parameters:

data (Any)

defaults: list[READMEDefaultField]#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class exlab_wizard.config.models.READMEDefaultField(**data)[source]#

Bases: BaseModel

One operator-defined extra README field. Backend Spec §9, §10.

Parameters:

data (Any)

default: Any#
hint: str | None#
id: str#
label: str#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

options: list[str] | None#
required: bool#
type: FieldType#
class exlab_wizard.config.models.RcloneTransport(**data)[source]#

Bases: BaseModel

transport: block when type == 'rclone'.

Parameters:

data (Any)

bandwidth: BandwidthConfig#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

rclone_remote: str#
rclone_remote_path: str#
type: Literal['rclone']#
class exlab_wizard.config.models.RsyncSshTransport(**data)[source]#

Bases: BaseModel

transport: block when type == 'rsync_ssh'.

The model rejects any input dict that contains a password key. SSH password auth is forbidden by spec; only key-based auth is supported. The extra='forbid' setting also rejects the field, but the explicit mode='before' validator emits a more actionable error message.

Parameters:

data (Any)

bandwidth: BandwidthConfig#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

remote_path: str#
ssh_key_path: str#
ssh_target: str#
type: Literal['rsync_ssh']#
class exlab_wizard.config.models.SyncConfig(**data)[source]#

Bases: BaseModel

sync: block. NAS sync engine kill-switch + retry policy.

Parameters:

data (Any)

enabled: bool#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

retry_attempts: int#
class exlab_wizard.config.models.ValidatorConfig(**data)[source]#

Bases: BaseModel

validator: block. Content-scan tuning. Backend Spec §8.1.1, §11.8.

Parameters:

data (Any)

content_scan_extensions: list[str]#
content_scan_max_mib: int#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'str_strip_whitespace': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].