stimulus_base#

Base class for stimulus devices that launch an external app subprocess.

Captures the lifecycle shared by every “launch an external stimulus program, wait for a stdout readiness handshake, terminate on stop” device (MousePortal today; PsychoPy is a candidate to adopt this later). Subclasses implement a few hooks; the base wires the mesofield device contract (StimulusDevice): DeviceSignals, initialize/arm/start/stop/shutdown, status/metadata, and a GUI-safe readiness wait.

A stimulus device is not a DataProducer: it never emits on signals.data. signals.started fires on the readiness handshake; signals.finished fires on stop or subprocess exit.

Required subclass surface#

  • ready_token (class attr) – stdout substring the child prints when ready.

  • build_command() – the argv to launch.

Optional hooks#

  • launch_phase (class attr, "arm" or "start") – when to launch. "arm" guarantees the stimulus is up before recording starts, since a Procedure runs all arm_all before start_all.

  • prepare() – per-run prep (generate config, open side channels) before launch.

  • preflight() – return an error string to abort launch with a clear message.

  • launch_cwd() / launch_env() – subprocess working dir / environment.

  • on_stop() – teardown of any side channels opened in prepare().

  • require_ready (class attr) – treat a missing readiness handshake as a failure even if the child is still alive (PsychoPy); default False.

  • enabled (instance attr) – per-run gate; a Procedure may set it False to record a stimulus-free task.

Operator presentation hooks (no-op/log by default, so automatic stimuli are unaffected; a GUI subclass overrides them to drive modal dialogs): present_launching() / dismiss_launching(), present_failure(), and confirm_ready_to_record() (the post-readiness “press to record” gate).

class mesofield.devices.stimulus_base.SubprocessStimulusDevice[source]#

Bases: object

Lifecycle skeleton for subprocess-backed stimulus devices.

__init__(cfg)[source]#
Parameters:

cfg (Dict[str, Any])

serves_task(task, config)[source]#

Whether this stimulus participates in task.

Drives per-run gating: before arming, a Procedure enables only the stimulus device(s) that serve the selected task (see Procedure._gate_stimuli_by_task), so a rig with several stimulus apps launches only what the task needs. The default serves every task – correct for a single-stimulus rig or a device with no task binding. Subclasses that bind to specific tasks override this.

Parameters:
Return type:

bool

prepare(config)[source]#

Per-run prep before launch (config files, side channels). No-op.

Parameters:

config (Any)

Return type:

None

preflight()[source]#

Return an actionable error string to abort launch, or None to proceed.

Return type:

str | None

build_command()[source]#

Return the full argv used to launch the stimulus subprocess.

Return type:

List[str]

on_stop()[source]#

Teardown for anything opened in prepare(). No-op by default.

Return type:

None

present_launching()[source]#

Show a non-blocking ‘launching, waiting for readiness’ indicator.

Called right after the subprocess is spawned and before the readiness wait (which pumps Qt events, so a shown-but-not-exec’d dialog stays responsive). Pair with dismiss_launching(). No-op by default.

Return type:

None

dismiss_launching()[source]#

Dismiss the indicator shown by present_launching(). No-op default.

Return type:

None

present_failure(message, detail='')[source]#

Surface a launch/handshake failure to the operator.

detail carries the child’s last output (see SubprocessSupervisor.output_tail). Logs by default; a GUI subclass shows a dialog.

Parameters:
Return type:

None

confirm_ready_to_record()[source]#

Operator gate after the stimulus reports ready; False cancels.

Runs inside start() for launch_phase == "start" devices once the readiness handshake has fired. Default proceeds immediately (automatic stimuli); PsychoPy shows a focused “press to start recording” dialog over its full-screen window.

Return type:

bool

property handshake_ok: bool#

True once the subprocess reported its ready_token.