exlab_wizard.controller#
Controller package. Backend Spec §4.4.1, §4.7, §4.7.1, §4.8.
Re-exports the public surface of the creation controller – the state
machine enums + transition helpers, the in-memory session store, and the
CreationController class itself – so callers can write
from exlab_wizard.controller import CreationController, SessionState
without reaching into the submodules.
- class exlab_wizard.controller.CreationController(*, config, validator, template_engine, plugin_host, cache_creation, cache_equipment, cache_log=None, readme_generator=None, nas_sync=None, session_store=None)[source]#
Bases:
objectDrives the §4.7 state machine end-to-end.
Composes the validator (Phase 4), template engine (Phase 5), plugin host (Phase 6), cache writers (Phase 3), README generator (Phase 8 – NoOp until then), and NAS sync client (Phase 10 – NoOp until then).
- Parameters:
config (
Config)validator (
Validator)template_engine (
TemplateEngine)plugin_host (
PluginHost|None)cache_creation (
CreationWriter)cache_equipment (
EquipmentCacheWriter)readme_generator (
ReadmeGeneratorProtocol|None)nas_sync (
NASSyncProtocol|None)session_store (
SessionStore|None)
- async cancel(session_id, *, discard_files=False)[source]#
Abort an in-flight session.
Pushes a
Noneonto the resume queue (so anINPUT_REQUIREDsession wakes immediately), cancels the pipeline task, and runs the cleanup hook.discard_filesdeletes the partially-created directory; otherwise the directory is left in place as an orphan (Backend Spec §4.7 / §4.8).
- async create_project(req)[source]#
Open a project-creation session and start the pipeline.
The session is registered with the store immediately and the pipeline runs as a background asyncio task; the returned
SessionHandlereflects the post-VALIDATING state. Failures from the validation gate transition the session toFAILEDsynchronously before returning – so the caller can detect them on the very first response.- Parameters:
req (
ProjectCreateRequest)- Return type:
- async create_run(req)[source]#
Open a run-creation session and start the pipeline.
- Parameters:
req (
RunCreateRequest)- Return type:
- async resume(session_id, extra_inputs)[source]#
Supply
extra_inputsafter aPluginInputRequiredprompt.Pushes the payload onto the session’s resume queue; the suspended pipeline wakes, re-spawns the trigger plugin’s worker with the new inputs, and continues. Backend Spec §4.7 / §6.4.
- Parameters:
- Return type:
- property session_store: SessionStore#
Expose the in-memory session store for the API surface.
- async status(session_id)[source]#
Return a snapshot
SessionHandleforsession_id.- Parameters:
session_id (
str)- Return type:
- class exlab_wizard.controller.NASSyncProtocol(*args, **kwargs)[source]#
Bases:
ProtocolThe NAS sync surface the controller depends on. Phase 10.
- class exlab_wizard.controller.NoOpNASSync[source]#
Bases:
objectNo-op stand-in for
NASSyncClientuntil Phase 10 lands.
- class exlab_wizard.controller.NoOpReadmeGenerator[source]#
Bases:
objectMinimal README generator used until Phase 8 lands the real one.
Writes a tiny
README.mdcontaining only the core fields so the post-validate pass has something to scan.- async generate(dst, ctx)[source]#
- Parameters:
dst (
Path)ctx (
ReadmeContext)
- Return type:
- class exlab_wizard.controller.Phase(*values)[source]#
Bases:
StrEnumExternally-emitted
phaseevent. Backend Spec §4.6.2.Sent over the
WS /api/v1/sessions/{id}/eventschannel on every state transition that has a corresponding phase event. The enum values match the spec’s wire-format strings verbatim.- DONE = 'done'#
- INPUT_REQUIRED = 'input_required'#
- QUEUEING_NAS_SYNC = 'queueing_nas_sync'#
- RENDERING_TEMPLATE = 'rendering_template'#
- RUNNING_PLUGINS = 'running_plugins'#
- VALIDATING_INPUTS = 'validating_inputs'#
- VALIDATING_POST_CREATION = 'validating_post_creation'#
- WRITING_CACHE = 'writing_cache'#
- class exlab_wizard.controller.ProjectCreateRequest(equipment_id, template_path, lims_project, variables, label, operator, objective, readme_extra=<factory>)[source]#
Bases:
objectInputs for
CreationController.create_project().Backend Spec §4.6.1 / UI-spec §3.1.
lims_projectmirrors the §11.3lims_projectblock (uid,short_id,name_at_creation,source).- Parameters:
- class exlab_wizard.controller.ReadmeContext(label, operator, objective, equipment_id, project_short_id, run_kind, variables, template, extra_fields=<factory>)[source]#
Bases:
objectInputs handed to the README generator. Phase 8 owns the canonical type; this lightweight stand-in lets Phase 7 ship before Phase 8 lands.
- Parameters:
- template: ResolvedTemplate#
- class exlab_wizard.controller.ReadmeGeneratorProtocol(*args, **kwargs)[source]#
Bases:
ProtocolThe README generator surface the controller depends on. Phase 8.
- async generate(dst, ctx)[source]#
- Parameters:
dst (
Path)ctx (
ReadmeContext)
- Return type:
- class exlab_wizard.controller.RunCreateRequest(equipment_id, project_short_id, template_path, run_kind, variables, label, operator, objective, readme_extra=<factory>, run_date=None, lims_project=<factory>)[source]#
Bases:
objectInputs for
CreationController.create_run().Backend Spec §4.6.1 / UI-spec §3.2 / §3.3.
run_kindis the core mode flag and is immutable mid-session per UI-spec §3.3.- Parameters:
- run_kind: RunKind#
- class exlab_wizard.controller.Session(session_id, kind, state, request, created_at, last_heartbeat, current_phase=None, next_action=NextAction.NONE, event_queue=None, pending_input=None, error=None, result=None)[source]#
Bases:
objectOne creation session. Backend Spec §4.4.7.
- session_id#
UUID4 string assigned by the store on
open().
- kind#
"project"or"run"– mirrors the controller’screate_*entry point.
- state#
Current
SessionState. Mutated only viaSessionStore.transition().
- request#
The original create request bundle (
ProjectCreateRequestorRunCreateRequest).
- created_at#
UTC timestamp at
SessionStore.open().
- last_heartbeat#
Most recent client-driven heartbeat. Refreshed by
SessionStore.heartbeat(); consulted by the GC.
- current_phase#
Mirrors
state_to_phase()ofstate. Maintained bySessionStore.transition().
- next_action#
"awaiting_input"while the session is inSessionState.INPUT_REQUIRED;"none"otherwise.
- event_queue#
WebSocket fan-out queue. Set by
SessionStore.attach_event_queue().
- pending_input#
Latest
InputRequiredPayloaddict surfaced by the plugin host; cleared on resume.
- error#
Structured error envelope (
{code, message, ...}) on failure.Nonewhile the session is in flight.
- result#
Structured
donepayload at session close.Nonewhile in flight or on failure.
- Parameters:
session_id (
str)kind (
SessionKind)state (
SessionState)request (
Any)created_at (
datetime)last_heartbeat (
datetime)next_action (
NextAction)
- kind: SessionKind#
- next_action: NextAction = 'none'#
- state: SessionState#
- class exlab_wizard.controller.SessionHandle(session_id, state, current_phase, next_action)[source]#
Bases:
objectSnapshot of session state. Backend Spec §4.4.1.
- Parameters:
session_id (
str)state (
SessionState)next_action (
str)
- state: SessionState#
- class exlab_wizard.controller.SessionState(*values)[source]#
Bases:
StrEnumInternal creation-session state. Backend Spec §4.7.
Values mirror the §4.7 state-machine diagram. Lower-case strings so JSON encoding is direct (
StrEnummakesSessionState.PENDINGrender as"pending").- ABORTED = 'aborted'#
- CACHE_WRITE = 'cache_write'#
- DONE = 'done'#
- FAILED = 'failed'#
- INPUT_REQUIRED = 'input_required'#
- PENDING = 'pending'#
- PLUGIN_PASS = 'plugin_pass'#
- POST_VALIDATE = 'post_validate'#
- RENDERING = 'rendering'#
- SYNC_QUEUED = 'sync_queued'#
- VALIDATING = 'validating'#
- class exlab_wizard.controller.SessionStore[source]#
Bases:
objectIn-memory session store. Backend Spec §4.4.7.
Sessions are keyed by UUID4 string; the dict is in-memory for v1 (no persistence across server restarts – Backend Spec §4.8).
- abandoned_older_than(age)[source]#
Return ids of
SessionState.INPUT_REQUIREDsessions whoselast_heartbeatis older thanage.Used by
gc_loop()to identify sessions abandoned by their operator (no client heartbeat for the configured window). OnlyINPUT_REQUIREDsessions are eligible – transient states are owned by the controller and finish on their own.
- attach_event_queue(session_id, queue)[source]#
Attach a WebSocket fan-out queue to the session.
The controller pushes WebSocket frames onto the queue; the
WS /api/v1/sessions/{id}/eventschannel reads from it. One queue per session; re-attaching replaces the prior queue.
- close(session_id, outcome)[source]#
Stamp a terminal-state session with the outcome envelope.
outcomeis the structured payload that the WebSocketdone/failedframe carried.DONEoutcomes go intoresult;FAILEDoutcomes go intoerror;ABORTEDsessions store the outcome underresultso the operator can recover the partial-creation summary if the cancel was a deliberate abort.
- async gc_loop(interval_seconds=300.0)[source]#
Run the abandoned-session GC forever. Backend Spec §4.4.7.
Sleeps
interval_secondsbetween passes (default 5 min); on each wake closes everyINPUT_REQUIREDsession whose heartbeat is older thanSESSION_GC_AFTER_SECONDS(default 1 hour). Cancellation is honored cleanly: the loop catchesasyncio.CancelledErrorand re-raises so the caller’s cancellation propagates.
- heartbeat(session_id)[source]#
Refresh
last_heartbeatso the GC will not close this session.No-op when the session is unknown so a stale client does not crash the server.
- open(kind, req)[source]#
Create a fresh session in
SessionState.PENDINGstate.
- transition(session_id, new_state)[source]#
Move
session_idtonew_state, updatingcurrent_phase.Validates the transition against
exlab_wizard.controller.state_machine.VALID_TRANSITIONSand raisesValueErroron illegal edges.next_actionis updated alongsidestate:INPUT_REQUIRED->"awaiting_input", every other state ->"none".- Parameters:
session_id (
str)new_state (
SessionState)
- Return type:
- exlab_wizard.controller.assert_transition(current, new_state)[source]#
Raise
ValueErrorifcurrent -> new_stateis illegal.Defensive guard used by
SessionStore.transitionand the controller’s pipeline. Backend Spec §4.7 / §4.7.1 are the source of truth for the legal edges; this function consultsVALID_TRANSITIONSvia the sharedexlab_wizard.utils.state.assert_forward_transition()helper.- Parameters:
current (
SessionState)new_state (
SessionState)
- Return type:
- exlab_wizard.controller.state_to_phase(state)[source]#
Return the
Phaseevent corresponding tostate.Backend Spec §4.7.1 mapping table.
PENDING,FAILED, andABORTEDreturnNone(no phase event).INPUT_REQUIREDreturnsPhase.INPUT_REQUIRED; the API surface encodes that as akind: "input_required"envelope rather than aphaseframe, but the mapping is preserved so a single dispatch knows the relationship.- Parameters:
state (
SessionState)- Return type:
Modules
Creation controller. |
|
In-memory session store + GC for creation sessions. |
|
Creation-session state machine. |