iqm-station-control-client 9.11.0__py3-none-any.whl → 9.13.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.
@@ -16,7 +16,7 @@
16
16
  These are used mainly for easy serialization and deserialization of list of objects.
17
17
  """
18
18
 
19
- from typing import Generic, TypeAlias, TypeVar
19
+ from typing import Generic, TypeVar
20
20
 
21
21
  from pydantic import ConfigDict, RootModel
22
22
 
@@ -64,12 +64,37 @@ class ListModel(RootModel):
64
64
  )
65
65
 
66
66
 
67
- DutList: TypeAlias = ListModel[list[DutData]] # type: ignore[type-arg]
68
- DutFieldDataList: TypeAlias = ListModel[list[DutFieldData]] # type: ignore[type-arg]
69
- ObservationDataList: TypeAlias = ListModel[list[ObservationData]] # type: ignore[type-arg]
70
- ObservationDefinitionList: TypeAlias = ListModel[list[ObservationDefinition]] # type: ignore[type-arg]
71
- ObservationLiteList: TypeAlias = ListModel[list[ObservationLite]] # type: ignore[type-arg]
72
- ObservationUpdateList: TypeAlias = ListModel[list[ObservationUpdate]] # type: ignore[type-arg]
73
- ObservationSetDataList: TypeAlias = ListModel[list[ObservationSetData]] # type: ignore[type-arg]
74
- SequenceMetadataDataList: TypeAlias = ListModel[list[SequenceMetadataData]] # type: ignore[type-arg]
75
- RunLiteList: TypeAlias = ListModel[list[RunLite]] # type: ignore[type-arg]
67
+ class DutList(ListModel):
68
+ root: list[DutData]
69
+
70
+
71
+ class DutFieldDataList(ListModel):
72
+ root: list[DutFieldData]
73
+
74
+
75
+ class ObservationDataList(ListModel):
76
+ root: list[ObservationData]
77
+
78
+
79
+ class ObservationDefinitionList(ListModel):
80
+ root: list[ObservationDefinition]
81
+
82
+
83
+ class ObservationLiteList(ListModel):
84
+ root: list[ObservationLite]
85
+
86
+
87
+ class ObservationUpdateList(ListModel):
88
+ root: list[ObservationUpdate]
89
+
90
+
91
+ class ObservationSetDataList(ListModel):
92
+ root: list[ObservationSetData]
93
+
94
+
95
+ class SequenceMetadataDataList(ListModel):
96
+ root: list[SequenceMetadataData]
97
+
98
+
99
+ class RunLiteList(ListModel):
100
+ root: list[RunLite]
@@ -16,10 +16,12 @@
16
16
  from __future__ import annotations
17
17
 
18
18
  from collections.abc import Iterable
19
- from dataclasses import dataclass, field
20
19
  from enum import StrEnum
21
20
  import logging
22
- from typing import Any, Final, TypeAlias
21
+ from typing import Annotated, Any, Final, TypeAlias
22
+
23
+ from pydantic import Field
24
+ from pydantic.dataclasses import dataclass
23
25
 
24
26
  from iqm.station_control.interface.models.observation import ObservationBase
25
27
 
@@ -35,6 +37,9 @@ _SUFFIX_SEPARATOR: Final[str] = ":"
35
37
  LOCUS_SEPARATOR: Final[str] = "__"
36
38
  """Separates QPU components in a locus string."""
37
39
 
40
+ _PATTERN: Final[str] = r"^[A-Za-z_][A-Za-z0-9_]*$"
41
+ """Regex that most observation name parts must follow."""
42
+
38
43
  Locus: TypeAlias = tuple[str, ...]
39
44
  """Sequence of QPU component physical names a quantum operation acts on. The order may matter."""
40
45
 
@@ -77,7 +82,7 @@ def _parse_suffixes(suffixes: Iterable[str]) -> Suffixes:
77
82
  return dict(sorted(suffix_dict.items()))
78
83
 
79
84
 
80
- @dataclass(frozen=True)
85
+ @dataclass(frozen=True, config={"extra": "forbid"}) # do not allow unknown keyword args
81
86
  class QON:
82
87
  """Qualified observation name.
83
88
 
