exlab_wizard.api.setup#

Setup-state gate + /setup/* endpoints. Backend Spec §4.6, §4.9.

Two responsibilities live here:

  1. The setup-state gate – a per-request dependency that consults paths.evaluate_setup_state() and returns 503 with code: "setup_incomplete" for routes that need a complete config.yaml (creation, browse, problems). Routes that must remain available during onboarding (/setup/*, /config, /health) skip the dependency.

  2. The setup endpointsGET /setup/status, POST /setup/test-lims, POST /setup/test-equipment, POST /setup/autostart. These are the wizard’s “diagnostics” surface and must work in any setup state.

Per Backend §4.9.4, INCOMPLETE_LIMS_UNREACHABLE is a soft block: the gate treats it as READY for endpoint-gating purposes; the /setup/status endpoint surfaces the soft state separately so the banner can render.

Functions

build_setup_router()

Construct the /setup/* router.

compute_setup_state(deps)

Evaluate the §4.9.1 state for the app's current dependencies.

is_creation_blocked(state)

Return True when state should gate creation flows.

setup_state_gate(request)

FastAPI dependency that gates a route on setup state.

Classes

AutostartRequest(**data)

POST /setup/autostart request body.

AutostartResult(**data)

POST /setup/autostart response.

EquipmentTestRequest(**data)

POST /setup/test-equipment request body.

LIMSTestRequest(**data)

POST /setup/test-lims request body.

ProbeResult(**data)

Common ok/reason payload for the diagnostics endpoints.

SetupStatusResponse(**data)

GET /setup/status response.

TestEquipmentRequest

TestLIMSRequest

TestResult

class exlab_wizard.api.setup.AutostartRequest(**data)[source]#

Bases: BaseModel

POST /setup/autostart request body. Backend Spec §4.9.5 step 0.

Parameters:

data (Any)

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

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

class exlab_wizard.api.setup.EquipmentTestRequest(**data)[source]#

Bases: BaseModel

POST /setup/test-equipment request body.

Parameters:

data (Any)

equipment: EquipmentConfig | None#
equipment_id: str | None#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}#

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

class exlab_wizard.api.setup.LIMSTestRequest(**data)[source]#

Bases: BaseModel

POST /setup/test-lims request body.

Either reference the currently-configured LIMS settings (no body fields) or supply a LIMSConfig candidate to test before save.

Class is named LIMSTestRequest (rather than TestLIMSRequest) so pytest does not pick it up as a test class on collection.

Parameters:

data (Any)

lims: LIMSConfig | None#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}#

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

password: str | None#
class exlab_wizard.api.setup.ProbeResult(**data)[source]#

Bases: BaseModel

Common ok/reason payload for the diagnostics endpoints.

Parameters:

data (Any)

latency_ms: int | None#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}#

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

ok: bool#
reason: str | None#
class exlab_wizard.api.setup.SetupStatusResponse(**data)[source]#

Bases: BaseModel

GET /setup/status response. Backend Spec §4.9.3.

Parameters:

data (Any)

missing: list[dict[str, str]]#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid'}#

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

next_action: str | None#
ready: bool#
state: str#
exlab_wizard.api.setup.TestEquipmentRequest#

alias of EquipmentTestRequest

exlab_wizard.api.setup.TestLIMSRequest#

alias of LIMSTestRequest

exlab_wizard.api.setup.TestResult#

alias of ProbeResult

exlab_wizard.api.setup.build_setup_router()[source]#

Construct the /setup/* router. Always-available endpoints.

Return type:

APIRouter

exlab_wizard.api.setup.compute_setup_state(deps)[source]#

Evaluate the §4.9.1 state for the app’s current dependencies.

The dependency object exposes config and a lims_reachable boolean (cached at startup; the POST /setup/test-lims endpoint refreshes it).

Parameters:

deps (Any)

Return type:

SetupState

exlab_wizard.api.setup.is_creation_blocked(state)[source]#

Return True when state should gate creation flows.

Per §4.9.4 the soft block (INCOMPLETE_LIMS_UNREACHABLE) does NOT gate creation – the operator may be on an offline machine using the cached project list. READY obviously does not gate.

Parameters:

state (SetupState)

Return type:

bool

exlab_wizard.api.setup.setup_state_gate(request)[source]#

FastAPI dependency that gates a route on setup state.

Looks up the app’s bound AppDependencies, evaluates the setup state, and raises 503 with the §4.9.2 envelope when the state is any non-soft INCOMPLETE_*. The dependency itself is a plain function so it can be overridden in tests via app.dependency_overrides.

Parameters:

request (Request)

Return type:

None