iqm-station-control-client 8.1.0__py3-none-any.whl → 9.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. iqm/station_control/client/__init__.py +1 -1
  2. iqm/station_control/client/iqm_server/error.py +1 -1
  3. iqm/station_control/client/iqm_server/grpc_utils.py +5 -3
  4. iqm/station_control/client/iqm_server/iqm_server_client.py +276 -45
  5. iqm/station_control/client/list_models.py +18 -12
  6. iqm/station_control/client/serializers/__init__.py +1 -1
  7. iqm/station_control/client/serializers/channel_property_serializer.py +12 -6
  8. iqm/station_control/client/serializers/datetime_serializers.py +1 -1
  9. iqm/station_control/client/serializers/playlist_serializers.py +1 -1
  10. iqm/station_control/client/serializers/run_serializers.py +1 -1
  11. iqm/station_control/client/serializers/setting_node_serializer.py +1 -1
  12. iqm/station_control/client/serializers/struct_serializer.py +1 -1
  13. iqm/station_control/client/serializers/sweep_serializers.py +2 -3
  14. iqm/station_control/client/serializers/task_serializers.py +1 -1
  15. iqm/station_control/client/station_control.py +162 -443
  16. iqm/station_control/client/utils.py +44 -17
  17. iqm/station_control/interface/__init__.py +1 -1
  18. iqm/station_control/interface/list_with_meta.py +1 -1
  19. iqm/station_control/interface/models/__init__.py +13 -1
  20. iqm/station_control/interface/models/dut.py +1 -1
  21. iqm/station_control/interface/models/dynamic_quantum_architecture.py +98 -0
  22. iqm/station_control/interface/models/observation.py +1 -1
  23. iqm/station_control/interface/models/observation_set.py +15 -1
  24. iqm/station_control/interface/models/run.py +1 -1
  25. iqm/station_control/interface/models/sequence.py +1 -1
  26. iqm/station_control/interface/models/static_quantum_architecture.py +40 -0
  27. iqm/station_control/interface/models/sweep.py +1 -1
  28. iqm/station_control/interface/models/type_aliases.py +7 -1
  29. iqm/station_control/interface/pydantic_base.py +1 -1
  30. iqm/station_control/interface/station_control.py +511 -0
  31. {iqm_station_control_client-8.1.0.dist-info → iqm_station_control_client-9.0.0.dist-info}/METADATA +2 -2
  32. {iqm_station_control_client-8.1.0.dist-info → iqm_station_control_client-9.0.0.dist-info}/RECORD +35 -33
  33. iqm/station_control/client/iqm_server/meta_class.py +0 -38
  34. {iqm_station_control_client-8.1.0.dist-info → iqm_station_control_client-9.0.0.dist-info}/LICENSE.txt +0 -0
  35. {iqm_station_control_client-8.1.0.dist-info → iqm_station_control_client-9.0.0.dist-info}/WHEEL +0 -0
  36. {iqm_station_control_client-8.1.0.dist-info → iqm_station_control_client-9.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,511 @@
1
+ # Copyright 2025 IQM
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Station control interface."""
15
+
16
+ from abc import ABC, abstractmethod
17
+ from collections.abc import Callable, Sequence
18
+ import logging
19
+ from typing import TypeVar
20
+ from uuid import UUID
21
+
22
+ from iqm.models.channel_properties import ChannelProperties
23
+
24
+ from exa.common.data.setting_node import SettingNode
25
+ from iqm.station_control.interface.list_with_meta import ListWithMeta
26
+ from iqm.station_control.interface.models import (
27
+ DutData,
28
+ DutFieldData,
29
+ DynamicQuantumArchitecture,
30
+ GetObservationsMode,
31
+ JobData,
32
+ ObservationData,
33
+ ObservationDefinition,
34
+ ObservationLite,
35
+ ObservationSetData,
36
+ ObservationSetDefinition,
37
+ ObservationSetUpdate,
38
+ ObservationUpdate,
39
+ QualityMetrics,
40
+ RunData,
41
+ RunDefinition,
42
+ RunLite,
43
+ SequenceMetadataData,
44
+ SequenceMetadataDefinition,
45
+ SequenceResultData,
46
+ SequenceResultDefinition,
47
+ SoftwareVersionSet,
48
+ StaticQuantumArchitecture,
49
+ Statuses,
50
+ SweepData,
51
+ SweepDefinition,
52
+ SweepResults,
53
+ )
54
+ from iqm.station_control.interface.pydantic_base import PydanticBase
55
+
56
+ logger = logging.getLogger(__name__)
57
+ TypePydanticBase = TypeVar("TypePydanticBase", bound=PydanticBase)
58
+
59
+
60
+ class StationControlInterface(ABC):
61
+ """Station control interface.
62
+
63
+ Station control interface implementation should implement generic query methods for certain objects,
64
+ like :meth:`query_observations`, :meth:`query_observation_sets`, and :meth:`query_sequence_metadatas`.
65
+ These methods accept only keyword arguments as parameters, which are based on the syntax ``field__lookup=value``.
66
+ Note double-underscore in the name, to separate field names like ``dut_field`` from lookup types like ``in``.
67
+ The syntax is based on Django implementation, documented
68
+ `here <https://docs.djangoproject.com/en/5.0/ref/models/querysets/#field-lookups>`__ and
69
+ `here <https://docs.djangoproject.com/en/5.0/ref/contrib/postgres/fields/#querying-arrayfield>`__.
70
+
71
+ As a convenience, when no lookup type is provided (like in ``dut_label="foo"``),
72
+ the lookup type is assumed to be exact (``dut_label__exact="foo"``). Other supported lookup types are:
73
+
74
+ - range: Range test (inclusive).
75
+ For example, ``created_timestamp__range=(datetime(2023, 10, 12), datetime(2024, 10, 14))``
76
+ - in: In a given iterable; often a list, tuple, or queryset.
77
+ For example, ``dut_field__in=["QB1.frequency", "gates.measure.constant.QB2.frequency"]``
78
+ - icontains: Case-insensitive containment test.
79
+ For example, ``origin_uri__icontains="local"``
80
+ - overlap: Returns objects where the data shares any results with the values passed.
81
+ For example, ``tags__overlap=["calibration=good", "2023-12-04"]``
82
+ - contains: The returned objects will be those where the values passed are a subset of the data.
83
+ For example, ``tags__contains=["calibration=good", "2023-12-04"]``
84
+ - isnull: Takes either True or False, which correspond to SQL queries of IS NULL and IS NOT NULL, respectively.
85
+ For example, ``end_timestamp__isnull=False``
86
+
87
+ In addition to model fields (like "dut_label", "dut_field", "created_timestamp", "invalid", etc.),
88
+ all of our generic query methods accept also following shared query parameters:
89
+
90
+ - latest: str. Return only the latest item for this field, based on "created_timestamp".
91
+ For example, ``latest="invalid"`` would return only one result (latest "created_timestamp")
92
+ for each different "invalid" value in the database. Thus, maximum three results would be returned,
93
+ one for each invalid value of `True`, `False`, and `None`.
94
+ - order_by: str. Prefix with "-" for descending order, for example "-created_timestamp".
95
+ - limit: int: Default 20. If 0 (or negative number) is given, then pagination is not used, i.e. limit=infinity.
96
+ - offset: int. Default 0.
97
+
98
+ Our generic query methods are not fully generalized yet, thus not all fields and lookup types are supported.
99
+ Check query methods own documentation for details about currently supported query parameters.
100
+
101
+ Generic query methods will return a list of objects, but with additional (optional) "meta" attribute,
102
+ which contains metadata, like pagination details. The client can ignore this data,
103
+ or use it to implement pagination logic for example to fetch all results available.
104
+
105
+ """
106
+
107
+ @abstractmethod
108
+ def get_about(self) -> dict:
109
+ """Return information about the station control."""
110
+
111
+ @abstractmethod
112
+ def get_health(self) -> dict:
113
+ """Return the status of the station control service."""
114
+
115
+ @abstractmethod
116
+ def get_configuration(self) -> dict:
117
+ """Return the configuration of the station control."""
118
+
119
+ @abstractmethod
120
+ def get_exa_configuration(self) -> str:
121
+ """Return the recommended EXA configuration from the server."""
122
+
123
+ @abstractmethod
124
+ def get_or_create_software_version_set(self, software_version_set: SoftwareVersionSet) -> int:
125
+ """Get software version set ID from the database, or create one if it doesn't exist."""
126
+
127
+ @abstractmethod
128
+ def get_settings(self) -> SettingNode:
129
+ """Return a tree representation of the default settings as defined in the configuration file."""
130
+
131
+ @abstractmethod
132
+ def get_chip_design_record(self, dut_label: str) -> dict:
133
+ """Get a raw chip design record matching the given chip label."""
134
+
135
+ @abstractmethod
136
+ def get_channel_properties(self) -> dict[str, ChannelProperties]:
137
+ """Get channel properties from the station.
138
+
139
+ Channel properties contain information regarding hardware limitations e.g. sampling rate, granularity
140
+ and supported instructions.
141
+
142
+ Returns:
143
+ Mapping from channel name to AWGProperties or ReadoutProperties.
144
+
145
+ """
146
+
147
+ @abstractmethod
148
+ def sweep(self, sweep_definition: SweepDefinition) -> dict:
149
+ """Execute an N-dimensional sweep of selected variables and save sweep and results.
150
+
151
+ The raw data for each spot in the sweep is saved as numpy arrays,
152
+ and the complete data for the whole sweep is saved as an x-array dataset
153
+ which has the `sweep_definition.sweeps` as coordinates and
154
+ data of `sweep_definition.return_parameters` data as DataArrays.
155
+
156
+ The values of `sweep_definition.playlist` will be uploaded to the controllers given by the keys of
157
+ `sweep_definition.playlist`.
158
+
159
+ Args:
160
+ sweep_definition: The content of the sweep to be created.
161
+
162
+ Returns:
163
+ Dict containing the task ID and sweep ID, and corresponding hrefs, of a successful sweep execution
164
+ in monolithic mode or successful submission to the task queue in remote mode.
165
+
166
+ Raises:
167
+ ExaError if submitting a sweep failed.
168
+
169
+ """
170
+
171
+ @abstractmethod
172
+ def get_sweep(self, sweep_id: UUID) -> SweepData:
173
+ """Get N-dimensional sweep data from the database."""
174
+
175
+ @abstractmethod
176
+ def delete_sweep(self, sweep_id: UUID) -> None:
177
+ """Delete sweep in the database."""
178
+
179
+ @abstractmethod
180
+ def get_sweep_results(self, sweep_id: UUID) -> SweepResults:
181
+ """Get N-dimensional sweep results from the database."""
182
+
183
+ @abstractmethod
184
+ def run(
185
+ self,
186
+ run_definition: RunDefinition,
187
+ update_progress_callback: Callable[[Statuses], None] | None = None,
188
+ wait_job_completion: bool = True,
189
+ ) -> bool:
190
+ """Execute an N-dimensional sweep of selected variables and save run, sweep and results."""
191
+
192
+ @abstractmethod
193
+ def get_run(self, run_id: UUID) -> RunData:
194
+ """Get run data from the database."""
195
+
196
+ @abstractmethod
197
+ def query_runs(self, **kwargs) -> ListWithMeta[RunLite]:
198
+ """Query runs from the database.
199
+
200
+ Runs are queried by the given query parameters. Currently supported query parameters:
201
+ - run_id: uuid.UUID
202
+ - run_id__in: list[uuid.UUID]
203
+ - sweep_id: uuid.UUID
204
+ - sweep_id__in: list[uuid.UUID]
205
+ - username: str
206
+ - username__in: list[str]
207
+ - username__contains: str
208
+ - username__icontains: str
209
+ - experiment_label: str
210
+ - experiment_label__in: list[str]
211
+ - experiment_label__contains: str
212
+ - experiment_label__icontains: str
213
+ - experiment_name: str
214
+ - experiment_name__in: list[str]
215
+ - experiment_name__contains: str
216
+ - experiment_name__icontains: str
217
+ - software_version_set_id: int
218
+ - software_version_set_id__in: list[int]
219
+ - begin_timestamp__range: tuple[datetime, datetime]
220
+ - end_timestamp__range: tuple[datetime, datetime]
221
+ - end_timestamp__isnull: bool
222
+
223
+ Returns:
224
+ Queried runs with some query related metadata.
225
+
226
+ """
227
+
228
+ @abstractmethod
229
+ def create_observations(
230
+ self, observation_definitions: Sequence[ObservationDefinition]
231
+ ) -> ListWithMeta[ObservationData]:
232
+ """Create observations in the database.
233
+
234
+ Args:
235
+ observation_definitions: A sequence of observation definitions,
236
+ each containing the content of the observation which will be created.
237
+
238
+ Returns:
239
+ Created observations, each including also the database created fields like ID and timestamps.
240
+
241
+ """
242
+
243
+ @abstractmethod
244
+ def get_observations(
245
+ self,
246
+ *,
247
+ mode: GetObservationsMode,
248
+ dut_label: str | None = None,
249
+ dut_field: str | None = None,
250
+ tags: list[str] | None = None,
251
+ invalid: bool | None = False,
252
+ run_ids: list[UUID] | None = None,
253
+ sequence_ids: list[UUID] | None = None,
254
+ limit: int | None = None,
255
+ ) -> list[ObservationData]:
256
+ """Get observations from the database.
257
+
258
+ Observations are queried by the given query parameters.
259
+
260
+ Args:
261
+ mode: The "mode" used to query the observations. Possible values "all_latest", "tags_and", or "tags_or".
262
+
263
+ - "all_latest":Query all the latest observations for the given ``dut_label``.
264
+ No other query parameters are accepted.
265
+ - "tags_and": Query observations. Query all the observations that have all the given ``tags``.
266
+ By default, only valid observations are included.
267
+ All other query parameters can be used to narrow down the query,
268
+ expect "run_ids" and "sequence_ids".
269
+ - "tags_or": Query all the latest observations that have at least one of the given ``tags``.
270
+ Additionally, ``dut_label`` must be given. No other query parameters are used.
271
+ - "sequence": Query observations originating from a list of run and/or sequence IDs.
272
+ No other query parameters are accepted.
273
+ dut_label: DUT label of the device the observations pertain to.
274
+ dut_field: Name of the property the observation is about.
275
+ tags: Human-readable tags of the observation.
276
+ invalid: Flag indicating if the object is invalid. Automated systems must not use invalid objects.
277
+ If ``None``, both valid and invalid objects are included.
278
+ run_ids: The run IDs for which to query the observations.
279
+ sequence_ids: The sequence IDs for which to query the observations.
280
+ limit: Indicates the maximum number of items to return.
281
+
282
+ Returns:
283
+ Observations, each including also the database created fields like ID and timestamps.
284
+
285
+ """
286
+
287
+ @abstractmethod
288
+ def query_observations(self, **kwargs) -> ListWithMeta[ObservationData]:
289
+ """Query observations from the database.
290
+
291
+ Observations are queried by the given query parameters. Currently supported query parameters:
292
+ - observation_id: int
293
+ - observation_id__in: list[int]
294
+ - dut_label: str
295
+ - dut_field: str
296
+ - dut_field__in: list[str]
297
+ - tags__overlap: list[str]
298
+ - tags__contains: list[str]
299
+ - invalid: bool
300
+ - source__run_id__in: list[uuid.UUID]
301
+ - source__sequence_id__in: list[uuid.UUID]
302
+ - source__type: str
303
+ - uncertainty__isnull: bool
304
+ - created_timestamp__range: tuple[datetime, datetime]
305
+ - observation_set_ids__overlap: list[uuid.UUID]
306
+ - observation_set_ids__contains: list[uuid.UUID]
307
+
308
+ Returns:
309
+ Queried observations with some query related metadata.
310
+
311
+ """
312
+
313
+ @abstractmethod
314
+ def update_observations(self, observation_updates: Sequence[ObservationUpdate]) -> list[ObservationData]:
315
+ """Update observations in the database.
316
+
317
+ Args:
318
+ observation_updates: A sequence of observation updates,
319
+ each containing the content of the observation which will be updated.
320
+
321
+ Returns:
322
+ Updated observations, each including also the database created fields like ID and timestamps.
323
+
324
+ """
325
+
326
+ @abstractmethod
327
+ def query_observation_sets(self, **kwargs) -> ListWithMeta[ObservationSetData]:
328
+ """Query observation sets from the database.
329
+
330
+ Observation sets are queried by the given query parameters. Currently supported query parameters:
331
+ - observation_set_id: UUID
332
+ - observation_set_id__in: list[UUID]
333
+ - observation_set_type: Literal["calibration-set", "generic-set", "quality-metric-set"]
334
+ - observation_ids__overlap: list[int]
335
+ - observation_ids__contains: list[int]
336
+ - describes_id: UUID
337
+ - describes_id__in: list[UUID]
338
+ - invalid: bool
339
+ - created_timestamp__range: tuple[datetime, datetime]
340
+ - end_timestamp__isnull: bool
341
+ - dut_label: str
342
+ - dut_label__in: list[str]
343
+
344
+ Returns:
345
+ Queried observation sets with some query related metadata
346
+
347
+ """
348
+
349
+ @abstractmethod
350
+ def create_observation_set(self, observation_set_definition: ObservationSetDefinition) -> ObservationSetData:
351
+ """Create an observation set in the database.
352
+
353
+ Args:
354
+ observation_set_definition: The content of the observation set to be created.
355
+
356
+ Returns:
357
+ The content of the observation set.
358
+
359
+ Raises:
360
+ ExaError: If creation failed.
361
+
362
+ """
363
+
364
+ @abstractmethod
365
+ def get_observation_set(self, observation_set_id: UUID) -> ObservationSetData:
366
+ """Get an observation set from the database.
367
+
368
+ Args:
369
+ observation_set_id: Observation set to retrieve.
370
+
371
+ Returns:
372
+ The content of the observation set.
373
+
374
+ Raises:
375
+ ExaError: If retrieval failed.
376
+
377
+ """
378
+
379
+ @abstractmethod
380
+ def update_observation_set(self, observation_set_update: ObservationSetUpdate) -> ObservationSetData:
381
+ """Update an observation set in the database.
382
+
383
+ Args:
384
+ observation_set_update: The content of the observation set to be updated.
385
+
386
+ Returns:
387
+ The content of the observation set.
388
+
389
+ Raises:
390
+ ExaError: If updating failed.
391
+
392
+ """
393
+
394
+ @abstractmethod
395
+ def finalize_observation_set(self, observation_set_id: UUID) -> None:
396
+ """Finalize an observation set in the database.
397
+
398
+ A finalized set is nearly immutable, allowing to change only ``invalid`` flag after finalization.
399
+
400
+ Args:
401
+ observation_set_id: Observation set to finalize.
402
+
403
+ Raises:
404
+ ExaError: If finalization failed.
405
+
406
+ """
407
+
408
+ @abstractmethod
409
+ def get_observation_set_observations(self, observation_set_id: UUID) -> list[ObservationLite]:
410
+ """Get the constituent observations of an observation set from the database.
411
+
412
+ Args:
413
+ observation_set_id: UUID of the observation set to retrieve.
414
+
415
+ Returns:
416
+ Observations belonging to the given observation set.
417
+
418
+ """
419
+
420
+ @abstractmethod
421
+ def get_default_calibration_set(self) -> ObservationSetData:
422
+ """Get default calibration set from the database."""
423
+
424
+ @abstractmethod
425
+ def get_default_calibration_set_observations(self) -> list[ObservationLite]:
426
+ """Get default calibration set observations from the database."""
427
+
428
+ @abstractmethod
429
+ def get_default_dynamic_quantum_architecture(self) -> DynamicQuantumArchitecture:
430
+ """Get dynamic quantum architecture for the default calibration set."""
431
+
432
+ @abstractmethod
433
+ def get_dynamic_quantum_architecture(self, calibration_set_id: UUID) -> DynamicQuantumArchitecture:
434
+ """Get dynamic quantum architecture for the given calibration set ID.
435
+
436
+ Returns:
437
+ Dynamic quantum architecture of the station for the given calibration set ID.
438
+
439
+ """
440
+
441
+ @abstractmethod
442
+ def get_default_calibration_set_quality_metrics(self) -> QualityMetrics:
443
+ """Get the latest quality metrics for the current default calibration set."""
444
+
445
+ @abstractmethod
446
+ def get_calibration_set_quality_metrics(self, calibration_set_id: UUID) -> QualityMetrics:
447
+ """Get the latest quality metrics for the given calibration set ID."""
448
+
449
+ @abstractmethod
450
+ def get_duts(self) -> list[DutData]:
451
+ """Get DUTs of the station control."""
452
+
453
+ @abstractmethod
454
+ def get_dut_fields(self, dut_label: str) -> list[DutFieldData]:
455
+ """Get DUT fields for the specified DUT label from the database."""
456
+
457
+ @abstractmethod
458
+ def query_sequence_metadatas(self, **kwargs) -> ListWithMeta[SequenceMetadataData]:
459
+ """Query sequence metadatas from the database.
460
+
461
+ Sequence metadatas are queried by the given query parameters. Currently supported query parameters:
462
+ - origin_id: str
463
+ - origin_id__in: list[str]
464
+ - origin_uri: str
465
+ - origin_uri__icontains: str
466
+ - created_timestamp__range: tuple[datetime, datetime]
467
+
468
+ Returns:
469
+ Sequence metadatas with some query related metadata.
470
+
471
+ """
472
+
473
+ @abstractmethod
474
+ def create_sequence_metadata(
475
+ self, sequence_metadata_definition: SequenceMetadataDefinition
476
+ ) -> SequenceMetadataData:
477
+ """Create sequence metadata in the database."""
478
+
479
+ @abstractmethod
480
+ def save_sequence_result(self, sequence_result_definition: SequenceResultDefinition) -> SequenceResultData:
481
+ """Save sequence result in the database.
482
+
483
+ This method creates the object if it doesn't exist and completely replaces the "data" and "final" if it does.
484
+ Timestamps are assigned by the database. "modified_timestamp" is not set on initial creation,
485
+ but it's updated on each subsequent call.
486
+ """
487
+
488
+ @abstractmethod
489
+ def get_sequence_result(self, sequence_id: UUID) -> SequenceResultData:
490
+ """Get sequence result from the database."""
491
+
492
+ @abstractmethod
493
+ def get_static_quantum_architecture(self, dut_label: str) -> StaticQuantumArchitecture:
494
+ """Get static quantum architecture of the station for the given DUT label.
495
+
496
+ Returns:
497
+ Static quantum architecture of the station for the given DUT label.
498
+
499
+ """
500
+
501
+ @abstractmethod
502
+ def get_job(self, job_id: UUID) -> JobData:
503
+ """Get job data."""
504
+
505
+ @abstractmethod
506
+ def abort_job(self, job_id: UUID) -> None:
507
+ """Either remove a job from the queue, or abort it gracefully if it's already executing.
508
+
509
+ The status of the job will be set to ``JobStatus.ABORTED``.
510
+ If the job is not found or is already finished nothing happens.
511
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-station-control-client
3
- Version: 8.1.0
3
+ Version: 9.0.0
4
4
  Summary: Python client for communicating with Station Control Service
5
5
  Author-email: IQM Finland Oy <info@meetiqm.com>
6
6
  License: Apache License
@@ -214,7 +214,7 @@ Requires-Python: >=3.11
214
214
  Description-Content-Type: text/x-rst
215
215
  License-File: LICENSE.txt
216
216
  Requires-Dist: iqm-exa-common <27,>=26
217
- Requires-Dist: iqm-data-definitions <3.0,>=2.8
217
+ Requires-Dist: iqm-data-definitions <3.0,>=2.13
218
218
  Requires-Dist: opentelemetry-exporter-otlp ==1.25.0
219
219
  Requires-Dist: protobuf <5.0,>=4.25.3
220
220
  Requires-Dist: grpcio <2.0,>=1.65.4
@@ -1,12 +1,11 @@
1
- iqm/station_control/client/__init__.py,sha256=BmBIBdZa10r-IWCFzZ1-0DG6GQKPIXqGXltfXop4ZeQ,942
2
- iqm/station_control/client/list_models.py,sha256=SjD0DbCrM9z1SSuGoQS83lyJmDLuMOatpJUoW8itW9s,2335
3
- iqm/station_control/client/station_control.py,sha256=ShSgH1lgaKE6UtcDcfwOg7vAINs_WKf2jynnL9ax50E,39661
4
- iqm/station_control/client/utils.py,sha256=cpS3hXEeeIXeqd_vBnnwo3JHS83FrNpG07SiTUwUx-I,1650
1
+ iqm/station_control/client/__init__.py,sha256=1ND-AkIE9xLGIscH3WN44eyll9nlFhXeyCm-8EDFGQ4,942
2
+ iqm/station_control/client/list_models.py,sha256=xnGk7Yzy-9bGBv_6eUzyai5hNJmG9ACUyu02ifSeSTE,2467
3
+ iqm/station_control/client/station_control.py,sha256=iN_c2WuzD8WBDF9Hjm92JpniuJ0kGiXd4L7xlSFMyvQ,26777
4
+ iqm/station_control/client/utils.py,sha256=-6K4KgOgA4iyUCqX-w26JvFxlwlGBehGj4tIWCEbn74,3360
5
5
  iqm/station_control/client/iqm_server/__init__.py,sha256=nLsRHN1rnOKXwuzaq_liUpAYV3sis5jkyHccSdacV7U,624
6
- iqm/station_control/client/iqm_server/error.py,sha256=ZLV2-gxFLHZjZVkI3L5sWcBMiay7NT-ijIEvrXgVJT8,1166
7
- iqm/station_control/client/iqm_server/grpc_utils.py,sha256=ee42C31_JIXlP6ikZQbohgUQjqCvcSSxIW_9lm9MMV8,5727
8
- iqm/station_control/client/iqm_server/iqm_server_client.py,sha256=6TuzBCv0yygy5B7re_nvK3NjEw_zSnP2ExBAHP0HyoY,14777
9
- iqm/station_control/client/iqm_server/meta_class.py,sha256=pePJ0Xy0aiJg-bZWK8D87gblq6imfXLsZHjpZkf5D9s,1399
6
+ iqm/station_control/client/iqm_server/error.py,sha256=a8l7UTnzfbD8KDHP-uOve77S6LR1ai9uM_J_xHbLs0Y,1175
7
+ iqm/station_control/client/iqm_server/grpc_utils.py,sha256=67-uxYnNQ9NkC6t8V1_e9XFuIYv47K1I4A39MfHncVM,5825
8
+ iqm/station_control/client/iqm_server/iqm_server_client.py,sha256=SXztyM3yDX2t4SEhBWuByFxVd0wo6kgaRvCGmg7y6uc,23412
10
9
  iqm/station_control/client/iqm_server/proto/__init__.py,sha256=mOJQ_H-NEyJMffRaDSSZeXrScHaHaHEXULv-O_OJA3A,1345
11
10
  iqm/station_control/client/iqm_server/proto/calibration_pb2.py,sha256=gum0DGmqxhbfaar8SqahmSif1pB6hgo0pVcnoi3VMUo,3017
12
11
  iqm/station_control/client/iqm_server/proto/calibration_pb2.pyi,sha256=4lTHY_GhrsLIHqoGDkNLYu56QHzX_iHEbLaYq-HR1m8,2016
@@ -25,30 +24,33 @@ iqm/station_control/client/iqm_server/proto/uuid_pb2.pyi,sha256=9LXcqNoQS1iapCso
25
24
  iqm/station_control/client/iqm_server/proto/uuid_pb2_grpc.py,sha256=SF40l84__r-OGGNYBru5ik9gih-XqeTq2iwM5gMN5Qc,726
26
25
  iqm/station_control/client/iqm_server/testing/__init__.py,sha256=wCNfJHIR_bqG3ZBlgm55v90Rih7VCpfctoIMfwRMgjk,567
27
26
  iqm/station_control/client/iqm_server/testing/iqm_server_mock.py,sha256=X_Chi8TKx95PiuhFfGnRu9LxeIpnKKynW_8tXwxFQD8,3340
28
- iqm/station_control/client/serializers/__init__.py,sha256=Hui5SrT4NVeV-27g116ZJgvRQo8ednLMsGpu4V39g1k,1436
29
- iqm/station_control/client/serializers/channel_property_serializer.py,sha256=ChlX8B-blM5hjv3pUExHOd-vE3O_myPwILu36KZYYNU,7121
30
- iqm/station_control/client/serializers/datetime_serializers.py,sha256=Ke6VRHa_359xYxXTegs8iweoDfuGeBDgkoOtGBbyC1Q,1122
31
- iqm/station_control/client/serializers/playlist_serializers.py,sha256=S8RuKdqeJxqUf7_kqTDXIKnuo6g-WpzGY7cesSQa3Rw,18086
32
- iqm/station_control/client/serializers/run_serializers.py,sha256=4zH0I5EvvaP7wgLMprXXWa36nAPO4Lv0fPkCrDC_v-g,6698
33
- iqm/station_control/client/serializers/setting_node_serializer.py,sha256=m4Sbm8Qr3GiSNiE-Jh8gFEgfscfN1xxELb0vCa9cK70,1197
34
- iqm/station_control/client/serializers/struct_serializer.py,sha256=QztBsbRlRG_UrtpQLE3bi0WKEVn48kVB91H1g26PvqQ,3270
35
- iqm/station_control/client/serializers/sweep_serializers.py,sha256=MbmAei4o8jl4a8vxmkLmj5hc3fCTMbHrtejk2aLafB4,5782
36
- iqm/station_control/client/serializers/task_serializers.py,sha256=KTd3zdfqr9kSIiEbwsoSNiSu_hxzFfDOlLuttoyBfps,3700
37
- iqm/station_control/interface/__init__.py,sha256=MIQla-cBKPbZqBkp-LNyPfjiV0gzf-IFEwrMMhsnKlg,785
38
- iqm/station_control/interface/list_with_meta.py,sha256=GAXIDEXKeua6-2FoQ_O1tkhx-d8pBMGHaIkdvgg-cag,1185
39
- iqm/station_control/interface/pydantic_base.py,sha256=MVzcsH7wG1DON-qTw6KLpUDay7_b_9CDQgymVzg9HwI,1303
40
- iqm/station_control/interface/models/__init__.py,sha256=NpUt2IcWVVAiYZTdl6uOMk0IVWmLgJrC9D9irIZvF4c,1595
41
- iqm/station_control/interface/models/dut.py,sha256=dd1SpcsBe4P057jvcPqv39SjzekewwP07hThFe5ulNA,1216
27
+ iqm/station_control/client/serializers/__init__.py,sha256=eSAjgO5DME9jR1VmtA5-ewJG7rZ6AiWgAc-gs640_20,1436
28
+ iqm/station_control/client/serializers/channel_property_serializer.py,sha256=VuWRqyPTeKK0gPHgE2r29k5JcdkTzDOOAdcC5hd7Nok,7283
29
+ iqm/station_control/client/serializers/datetime_serializers.py,sha256=PzSDJFc81BtfTfBDJdeh98pfpwIhloxko-I4HjvjAEM,1122
30
+ iqm/station_control/client/serializers/playlist_serializers.py,sha256=ueB6IzeNx9Ube3phV9vqPY6NaSnO92p5wOdHqOtYUaI,18086
31
+ iqm/station_control/client/serializers/run_serializers.py,sha256=6a6c13mgydP02qIcuPPGCmY7CgQEWe4LKXOQ_TrvD00,6698
32
+ iqm/station_control/client/serializers/setting_node_serializer.py,sha256=ghqgINjEH0-rn_q8A8GFP9wOk4RVqC97HeAkFB4vwrk,1197
33
+ iqm/station_control/client/serializers/struct_serializer.py,sha256=7LSlrGVz0c-yiy9NitshWHr3OSqRMFZRTu5k-vNxeDE,3270
34
+ iqm/station_control/client/serializers/sweep_serializers.py,sha256=NEywml9VqVfeCTONxITo8bUweaA2bKybEY2lFHqKunU,5729
35
+ iqm/station_control/client/serializers/task_serializers.py,sha256=mj5HWOolXLsqGaky7OYAWCW-BVp1RKN7vPtyiYpMaO8,3700
36
+ iqm/station_control/interface/__init__.py,sha256=bBjhkiUSdwmx-CoNrT8pI4eGStI9RFUcW5CdpIRrd5k,785
37
+ iqm/station_control/interface/list_with_meta.py,sha256=IPuho6LOiOCKEaz-QWnhbPwmWIDmcWD9JIqWf-2dxAU,1185
38
+ iqm/station_control/interface/pydantic_base.py,sha256=pQCa-8SRgBKMSwG-KyXA1HcIxE_qGMJt9g_eOGdZ31g,1303
39
+ iqm/station_control/interface/station_control.py,sha256=Uh9bDEZjc9M5KOYsGjPMYVhnYsfVQfjT05sUjUSoDXA,20303
40
+ iqm/station_control/interface/models/__init__.py,sha256=Kg-XRLuU7G4Zjtu8LhYD-v3zkCYHzLFaNvC_nukezlQ,1968
41
+ iqm/station_control/interface/models/dut.py,sha256=Hc_0XllXeIPGWhHsY7PC_jMpi7swpqo3jQQEQVnF3AM,1216
42
+ iqm/station_control/interface/models/dynamic_quantum_architecture.py,sha256=5W8e5oRNxvXm2nI36NipDrErg2vHdpC8zzpeGyqSNDQ,3621
42
43
  iqm/station_control/interface/models/jobs.py,sha256=4CVVGMsUOm_UO4w7UH-Shq7cbZe_5MkhGDpoBwHoHkc,5105
43
44
  iqm/station_control/interface/models/monitor.py,sha256=ItlgxtBup1hHg64uKeMKiFE7MaRRqSYdVRttsFD_XeU,1352
44
- iqm/station_control/interface/models/observation.py,sha256=Jce4lIsUtHRIFT3nr-cbKvh3dbR2Y_yM5x0yyvUdjF8,3261
45
- iqm/station_control/interface/models/observation_set.py,sha256=Ko2o3-9I38NfjNF2IQPcwfbwpkTQ3PIU7fUiSaDleX8,3031
46
- iqm/station_control/interface/models/run.py,sha256=m-iE3QMPQUOF7bsw8JCAM1Bd6bDVhAgxrtc_AC7rCkc,4097
47
- iqm/station_control/interface/models/sequence.py,sha256=uOqMwF1x-vW6UHs2WnPD3PsuSgV3a8OTAsgn_4UENLw,2723
48
- iqm/station_control/interface/models/sweep.py,sha256=uzpbQ_nky7UxNE4c15U4oDN96f_-SgPDNVK9Sjdan3Q,2509
49
- iqm/station_control/interface/models/type_aliases.py,sha256=3LB9viZVi8osavY5kKF8TH1crayG7-MLjgBqXDCqL2s,1018
50
- iqm_station_control_client-8.1.0.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
51
- iqm_station_control_client-8.1.0.dist-info/METADATA,sha256=JIak37YrbVnuaupwBxYbRSn4Mc6nCfEmO5rawNnnlQI,14009
52
- iqm_station_control_client-8.1.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
53
- iqm_station_control_client-8.1.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
54
- iqm_station_control_client-8.1.0.dist-info/RECORD,,
45
+ iqm/station_control/interface/models/observation.py,sha256=FwhlI2xXZ_2-PA-LcDvscHuTbfdTWhw67zSNa9Buuvg,3261
46
+ iqm/station_control/interface/models/observation_set.py,sha256=ZNgc-5Yn2o3hmXpjb-3yWGVTz9HNpovu5hhSvDvg5b4,3582
47
+ iqm/station_control/interface/models/run.py,sha256=uEuAMryG-AjAIBTchftw94GpoSBE5SQK2qmlZZ4tq5k,4097
48
+ iqm/station_control/interface/models/sequence.py,sha256=boWlMfP3woVgVObW3OaNbxsUV_qHYP1DA-oIBWj6XIo,2723
49
+ iqm/station_control/interface/models/static_quantum_architecture.py,sha256=gsfJKlYsfZVEK3dqEKXkBSIHiY14DGwNbhPJdNHMtNM,1435
50
+ iqm/station_control/interface/models/sweep.py,sha256=HFoFIrKhlYmHIBfGltY2O9_J28OvkkZILRbDHuqR0wc,2509
51
+ iqm/station_control/interface/models/type_aliases.py,sha256=gEYJ8zOpV1m0NVyYUbAL43psp9Lxw_0t68mYlI65Sds,1262
52
+ iqm_station_control_client-9.0.0.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
53
+ iqm_station_control_client-9.0.0.dist-info/METADATA,sha256=FRT6FTdEW3pCuc4YC9dNY5j4k7cwHjn03v2eBAaHmnk,14010
54
+ iqm_station_control_client-9.0.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
55
+ iqm_station_control_client-9.0.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
56
+ iqm_station_control_client-9.0.0.dist-info/RECORD,,
@@ -1,38 +0,0 @@
1
- # Copyright 2025 IQM
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- import inspect
15
-
16
-
17
- class IqmServerClientMeta(type):
18
- """Custom metaclass that automatically adds '<feature> not implemented'
19
- stub implementations for all StationControlClient functions that are
20
- not overridden by IqmServerClient.
21
- """
22
-
23
- def __new__(cls, name, bases, dct):
24
- for f_name, _ in inspect.getmembers(
25
- bases[0], predicate=lambda m: inspect.isfunction(m) and not m.__name__.startswith("__")
26
- ):
27
- if f_name not in dct:
28
- dct[f_name] = _not_implemented_stub(f_name)
29
- return super().__new__(cls, name, bases, dct)
30
-
31
-
32
- def _not_implemented_stub(feature: str):
33
- """Generate a function that raises NotImplementedError."""
34
-
35
- def stub(*args, **kwargs):
36
- raise NotImplementedError(f"'{feature}' is not implemented for this backend")
37
-
38
- return stub