@@ -103,7 +108,7 @@ class QON:
103
108
  raise NotImplementedError
104
109
 
105
110
  @classmethod
106
- def from_str(cls, name: str) -> "QON":
111
+ def from_str(cls, name: str) -> QON:
107
112
  """Parse an observation name into a QON object.
108
113
 
109
114
  Args:
@@ -162,7 +167,7 @@ class QONCharacterization(QON):
162
167
  return _FIELD_SEPARATOR.join([self.domain, "model", self.component, self.quantity])
163
168
 
164
169
  @classmethod
165
- def _parse(cls, rest: str) -> "QONCharacterization":
170
+ def _parse(cls, rest: str) -> QONCharacterization:
166
171
  """Parse a characterization observation name."""
167
172
  parts = rest.split(_FIELD_SEPARATOR, maxsplit=1)
168
173
  if len(parts) < 2:
@@ -175,8 +180,131 @@ class QONCharacterization(QON):
175
180
  )
176
181
 
177
182
 
183
+ class QONMetricRegistry:
184
+ """Registry for QONMetric subclasses, mapping method names to parser classes.
185
+
186
+ Allows extensible registration of new metric parsing strategies for new methods.
187
+ """
188
+
189
+ _registry: dict[str, type[QONMetric]] = {}
190
+ """Mapping from QONMetric method name to the subclass that handles it."""
191
+ _inv_registry: dict[type[QONMetric], frozenset[str]] = {}
192
+ """Mapping from QONMetric subclass to the methods it handles."""
193
+
194
+ @classmethod
195
+ def register(cls, method_names: Iterable[str]):
196
+ """Decorator for registering a QONMetric subclass as the parser for one or more method names.
197
+
198
+ Args:
199
+ method_names: One or more method names to associate with the subclass.
200
+
201
+ Returns:
202
+ The decorator function.
203
+
204
+ """
205
+
206
+ def decorator(subclass: type[QONMetric]):
207
+ for name in method_names:
208
+ if (owner := cls._registry.get(name)) is not None:
209
+ raise ValueError(f"Method {name} already registered to {owner.__name__}")
210
+ cls._registry[name] = subclass
211
+ cls._inv_registry[subclass] = frozenset(method_names)
212
+ return subclass
213
+
214
+ return decorator
215
+
216
+ @classmethod
217
+ def get_parser(cls, method_name: str) -> type[QONMetric]:
218
+ """Retrieve the parser class for a given method name.
219
+
220
+ Args:
221
+ method_name: The method name to look up.
222
+
223
+ Returns:
224
+ The QONMetric subclass registered for the method.
225
+
226
+ Raises:
227
+ UnknownObservationError: ``method_name`` is not registered.
228
+
229
+ """
230
+ try:
231
+ return cls._registry[method_name]
232
+ except KeyError:
233
+ raise UnknownObservationError("Unknown quality metric.")
234
+
235
+ @classmethod
236
+ def registered_methods(cls) -> list[str]:
237
+ """Get a list of all registered method names.
238
+
239
+ Returns:
240
+ List of registered method names.
241
+
242
+ """
243
+ return list(cls._registry.keys())
244
+
245
+
178
246
  @dataclass(frozen=True)
179
247
  class QONMetric(QON):
248
+ """Base class for QON representing a gate quality metric.
249
+
250
+ Subclasses implement parsing and string representation for specific methods.
251
+ """
252
+
253
+ method: Annotated[str, Field(pattern=_PATTERN)]
254
+ locus: str
255
+ """Sequence of names of QPU components on which the gate is applied, or on which the experiment is run."""
256
+ metric: Annotated[str, Field(pattern=r"^[A-Za-z_0-9][A-Za-z0-9_]*$")]
257
+ """Measured metric."""
258
+
259
+ def __post_init__(self):
260
+ if self.method not in QONMetricRegistry._inv_registry[self.__class__]:
261
+ raise UnknownObservationError(
262
+ f"{self.__class__.__name__} is not registered to handle the method {self.method}"
263
+ )
264
+
265
+ @property
266
+ def domain(self) -> Domain:
267
+ """Return the QON domain for metrics."""
268
+ return Domain.METRIC
269
+
270
+ @classmethod
271
+ def _parse(cls, method: str, method_specific_part: str) -> QONMetric:
272
+ """Parse a metric observation name using the appropriate registered subclass.
273
+
274
+ Args:
275
+ method: The method name.
276
+ method_specific_part: The method-specific part of the metric observation name.
277
+
278
+ Returns:
279
+ Parsed metric name.
280
+
281
+ Raises:
282
+ UnknownObservationError: ``method`` is not registered.
283
+
284
+ """
285
+ parser_cls = QONMetricRegistry.get_parser(method)
286
+ return parser_cls._parse(method, method_specific_part)
287
+
288
+
289
+ @QONMetricRegistry.register(
290
+ [
291
+ "rb",
292
+ "irb",
293
+ "ssro",
294
+ "restless_ssro",
295
+ "readout_rb",
296
+ "qndness",
297
+ "msmt_qndness",
298
+ "npopex_echo",
299
+ "npopex_long",
300
+ "coherence_cz",
301
+ "ncz_swap",
302
+ "entanglement_coherence",
303
+ "conditional_reset",
304
+ ]
305
+ )
306
+ @dataclass(frozen=True)
307
+ class QONGateMetric(QONMetric):
180
308
  """QON representing a gate quality metric.
