Server¶
icon.server.apiicon.server.data_access.models.enumsicon.server.data_access.models.sqliteicon.server.data_access.repositoriesicon.server.hardware_processingicon.server.post_processingicon.server.pre_processingicon.server.schedulericon.server.utils.typesicon.server.web_server
icon.server.api
¶
This module defines the API layer of ICON, implemented as a pydase.DataService.
The main entry point is the APIService,
which is exposed by the IconServer.
The IconServer itself is a pydase.Server hosting the API.
Structure¶
The APIService aggregates multiple “controller” services as attributes. Each
controller is itself a pydase.DataService exposing related API methods.
Background tasks¶
Controllers can define periodic
pydase tasks,
which are asyncio tasks automatically started with the service.
api_service
¶
APIService
¶
APIService(
pre_processing_event_queues: list[Queue[UpdateQueue]],
experiment_library_client: ReconfigurableExperimentLibraryClient,
devices: Devices,
)
Bases: DataService
Aggregates ICON’s API controllers and manages background tasks.
The APIService groups multiple controllers, each of which is a
pydase.DataService exposing related API methods. It also defines
background tasks for keeping experiment and parameter metadata
in sync with the experiment library and InfluxDB.
Note
Controllers are pydase.DataService instances exposed as attributes to group
related API methods. Background tasks are implemented with
pydase tasks.
Create a new APIService.
pre_processing_event_queues: Queues used by ScansController to notify
pre-processing workers.
experiment_library_client: Client for an experiment library
devices: Controllers for the hardware devices
Source code in src/icon/server/api/api_service.py
config
instance-attribute
¶
config = ConfigurationController()
Controller for managing and updating the application’s configuration.
data
instance-attribute
¶
data = ExperimentDataController()
Controller for accessing stored experiment data.
devices
instance-attribute
¶
devices = DevicesController()
Controller for managing external pydase-based devices.
experiments
instance-attribute
¶
experiments = ExperimentsController()
Controller for experiment metadata.
parameters
instance-attribute
¶
parameters = ParametersController()
Controller for parameter metadata and shared parameter values.
scans
instance-attribute
¶
scans = ScansController(
pre_processing_update_queues=pre_processing_event_queues
)
Controller for triggering update events for jobs across multiple worker processes.
scheduler
instance-attribute
¶
scheduler = SchedulerController(
devices_controller=self.devices,
parameters_controller=self.parameters,
)
Controller to submit, inspect, and cancel scheduled jobs.
status
instance-attribute
¶
status = StatusController(devices)
Controller for system status monitoring.
configuration_controller
¶
ConfigurationController
¶
Bases: DataService
Controller for managing and updating the application’s configuration.
This class provides an API to get and update the configuration, validate it, and save the updated configuration back to the source file.
get_config
¶
update_config_option
¶
Update a specific configuration option.
Traverses the configuration using the dot-separated key, updates the specified value, validates the entire configuration, and saves the changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The dot-separated key of the configuration option (e.g., “experiment_library.git_repository”). |
required |
value
|
Any
|
The new value for the configuration option. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the update is successful, False otherwise. |
Source code in src/icon/server/api/configuration_controller.py
set_nested
¶
Set a value in a nested dict.
Source code in src/icon/server/api/configuration_controller.py
devices_controller
¶
DeviceParameterValueyType
module-attribute
¶
Allowed primitive types for device parameter values.
A parameter value sent to or retrieved from a device may be one of these
basic types. Quantities with units are handled separately via pydase.units.Quantity.
DevicesController
¶
Bases: DataService
Controller for managing external pydase-based devices.
Maintains client connections to configured devices, exposes helpers to add/update device entries in SQLite, and provides async accessors for device parameter values through pydase proxies. Also discovers scannable device parameters for integration with ICON scans.
Source code in src/icon/server/api/devices_controller.py
device_proxies
instance-attribute
¶
Live pydase proxies keyed by device name.
add_device
¶
add_device(
*,
name: str,
url: str,
status: Literal["disabled", "enabled"] = "enabled",
description: str | None = None,
retry_delay_seconds: float = 0.0,
retry_attempts: int = 3,
) -> Device
Create a device record in SQLite and (optionally) connect to it.
If status=="enabled", a non-blocking pydase client is created and its
proxy is registered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique device name. |
required |
url
|
str
|
pydase server URL of the device. |
required |
status
|
Literal['disabled', 'enabled']
|
Whether the device should be connected immediately. |
'enabled'
|
description
|
str | None
|
Optional human-readable description. |
None
|
retry_delay_seconds
|
float
|
Backoff delay used by device-side logic. |
0.0
|
retry_attempts
|
int
|
Number of retries used by device-side logic. |
3
|
Returns:
| Type | Description |
|---|---|
Device
|
The |
Source code in src/icon/server/api/devices_controller.py
get_devices_by_status
¶
get_devices_by_status(
*, status: DeviceStatus | None = None
) -> dict[str, DeviceDict]
List devices (optionally filtered by status) with reachability & scan info.
Augments each device entry with
reachable: Whether a live proxy is connected.scannable_params: Flat list of scannable parameter access paths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
DeviceStatus | None
|
Optional filter ( |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, DeviceDict]
|
Mapping from device name to a |
Source code in src/icon/server/api/devices_controller.py
get_parameter_value
async
¶
Get a parameter value from a connected device.
Logs a warning if the device is not connected or not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Device name. |
required |
parameter_id
|
str
|
Access path on the device service. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The parameter value as returned by the device, or |
Source code in src/icon/server/api/devices_controller.py
update_device
¶
update_device(
*,
name: str,
status: Literal["disabled", "enabled"] | None = None,
url: str | None = None,
retry_attempts: int | None = None,
retry_delay_seconds: float | None = None,
) -> Device
Update a device record and its live connection.
When transitioning to disabled, the client is disconnected and removed.
When transitioning to enabled, a client is (re)created and registered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Device name. |
required |
status
|
Literal['disabled', 'enabled'] | None
|
Target enable/disable status. |
None
|
url
|
str | None
|
Updated pydase URL. |
None
|
retry_attempts
|
int | None
|
Updated retry attempts metadata. |
None
|
retry_delay_seconds
|
float | None
|
Updated retry delay metadata. |
None
|
Returns:
| Type | Description |
|---|---|
Device
|
The updated |
Source code in src/icon/server/api/devices_controller.py
update_parameter_value
async
¶
update_parameter_value(
*,
name: str,
parameter_id: str,
new_value: DeviceParameterValueyType | QuantityDict,
type_: Literal["float", "int", "Quantity"],
) -> None
Set a parameter value on a connected device.
Performs type-normalization (float, int, or Quantity) before delegating
to the device client.
Logs a warning if the device is not connected or not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Device name. |
required |
parameter_id
|
str
|
Access path on the device service. |
required |
new_value
|
DeviceParameterValueyType | QuantityDict
|
New value (native type or quantity dict). |
required |
type_
|
Literal['float', 'int', 'Quantity']
|
Expected type of the value for normalization. |
required |
Source code in src/icon/server/api/devices_controller.py
experiment_data_controller
¶
ExperimentDataController
¶
Bases: DataService
Controller for accessing stored experiment data.
Provides API methods to fetch experiment data associated with jobs.
delete_fit
async
¶
Delete a fit result for a result channel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
result_channel
|
str
|
Name of the result channel whose fit to remove. |
required |
Source code in src/icon/server/api/experiment_data_controller.py
get_experiment_data_by_job_id
async
¶
get_experiment_data_by_job_id(
job_id: int,
max_transfer_bytes: int = DEFAULT_MAX_TRANSFER_BYTES,
*,
include_hardware_instructions: bool = False,
include_all_shots: bool = False,
) -> str
Return experiment data for a given job.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
The unique identifier of the job. |
required |
max_transfer_bytes
|
int
|
Approximate cap on the serialised payload
size in bytes. The number of data points loaded is
derived from HDF5 metadata so that the response stays
within this budget. Defaults to
|
DEFAULT_MAX_TRANSFER_BYTES
|
include_hardware_instructions
|
bool
|
If True, include per-point pulse
|
False
|
include_all_shots
|
bool
|
If True, include the raw shots of every data point. Defaults to False, which returns only the newest data point’s shots because one array per point per channel dominates the payload; live updates still carry the shots of each new data point. |
False
|
Returns:
| Type | Description |
|---|---|
str
|
The experiment data linked to the job as a JSON string representing an |
str
|
[ExperimentData][icon.server.data_access.repositories.experiment_data_repository.ExperimentData] |
str
|
instance. |
Source code in src/icon/server/api/experiment_data_controller.py
get_hardware_instructions
async
¶
Return stored hardware instructions (the serialized sequence JSON).
Used by the sequence visualizer to display the pulse sequence of a specific data point, a job, or the most recent experiment run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int | None
|
Job to read from. Defaults to the most recent job with stored hardware instructions. |
None
|
index
|
int | None
|
Data point index within the job. Defaults to the last stored entry. |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
The serialized hardware instructions, or None when nothing is |
str | None
|
stored for the requested scope. |
Source code in src/icon/server/api/experiment_data_controller.py
run_fit
async
¶
run_fit(
job_id: int,
result_channel: str,
func_type: str,
x_range: list[float] | None = None,
init: dict[str, float] | None = None,
) -> dict[str, Any]
Run a curve fit on a result channel of a finished job.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
result_channel
|
str
|
Name of the result channel to fit. |
required |
func_type
|
str
|
Fit model name (e.g. “lorentzian”). |
required |
x_range
|
list[float] | None
|
Optional [min, max] to restrict fit domain. |
None
|
init
|
dict[str, float] | None
|
Optional initial parameter overrides. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Serialised FitResult dict. |
Source code in src/icon/server/api/experiment_data_controller.py
experiments_controller
¶
ExperimentsController
¶
Bases: DataService
Controller for experiment metadata.
Stores the current set of experiments and exposes them to the API. Updates are compared against the existing metadata and, if changes are detected, an update event is pushed to the Socket.IO emit queue.
Source code in src/icon/server/api/experiments_controller.py
get_experiments
¶
get_metadata
¶
Serve experiment metadata for experiment id experiment_id.
models
¶
device_dict
¶
experiment_dict
¶
ExperimentDict
module-attribute
¶
ExperimentDict = dict[str, ExperimentMetadata]
Dictionary mapping the unique experiment identifier to its metadata.
Example
experiment_dict: ExperimentDict = {
"experiment_library.experiments.my_experiment.MyExperiment (Cool Det)": ExperimentMetadata(
class_name="MyExperiment",
constructor_kwargs={
"name": "Cool Det",
},
parameters={
"Local Parameters": {
"namespace='experiment_library.experiments.my_experiment.MyExperiment.Cool Det' parameter_group='default' param_type='ParameterTypes.AMPLITUDE'": {
"allowed_values": None,
"default_value": 0.0,
"display_name": "amplitude",
"max_value": 100.0,
"min_value": 0.0,
"unit": "%",
},
},
"ParameterGroup": {
"namespace='experiment_library.globals.global_parameters' parameter_group='ParameterGroup' param_type='ParameterTypes.AMPLITUDE'": {
"allowed_values": None,
"default_value": 0.0,
"display_name": "amplitude",
"max_value": 100.0,
"min_value": 0.0,
"unit": "%",
},
},
},
),
}
ExperimentMetadata
dataclass
¶
ExperimentMetadata(
class_name: str,
constructor_kwargs: dict[str, Any],
parameters: dict[str, dict[str, ParameterMetadata]],
device_parameter_groups: list[Any] = list(),
)
parameter_metadata
¶
parameters_controller
¶
ParametersController
¶
Bases: DataService
Controller for parameter metadata and shared parameter values.
Maintains metadata for all parameters and their display groups, exposes read/write access to parameter value via the API, and ensures parameters are initialized in the InfluxDB backend.
Source code in src/icon/server/api/parameters_controller.py
get_all_parameters
¶
get_display_groups
¶
get_display_groups() -> dict[
str, dict[str, ParameterMetadata]
]
Return metadata grouped by display group.
Returns:
| Type | Description |
|---|---|
dict[str, dict[str, ParameterMetadata]]
|
Mapping from display group names to parameter metadata. |
Source code in src/icon/server/api/parameters_controller.py
get_parameter_by_id
¶
get_parameter_by_id(parameter_id: str) -> DatabaseValueType
Return the current value of a single parameter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameter_id
|
str
|
The unique identifier of the parameter. |
required |
Returns:
| Type | Description |
|---|---|
DatabaseValueType
|
The current value stored in the shared parameters dict. |
Source code in src/icon/server/api/parameters_controller.py
initialise_parameters_repository
¶
Initialize the global ParametersRepository.
Loads existing parameters from InfluxDB, populates the shared parameters dict in
the shared resource manager, and marks the ParametersRepository as
initialized.
Source code in src/icon/server/api/parameters_controller.py
get_added_removed_and_updated_keys
¶
get_added_removed_and_updated_keys(
new_dict: dict[str, Any], cached_dict: dict[str, Any]
) -> tuple[list[str], list[str], list[str]]
Compare two dictionaries and return added, removed, and updated keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_dict
|
dict[str, Any]
|
The latest dictionary state. |
required |
cached_dict
|
dict[str, Any]
|
The previously cached dictionary state. |
required |
Returns:
| Type | Description |
|---|---|
tuple[list[str], list[str], list[str]]
|
A tuple of three lists:
|
Source code in src/icon/server/api/parameters_controller.py
scans_controller
¶
ScansController
¶
ScansController(
pre_processing_update_queues: list[Queue[UpdateQueue]],
)
Bases: DataService
Controller for triggering update events for jobs across multiple worker processes.
Each worker process has its own update queue ([multiprocessing.Queue][]), which
this controller writes to when an update event is triggered.
Source code in src/icon/server/api/scans_controller.py
trigger_update_job_params
async
¶
trigger_update_job_params(
*, job_id: int | None = None
) -> None
Triggers an ‘update_parameters’ event for the given job ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int | None
|
The ID of the job whose parameters should be updated. If None, all jobs will update their parameters. |
None
|
Source code in src/icon/server/api/scans_controller.py
scheduler_controller
¶
JOB_LIST_PAGE_SIZE
module-attribute
¶
Default number of jobs returned in a get_job_list page.
SchedulerController
¶
SchedulerController(
devices_controller: DevicesController,
parameters_controller: ParametersController,
)
Bases: DataService
Controller to submit, inspect, and cancel scheduled jobs.
Provides methods to submit new jobs, cancel pending or running jobs, and query jobs or runs by ID or status. Ensures scan parameters are cast to the correct runtime type before persisting them.
Create a new SchedulerController.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
devices_controller
|
DevicesController
|
Reference to the devices controller. Used to read current values of device parameters when casting scan values. |
required |
parameters_controller
|
ParametersController
|
Reference to the parameters controller. Used to resolve display names for scan parameters at submission time. |
required |
Source code in src/icon/server/api/scheduler_controller.py
cancel_job
¶
cancel_job(*, job_id: int) -> None
Cancel a job.
The following status updates are performed:
- Job: → PROCESSED
- JobRun: PENDING/PROCESSING/PAUSED → CANCELLED
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to cancel. |
required |
Source code in src/icon/server/api/scheduler_controller.py
get_active_jobs
¶
get_active_jobs(
*, limit: int = JOB_LIST_PAGE_SIZE
) -> list[JobListItemDict]
Return the queued and currently running jobs, newest first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of jobs to return. |
JOB_LIST_PAGE_SIZE
|
Returns:
| Type | Description |
|---|---|
list[JobListItemDict]
|
List of job-list entries ordered by descending job ID. |
Source code in src/icon/server/api/scheduler_controller.py
get_job_by_id
¶
get_job_list
¶
get_job_list(
*,
before_id: int | None = None,
limit: int = JOB_LIST_PAGE_SIZE,
) -> list[JobListItemDict]
Return one page of finished jobs, newest first.
Only the fields the job list renders are returned, which keeps a page
roughly 5x smaller on the wire than the equivalent get_scheduled_jobs
response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
before_id
|
int | None
|
Exclusive upper bound on the job ID. Pass the lowest ID of the previous page to fetch the next one; omit it for the first page. |
None
|
limit
|
int
|
Maximum number of jobs to return. |
JOB_LIST_PAGE_SIZE
|
Returns:
| Type | Description |
|---|---|
list[JobListItemDict]
|
List of job-list entries ordered by descending job ID. A result |
list[JobListItemDict]
|
shorter than |
Source code in src/icon/server/api/scheduler_controller.py
get_job_run_by_id
¶
get_scheduled_jobs
¶
get_scheduled_jobs(
*,
status: JobStatus | None = None,
start: str | None = None,
stop: str | None = None,
) -> dict[int, Job]
List jobs filtered by status and optional ISO timeframe.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
JobStatus | None
|
Optional job status filter. |
None
|
start
|
str | None
|
Optional ISO8601 start timestamp (inclusive). |
None
|
stop
|
str | None
|
Optional ISO8601 stop timestamp (exclusive). |
None
|
Returns:
| Type | Description |
|---|---|
dict[int, Job]
|
Mapping from job ID to job record. |
Source code in src/icon/server/api/scheduler_controller.py
pause_job
¶
pause_job(*, job_id: int) -> None
Pause a running job.
The pre-processing worker holding the job will finish any in-flight work and
then block in a polling loop, keeping the remaining scan state in memory.
Tasks already queued for the hardware worker are diverted back to the
pre-processing worker via the existing outdated_tasks rewind mechanism.
No-op if the job run is not in PROCESSING state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to pause. |
required |
Source code in src/icon/server/api/scheduler_controller.py
resume_job
¶
resume_job(*, job_id: int) -> None
Resume a paused job.
The pre-processing worker observes the status change, regenerates any tasks the hardware worker diverted while paused (picking up fresh parameter values in the process), and continues producing data points from where it left off.
No-op if the job run is not in PAUSED state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to resume. |
required |
Source code in src/icon/server/api/scheduler_controller.py
submit_job
async
¶
submit_job(
*,
experiment_id: str,
scan_parameters: list[dict[str, Any]],
priority: int = 20,
local_parameters_timestamp: datetime | None = None,
repetitions: int = 1,
number_of_shots: int = 50,
git_commit_hash: str | None = None,
auto_calibration: bool = False,
) -> int
Create and submit a job with typed scan parameters.
Each scan parameter’s values are cast to the current type of the target
parameter (device parameter via DevicesController or shared parameter via
ParametersRepository).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
experiment_id
|
str
|
Experiment identifier (from experiment library). |
required |
scan_parameters
|
list[dict[str, Any]]
|
List of scan parameter specs (id, values, optional device_name). |
required |
priority
|
int
|
Higher values run sooner. |
20
|
local_parameters_timestamp
|
datetime | None
|
ISO timestamp to snapshot local parameters;
defaults to |
None
|
repetitions
|
int
|
Number of experiment repetitions. |
1
|
number_of_shots
|
int
|
Shots per data point. |
50
|
git_commit_hash
|
str | None
|
Git commit to associate with the job; if |
None
|
auto_calibration
|
bool
|
Whether to run auto-calibration for the job. |
False
|
Returns:
| Type | Description |
|---|---|
int
|
The persisted job ID. |
Source code in src/icon/server/api/scheduler_controller.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
status_controller
¶
StatusController
¶
StatusController(devices: Devices)
Bases: DataService
Controller for system status monitoring.
Periodically checks availability of InfluxDB and hardware and emits status events via the Socket.IO queue.
Source code in src/icon/server/api/status_controller.py
check_hardware_status
async
¶
Check hardware connection and reconnect if necessary.
Ensures the hardware controller matches the configured host/port and reconnects in a background thread if required.
Emits a "status.hardware" event to the Socket.IO queue.
Source code in src/icon/server/api/status_controller.py
check_influxdb_status
¶
Check if InfluxDB is responsive and update status.
Emits a "status.influxdb" event to the Socket.IO queue.
Source code in src/icon/server/api/status_controller.py
get_status
¶
Return the current system status flags.
Returns:
| Type | Description |
|---|---|
Status
|
A dictionary with:
|
Source code in src/icon/server/api/status_controller.py
icon.server.data_access.models.enums
¶
This module defines enums used by the SQLAlchemy models.
These enums represent database-level states for jobs, job runs, and devices. They are stored as strings in the database and used throughout ICON’s scheduling and device management logic.
DeviceStatus
¶
JobRunStatus
¶
Bases: Enum
Lifecycle states of a job run.
CANCELLED
class-attribute
instance-attribute
¶
Run was cancelled before completion.
FAILED
class-attribute
instance-attribute
¶
Run ended unsuccessfully due to an error.
PAUSED
class-attribute
instance-attribute
¶
Run has been paused by the user; its pre-processing worker is holding its remaining state in memory until the run is resumed or cancelled.
PENDING
class-attribute
instance-attribute
¶
Run is queued but has not started yet.
PROCESSING
class-attribute
instance-attribute
¶
Run is currently executing.
JobStatus
¶
Bases: Enum
Lifecycle states of a job submission.
PROCESSED
class-attribute
instance-attribute
¶
Job has finished or was cancelled and is no longer active.
PROCESSING
class-attribute
instance-attribute
¶
Job has been put into the pre-processing task queue.
SUBMITTED
class-attribute
instance-attribute
¶
Job has been created and is waiting to be scheduled.
icon.server.data_access.models.sqlite
¶
This module contains the SQLAlchemy models for ICON.
All models must be imported and added to the __all__ list here so that Alembic can
correctly detect them during schema autogeneration.
Alembic inspects Base.metadata, which is only populated with models that are
actually imported at runtime.
Base
¶
Bases: DeclarativeBase
Base class for all SQLAlchemy ORM models in ICON.
This class configures the declarative mapping and provides a datetime type mapping for all models that inherit from it.
type_annotation_map
class-attribute
¶
Custom type mapping used when interpreting Python type annotations.
Currently, datetime.datetime is mapped to
sqlalchemy.TIMESTAMP(timezone=True) to ensure timezone-aware timestamps across all
models.
Device
¶
Bases: Base
SQLAlchemy model for a registered device.
Represents an external device accessible via a pydase service. Stores configuration, connection details, and retry behaviour. A device may be linked to multiple scan parameters.
created
class-attribute
instance-attribute
¶
created: Mapped[datetime] = sqlalchemy.orm.mapped_column(
default=now
)
Timestamp when the device entry was created.
description
class-attribute
instance-attribute
¶
description: Mapped[str | None] = (
sqlalchemy.orm.mapped_column(default=None)
)
Optional human-readable description of the device.
id
class-attribute
instance-attribute
¶
id: Mapped[int] = sqlalchemy.orm.mapped_column(
primary_key=True, autoincrement=True
)
Primary key identifier for the device.
name
class-attribute
instance-attribute
¶
name: Mapped[str] = sqlalchemy.orm.mapped_column(
unique=True, index=True
)
Unique name of the device.
retry_attempts
class-attribute
instance-attribute
¶
retry_attempts: Mapped[int] = sqlalchemy.orm.mapped_column(
default=3, nullable=False
)
Number of attempts to verify the device value was set correctly.
retry_delay_seconds
class-attribute
instance-attribute
¶
retry_delay_seconds: Mapped[float] = (
sqlalchemy.orm.mapped_column(
default=0.0, nullable=False
)
)
Delay in seconds between retry attempts
scan_parameters
class-attribute
instance-attribute
¶
scan_parameters: Mapped[list[ScanParameter]] = (
sqlalchemy.orm.relationship(
"ScanParameter", back_populates="device"
)
)
Relationship to scan parameters linked to this device.
status
class-attribute
instance-attribute
¶
status: Mapped[DeviceStatus] = sqlalchemy.orm.mapped_column(
default=DeviceStatus.ENABLED, index=True
)
Current status of the device (enabled or disabled).
url
class-attribute
instance-attribute
¶
url: Mapped[str] = sqlalchemy.orm.mapped_column()
pydase service URL of the device.
ExperimentSource
¶
Bases: Base
SQLAlchemy model for experiment sources.
Represents a unique experiment identifier from the experiment library. Each experiment source may be linked to multiple jobs.
experiment_id
class-attribute
instance-attribute
¶
experiment_id: Mapped[str] = sqlalchemy.orm.mapped_column()
Unique experiment identifier string (as defined in the experiment library).
id
class-attribute
instance-attribute
¶
id: Mapped[int] = sqlalchemy.orm.mapped_column(
primary_key=True, autoincrement=True
)
Primary key identifier for the experiment source.
jobs
class-attribute
instance-attribute
¶
jobs: Mapped[list[Job]] = sqlalchemy.orm.relationship(
back_populates="experiment_source"
)
Relationship to jobs associated with this experiment source.
Job
¶
Bases: Base
SQLAlchemy model for experiment jobs.
Represents a scheduled or running experiment job, including its metadata, status, and relationships to experiment sources, runs, and scan parameters.
Constraints
prioritymust be between 0 and 20.- Indexed by
(experiment_source_id, status, priority, created).
auto_calibration
class-attribute
instance-attribute
¶
auto_calibration: Mapped[bool] = (
sqlalchemy.orm.mapped_column(default=False)
)
Whether auto-calibration is enabled for this job. Currently unused.
created
class-attribute
instance-attribute
¶
created: Mapped[datetime] = sqlalchemy.orm.mapped_column(
default=now
)
Timestamp when the job was created. This cannot be set manually.
debug_mode
class-attribute
instance-attribute
¶
debug_mode: Mapped[bool] = sqlalchemy.orm.mapped_column(
default=False
)
Whether the job was submitted in debug mode (no commit hash).
experiment_source
class-attribute
instance-attribute
¶
experiment_source: Mapped[ExperimentSource] = (
sqlalchemy.orm.relationship(back_populates="jobs")
)
Relationship to the experiment source.
experiment_source_id
class-attribute
instance-attribute
¶
experiment_source_id: Mapped[int] = (
sqlalchemy.orm.mapped_column(
sqlalchemy.ForeignKey("experiment_sources.id")
)
)
Foreign key referencing the associated experiment source.
git_commit_hash
class-attribute
instance-attribute
¶
git_commit_hash: Mapped[str | None] = (
sqlalchemy.orm.mapped_column(default=None)
)
Git commit hash of the experiment code associated with the job.
id
class-attribute
instance-attribute
¶
id: Mapped[int] = sqlalchemy.orm.mapped_column(
primary_key=True, autoincrement=True
)
Primary key identifier for the job.
local_parameters_timestamp
class-attribute
instance-attribute
¶
local_parameters_timestamp: Mapped[datetime] = (
sqlalchemy.orm.mapped_column(default=now)
)
Timestamp of the local parameter snapshot used for this job.
number_of_shots
class-attribute
instance-attribute
¶
number_of_shots: Mapped[int] = sqlalchemy.orm.mapped_column(
default=50
)
Number of shots per repetition.
parent_job
class-attribute
instance-attribute
¶
parent_job: Mapped[Job | None] = (
sqlalchemy.orm.relationship(
"Job",
remote_side=[id],
back_populates="resubmitted_jobs",
)
)
Relationship to the parent job from which this job was resubmitted.
parent_job_id
class-attribute
instance-attribute
¶
parent_job_id: Mapped[int | None] = (
sqlalchemy.orm.mapped_column(
sqlalchemy.ForeignKey("job_submissions.id"),
nullable=True,
)
)
Foreign key referencing the original job if this job was resubmitted.
priority
class-attribute
instance-attribute
¶
priority: Mapped[int] = sqlalchemy.orm.mapped_column(
default=20
)
Job priority, between 0 (lowest) and 20 (highest).
repetitions
class-attribute
instance-attribute
¶
repetitions: Mapped[int] = sqlalchemy.orm.mapped_column(
default=1
)
Number of times the experiment should be repeated.
resubmitted_jobs
class-attribute
instance-attribute
¶
resubmitted_jobs: Mapped[list[Job]] = (
sqlalchemy.orm.relationship(
"Job", back_populates="parent_job"
)
)
List of jobs resubmitted from this job.
run
class-attribute
instance-attribute
¶
run: Mapped[JobRun] = sqlalchemy.orm.relationship(
back_populates="job"
)
Relationship to the job run associated with this job.
scan_parameters
class-attribute
instance-attribute
¶
scan_parameters: Mapped[list[ScanParameter]] = (
sqlalchemy.orm.relationship(back_populates="job")
)
List of scan parameters associated with this job.
JobRun
¶
Bases: Base
SQLAlchemy model for job runs.
Represents the execution of a job, including its scheduled time, current status, and log messages.
Constraints
- Indexed by
(job_id, status, scheduled_time). scheduled_timemust be unique across runs.
id
class-attribute
instance-attribute
¶
id: Mapped[int] = sqlalchemy.orm.mapped_column(
primary_key=True, autoincrement=True
)
Primary key identifier for the job run.
job
class-attribute
instance-attribute
¶
job: Mapped[Job] = sqlalchemy.orm.relationship(
back_populates="run"
)
Relationship to the job associated with this run.
job_id
class-attribute
instance-attribute
¶
job_id: Mapped[int] = sqlalchemy.orm.mapped_column(
sqlalchemy.ForeignKey("job_submissions.id")
)
Foreign key referencing the job being executed.
log
class-attribute
instance-attribute
¶
log: Mapped[str | None] = sqlalchemy.orm.mapped_column(
default=None
)
Optional log message for this run (e.g., cancellation reason).
parameter_update_timestamp
class-attribute
instance-attribute
¶
parameter_update_timestamp: Mapped[datetime | None] = (
sqlalchemy.orm.mapped_column(default=None)
)
Timestamp of the last parameter update.
scheduled_time
class-attribute
instance-attribute
¶
scheduled_time: Mapped[datetime] = (
sqlalchemy.orm.mapped_column(default=now)
)
Time when the run was scheduled to start.
status
class-attribute
instance-attribute
¶
status: Mapped[JobRunStatus] = sqlalchemy.orm.mapped_column(
default=JobRunStatus.PENDING
)
Current status of the run (pending, processing, cancelled, etc.).
ScanParameter
¶
Bases: Base
SQLAlchemy model for scan parameters.
Represents a parameter scanned during a job execution. Each parameter is linked to a job and optionally to a device.
device
class-attribute
instance-attribute
¶
device: Mapped[Device | None] = sqlalchemy.orm.relationship(
back_populates="scan_parameters", lazy="joined"
)
Relationship to the device associated with this parameter.
device_id
class-attribute
instance-attribute
¶
device_id: Mapped[int | None] = (
sqlalchemy.orm.mapped_column(
sqlalchemy.ForeignKey("devices.id"), nullable=True
)
)
Foreign key referencing the associated device, if any.
id
class-attribute
instance-attribute
¶
id: Mapped[int] = sqlalchemy.orm.mapped_column(
primary_key=True, autoincrement=True
)
Primary key identifier for the scan parameter.
job
class-attribute
instance-attribute
¶
job: Mapped[Job] = sqlalchemy.orm.relationship(
back_populates="scan_parameters"
)
Relationship to the job.
job_id
class-attribute
instance-attribute
¶
job_id: Mapped[int] = sqlalchemy.orm.mapped_column(
sqlalchemy.ForeignKey("job_submissions.id")
)
Foreign key referencing the job this parameter belongs to.
name
class-attribute
instance-attribute
¶
name: Mapped[str] = sqlalchemy.orm.mapped_column(
nullable=False
)
Human-friendly display name persisted at submission time.
scan_values
class-attribute
instance-attribute
¶
scan_values: Mapped[list[DatabaseValueType]] = (
sqlalchemy.orm.mapped_column(
JSONEncodedList, nullable=False
)
)
List of values scanned for this parameter (stored as JSON).
variable_id
class-attribute
instance-attribute
¶
variable_id: Mapped[str] = sqlalchemy.orm.mapped_column()
Identifier of the parameter being scanned.
icon.server.data_access.repositories
¶
This module contains the repository layer for ICON’s data access.
Repositories encapsulate database access logic and hide the underlying persistence technology (SQLAlchemy sessions, InfluxDB queries, etc.) from the rest of the application. They expose simple, intention-revealing methods for creating, retrieving, and updating domain objects, while emitting Socket.IO events when relevant.
By using repositories, controllers and services can work with high-level operations (e.g. “submit a job”, “update a device”) without needing to know how the data is stored or which database backend is used. This keeps the codebase modular, easier to maintain, and allows the persistence layer to evolve independently of business logic.
device_repository
¶
DeviceRepository
¶
Repository for Device entities.
Provides methods to create, update, and query devices in the SQLite database. All methods open their own SQLAlchemy session and return detached ORM objects.
add_device
staticmethod
¶
Insert a new device into the database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device
|
Device
|
Device instance to persist. |
required |
Returns:
| Type | Description |
|---|---|
Device
|
The persisted device with database-generated fields (e.g., |
Source code in src/icon/server/data_access/repositories/device_repository.py
get_all_device_names
staticmethod
¶
get_device_by_id
staticmethod
¶
Return a device by database ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
int
|
Primary key identifier of the device. |
required |
Returns:
| Type | Description |
|---|---|
Device
|
The matching device. |
Raises:
| Type | Description |
|---|---|
NoResultFound
|
If no device exists with the given ID. |
Source code in src/icon/server/data_access/repositories/device_repository.py
get_device_by_name
staticmethod
¶
Return a device by unique name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Device name. |
required |
Returns:
| Type | Description |
|---|---|
Device
|
The matching device. |
Raises:
| Type | Description |
|---|---|
NoDeviceFoundError
|
If no device exists with the given name. |
Source code in src/icon/server/data_access/repositories/device_repository.py
get_devices_by_status
staticmethod
¶
get_devices_by_status(
*, status: DeviceStatus | None = None
) -> Sequence[Device]
Return devices filtered by status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
DeviceStatus | None
|
Optional device status to filter on. |
None
|
Returns:
| Type | Description |
|---|---|
Sequence[Device]
|
All devices matching the filter (or all devices if no filter is given). |
Source code in src/icon/server/data_access/repositories/device_repository.py
update_device
staticmethod
¶
update_device(
*,
name: str,
url: str | None = None,
status: DeviceStatus | None = None,
retry_attempts: int | None = None,
retry_delay_seconds: float | None = None,
) -> Device
Update an existing device by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique device name. |
required |
url
|
str | None
|
New device URL (cannot change if the device is enabled). |
None
|
status
|
DeviceStatus | None
|
New device status (enabled/disabled). |
None
|
retry_attempts
|
int | None
|
Updated retry attempt count. |
None
|
retry_delay_seconds
|
float | None
|
Updated retry delay in seconds. |
None
|
Returns:
| Type | Description |
|---|---|
Device
|
The updated device. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If attempting to change the URL of an enabled device. |
NoDeviceFoundError
|
If no device with the given name exists. |
Source code in src/icon/server/data_access/repositories/device_repository.py
experiment_data_repository
¶
DEFAULT_MAX_TRANSFER_BYTES
module-attribute
¶
Approximate cap on the serialised payload of one data request.
MOST_RECENT_JOB_RUNS
module-attribute
¶
How many of the newest job runs to search when no job is specified.
ExperimentDataRepository
¶
Repository for HDF5-based experiment data.
Manages HDF5 file creation and updates (metadata, results, parameters), with hdf5-level locking to support concurrent writers.
Initialize the data container for a new job by calling :meth:initialize_for_job_id.
Initialization is required before any read/write operation is triggered.
get_experiment_data_by_job_id
staticmethod
¶
get_experiment_data_by_job_id(
*,
job_id: int,
max_transfer_bytes: int = DEFAULT_MAX_TRANSFER_BYTES,
include_hardware_instructions: bool = False,
include_all_shots: bool = False,
) -> ExperimentData
Load stored data for a job from its HDF5 file.
When loading all data would exceed max_transfer_bytes, only the last N data points that fit within the budget are returned. The budget is estimated from HDF5 metadata (channel count, shots per channel) without reading actual data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
max_transfer_bytes
|
int
|
Approximate cap on the serialised payload size in bytes. Defaults to 4 MB. |
DEFAULT_MAX_TRANSFER_BYTES
|
include_hardware_instructions
|
bool
|
If True, load |
False
|
include_all_shots
|
bool
|
If True, return the raw shots of every data point. Defaults to False, which returns only the newest data point’s shots. |
False
|
Returns:
| Type | Description |
|---|---|
ExperimentData
|
Experiment data payload suitable for the API. |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
get_hardware_instructions
staticmethod
¶
Return stored hardware instructions (the serialized sequence JSON).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int | None
|
Job to read from. Defaults to the most recent job with
stored hardware instructions, looking no further back than the
|
None
|
index
|
int | None
|
Data point index within the job. Defaults to the last stored entry. Instructions are stored deduplicated (one entry per change), so the entry active at index is returned. |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
The serialized hardware instructions, or None when nothing is |
str | None
|
stored for the requested scope. |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
initialize_for_job_id
staticmethod
¶
initialize_for_job_id(*, job_id: int) -> None
Create the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
update_metadata_by_job_id
staticmethod
¶
update_metadata_by_job_id(
*,
job_id: int,
number_of_shots: int,
repetitions: int,
readout_metadata: ReadoutMetadata,
local_parameter_timestamp: datetime | None = None,
parameters: list[ScanParameter] | None = None,
) -> None
Create or update HDF5 metadata for a job.
Initializes datasets, sets file-level attributes, and stores plot window metadata for result/shot/vector channels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
number_of_shots
|
int
|
Shots per data point. |
required |
repetitions
|
int
|
Number of repetitions. |
required |
readout_metadata
|
ReadoutMetadata
|
Plot/window/channel metadata. |
required |
local_parameter_timestamp
|
datetime | None
|
Optional timestamp for local parameters. |
None
|
parameters
|
list[ScanParameter] | None
|
Scan parameters. |
None
|
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_experiment_data_by_job_id
staticmethod
¶
write_experiment_data_by_job_id(
*, job_id: int, data_point: ExperimentDataPoint
) -> None
Append a complete data point to the HDF5 file and emit an event.
Writes scan parameters, result/shot/vector channels, and hardware instructions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
data_point
|
ExperimentDataPoint
|
Data point payload to append. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_parameter_update_by_job_id
staticmethod
¶
write_parameter_update_by_job_id(
*,
job_id: int,
timestamp: str,
parameter_values: dict[str, str | int | float | bool],
) -> None
Append parameter updates under the ‘parameters’ group.
Appends only when the value changed from the last entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
timestamp
|
str
|
ISO timestamp string. |
required |
parameter_values
|
dict[str, str | int | float | bool]
|
Mapping of parameter id to value. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
HDF5FileMode
¶
Bases: StrEnum
HDF5 File modes - see https://docs.h5py.org/en/stable/high/file.html#opening-creating-files.
CREATE_OR_FAIL
class-attribute
instance-attribute
¶
Create file, fail if exists
CREATE_OR_TRUNCATE
class-attribute
instance-attribute
¶
Create file, truncate if exists
READ_WRITE_OR_CREATE
class-attribute
instance-attribute
¶
Read/write if exists, create otherwise
READ_WRITE_OR_FAIL
class-attribute
instance-attribute
¶
Read/write, fail if not exists
delete_fit_result_by_job_id
¶
Delete a fit result for a specific channel from the HDF5 file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
result_channel
|
str
|
Name of the result channel whose fit to delete. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
estimate_bytes_per_data_point
¶
estimate_bytes_per_data_point(
total: int,
shot_channels_group: Group | None,
result_channel_dataset: Group | None,
vector_channels_group: Group | None,
scan_parameters: Dataset | None,
) -> int
Estimate bytes per data point from HDF5 metadata.
Return total number of data points in h5file and estimated bytes per data point.
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
get_filename_by_job_id
¶
get_fit_results_by_job_id
¶
Read all fit results for a job from its HDF5 file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, FitResult]
|
Dict mapping result channel names to their fit result dicts. |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
get_hdf5_dtype
¶
Return the HDF5-compatible dtype.
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
get_result_channels_dataset
¶
get_result_channels_dataset(
h5file: File,
result_channels: list[str],
number_of_data_points: int = 0,
) -> Dataset
Return the ‘result_channels’ dataset, creating it if it does not exist yet.
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
h5_open
¶
h5_open(
path: Path,
mode: HDF5FileMode,
*,
timeout: float | None = None,
**kwargs: Any,
) -> Generator[File]
Open an HDF5 file under a process-wide per-file lock.
Opens of the same file are serialised within this process by a per-file lock; different files proceed in parallel. The OS-native HDF5 lock may still be held by another process, in which case the open is retried with a capped backoff. Every other failure is permanent and raised immediately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Path of the HDF5 file. |
required |
mode
|
HDF5FileMode
|
Mode passed to |
required |
timeout
|
float | None
|
Seconds to wait in total, for the in-process lock and the file
lock together. Defaults to |
None
|
kwargs
|
Any
|
Additional arguments passed to |
{}
|
Yields:
| Type | Description |
|---|---|
Generator[File]
|
The open |
Raises:
| Type | Description |
|---|---|
TimeoutError
|
The file could not be opened within |
OSError
|
The file could not be opened for any other reason. |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
load_experiment_data
¶
load_experiment_data(
h5file: File,
max_transfer_bytes: int = DEFAULT_MAX_TRANSFER_BYTES,
*,
include_hardware_instructions: bool = False,
include_all_shots: bool = False,
) -> ExperimentData
Load stored data for a job from its HDF5 file.
When loading all data would exceed max_transfer_bytes, only the last N data points that fit within the budget are returned. The budget is estimated from HDF5 metadata (channel count, shots per channel) without reading actual data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
File to load from. |
required |
max_transfer_bytes
|
int
|
Approximate cap on the serialised payload size in bytes. Defaults to 4 MB. |
DEFAULT_MAX_TRANSFER_BYTES
|
include_hardware_instructions
|
bool
|
Whether to include hardware instructions. |
False
|
include_all_shots
|
bool
|
If True, return the raw shots of every data point. Defaults to False, which returns only the newest data point’s shots. |
False
|
Returns:
| Type | Description |
|---|---|
ExperimentData
|
Experiment data payload suitable for the API. |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | |
resize_dataset
¶
Resize a dataset to accommodate writing at a target index.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
Dataset
|
HDF5 dataset to resize. |
required |
next_index
|
int
|
Index that must be writable. |
required |
axis
|
int
|
Axis along which to grow. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_fit_result_by_job_id
¶
write_fit_result_by_job_id(
*, job_id: int, fit_result: FitResult
) -> None
Write a fit result into the HDF5 file for a job.
Creates or overwrites the fits/<result_channel> group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
fit_result
|
FitResult
|
The fit result to persist. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_hardware_instructions_to_dataset
¶
write_hardware_instructions_to_dataset(
h5file: File,
data_point_index: int,
hardware_instructions: str,
) -> None
Append hardware instructions if it changed since the last entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Open HDF5 file handle. |
required |
data_point_index
|
int
|
Index of the current data point. |
required |
hardware_instructions
|
str
|
Serialized hardware instructions to append. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_results_to_dataset
¶
write_results_to_dataset(
h5file: File,
data_point_index: int,
result_channels: dict[str, float],
number_of_data_points: int,
) -> None
Write scalar result channels into the ‘result_channels’ dataset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Open HDF5 file handle. |
required |
data_point_index
|
int
|
Index of the current data point. |
required |
result_channels
|
dict[str, float]
|
Mapping of channel name to float value. |
required |
number_of_data_points
|
int
|
Current total number of stored data points. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_scan_parameters_and_timestamp_to_dataset
¶
write_scan_parameters_and_timestamp_to_dataset(
h5file: File,
data_point_index: int,
scan_params: dict[str, DatabaseValueType],
timestamp: str,
number_of_data_points: int,
) -> None
Write scan parameters and timestamp to the ‘scan_parameters’ dataset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Open HDF5 file handle. |
required |
data_point_index
|
int
|
Index of the current data point. |
required |
scan_params
|
dict[str, DatabaseValueType]
|
Parameter values for this data point. |
required |
timestamp
|
str
|
Acquisition timestamp (ISO string). |
required |
number_of_data_points
|
int
|
Current total number of stored data points. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_shot_channels_to_datasets
¶
write_shot_channels_to_datasets(
h5file: File,
data_point_index: int,
shot_channels: dict[str, list[int]],
number_of_data_points: int,
number_of_shots: int,
) -> None
Write per-shot data into datasets under the ‘shot_channels’ group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Open HDF5 file handle. |
required |
data_point_index
|
int
|
Index of the current data point. |
required |
shot_channels
|
dict[str, list[int]]
|
Mapping of channel to per-shot integers. |
required |
number_of_data_points
|
int
|
Current total number of stored data points. |
required |
number_of_shots
|
int
|
Expected number of shots per channel. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
write_vector_channels_to_datasets
¶
write_vector_channels_to_datasets(
h5file: File,
data_point_index: int,
vector_channels: dict[str, list[float]],
) -> None
Write vector channel data under the ‘vector_channels’ group.
Creates one dataset per channel per data point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Open HDF5 file handle. |
required |
data_point_index
|
int
|
Index of the current data point. |
required |
vector_channels
|
dict[str, list[float]]
|
Mapping of channel to vector of floats. |
required |
Source code in src/icon/server/data_access/repositories/experiment_data_repository.py
experiment_source_repository
¶
ExperimentSourceRepository
¶
Repository for ExperimentSource entities.
Provides methods to query and persist experiment sources in the database. Encapsulates the SQLAlchemy session and query logic.
get_or_create_experiment
staticmethod
¶
get_or_create_experiment(
*, experiment_source: ExperimentSource
) -> ExperimentSource
Return an existing experiment source or create it if not found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
experiment_source
|
ExperimentSource
|
The experiment source to look up by |
required |
Returns:
| Type | Description |
|---|---|
ExperimentSource
|
The existing or newly created experiment source. |
Source code in src/icon/server/data_access/repositories/experiment_source_repository.py
job_repository
¶
JobRepository
¶
Repository for Job entities.
Encapsulates SQLAlchemy session/query logic and emits Socket.IO events on changes. All methods open their own session and return detached ORM objects.
get_job_by_experiment_source_and_status
staticmethod
¶
get_job_by_experiment_source_and_status(
*,
experiment_source_id: int,
status: JobStatus | None = None,
) -> Sequence[Row[tuple[Job]]]
List jobs for an experiment source, optionally filtered by status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
experiment_source_id
|
int
|
Foreign key of the experiment source. |
required |
status
|
JobStatus | None
|
Optional status filter. |
None
|
Returns:
| Type | Description |
|---|---|
Sequence[Row[tuple[Job]]]
|
Rows containing |
Source code in src/icon/server/data_access/repositories/job_repository.py
get_job_by_id
staticmethod
¶
get_job_by_id(
*,
job_id: int,
load_experiment_source: bool = False,
load_scan_parameters: bool = False,
) -> Job
Fetch a job by ID with optional eager-loading.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
Job identifier. |
required |
load_experiment_source
|
bool
|
If True, eager-load |
False
|
load_scan_parameters
|
bool
|
If True, eager-load |
False
|
Returns:
| Type | Description |
|---|---|
Job
|
The requested job. |
Source code in src/icon/server/data_access/repositories/job_repository.py
get_job_list
staticmethod
¶
get_job_list(
*,
statuses: Sequence[JobStatus] | None = None,
before_id: int | None = None,
limit: int | None = None,
) -> list[JobListItemDict]
List jobs as lightweight JobListItemDict items.
Pagination is cursor-based on Job.id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statuses
|
Sequence[JobStatus] | None
|
Optional status filter; jobs matching any of the given statuses are returned. |
None
|
before_id
|
int | None
|
Exclusive upper bound on the job ID; pass the lowest ID of the previous page to fetch the next one. |
None
|
limit
|
int | None
|
Maximum number of jobs to return. |
None
|
Returns:
| Type | Description |
|---|---|
list[JobListItemDict]
|
Job list entries ordered by descending job ID. |
Source code in src/icon/server/data_access/repositories/job_repository.py
get_jobs_by_status_and_timeframe
staticmethod
¶
get_jobs_by_status_and_timeframe(
*,
status: JobStatus | None = None,
start: datetime | None = None,
stop: datetime | None = None,
) -> Sequence[Job]
List jobs filtered by status and optional creation time window.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
JobStatus | None
|
Optional status filter. |
None
|
start
|
datetime | None
|
Inclusive start timestamp. |
None
|
stop
|
datetime | None
|
Exclusive stop timestamp. |
None
|
Returns:
| Type | Description |
|---|---|
Sequence[Job]
|
Matching jobs ordered by priority then creation time. |
Source code in src/icon/server/data_access/repositories/job_repository.py
resubmit_job_by_id
staticmethod
¶
Clone an existing job as a new submission.
If the source job is not itself a resubmission, the new job’s parent_job_id is
set to the original job’s id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to clone. |
required |
Returns:
| Type | Description |
|---|---|
Job
|
The newly created job. |
Source code in src/icon/server/data_access/repositories/job_repository.py
submit_job
staticmethod
¶
Insert a new job and emit a creation event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job
|
Job
|
The job instance to persist. |
required |
Returns:
| Type | Description |
|---|---|
Job
|
The persisted job with generated fields populated. |
Source code in src/icon/server/data_access/repositories/job_repository.py
update_job_status
staticmethod
¶
Update a job’s status and emit an update event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to update. |
required |
status
|
JobStatus
|
New job status. |
required |
Returns:
| Type | Description |
|---|---|
Job
|
The updated job with relationships loaded. |
Source code in src/icon/server/data_access/repositories/job_repository.py
job_run_repository
¶
JobRunRepository
¶
Repository for JobRun entities.
Provides methods to update and query job runs from the database. Runs are
created by job_transactions.dispatch_job.
Emits Socket.IO events when job runs are updated.
get_parameter_update_timestamp
staticmethod
¶
Get the paramter update timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
int
|
ID of the job. |
required |
Returns:
| Type | Description |
|---|---|
datetime | None
|
The parameter update timestamp, or None if no parameter update has |
datetime | None
|
been recorded for this run yet. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
get_recent_scheduled_times
staticmethod
¶
Return the scheduled times of the most recent runs, newest first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of scheduled times to return. |
required |
Returns:
| Type | Description |
|---|---|
Sequence[datetime]
|
Scheduled times ordered from newest to oldest. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
get_run_by_job_id
staticmethod
¶
Return the run associated with a given job ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job. |
required |
load_job
|
bool
|
If True, eagerly load the related |
False
|
Returns:
| Type | Description |
|---|---|
JobRun
|
The run linked to the given job. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
get_runs_by_status
staticmethod
¶
get_runs_by_status(
*,
status: JobRunStatus | list[JobRunStatus],
load_job: bool = False,
) -> Sequence[JobRun]
Return job runs filtered by status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
JobRunStatus | list[JobRunStatus]
|
Single or list of run statuses to filter on. |
required |
load_job
|
bool
|
If True, eagerly load the related |
False
|
Returns:
| Type | Description |
|---|---|
Sequence[JobRun]
|
All matching runs. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
get_scheduled_time_by_job_id
staticmethod
¶
Return the scheduled time of a run by job ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job. |
required |
Returns:
| Type | Description |
|---|---|
datetime
|
The scheduled start time of the run. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
set_parameter_update_timestamp
staticmethod
¶
Set the paramter update timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
int
|
ID of the job. |
required |
timestamp
|
datetime
|
New parameter update timestamp. |
required |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
update_run_by_id
staticmethod
¶
update_run_by_id(
*,
run_id: int,
status: JobRunStatus,
log: str | None = None,
only_if_status: Sequence[JobRunStatus] | None = None,
) -> JobRun | None
Update a job run by ID and emit an update event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
int
|
The ID of the job run to update. |
required |
status
|
JobRunStatus
|
New status of the run. |
required |
log
|
str | None
|
Optional log message (e.g. failure reason). |
None
|
only_if_status
|
Sequence[JobRunStatus] | None
|
Apply the update only if current status is in the list. |
None
|
Returns:
| Type | Description |
|---|---|
JobRun | None
|
The updated job run, or None when the current status is non of the |
JobRun | None
|
|
Source code in src/icon/server/data_access/repositories/job_run_repository.py
job_run_cancelled_or_failed
¶
Check if a job’s run was cancelled or failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job whose run should be checked. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the run status is CANCELLED or FAILED, False otherwise. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
run_cancelled_or_failed
¶
Check if an already fetched run was cancelled or failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_run
|
JobRun
|
The run to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the run status is CANCELLED or FAILED, False otherwise. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
try_update_run_by_id
¶
try_update_run_by_id(
*,
run_id: int,
status: JobRunStatus,
log: str | None = None,
only_if_status: Sequence[JobRunStatus] | None = None,
) -> JobRun | None
Update a job run, logging any failure instead of raising.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
int
|
ID of the job run to update. |
required |
status
|
JobRunStatus
|
New status of the run. |
required |
log
|
str | None
|
Optional log message (e.g. failure reason). |
None
|
only_if_status
|
Sequence[JobRunStatus] | None
|
Apply the update only while the stored status is one of
these; see |
None
|
Returns:
| Type | Description |
|---|---|
JobRun | None
|
The updated job run, or None when the update failed or did not apply. |
Source code in src/icon/server/data_access/repositories/job_run_repository.py
job_transactions
¶
LIVE_RUN_STATUSES
module-attribute
¶
LIVE_RUN_STATUSES = (
JobRunStatus.PENDING,
JobRunStatus.PROCESSING,
JobRunStatus.PAUSED,
)
Run states in which a pre-processing worker still owns the job.
cancel_job
¶
cancel_job(
*,
job_id: int,
log: str | None = None,
run_status: JobRunStatus = CANCELLED,
) -> None
Cancel a job and move its run to run_status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to retire. |
required |
run_status
|
JobRunStatus
|
Terminal status to give the run. |
CANCELLED
|
log
|
str | None
|
Reason recorded on the run, if there is one. |
None
|
Source code in src/icon/server/data_access/repositories/job_transactions.py
dispatch_job
¶
Insert a run for a SUBMITTED job and progress it to PROCESSING.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job_id
|
int
|
ID of the job to dispatch. |
required |
Returns:
| Type | Description |
|---|---|
tuple[Job, JobRun] | None
|
The claimed job with its relationships loaded and its new run, or None |
tuple[Job, JobRun] | None
|
when the job is no longer SUBMITTED, i.e. cancelled or processing. |
Source code in src/icon/server/data_access/repositories/job_transactions.py
parameters_repository
¶
NotInitialisedError
¶
Bases: Exception
Raised when repository methods are called before initialization.
ParametersRepository
¶
Repository for parameter values and metadata.
Provides methods to read and update shared parameter state (via a
multiprocessing.Manager dict) and to persist/retrieve parameters from InfluxDB.
Emits Socket.IO events on updates.
get_influxdb_parameter_by_id
classmethod
¶
get_influxdb_parameter_by_id(
parameter_id: str,
) -> DatabaseValueType | None
Return a single parameter value from InfluxDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameter_id
|
str
|
ID of the parameter. |
required |
Returns:
| Type | Description |
|---|---|
DatabaseValueType | None
|
The parameter value, or None if not found. |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
get_influxdb_parameter_keys
classmethod
¶
Return all known parameter identifiers from InfluxDB.
get_influxdb_parameters
classmethod
¶
get_influxdb_parameters(
*,
before: str | None = None,
namespace: str | None = None,
measurement: str | None = None,
) -> dict[str, DatabaseValueType]
Return the latest parameter values from InfluxDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
before
|
str | None
|
Optional ISO timestamp to query parameters before. |
None
|
namespace
|
str | None
|
Optional namespace filter. |
None
|
measurement
|
str | None
|
Optional measurement override; defaults to the active backend’s measurement. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, DatabaseValueType]
|
Mapping of parameter IDs to values. |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
get_shared_parameter_by_id
classmethod
¶
get_shared_parameter_by_id(
*, parameter_id: str
) -> DatabaseValueType | None
Return a single parameter value from shared state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameter_id
|
str
|
ID of the parameter. |
required |
Returns:
| Type | Description |
|---|---|
DatabaseValueType | None
|
The parameter value, or None if not set. |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
get_shared_parameters
classmethod
¶
get_shared_parameters() -> DictProxy[
str, DatabaseValueType
]
Return the full shared parameter dictionary.
Returns:
| Type | Description |
|---|---|
DictProxy[str, DatabaseValueType]
|
Proxy dictionary of parameters. |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
initialize
classmethod
¶
initialize(
*, shared_parameters: DictProxy[str, DatabaseValueType]
) -> None
Initialize the repository with a shared parameters dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shared_parameters
|
DictProxy[str, DatabaseValueType]
|
Proxy dictionary used to store shared state. |
required |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
update_parameters
classmethod
¶
Update parameters in both shared state and InfluxDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parameter_mapping
|
dict[str, DatabaseValueType]
|
Mapping of parameter IDs to values. |
required |
Source code in src/icon/server/data_access/repositories/parameters_repository.py
icon.server.hardware_processing
¶
Modules:
| Name | Description |
|---|---|
devices |
|
hardware_controller |
|
rpc |
|
task |
|
tiqizedboard_controller |
|
utils |
|
worker |
|
zedboard_controller |
|
devices
¶
Classes:
| Name | Description |
|---|---|
Devices |
|
Hardware |
|
Functions:
| Name | Description |
|---|---|
load |
|
Devices
¶
Methods:
| Name | Description |
|---|---|
__getitem__ |
|
items |
|
main_device |
|
reload |
|
retry_disconnected |
|
Source code in src/icon/server/hardware_processing/devices.py
__reloader
instance-attribute
¶
__reloader = DictReloader(
initial_objs=self.__devices,
obj_factory=load,
subconfig=lambda config: {
dev["id"]: dev
for dev in config.hardware.model_dump()["devices"]
},
)
__getitem__
¶
items
¶
main_device
¶
main_device() -> HardwareController
Source code in src/icon/server/hardware_processing/devices.py
reload
¶
reload(*, retry_disconnected: bool = False) -> None
Source code in src/icon/server/hardware_processing/devices.py
Hardware
dataclass
¶
Hardware(
controller: HardwareController | ReloadError,
enabled: bool,
)
load
¶
load(
controller_module: str,
controller_class: str,
id: str,
args: dict[str, Any],
*,
enabled: bool,
) -> Hardware
Source code in src/icon/server/hardware_processing/devices.py
hardware_controller
¶
Classes:
| Name | Description |
|---|---|
FallbackHardwareController |
Noop hardware controller. |
HardwareController |
|
StatusFlag |
|
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
FallbackHardwareController
¶
rpc
¶
Modules:
| Name | Description |
|---|---|
client |
Blocking client for lock-step msgpack-rpc. Only one .call() can be in flight. |
connection |
|
errors |
Exception hierarchy for the RPC client. |
zedboard |
|
client
¶
Blocking client for lock-step msgpack-rpc. Only one .call() can be in flight.
REQUEST := [0, msgid_u32, method: str, params: array] RESPONSE := [1, msgid_u32, error, result] NOTIFICATION := [2, method: str, params]
Classes:
| Name | Description |
|---|---|
MessageType |
First element of every msgpack-rpc message array. |
MsgPackRPCClient |
Blocking msgpack-rpc client, with one request in flight at a time. |
RPCNotification |
A message the server pushed of its own accord, answering no request. |
RPCResponse |
A reply to one request, tied to it by :attr: |
Attributes:
| Name | Type | Description |
|---|---|---|
DEFAULT_LOCK_ACQUSITION_TIME |
Final
|
Default time for a RPC round-trip lock to become available. |
DEFAULT_NOTIFICATION_BUFFER |
Final
|
Notifications retained while nobody polls. Past this the oldest are dropped, which is |
DEFAULT_NOTIFICATION_LIMIT |
Final
|
Default consumption batch size when calling :meth: |
logger |
|
DEFAULT_LOCK_ACQUSITION_TIME
module-attribute
¶
DEFAULT_LOCK_ACQUSITION_TIME: Final = 1.0
Default time for a RPC round-trip lock to become available.
DEFAULT_NOTIFICATION_BUFFER
module-attribute
¶
DEFAULT_NOTIFICATION_BUFFER: Final = 1000
Notifications retained while nobody polls. Past this the oldest are dropped, which is reported once per poll rather than once per message.
DEFAULT_NOTIFICATION_LIMIT
module-attribute
¶
DEFAULT_NOTIFICATION_LIMIT: Final = 100
Default consumption batch size when calling :meth:MsgPackRPCClient.consume_notifications
MessageType
¶
Bases: IntEnum
First element of every msgpack-rpc message array.
Attributes:
| Name | Type | Description |
|---|---|---|
NOTIFICATION |
|
|
REQUEST |
|
|
RESPONSE |
|
MsgPackRPCClient
¶
MsgPackRPCClient(
hostname: str,
port: int,
timeout: float | None = None,
*,
framed: bool = True,
lock_timeout: float = DEFAULT_LOCK_ACQUSITION_TIME,
notification_buffer: int = DEFAULT_NOTIFICATION_BUFFER,
)
Blocking msgpack-rpc client, with one request in flight at a time.
Call :meth:connect to open the connection.
For example::
client = MsgPackRPCClient("localhost", 1234)
client.connect()
print(client.call("hello"))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hostname
|
str
|
Host to connect to. |
required |
port
|
int
|
TCP port to connect to. |
required |
timeout
|
float | None
|
Default timeout for a call, in seconds, counted from when the request is
sent. |
None
|
framed
|
bool
|
Whether to use framed transport, where every message is preceeded with a 4-byte length header. |
True
|
lock_timeout
|
float
|
How long a call waits for another thread’s round trip to finish. |
DEFAULT_LOCK_ACQUSITION_TIME
|
notification_buffer
|
int
|
How many pushed notifications to retain in the buffer. Oldest are dropped first. |
DEFAULT_NOTIFICATION_BUFFER
|
Methods:
| Name | Description |
|---|---|
__repr__ |
|
call |
Invoke a blocking remote function call and return its result. |
connect |
|
consume_notifications |
Return up to |
disconnect |
|
notify |
Send a one-way notification, for which the server sends no reply. |
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
|
Source code in src/icon/server/hardware_processing/rpc/client.py
call
¶
Invoke a blocking remote function call and return its result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method_name
|
str
|
The name of the RPC method to call. |
required |
*args
|
Any
|
Positional arguments passed to the RPC method. |
()
|
timeout
|
float | None
|
Maximum time to wait for a response, in seconds. Uses the client’s default timeout when omitted. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The |
Raises:
| Type | Description |
|---|---|
RPCResponseError
|
If the server answers with an error. |
ProtocolError
|
If the server sends something unreadable. |
TimeoutError
|
If no response arrives within |
ConnectionBusyError
|
If another thread holds the connection. Nothing was sent, so retrying is safe. |
ConnectionError
|
If the connection is not open, or the peer closed it. |
Source code in src/icon/server/hardware_processing/rpc/client.py
connect
¶
consume_notifications
¶
Return up to limit received notifications.
Reads the socket for more only if fewer than limit are already buffered, and
only what has already arrived. A connection busy with a call is not an error here:
that call is reading the same socket and buffers every notification it passes, so
the poll gives up its turn and returns what it has.
Source code in src/icon/server/hardware_processing/rpc/client.py
disconnect
¶
notify
¶
Send a one-way notification, for which the server sends no reply.
Source code in src/icon/server/hardware_processing/rpc/client.py
RPCNotification
dataclass
¶
RPCResponse
dataclass
¶
connection
¶
Classes:
| Name | Description |
|---|---|
Connection |
Blocking connection with a raw msgpack stream. |
FramedConnection |
Connection with framed transport: single msgpack message following a 4-byte length header. |
Transaction |
Exclusive use of a connection for one exchange, under a single deadline. |
Functions:
| Name | Description |
|---|---|
deadline_from |
Compute absolute deadline from timeout. |
time_left |
Compute time left until deadline is reached. |
Attributes:
| Name | Type | Description |
|---|---|---|
DEFAULT_KEEPALIVE_COUNT |
Final
|
|
DEFAULT_KEEPALIVE_IDLE |
Final
|
|
DEFAULT_KEEPALIVE_INTERVAL |
Final
|
|
DEFAULT_MAX_MESSAGE_SIZE |
Final
|
Msgpack maximum message size. |
HEADER_SIZE |
Final
|
|
HEADER_STRUCT |
Final
|
|
MsgPackRecord |
|
|
RECV_CHUNK_SIZE |
Final
|
Socket reads are done in chunks of this size. |
logger |
|
DEFAULT_MAX_MESSAGE_SIZE
module-attribute
¶
DEFAULT_MAX_MESSAGE_SIZE: Final = 256 * 1024 * 1024
Msgpack maximum message size.
RECV_CHUNK_SIZE
module-attribute
¶
RECV_CHUNK_SIZE: Final = 256 * 1024
Socket reads are done in chunks of this size.
Connection
¶
Connection(
hostname: str,
port: int,
*,
timeout: float | None = None,
lock_timeout: float = 1.0,
max_message_size: int = DEFAULT_MAX_MESSAGE_SIZE,
keepalive: bool = True,
keepalive_idle: int = DEFAULT_KEEPALIVE_IDLE,
keepalive_interval: int = DEFAULT_KEEPALIVE_INTERVAL,
keepalive_count: int = DEFAULT_KEEPALIVE_COUNT,
user_timeout: float | None = None,
)
Blocking connection with a raw msgpack stream.
The connection is opened by :meth:connect. Every I/O operation must be wrapped in a
:meth:transaction to be thread-safe.
On any error, the connection is closed. The caller must explicitly re-open with :meth:connect.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hostname
|
str
|
Host to connect to. |
required |
port
|
int
|
TCP port to connect to. |
required |
timeout
|
float | None
|
Default bound in seconds, used for connecting and for any
:meth: |
None
|
lock_timeout
|
float
|
How long :meth: |
1.0
|
max_message_size
|
int
|
Messages larger than this will not be accepted and the connection closed. |
DEFAULT_MAX_MESSAGE_SIZE
|
keepalive
|
bool
|
Enable OS-level TCP keepalive. |
True
|
keepalive_idle
|
int
|
Seconds of inactivity before the first probe. |
DEFAULT_KEEPALIVE_IDLE
|
keepalive_interval
|
int
|
Seconds between probes once they start. |
DEFAULT_KEEPALIVE_INTERVAL
|
keepalive_count
|
int
|
Unanswered probes before the connection is declared dead. |
DEFAULT_KEEPALIVE_COUNT
|
user_timeout
|
float | None
|
Seconds until sent data may go unacknowledged before the kernel
declares the connection dead. Defaults to the full keepalive budget. Applied
on Linux whether or not |
None
|
Methods:
| Name | Description |
|---|---|
__repr__ |
|
connect |
Open the connection, replacing any socket this instance still holds. |
disconnect |
Close the connection. |
locked |
Hold the connection without starting an exchange. |
receive |
Wait for the next message. |
send |
Encode and write one message. |
transaction |
Context manager for owning the connection for one exchange. |
try_receive |
Non-blocking variant of :meth: |
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Check if the socket is up. |
Source code in src/icon/server/hardware_processing/rpc/connection.py
is_connected
property
¶
is_connected: bool
Check if the socket is up.
Reports False if FIN or RST was received. Idle or dead connections will report as connected until keepalive timeout is reached (if configured).
connect
¶
Open the connection, replacing any socket this instance still holds.
Idempotent, and the only way a socket is ever installed. Any previous socket is closed and the decoder is reset first, so no bytes left over from a dead stream can be spliced onto the new one and no file descriptor is orphaned.
Source code in src/icon/server/hardware_processing/rpc/connection.py
disconnect
¶
locked
¶
locked() -> Generator[None]
Hold the connection without starting an exchange.
For operations that must not interleave with a round trip but send nothing themselves, such as reconnecting.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
if the connection lock could not be acquired within
|
Source code in src/icon/server/hardware_processing/rpc/connection.py
receive
¶
receive(timeout: float | None = None) -> MsgPackRecord
Wait for the next message.
Blocks until full message is received, potentially over multiple reads.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Seconds to wait for a whole message, potentially over multiple reads.
|
None
|
Returns:
| Type | Description |
|---|---|
MsgPackRecord
|
The unpacked opaque message. |
Raises:
| Type | Description |
|---|---|
ProtocolError
|
If the bytes cannot belong to a valid msgpack stream. |
TimeoutError
|
If no complete message arrives in time. |
ConnectionError
|
If the peer closed the connection. |
Source code in src/icon/server/hardware_processing/rpc/connection.py
send
¶
send(message: MsgPackRecord) -> None
transaction
¶
transaction(
timeout: float | None = None,
) -> Generator[Transaction]
Context manager for owning the connection for one exchange.
Blocks at most lock_timeout seconds on the connection lock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Total time limit for the transaction to complete.
|
None
|
Yields:
| Name | Type | Description |
|---|---|---|
A |
Generator[Transaction]
|
class: |
A failed exchange closes the connection but never re-opens it. Once a read has
timed out or the framing has desynced, the bytes still in flight belong to a
request nobody is waiting for, so the stream cannot be reused – but reconnecting
here would do it silently, behind a caller that may have session state to
re-establish (discovered ids, subscriptions) and no way to notice it must. So the
socket is dropped, :attr:is_connected goes false, and reconnecting is the
caller’s decision.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
if the connection lock could not be acquired within
|
Source code in src/icon/server/hardware_processing/rpc/connection.py
try_receive
¶
try_receive() -> MsgPackRecord | None
Non-blocking variant of :meth:receive. Suitable for polling.
Consumes what the decoder already holds, plus whatever bytes are readable right now. A message that has only partly arrived stays buffered for the next call, so this never waits on the peer.
Source code in src/icon/server/hardware_processing/rpc/connection.py
FramedConnection
¶
Bases: Connection
Connection with framed transport: single msgpack message following a 4-byte length header.
Bytes are accumulated in one buffer that both the blocking and the polling read path draw on, so a frame that arrives in pieces is never half-consumed by a poll.
Methods:
| Name | Description |
|---|---|
__repr__ |
|
connect |
Open the connection, replacing any socket this instance still holds. |
disconnect |
Close the connection. |
locked |
Hold the connection without starting an exchange. |
receive |
Wait for the next message. |
send |
Override for the framed decode case. Prepend message with length header. |
transaction |
Context manager for owning the connection for one exchange. |
try_receive |
|
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Check if the socket is up. |
Source code in src/icon/server/hardware_processing/rpc/connection.py
is_connected
property
¶
is_connected: bool
Check if the socket is up.
Reports False if FIN or RST was received. Idle or dead connections will report as connected until keepalive timeout is reached (if configured).
connect
¶
Open the connection, replacing any socket this instance still holds.
Idempotent, and the only way a socket is ever installed. Any previous socket is closed and the decoder is reset first, so no bytes left over from a dead stream can be spliced onto the new one and no file descriptor is orphaned.
Source code in src/icon/server/hardware_processing/rpc/connection.py
disconnect
¶
locked
¶
locked() -> Generator[None]
Hold the connection without starting an exchange.
For operations that must not interleave with a round trip but send nothing themselves, such as reconnecting.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
if the connection lock could not be acquired within
|
Source code in src/icon/server/hardware_processing/rpc/connection.py
receive
¶
receive(timeout: float | None = None) -> MsgPackRecord
Wait for the next message.
Blocks until full message is received, potentially over multiple reads.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Seconds to wait for a whole message, potentially over multiple reads.
|
None
|
Returns:
| Type | Description |
|---|---|
MsgPackRecord
|
The unpacked opaque message. |
Raises:
| Type | Description |
|---|---|
ProtocolError
|
If the bytes cannot belong to a valid msgpack stream. |
TimeoutError
|
If no complete message arrives in time. |
ConnectionError
|
If the peer closed the connection. |
Source code in src/icon/server/hardware_processing/rpc/connection.py
send
¶
send(message: MsgPackRecord) -> None
Override for the framed decode case. Prepend message with length header.
Source code in src/icon/server/hardware_processing/rpc/connection.py
transaction
¶
transaction(
timeout: float | None = None,
) -> Generator[Transaction]
Context manager for owning the connection for one exchange.
Blocks at most lock_timeout seconds on the connection lock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Total time limit for the transaction to complete.
|
None
|
Yields:
| Name | Type | Description |
|---|---|---|
A |
Generator[Transaction]
|
class: |
A failed exchange closes the connection but never re-opens it. Once a read has
timed out or the framing has desynced, the bytes still in flight belong to a
request nobody is waiting for, so the stream cannot be reused – but reconnecting
here would do it silently, behind a caller that may have session state to
re-establish (discovered ids, subscriptions) and no way to notice it must. So the
socket is dropped, :attr:is_connected goes false, and reconnecting is the
caller’s decision.
Raises:
| Type | Description |
|---|---|
ConnectionBusyError
|
if the connection lock could not be acquired within
|
Source code in src/icon/server/hardware_processing/rpc/connection.py
try_receive
¶
try_receive() -> MsgPackRecord | None
Source code in src/icon/server/hardware_processing/rpc/connection.py
Transaction
¶
Transaction(connection: Connection, deadline: float | None)
Exclusive use of a connection for one exchange, under a single deadline.
Handed out by :meth:Connection.transaction, which holds the connection’s lock for as
long as this object is in scope. Every read draws on the same budget, so a reply
arriving behind a burst of notifications still cannot outlive the caller’s timeout –
and no call site has to do the arithmetic. That is the point of the object: the
deadline is derived once, here, and no absolute time ever crosses the boundary.
Methods:
| Name | Description |
|---|---|
receive |
Wait for the next message, within what is left of the budget. |
send |
Encode and write one message. |
try_receive |
Return the next message if one is already available, else |
Source code in src/icon/server/hardware_processing/rpc/connection.py
receive
¶
receive() -> MsgPackRecord
send
¶
send(message: MsgPackRecord) -> None
try_receive
¶
try_receive() -> MsgPackRecord | None
Return the next message if one is already available, else None.
Spends none of the budget, because it never waits.
deadline_from
¶
time_left
¶
Compute time left until deadline is reached.
Returns:
| Type | Description |
|---|---|
float | None
|
Remaining time in seconds. Always positive. |
Raises:
| Type | Description |
|---|---|
TimeoutError
|
If |
Source code in src/icon/server/hardware_processing/rpc/connection.py
errors
¶
Exception hierarchy for the RPC client.
Classes:
| Name | Description |
|---|---|
ConnectionBusyError |
The thread lock could not be acquired within |
ProtocolError |
A server message could not be decoded. |
RPCError |
Base class for every error this package defines. |
RPCResponseError |
The server answered a request with a non- |
ConnectionBusyError
¶
Bases: RPCError, TimeoutError
The thread lock could not be acquired within lock_timeout.
ProtocolError
¶
Bases: RPCError
A server message could not be decoded.
This error is fatal to the connection as it otherwise lead to desynchronization between client and server. Recover by opening the connection again.
RPCResponseError
¶
Bases: RPCError
The server answered a request with a non-nil error field.
The payload has the form [code, "message"].
:func:icon.server.hardware_processing.utils.extract_hardware_error_message parses the
error: prefix to pull the hardware message out for
hardware_processing/worker.py, so it must not change without updating that helper.
Attributes:
| Name | Type | Description |
|---|---|---|
error |
|
|
msgid |
|
Source code in src/icon/server/hardware_processing/rpc/errors.py
zedboard
¶
Classes:
| Name | Description |
|---|---|
ExperimentResult |
|
Zedboard |
Direct RPC interface to the legacy experiment runtime on the Zedboard. |
ZedboardError |
The device is configured differently than the client expects. |
ZedboardSeqRunner |
Representation of the Sequence Runner Experiment on the Zedboard. |
ZedboardSeqRunnerCached |
Cached variant of ZedboardSeqRunner. |
Attributes:
| Name | Type | Description |
|---|---|---|
PageDescr |
|
|
ParamDescr |
|
|
ParamVal |
|
|
logger |
|
ParamDescr
module-attribute
¶
ExperimentResult
dataclass
¶
ExperimentResult(
result_channels: dict[str, float] = dict(),
vector_channels: dict[str, list[float]] = dict(),
shot_channels: dict[str, list[int]] = dict(),
)
Zedboard
¶
Direct RPC interface to the legacy experiment runtime on the Zedboard.
Provides typed stateless methods for the following operations * read pages, parameters, channels, and remote action. * write parameters and invoke remote actions. * execute experiment with channel name resolution
Intended to serve as a base class for specialized clients on top of the experiment runtime.
Note: This is a compatibility module for the legacy Zedboard controller interface. The interface is deprecated and will be replaced in the future.
Methods:
| Name | Description |
|---|---|
__enter__ |
|
__exit__ |
|
__repr__ |
|
call_remote_action |
Call remote action by page id and action id. See :meth: |
connect |
Establish a connection to the Zedboard. |
disconnect |
|
get_data_channels |
Returns list of data channel names for the page. |
get_pages |
Returns page list. Position in the list is the page’s id. |
get_params |
Returns global parameter list. |
get_remote_actions |
Returns list of remote action names for the page. Position in the list is the action’s id. |
get_shot_channels |
Returns list of shot channel names for the page. |
get_vector_channels |
Returns list of vector channel names for the page. |
run_experiment |
Run the experiment corresponding to the page. |
set_param |
|
set_params |
Write several parameters in one round trip. |
set_ttl_mask |
Set TTL |
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Whether the underlying socket is up. |
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
__exit__
¶
__exit__(
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None
call_remote_action
¶
Call remote action by page id and action id. See :meth:get_remote_actions.
connect
¶
Establish a connection to the Zedboard.
Raises:
| Type | Description |
|---|---|
ConnectionRefusedError
|
if the peer does not accept the connection. Probably not listening. |
OSError
|
if the host cannot be reached or resolved. |
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
disconnect
¶
get_data_channels
¶
get_pages
¶
get_params
¶
get_params() -> list[ParamDescr]
get_remote_actions
¶
Returns list of remote action names for the page. Position in the list is the action’s id.
get_shot_channels
¶
get_vector_channels
¶
run_experiment
¶
run_experiment(page_id: int) -> ExperimentResult
Run the experiment corresponding to the page.
Channel names are resolved dynamically. This is required for experiments which build their channels dynamically (like the sequence runner experiment).
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
set_param
¶
set_params
¶
Write several parameters in one round trip.
set_ttl_mask
¶
ZedboardError
¶
Bases: RPCError
The device is configured differently than the client expects.
When reading and evaluating server state like page, parameter or remote action this error indicates unexpected results mich may indicate misconfiguration.
ZedboardSeqRunner
¶
Bases: Zedboard
Representation of the Sequence Runner Experiment on the Zedboard.
On connect, the necessary configuration values for a sequence run are discovered once.
Usage:
zedboard = ZedboardSeqRunner(hostname="localhost", port=6000)
zedboard.connect()
The following steps are required for each sequence run:
zedboard.load_sequence(seq_json)
res = zedboard.run_sequence()
Methods:
| Name | Description |
|---|---|
__enter__ |
|
__exit__ |
|
__repr__ |
|
call_remote_action |
Call remote action by page id and action id. See :meth: |
connect |
Connect to the device and discover configuration values. |
disconnect |
|
get_data_channels |
Returns list of data channel names for the page. |
get_pages |
Returns page list. Position in the list is the page’s id. |
get_params |
Returns global parameter list. |
get_remote_actions |
Returns list of remote action names for the page. Position in the list is the action’s id. |
get_shot_channels |
Returns list of shot channel names for the page. |
get_vector_channels |
Returns list of vector channel names for the page. |
load_sequence |
Transmit the sequence description to the device. |
run_experiment |
Run the experiment corresponding to the page. |
run_sequence |
Execute the experiment, fetch the channel names and map the result data to the channels. |
set_param |
|
set_params |
Write several parameters in one round trip. |
set_ttl_mask |
Set TTL |
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Whether the underlying socket is up. |
is_ready |
bool
|
Whether the socket is up and discovery has completed. |
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
__exit__
¶
__exit__(
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None
call_remote_action
¶
Call remote action by page id and action id. See :meth:get_remote_actions.
connect
¶
disconnect
¶
get_data_channels
¶
get_pages
¶
get_params
¶
get_params() -> list[ParamDescr]
get_remote_actions
¶
Returns list of remote action names for the page. Position in the list is the action’s id.
get_shot_channels
¶
get_vector_channels
¶
run_experiment
¶
run_experiment(page_id: int) -> ExperimentResult
Run the experiment corresponding to the page.
Channel names are resolved dynamically. This is required for experiments which build their channels dynamically (like the sequence runner experiment).
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
run_sequence
¶
run_sequence() -> ExperimentResult
Execute the experiment, fetch the channel names and map the result data to the channels.
set_param
¶
set_params
¶
Write several parameters in one round trip.
set_ttl_mask
¶
ZedboardSeqRunnerCached
¶
Bases: ZedboardSeqRunner
Cached variant of ZedboardSeqRunner.
By default, the run_experiment routine fetches the channel names after every experiment run. This is because the channel names are not known a priori as they are built according to the instructions in the sequence description. This Sequence Runner infers the channel names from the sequence description and allows to retrieve the channel names directly from the cache. This avoids three round trips to the device for querying the individual channel names. The assumption is that three round trips takes longer than decoding the sequence description.
Usage:
Identical to :class:ZedboardSeqRunner
Classes:
| Name | Description |
|---|---|
ChannelTypes |
Channel types as defined in the sequence description with the {ChannelTypes}_channel_names key. |
Methods:
| Name | Description |
|---|---|
__enter__ |
|
__exit__ |
|
__repr__ |
|
call_remote_action |
Call remote action by page id and action id. See :meth: |
connect |
Connect to the device and discover configuration values. |
disconnect |
|
get_data_channels |
Returns list of data channel names for the page. |
get_pages |
Returns page list. Position in the list is the page’s id. |
get_params |
Returns global parameter list. |
get_remote_actions |
Returns list of remote action names for the page. Position in the list is the action’s id. |
get_shot_channels |
Returns list of shot channel names for the page. |
get_vector_channels |
Returns list of vector channel names for the page. |
load_sequence |
Update the cache with the new sequence description. |
run_experiment |
Run the experiment corresponding to the page. |
run_sequence |
Execute the experiment, fetch the channel names and map the result data to the channels. |
set_param |
|
set_params |
Write several parameters in one round trip. |
set_ttl_mask |
Set TTL |
Attributes:
| Name | Type | Description |
|---|---|---|
is_connected |
bool
|
Whether the underlying socket is up. |
is_ready |
bool
|
Whether the socket is up and discovery has completed. |
marker |
|
|
marker_len |
|
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
ChannelTypes
¶
__exit__
¶
__exit__(
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None
call_remote_action
¶
Call remote action by page id and action id. See :meth:get_remote_actions.
connect
¶
disconnect
¶
get_data_channels
¶
get_pages
¶
get_params
¶
get_params() -> list[ParamDescr]
get_remote_actions
¶
Returns list of remote action names for the page. Position in the list is the action’s id.
get_shot_channels
¶
get_vector_channels
¶
load_sequence
¶
load_sequence(sequence_json: str) -> None
Update the cache with the new sequence description.
run_experiment
¶
run_experiment(page_id: int) -> ExperimentResult
Run the experiment corresponding to the page.
Channel names are resolved dynamically. This is required for experiments which build their channels dynamically (like the sequence runner experiment).
Source code in src/icon/server/hardware_processing/rpc/zedboard.py
run_sequence
¶
run_sequence() -> ExperimentResult
Execute the experiment, fetch the channel names and map the result data to the channels.
set_param
¶
set_params
¶
Write several parameters in one round trip.
set_ttl_mask
¶
task
¶
Classes:
| Name | Description |
|---|---|
HardwareProcessingTask |
|
HardwareProcessingTask
¶
Bases: BaseModel
Methods:
| Name | Description |
|---|---|
__lt__ |
|
Attributes:
| Name | Type | Description |
|---|---|---|
created |
datetime
|
|
data_point_index |
int
|
|
global_parameter_timestamp |
datetime
|
|
hardware_instructions |
str
|
|
model_config |
|
|
outdated_tasks |
PriorityQueue[HardwareProcessingTask]
|
|
pre_processing_task |
PreProcessingTask
|
|
priority |
int
|
|
scan_progress |
ScanProgress
|
|
scanned_params |
dict[str, DatabaseValueType]
|
|
src_dir |
str | None
|
|
model_config
class-attribute
instance-attribute
¶
model_config = pydantic.ConfigDict(
arbitrary_types_allowed=True
)
__lt__
¶
__lt__(other: HardwareProcessingTask) -> bool
tiqizedboard_controller
¶
Classes:
| Name | Description |
|---|---|
ZedboardController |
Zedboard Hardware Controller relying on the tiqi_zedboard client. |
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
ZedboardController
¶
Bases: HardwareController
Zedboard Hardware Controller relying on the tiqi_zedboard client.
Initialise the controller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Hostname of the Zedboard. |
required |
port
|
int
|
Port the Zedboard RPC server listens on. |
required |
timeout
|
int
|
RPC timeout in seconds for calls such as runExperiment. Configurable in the config file. |
5
|
Methods:
| Name | Description |
|---|---|
connect |
|
receive |
|
run |
|
send |
|
status |
|
Attributes:
| Name | Type | Description |
|---|---|---|
connected |
bool
|
|
Source code in src/icon/server/hardware_processing/tiqizedboard_controller.py
connect
¶
Source code in src/icon/server/hardware_processing/tiqizedboard_controller.py
receive
¶
Source code in src/icon/server/hardware_processing/tiqizedboard_controller.py
run
¶
utils
¶
Functions:
| Name | Description |
|---|---|
extract_hardware_error_message |
Extract the error message from a hardware exception. |
extract_hardware_error_message
¶
Extract the error message from a hardware exception.
tiqi_rpc wraps hardware errors as::
RPCResponseError("Server reported msgid <N> error: [<code>, '<message>']")
This strips the RPC wrapper and the error-code list, returning just the hardware message. For any other exception the full string is returned.
Source code in src/icon/server/hardware_processing/utils.py
worker
¶
Classes:
| Name | Description |
|---|---|
HardwareProcessingWorker |
|
Functions:
| Name | Description |
|---|---|
parse_parameter_id |
Parses a parameter ID string into a device name and variable ID. |
should_divert_task |
Whether the hardware worker should divert a task back to pre-processing. |
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
|
timezone |
|
HardwareProcessingWorker
¶
HardwareProcessingWorker(
hardware_processing_queue: PriorityQueue[
HardwareProcessingTask
],
post_processing_queue: Queue[PostProcessingTask],
manager: SharedResourceManager,
devices: Devices,
)
Bases: Process
Methods:
| Name | Description |
|---|---|
run |
|
Source code in src/icon/server/hardware_processing/worker.py
run
¶
Source code in src/icon/server/hardware_processing/worker.py
parse_parameter_id
¶
Parses a parameter ID string into a device name and variable ID.
If the input string is in the format “Device(device_name) variable_id”, the device name and variable ID are returned as a tuple.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
param_id
|
str
|
The parameter identifier string. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
A tuple (device_name, variable_id). If the input does not match the expected |
str
|
format, device_name is None and the entire param_id is returned as the |
tuple[str | None, str]
|
variable_id. |
Examples:
Source code in src/icon/server/hardware_processing/worker.py
should_divert_task
¶
should_divert_task(
task: HardwareProcessingTask,
parameter_update_timestamp: datetime | None,
job_run_status: JobRunStatus,
) -> bool
Whether the hardware worker should divert a task back to pre-processing.
A paused job always diverts. Otherwise a task is diverted when its parameters went stale (it was built before the last parameter update) – except for realtime scans, whose sequences the realtime handler regenerates in place, so diverting a stale realtime task would just bounce it back and forth in a tight loop.
parameter_update_timestamp is stored without timezone info (as UTC), so it is
made timezone-aware before comparing with the task’s timezone-aware created.
Source code in src/icon/server/hardware_processing/worker.py
zedboard_controller
¶
Classes:
| Name | Description |
|---|---|
ZedboardController |
Zedboard Hardware Controller using a stripped-down minimal Zedboard-compatible RPC client. |
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
ZedboardController
¶
Bases: HardwareController
Zedboard Hardware Controller using a stripped-down minimal Zedboard-compatible RPC client.
Initialise the controller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host
|
str
|
Hostname of the zedboard. |
required |
port
|
int
|
Port the Zedoard RPC server listens on. |
required |
timeout
|
int
|
RPC timeout in seconds for calls such as runExperiment. Configurable in the config file. |
5
|
cached
|
bool
|
Whether to read the channel names out of the sequence description instead of asking the device for them after every run. Saves three round trips per data point. |
True
|
Methods:
| Name | Description |
|---|---|
connect |
|
receive |
|
run |
The sequence is executed in the :meth: |
send |
|
status |
|
Attributes:
| Name | Type | Description |
|---|---|---|
connected |
bool
|
Zedboard is ready to process sequences. |
Source code in src/icon/server/hardware_processing/zedboard_controller.py
connect
¶
Source code in src/icon/server/hardware_processing/zedboard_controller.py
receive
¶
Source code in src/icon/server/hardware_processing/zedboard_controller.py
run
¶
icon.server.post_processing
¶
Modules:
| Name | Description |
|---|---|
task |
|
worker |
|
task
¶
Classes:
| Name | Description |
|---|---|
PostProcessingTask |
|
PostProcessingTask
¶
Bases: BaseModel
Methods:
| Name | Description |
|---|---|
__lt__ |
|
Attributes:
| Name | Type | Description |
|---|---|---|
created |
datetime
|
|
data_point |
ExperimentDataPoint
|
|
pre_processing_task |
PreProcessingTask
|
|
priority |
int
|
|
src_dir |
str | None
|
|
__lt__
¶
__lt__(other: PostProcessingTask) -> bool
worker
¶
Classes:
| Name | Description |
|---|---|
PostProcessingWorker |
|
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
PostProcessingWorker
¶
PostProcessingWorker(
post_processing_queue: Queue[PostProcessingTask],
)
Bases: Process
Methods:
| Name | Description |
|---|---|
run |
|
Source code in src/icon/server/post_processing/worker.py
run
¶
Source code in src/icon/server/post_processing/worker.py
icon.server.pre_processing
¶
Modules:
| Name | Description |
|---|---|
task |
|
worker |
|
task
¶
Classes:
| Name | Description |
|---|---|
PreProcessingTask |
|
PreProcessingTask
¶
Bases: BaseModel
Methods:
| Name | Description |
|---|---|
__lt__ |
|
Attributes:
| Name | Type | Description |
|---|---|---|
auto_calibration |
bool
|
|
debug_mode |
bool
|
|
git_commit_hash |
str | None
|
|
job |
Job
|
|
job_run |
JobRun
|
|
local_parameters_timestamp |
str
|
|
model_config |
|
|
priority |
int
|
|
repetitions |
int
|
|
scan_parameters |
list[ScanParameter]
|
|
model_config
class-attribute
instance-attribute
¶
model_config = pydantic.ConfigDict(
arbitrary_types_allowed=True
)
__lt__
¶
__lt__(other: PreProcessingTask) -> bool
worker
¶
Classes:
| Name | Description |
|---|---|
ExperimentIdentifier |
|
ParamUpdateMode |
|
PreProcessingWorker |
|
Functions:
| Name | Description |
|---|---|
change_process_priority |
Changes process priority. |
clear_queue |
|
consume_queue |
|
create_hardware_instructions |
|
freeze_dict |
|
get_scan_combinations |
Generates all combinations of scan parameters for a given job. |
is_global_parameter |
Whether a parameter is a global one rather than scoped to an experiment. |
parameter_namespace |
Return the namespace a parameter identifier is scoped to (empty if it has none). |
parse_experiment_identifier |
Parses an experiment identifier. |
Attributes:
| Name | Type | Description |
|---|---|---|
GLOBAL_NAMESPACE_SEGMENT |
Module path segment identifying the experiment library’s global parameters. |
|
SCAN_COMPLETION_POLL_INTERVAL |
Seconds to wait between completion checks once every data point of a regular scan |
|
ScanCombination |
|
|
T |
|
|
logger |
|
|
timezone |
|
GLOBAL_NAMESPACE_SEGMENT
module-attribute
¶
Module path segment identifying the experiment library’s global parameters.
pycrystal derives a parameter’s namespace from where it is declared: a parameter
declared inside an experiment instance gets <module>.<ClassName>.<instance name>
Global parameters live in the library’s globals package, e.g.
experiment_library.globals.global_parameters.
SCAN_COMPLETION_POLL_INTERVAL
module-attribute
¶
Seconds to wait between completion checks once every data point of a regular scan has been handed to the hardware worker.
ExperimentIdentifier
dataclass
¶
Methods:
| Name | Description |
|---|---|
__str__ |
|
from_str |
Parses an experiment identifier. |
Attributes:
| Name | Type | Description |
|---|---|---|
class_name |
str
|
Experiment class name (e.g. ‘ClassName’) |
instance_name |
str
|
Experiment instance name (e.g. ‘Instance name’) |
module_name |
str
|
Module path (e.g. ‘experiment_library.experiments.exp_name’) |
instance_name
instance-attribute
¶
instance_name: str
Experiment instance name (e.g. ‘Instance name’)
module_name
instance-attribute
¶
module_name: str
Module path (e.g. ‘experiment_library.experiments.exp_name’)
from_str
classmethod
¶
Parses an experiment identifier.
Returns: - the module path (e.g. ‘experiment_library.experiments.exp_name’) - the experiment class name (e.g. ‘ClassName’) - the experiment instance name (e.g. ‘Instance name’)
Example
“experiment_library.experiments.exp_name.ClassName (Instance name)” -> (“experiment_library.experiments.exp_name”, “ClassName”, “Instance name”)
Source code in src/icon/server/pre_processing/worker.py
ParamUpdateMode
¶
Attributes:
| Name | Type | Description |
|---|---|---|
ALL_FROM_TIMESTAMP |
|
|
ALL_UP_TO_DATE |
|
|
LOCALS_FROM_TS_GLOBALS_LATEST |
|
|
ONLY_NEW_PARAMETERS |
|
PreProcessingWorker
¶
PreProcessingWorker(
worker_number: int,
pre_processing_queue: PriorityQueue[PreProcessingTask],
update_queue: Queue[UpdateQueue],
hardware_processing_queue: PriorityQueue[
HardwareProcessingTask
],
manager: SharedResourceManager,
experiment_library_client: ExperimentLibraryClient,
)
Bases: Process
Methods:
| Name | Description |
|---|---|
run |
|
Source code in src/icon/server/pre_processing/worker.py
run
¶
Source code in src/icon/server/pre_processing/worker.py
change_process_priority
¶
change_process_priority(priority: int) -> None
Changes process priority.
Only superusers can decrease the niceness of a process.
clear_queue
¶
consume_queue
¶
create_hardware_instructions
¶
create_hardware_instructions(
client: ExperimentLibraryClient,
n_shots: int,
parameter_dict: dict[str, DatabaseValueType],
namespace: ExperimentIdentifier,
) -> str
Source code in src/icon/server/pre_processing/worker.py
freeze_dict
¶
freeze_dict(
combination: dict[str, DatabaseValueType],
) -> ScanCombination
get_scan_combinations
¶
Generates all combinations of scan parameters for a given job.
Repeats each combination job.repetitions times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job
|
Job
|
The job containing scan parameters. |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, DatabaseValueType]]
|
A list of dictionaries, where each dictionary represents a combination of |
list[dict[str, DatabaseValueType]]
|
parameter values. |
Source code in src/icon/server/pre_processing/worker.py
is_global_parameter
¶
Whether a parameter is a global one rather than scoped to an experiment.
parameter_namespace
¶
Return the namespace a parameter identifier is scoped to (empty if it has none).
parse_experiment_identifier
¶
Parses an experiment identifier.
Returns: - the module path (e.g. ‘experiment_library.experiments.exp_name’) - the experiment class name (e.g. ‘ClassName’) - the experiment instance name (e.g. ‘Instance name’)
Example
“experiment_library.experiments.exp_name.ClassName (Instance name)” -> (“experiment_library.experiments.exp_name”, “ClassName”, “Instance name”)
Source code in src/icon/server/pre_processing/worker.py
icon.server.scheduler
¶
Modules:
| Name | Description |
|---|---|
scheduler |
|
scheduler
¶
Classes:
| Name | Description |
|---|---|
Scheduler |
|
Functions:
| Name | Description |
|---|---|
initialise_job_tables |
|
should_exit |
|
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
Scheduler
¶
Scheduler(
pre_processing_queue: PriorityQueue[PreProcessingTask],
**kwargs: Any,
)
Bases: Process
Methods:
| Name | Description |
|---|---|
run |
|
Attributes:
| Name | Type | Description |
|---|---|---|
kwargs |
|
Source code in src/icon/server/scheduler/scheduler.py
run
¶
Source code in src/icon/server/scheduler/scheduler.py
initialise_job_tables
¶
Source code in src/icon/server/scheduler/scheduler.py
icon.server.utils.types
¶
Classes:
| Name | Description |
|---|---|
UpdateQueue |
|
UpdateQueue
¶
Bases: TypedDict
Attributes:
| Name | Type | Description |
|---|---|---|
event |
Literal['update_parameters', 'calibration']
|
|
job_id |
NotRequired[int | None]
|
|
new_parameters |
NotRequired[dict[str, DatabaseValueType]]
|
|
icon.server.web_server
¶
Modules:
| Name | Description |
|---|---|
icon_server |
|
sio_setup |
|
socketio_emit_queue |
|
visualiser |
Serves the sequence-visualizer build under |
icon_server
¶
Classes:
| Name | Description |
|---|---|
IconServer |
|
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
IconServer
¶
Bases: Server
Methods:
| Name | Description |
|---|---|
post_startup |
|
post_startup
async
¶
Source code in src/icon/server/web_server/icon_server.py
sio_setup
¶
Classes:
| Name | Description |
|---|---|
AsyncServer |
|
Functions:
| Name | Description |
|---|---|
device_updates_room |
Construct device update room name for device-specific updates. Broadcast room if device_name is None. |
log_id |
|
patch_sio_setup |
|
setup_sio_events |
|
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
|
pydase_setup_sio_events |
|
pydase_setup_sio_events
module-attribute
¶
pydase_setup_sio_events = (
pydase.server.web_server.sio_setup.setup_sio_events
)
AsyncServer
¶
Bases: AsyncServer
Attributes:
| Name | Type | Description |
|---|---|---|
controlling_sid |
str | None
|
Socketio SID of the client controlling the frontend. |
device_updates_room
¶
Construct device update room name for device-specific updates. Broadcast room if device_name is None.
Source code in src/icon/server/web_server/sio_setup.py
log_id
¶
Source code in src/icon/server/web_server/sio_setup.py
patch_sio_setup
¶
setup_sio_events
¶
setup_sio_events(
sio: AsyncServer, state_manager: StateManager
) -> None
Source code in src/icon/server/web_server/sio_setup.py
socketio_emit_queue
¶
visualiser
¶
Serves the sequence-visualizer build under /visualizer/.
The files in src/icon/server/frontend_visualizer/ are a build of the
ionpulse-sequence-visualiser, produced by the frontend build (see
frontend/README.md).
pydase’s WebServer constructs and runs its aiohttp application inside
serve() without an extension hook, and its catch-all index route swallows
every path. The application object only becomes reachable when serve()
hands it to aiohttp.web._run_app, so IconWebServer wraps that call to
attach a middleware which serves the visualizer files before route handlers
run.
Classes:
| Name | Description |
|---|---|
IconWebServer |
pydase |
Functions:
| Name | Description |
|---|---|
patch_web_server |
Make |
visualiser_middleware |
|
Attributes:
| Name | Type | Description |
|---|---|---|
DIST_DIR |
|
|
URL_PREFIX |
|
DIST_DIR
module-attribute
¶
DIST_DIR = (
Path(__file__).parent.parent / "frontend_visualizer"
).resolve()
IconWebServer
¶
Bases: WebServer
pydase WebServer that additionally serves the sequence visualizer.
Methods:
| Name | Description |
|---|---|
serve |
|
serve
async
¶
Source code in src/icon/server/web_server/visualiser.py
patch_web_server
¶
Make pydase.Server instantiate :class:IconWebServer.