181
309
 
182
310
  Has the form ``metrics.{method}.{method_specific_part}``.
@@ -209,97 +337,107 @@ class QONMetric(QON):
209
337
  locus: QB4
210
338
  metric: fidelity
211
339
  suffixes: {"par": "d2"}
212
-
213
- ``metrics.ghz_state.QB1__QB2.coherence_lower_bound``
214
-
215
- method: ghz_state
216
- gate: None
217
- implementation: None
218
- locus: QB1__QB2
219
- metric: coherence_lower_bound
220
- suffixes: {}
221
-
222
340
  """
223
341
 
224
- method: str
225
- gate: str | None
342
+ gate: Annotated[str, Field(pattern=_PATTERN)]
226
343
  """Name of the gate/quantum operation."""
227
- implementation: str | None
344
+ implementation: Annotated[str, Field(pattern=_PATTERN)]
228
345
  """Name of the gate implementation."""
229
- locus: str
230
- """Sequence of names of QPU components on which the gate/operation is applied."""
231
- metric: str
232
- """Measured metric."""
233
- suffixes: Suffixes = field(default_factory=dict)
346
+ suffixes: Suffixes = Field(default_factory=dict)
234
347
  """Suffixes defining the metric further (if any)."""
235
348
 
236
- @property
237
- def domain(self) -> Domain:
238
- return Domain.METRIC
239
-
240
349
  def __str__(self) -> str:
241
- if self.method == "ghz_state":
242
- parts = [self.domain, self.method, self.locus, self.metric]
243
- else:
244
- gate_str = self.gate if self.gate is not None else ""
245
- impl_str = self.implementation if self.implementation is not None else ""
246
- parts = [self.domain, self.method, gate_str, impl_str, self.locus, self.metric]
350
+ parts = [self.domain, self.method, self.gate, self.implementation, self.locus, self.metric]
247
351
  name = _FIELD_SEPARATOR.join(parts)
248
- suffixes = _SUFFIX_SEPARATOR.join(f"{key}={value}" for key, value in self.suffixes.items())
249
- if suffixes:
250
- return f"{name}:{suffixes}"
352
+ if self.suffixes:
353
+ suffix_str = _SUFFIX_SEPARATOR.join(f"{k}={v}" for k, v in sorted(self.suffixes.items()))
354
+ return f"{name}:{suffix_str}"
251
355
  return name
252
356
 
253
357
  @classmethod
254
- def _parse(cls, method: str, method_specific_part: str) -> "QONMetric":
255
- """Parse a gate quality metric name.
358
+ def _parse(cls, method: str, method_specific_part: str) -> QONGateMetric:
359
+ """Parse a metric observation name that includes a gate and an implementation.
256
360
 
257
361
  Args:
258
- method: Method used to measure the gate metric.
259
- method_specific_part: Dot-separated fields specific to ``method``, possibly followed by suffixes.
362
+ method: The method name.
363
+ method_specific_part: The method-specific part of the metric observation name.
364
+
365
+ Returns:
366
+ Parsed metric name.
260
367
 
261
368
  Raises:
262
- ValueError: Failed to parse ``name`` because it was syntactically incorrect.
263
- UnknownObservationError: Failed to parse ``name`` because it contains unknown elements.
369
+ ValueError: Observation name is malformed.
264
370
 
265
371
  """
266
- # gate metrics may have suffixes, split them off
267
- fragments = method_specific_part.split(_SUFFIX_SEPARATOR)
268
- suffixes = _parse_suffixes(fragments[1:])
269
-
270
- # parse the rest of the method specific part
271
- fields = fragments[0]
272
- if method in ("rb", "irb", "ssro"):
273
- # {gate}.{implementation}.{locus_str}.{metric}"
274
- parts = fields.split(_FIELD_SEPARATOR, maxsplit=3)
275
- if len(parts) < 4:
276
- raise ValueError(f"{method} gate quality metric name has less than 6 parts")
277
- gate, implementation, locus, metric = parts
278
- return cls(
279
- method=method,
280
- gate=gate,
281
- implementation=implementation,
282
- locus=locus,
283
- metric=metric,
284
- suffixes=suffixes,
285
- )
372
+ parts, suffixes = _split_obs_name(method_specific_part, maxsplit=3)
373
+ if len(parts) < 4:
374
+ raise ValueError(f"{method} gate quality metric name has less than 6 parts")
375
+ gate, implementation, locus, metric = parts
376
+ return cls(
377
+ method=method,
378
+ gate=gate,
379
+ implementation=implementation,
380
+ locus=locus,
381
+ metric=metric,
382
+ suffixes=suffixes,
383
+ )
286
384
 
287
- if method == "ghz_state":
288
- # {locus_str}.{metric}
289
- parts = fields.split(_FIELD_SEPARATOR, maxsplit=1)
290
- if len(parts) < 2:
291
- raise ValueError(f"{method} gate quality metric name has less than 4 parts")
292
- locus, metric = parts
293
- return cls(
294
- method=method,
295
- gate=None,
296
- implementation=None,
297
- locus=locus,
298
- metric=metric,
299
- suffixes=suffixes,
300
- )
301
385
 
302
- raise UnknownObservationError("Unknown gate quality metric.")
386
+ @QONMetricRegistry.register(["ghz_state", "coherence_gef", "relaxation_ef", "simultaneous_coherence_gef", "t1_coupled"])
387
+ @dataclass(frozen=True)
388
+ class QONSystemMetric(QONMetric):
389
+ """QON representing a system quality metric.
390
+
391
+ Has the form ``metrics.{method}.{locus}.{metric}``.
392
+
393
+ Can parse/represent e.g. the following metrics:
394
+
395
+ ``metrics.irb.circuit.random_circuit.QB4.fidelity:par=d2``
396
+
397
+ method: irb
398
+ gate: circuit
399
+ implementation: random_circuit
400
+ locus: QB4
401
+ metric: fidelity
402
+ suffixes: {"par": "d2"}
403
+
404
+ ``metrics.ghz_state.QB1__QB2.coherence_lower_bound``
405
+
406
+ method: ghz_state
407
+ locus: QB1__QB2
408
+ metric: coherence_lower_bound
409
+
410
+ Subclasses implement parsing and string representation for specific methods.
411
+ """
412
+
413
+ def __str__(self) -> str:
414
+ parts = [self.domain, self.method, self.locus, self.metric]
415
+ return _FIELD_SEPARATOR.join(parts)
416
+
417
+ @classmethod
418
+ def _parse(cls, method: str, method_specific_part: str) -> QONSystemMetric:
419
+ """Parse a metric observation name without a gate or an implementation.
420
+
421
+ Args:
422
+ method: The method name.
423
+ method_specific_part: The method-specific part of the metric observation name.
424
+
425
+ Returns:
426
+ Parsed metric name.
427
+
428
+ Raises:
429
+ ValueError: Observation name is malformed.
430
+
431
+ """
432
+ parts = method_specific_part.split(_FIELD_SEPARATOR, maxsplit=1)
433
+ if len(parts) < 2:
434
+ raise ValueError(f"{method} system quality metric name has less than 4 parts")
435
+ locus, metric = parts
436
+ return cls(
437
+ method=method,
438
+ locus=locus,
439
+ metric=metric,
440
+ )
303
441
 
304
442
 
305
443
  @dataclass(frozen=True)
@@ -309,7 +447,7 @@ class QONControllerSetting(QON):
309
447
  Has the form ``controllers.{controller}[.{subcontroller}]*.{setting}``.
310
448
  """
311
449
 
312
- controller: str
450
+ controller: Annotated[str, Field(pattern=_PATTERN)]
313
451
  """Name of the controller."""
314
452
  rest: str
315
453
  """Possible subcontroller names in a dotted structure, ending in the setting name."""
@@ -322,7 +460,7 @@ class QONControllerSetting(QON):
322
460
  return _FIELD_SEPARATOR.join([self.domain, self.controller, self.rest])
323
461
 
324
462
  @classmethod
325
- def _parse(cls, controller: str, controller_specific_part: str) -> "QONControllerSetting":
463
+ def _parse(cls, controller: str, controller_specific_part: str) -> QONControllerSetting:
326
464
  """Parse a controller setting observation name."""
327
465
  return cls(
328
466
  controller=controller,
@@ -337,9 +475,9 @@ class QONGateParam(QON):
337
475
  Has the form ``gates.{gate}.{implementation}.{locus_str}.{parameter}``.
338
476
  """
339
477
 
340
- gate: str
478
+ gate: Annotated[str, Field(pattern=_PATTERN)]
341
479
  """Name of the gate/quantum operation."""
342
- implementation: str | None
480
+ implementation: Annotated[str, Field(pattern=_PATTERN)]
343
481
  """Name of the gate implementation."""
344
482
  locus: str
345
483
  """Sequence of names of QPU components on which the gate is applied."""
@@ -351,11 +489,10 @@ class QONGateParam(QON):
351
489
  return Domain.GATE_PARAMETER
352
490
 
353
491
  def __str__(self) -> str:
354
- impl_str = self.implementation if self.implementation is not None else ""
355
- return _FIELD_SEPARATOR.join([self.domain, self.gate, impl_str, self.locus, self.parameter])
492
+ return _FIELD_SEPARATOR.join([self.domain, self.gate, self.implementation, self.locus, self.parameter])
356
493
 
357
494
  @classmethod
358
- def _parse(cls, gate: str, rest: str) -> "QONGateParam":
495
+ def _parse(cls, gate: str, rest: str) -> QONGateParam:
359
496
  """Parse a gate parameter observation name."""
360
497
  parts = rest.split(_FIELD_SEPARATOR, maxsplit=2)
361
498
  if len(parts) < 3:
@@ -369,14 +506,14 @@ class QONGateParam(QON):
369
506
  )
370
507
 
371
508
 
372
- def _split_obs_name(obs_name: str) -> tuple[list[str], Suffixes]:
509
+ def _split_obs_name(obs_name: str, *, maxsplit: int = -1) -> tuple[list[str], Suffixes]:
373
510
  """Split the given observation name into path elements and suffixes."""
374
511
  # some observation names may have suffixes, split them off
375
512
  fragments = obs_name.split(_SUFFIX_SEPARATOR)
376
513
  suffixes = _parse_suffixes(fragments[1:])
377
514
 
378
515
  # split the path elements
379
- path = fragments[0].split(_FIELD_SEPARATOR)
516
+ path = fragments[0].split(_FIELD_SEPARATOR, maxsplit=maxsplit)
380
517
  return path, suffixes
381
518
 
382
519
 
@@ -62,7 +62,7 @@ from iqm.station_control.client.serializers import (
62
62
  from iqm.station_control.client.serializers.channel_property_serializer import unpack_channel_properties
63
63
  from iqm.station_control.client.serializers.setting_node_serializer import deserialize_setting_node
64
64
  from iqm.station_control.client.serializers.sweep_serializers import deserialize_sweep_data
65
- from iqm.station_control.interface.list_with_meta import ListWithMeta
65
+ from iqm.station_control.interface.list_with_meta import ListWithMeta, Meta
66
66
  from iqm.station_control.interface.models import (
67
67
  DutData,
68
68
  DutFieldData,
@@ -358,7 +358,7 @@ class StationControlClient(_StationControlClientBase):
358
358
  def create_observations(
359
359
  self, observation_definitions: Sequence[ObservationDefinition]
360
360
  ) -> ListWithMeta[ObservationData]: # type: ignore[type-arg]
361
- json_str = self._serialize_model(ObservationDefinitionList(observation_definitions))
361
+ json_str = self._serialize_model(ObservationDefinitionList(list(observation_definitions)))
362
362
  response = self._send_request(requests.post, "observations", json_str=json_str)
363
363
  return self._deserialize_response(response, ObservationDataList, list_with_meta=True)
364
364
 
@@ -394,7 +394,7 @@ class StationControlClient(_StationControlClientBase):
394
394
  return self._deserialize_response(response, ObservationDataList, list_with_meta=True)
395
395
 
396
396
  def update_observations(self, observation_updates: Sequence[ObservationUpdate]) -> list[ObservationData]:
397
- json_str = self._serialize_model(ObservationUpdateList(observation_updates))
397
+ json_str = self._serialize_model(ObservationUpdateList(list(observation_updates)))
398
398
  response = self._send_request(requests.patch, "observations", json_str=json_str)
399
399
  return self._deserialize_response(response, ObservationDataList)
400
400
 
@@ -612,22 +612,23 @@ class StationControlClient(_StationControlClientBase):
612
612
  @staticmethod
613
613
  def _deserialize_response(
614
614
  response: requests.Response,
615
- model_class: type[TypePydanticBase | ListModel[list[TypePydanticBase]]], # type: ignore[type-arg]
615
+ model_class: type[TypePydanticBase | ListModel],
616
616
  *,
617
617
  list_with_meta: bool = False,
618
- ) -> TypePydanticBase | ListWithMeta[TypePydanticBase]: # type: ignore[type-arg]
618
+ ) -> TypePydanticBase | ListWithMeta:
619
619
  # Use "model_validate_json(response.text)" instead of "model_validate(response.json())".
620
620
  # This validates the provided data as a JSON string or bytes object.
621
621
  # If your incoming data is a JSON payload, this is generally considered faster.
622
622
  if list_with_meta:
623
- response_with_meta = ResponseWithMeta.model_validate_json(response.text) # type: ignore[var-annotated]
624
- if response_with_meta.meta and response_with_meta.meta.errors:
625
- logger.warning(
626
- "Errors in station control response:\n - %s", "\n - ".join(response_with_meta.meta.errors)
627
- )
628
- return ListWithMeta(model_class.model_validate(response_with_meta.items), meta=response_with_meta.meta) # type: ignore[arg-type]
623
+ response_with_meta: ResponseWithMeta = ResponseWithMeta.model_validate_json(response.text)
624
+ meta = response_with_meta.meta or Meta()
625
+ if meta and meta.errors:
626
+ logger.warning("Errors in station control response:\n - %s", "\n - ".join(meta.errors))
627
+ return ListWithMeta(model_class.model_validate(response_with_meta.items), meta=meta)
629
628
  model = model_class.model_validate_json(response.text)
630
- return model # type: ignore[return-value]
629
+ if isinstance(model, ListModel):
630
+ return model.root
631
+ return model
631
632
 
632
633
 
633
634
  def _remove_empty_values(kwargs: dict[str, Any]) -> dict[str, Any]:
@@ -11,7 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- """Models to extend standard list with metadata."""
14
+ """Models to extend a standard list with metadata."""
15
15
 
16
16
  from collections.abc import Iterable
17
17
  from dataclasses import dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-station-control-client
3
- Version: 9.11.0
3
+ Version: 9.13.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
@@ -1,8 +1,8 @@
1
1
  iqm/station_control/client/__init__.py,sha256=1ND-AkIE9xLGIscH3WN44eyll9nlFhXeyCm-8EDFGQ4,942
2
- iqm/station_control/client/list_models.py,sha256=7JJyn5jCBOvMBJWdsVsPRLhtChMxqLa6O9hElpeXEt8,2701
2
+ iqm/station_control/client/list_models.py,sha256=w_KUflrR9J1ODphu7dy3BOj1d4fzNrHj0J0HfgNitO4,2508
3
3
  iqm/station_control/client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- iqm/station_control/client/qon.py,sha256=--vWZ8ueX3pFIZPSt4N_5eQt4Ski_FJCceXDHKr77Ns,22782
5
- iqm/station_control/client/station_control.py,sha256=cQqHuTu3K7iVtZzdtIuihTXa_GPydyZFIjZtyCPzh7s,29208
4
+ iqm/station_control/client/qon.py,sha256=_jGGTGIfoy1ANg65Ht07_7YKFAFxukxxV9lgcatq-hk,26865
5
+ iqm/station_control/client/station_control.py,sha256=X19lCDgaoH36zOvNpsBxEE9BgijdeE2cp639S-G2hjw,29073
6
6
  iqm/station_control/client/utils.py,sha256=-6K4KgOgA4iyUCqX-w26JvFxlwlGBehGj4tIWCEbn74,3360
7
7
  iqm/station_control/client/iqm_server/__init__.py,sha256=nLsRHN1rnOKXwuzaq_liUpAYV3sis5jkyHccSdacV7U,624
8
8
  iqm/station_control/client/iqm_server/error.py,sha256=a8l7UTnzfbD8KDHP-uOve77S6LR1ai9uM_J_xHbLs0Y,1175
@@ -36,7 +36,7 @@ iqm/station_control/client/serializers/struct_serializer.py,sha256=7LSlrGVz0c-yi
36
36
  iqm/station_control/client/serializers/sweep_serializers.py,sha256=iFeBb4RFbHpVZifyduUypACSvulhkzdQIyG0gDoXOwM,5807
37
37
  iqm/station_control/client/serializers/task_serializers.py,sha256=mj5HWOolXLsqGaky7OYAWCW-BVp1RKN7vPtyiYpMaO8,3700
38
38
  iqm/station_control/interface/__init__.py,sha256=bBjhkiUSdwmx-CoNrT8pI4eGStI9RFUcW5CdpIRrd5k,785
39
- iqm/station_control/interface/list_with_meta.py,sha256=IPuho6LOiOCKEaz-QWnhbPwmWIDmcWD9JIqWf-2dxAU,1185
39
+ iqm/station_control/interface/list_with_meta.py,sha256=M8BacgBDjbf7yabNK-OHCJWrci5hewXA9vd8MrqrZts,1187
40
40
  iqm/station_control/interface/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  iqm/station_control/interface/pydantic_base.py,sha256=pQCa-8SRgBKMSwG-KyXA1HcIxE_qGMJt9g_eOGdZ31g,1303
42
42
  iqm/station_control/interface/station_control.py,sha256=5gtDouAQ13KnyXNQUcBrpKG9pZdjIsX6fLJU9bmYJxU,20433
@@ -52,8 +52,8 @@ iqm/station_control/interface/models/sequence.py,sha256=boWlMfP3woVgVObW3OaNbxsU
52
52
  iqm/station_control/interface/models/static_quantum_architecture.py,sha256=gsfJKlYsfZVEK3dqEKXkBSIHiY14DGwNbhPJdNHMtNM,1435
53
53
  iqm/station_control/interface/models/sweep.py,sha256=HFoFIrKhlYmHIBfGltY2O9_J28OvkkZILRbDHuqR0wc,2509
54
54
  iqm/station_control/interface/models/type_aliases.py,sha256=gEYJ8zOpV1m0NVyYUbAL43psp9Lxw_0t68mYlI65Sds,1262
55
- iqm_station_control_client-9.11.0.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
56
- iqm_station_control_client-9.11.0.dist-info/METADATA,sha256=IOUlvKf6Bc5KW2hHiXbdkq4giUymE_YH5U4AHzkRJUg,14107
57
- iqm_station_control_client-9.11.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
58
- iqm_station_control_client-9.11.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
59
- iqm_station_control_client-9.11.0.dist-info/RECORD,,
55
+ iqm_station_control_client-9.13.0.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
56
+ iqm_station_control_client-9.13.0.dist-info/METADATA,sha256=hpH1t_jyd8TBZhZ_kSSk6pUlKKZmIyjJO0VKzYTjmRw,14107
57
+ iqm_station_control_client-9.13.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
58
+ iqm_station_control_client-9.13.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
59
+ iqm_station_control_client-9.13.0.dist-info/RECORD,,