iqm-exa-common 25.34__py3-none-any.whl → 26.1__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 (42) hide show
  1. exa/common/api/proto_serialization/_parameter.py +4 -3
  2. exa/common/api/proto_serialization/nd_sweep.py +3 -8
  3. exa/common/api/proto_serialization/sequence.py +5 -5
  4. exa/common/api/proto_serialization/setting_node.py +3 -1
  5. exa/common/control/sweep/exponential_sweep.py +15 -47
  6. exa/common/control/sweep/fixed_sweep.py +10 -14
  7. exa/common/control/sweep/linear_sweep.py +15 -40
  8. exa/common/control/sweep/option/__init__.py +1 -1
  9. exa/common/control/sweep/option/center_span_base_options.py +14 -7
  10. exa/common/control/sweep/option/center_span_options.py +13 -6
  11. exa/common/control/sweep/option/constants.py +2 -2
  12. exa/common/control/sweep/option/fixed_options.py +8 -2
  13. exa/common/control/sweep/option/option_converter.py +4 -8
  14. exa/common/control/sweep/option/start_stop_base_options.py +20 -6
  15. exa/common/control/sweep/option/start_stop_options.py +20 -5
  16. exa/common/control/sweep/option/sweep_options.py +9 -0
  17. exa/common/control/sweep/sweep.py +52 -16
  18. exa/common/control/sweep/sweep_values.py +58 -0
  19. exa/common/data/base_model.py +40 -0
  20. exa/common/data/parameter.py +123 -68
  21. exa/common/data/setting_node.py +481 -135
  22. exa/common/data/settingnode_v2.html.jinja2 +6 -6
  23. exa/common/data/value.py +49 -0
  24. exa/common/logger/logger.py +1 -1
  25. exa/common/qcm_data/file_adapter.py +2 -6
  26. exa/common/qcm_data/qcm_data_client.py +1 -37
  27. exa/common/sweep/database_serialization.py +30 -98
  28. exa/common/sweep/util.py +4 -5
  29. {iqm_exa_common-25.34.dist-info → iqm_exa_common-26.1.dist-info}/METADATA +2 -2
  30. iqm_exa_common-26.1.dist-info/RECORD +54 -0
  31. exa/common/api/model/__init__.py +0 -15
  32. exa/common/api/model/parameter_model.py +0 -111
  33. exa/common/api/model/setting_model.py +0 -63
  34. exa/common/api/model/setting_node_model.py +0 -72
  35. exa/common/api/model/sweep_model.py +0 -63
  36. exa/common/control/sweep/function_sweep.py +0 -35
  37. exa/common/control/sweep/option/function_options.py +0 -26
  38. exa/common/control/sweep/utils.py +0 -43
  39. iqm_exa_common-25.34.dist-info/RECORD +0 -59
  40. {iqm_exa_common-25.34.dist-info → iqm_exa_common-26.1.dist-info}/LICENSE.txt +0 -0
  41. {iqm_exa_common-25.34.dist-info → iqm_exa_common-26.1.dist-info}/WHEEL +0 -0
  42. {iqm_exa_common-25.34.dist-info → iqm_exa_common-26.1.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,7 @@
29
29
  {% endmacro %}
30
30
 
31
31
  {% macro slisttabrow(key, s) %}
32
- <tr>
32
+ <tr style={{"color:gray" if s.read_only else ""}}>
33
33
  <td style="text-align: left">
34
34
  <span style="font-family: monospace;
35
35
  font-weight: bold"
@@ -59,18 +59,18 @@
59
59
  {% macro snlist(s, lvl=0) %}
60
60
  {% if slistmode %}
61
61
  <ul style="padding-left: 2em; list-style: none;">
62
- {% for key, subs in s._settings.items() %}{{ slistitem(key, subs) }}{% endfor %}
62
+ {% for key, subs in s.settings.items() %}{{ slistitem(key, subs) }}{% endfor %}
63
63
  </ul>
64
64
  {% else %}
65
- {% if s._settings %}
65
+ {% if s.settings %}
66
66
  <table style="margin-left: 1em;">
67
- {% for key, subs in s._settings.items() %}{{ slisttabrow(key, subs) }}{% endfor %}
67
+ {% for key, subs in s.settings.items() %}{{ slisttabrow(key, subs) }}{% endfor %}
68
68
  </table>
69
69
  {% endif %}
70
70
  {% endif %}
71
- {% if s._subtrees %}
71
+ {% if s.subtrees %}
72
72
  <ul class="exa-subtree">
73
- {% for key, subsn in s._subtrees.items() %}{{ snlistitem(key, subsn, lvl+1) }}{% endfor %}
73
+ {% for key, subsn in s.subtrees.items() %}{{ snlistitem(key, subsn, lvl+1) }}{% endfor %}
74
74
  </ul>
75
75
  {% endif %}
76
76
  {% endmacro %}
@@ -0,0 +1,49 @@
1
+ import base64
2
+ from typing import Annotated, Any
3
+
4
+ import numpy as np
5
+ from pydantic import PlainSerializer, PlainValidator, WithJsonSchema
6
+ from pydantic_core import core_schema
7
+
8
+
9
+ def validate_value(value: Any) -> Any:
10
+ """Validate (i.e. deserialize) JSON serializable value to Python type, to support complex and ndarray types."""
11
+ if isinstance(value, dict):
12
+ if "__complex__" in value:
13
+ value = complex(value["real"], value["imag"])
14
+ elif "__ndarray__" in value:
15
+ data = base64.b64decode(value["data"])
16
+ value = np.frombuffer(data, value["dtype"]).reshape(value["shape"])
17
+ return value
18
+
19
+
20
+ def serialize_value(value: Any) -> Any:
21
+ """Serialize value type to JSON serializable type, to support complex and ndarray types."""
22
+ if isinstance(value, complex):
23
+ value = {"__complex__": "true", "real": value.real, "imag": value.imag}
24
+ elif isinstance(value, np.ndarray):
25
+ # ensure array buffer is contiguous and in C order
26
+ value = np.require(value, requirements=["A", "C"])
27
+ data = base64.b64encode(value.data)
28
+ value = {"__ndarray__": "true", "data": data, "dtype": str(value.dtype), "shape": value.shape}
29
+ return value
30
+
31
+
32
+ # TODO: We might want to rename these to ObservationValue and ObservationUncertainty, respectively.
33
+ Value = Annotated[
34
+ bool | str | int | float | complex | np.ndarray,
35
+ PlainValidator(validate_value),
36
+ PlainSerializer(serialize_value),
37
+ WithJsonSchema(core_schema.any_schema()),
38
+ ]
39
+ Uncertainty = Annotated[
40
+ int | float | complex | np.ndarray,
41
+ PlainValidator(validate_value),
42
+ PlainSerializer(serialize_value),
43
+ WithJsonSchema(core_schema.any_schema()),
44
+ ]
45
+
46
+ # TODO (Marko): Consider if we want to rename these?
47
+ # We have "as" imports so seems like more descriptive name would be better.
48
+ ObservationValue = Value
49
+ ObservationUncertainty = Uncertainty
@@ -19,7 +19,7 @@ from typing import Any, Callable, Optional
19
19
  BRIEF_DATEFMT = "%m-%d %H:%M:%S"
20
20
 
21
21
  BRIEF = "[{asctime};{levelname:.1}{extra_info}] {message}"
22
- VERBOSE = "[{asctime};{levelname};{processName}({process});{threadName}({thread});{name};{filename}:{lineno}:{funcName}{extra_info}] {message}" # pylint:disable=line-too-long # noqa: E501
22
+ VERBOSE = "[{asctime};{levelname};{processName}({process});{threadName}({thread});{name};{filename}:{lineno}:{funcName}{extra_info}] {message}" # noqa: E501
23
23
 
24
24
 
25
25
  class ExtraFormatter(logging.Formatter):
@@ -17,7 +17,7 @@ from http import HTTPStatus
17
17
  import io
18
18
  import locale
19
19
  from pathlib import Path
20
- from urllib.parse import parse_qs, urlparse
20
+ from urllib.parse import urlparse
21
21
  from urllib.request import url2pathname
22
22
 
23
23
  from requests import Response
@@ -37,12 +37,8 @@ class FileAdapter(BaseAdapter):
37
37
  raise ValueError("Invalid request method %s" % request.method)
38
38
 
39
39
  url_parts = urlparse(request.url)
40
- params: dict = parse_qs(url_parts.query, keep_blank_values=True)
41
40
 
42
- if "chip_label" in params: # For deprecated CHAD and QDP files
43
- path = url2pathname(str(Path(url_parts.path, f"{params['chip_label'][0]}.json")))
44
- else:
45
- path = url_parts.netloc + f"{str(Path(url2pathname(url_parts.path)))}.json"
41
+ path = url_parts.netloc + f"{str(Path(url2pathname(url_parts.path)))}.json"
46
42
  response = Response()
47
43
  try:
48
44
  response.status_code = HTTPStatus.OK
@@ -19,7 +19,7 @@ from functools import cache
19
19
  import json
20
20
  import logging
21
21
  from pathlib import Path
22
- from typing import Any, Optional
22
+ from typing import Any
23
23
 
24
24
  from packaging.version import Version
25
25
  import requests
@@ -101,42 +101,6 @@ class QCMDataClient:
101
101
  self._validate_chip_design_record(data, chip_label)
102
102
  return data
103
103
 
104
- def get_chad(self, chip_label: str) -> Optional[dict]:
105
- """DEPRECATED. Use :meth:`get_chip_design_record` instead."""
106
- url_tail = f"/v2/chads/?chip_label={chip_label}&limit=1"
107
- try:
108
- response = self._send_request(self.session.get, f"{self.root_url}{url_tail}")
109
- except RequestError as err:
110
- if self._fallback_root_url:
111
- response = self._send_request(self.session.get, f"{self._fallback_root_url}{url_tail}")
112
- else:
113
- raise err
114
- data = response.json()["data"]
115
- if data:
116
- chad = data[0]
117
- self._validate_chip_design_record(chad, chip_label)
118
- return chad
119
- return None
120
-
121
- def get_qubit_design_properties(self, chip_label: str) -> dict | None:
122
- """DEPRECATED. Use :meth:`get_chip_design_record` instead."""
123
- self.logger.warning(
124
- "QCMDataClient.get_qubit_design_properties is deprecated, use QCMDataClient.get_chip_design_record instead."
125
- )
126
- url_tail = f"/qubit-design-properties/?chip_label={chip_label}&limit=10&content_format=json"
127
- try:
128
- response = self._send_request(self.session.get, f"{self.root_url}{url_tail}")
129
- except RequestError as err:
130
- if self._fallback_root_url:
131
- response = self._send_request(self.session.get, f"{self._fallback_root_url}{url_tail}")
132
- else:
133
- raise err
134
- data = response.json()["data"]
135
- if data:
136
- qdp = data[0]
137
- return qdp
138
- return None
139
-
140
104
  def _send_request(self, http_method: Callable[..., requests.Response], url: str) -> requests.Response:
141
105
  # Send the request and return the response.
142
106
  # Will raise an error if respectively an error response code is returned.
@@ -18,16 +18,14 @@ serializing and deserializing sweep arguments before saving them to database.
18
18
  """
19
19
 
20
20
  import json
21
- from typing import Any, Optional, Union, cast
21
+ from typing import Any, cast
22
22
 
23
- from exa.common.api.model.parameter_model import ParameterModel
24
- from exa.common.api.model.setting_node_model import SettingNodeModel
25
- from exa.common.api.model.sweep_model import SweepModel
26
23
  from exa.common.control.sweep.sweep import Sweep
27
- from exa.common.data.parameter import Parameter, Setting
24
+ from exa.common.data.parameter import Parameter
28
25
  from exa.common.data.setting_node import SettingNode
26
+ from exa.common.helpers import json_helper
29
27
  from exa.common.helpers.json_helper import decode_json, get_json_encoder
30
- from exa.common.sweep.util import NdSweep, Sweeps, linear_index_sweep
28
+ from exa.common.sweep.util import NdSweep, Sweeps
31
29
 
32
30
 
33
31
  def encode_nd_sweeps(sweeps: NdSweep, **kwargs) -> str:
@@ -45,22 +43,7 @@ def encode_nd_sweeps(sweeps: NdSweep, **kwargs) -> str:
45
43
  return json.dumps(sweeps, **kwargs)
46
44
 
47
45
 
48
- def encode_return_parameters_legacy(return_parameters: dict[Parameter, Optional[NdSweep]], **kwargs) -> str:
49
- """Encode sweeps to a JSON string.
50
-
51
- Args:
52
- return_parameters: Return parameters as specified by :meth:`~.Backend.sweep`.
53
- kwargs: keyword arguments passed to json.dumps
54
-
55
- Returns:
56
- json as a string
57
-
58
- """
59
- kwargs.setdefault("cls", _SweepDataEncoder)
60
- return json.dumps(return_parameters, **kwargs)
61
-
62
-
63
- def encode_return_parameters(return_parameters: dict[Parameter, Optional[NdSweep]], **kwargs) -> str:
46
+ def encode_return_parameters(return_parameters: dict[Parameter, NdSweep | None], **kwargs) -> str:
64
47
  """Encode sweeps to a JSON string.
65
48
 
66
49
  Args:
@@ -102,40 +85,7 @@ def decode_and_validate_sweeps(sweeps_json: str) -> Sweeps:
102
85
  return cast(Sweeps, decoded)
103
86
 
104
87
 
105
- def decode_return_parameters_legacy(json_str: str) -> dict[Parameter, Optional[NdSweep]]:
106
- """Deserialize return parameters.
107
-
108
- For backwards compatibility, changes values of the return parameters dict to a new,
109
- more general format: NdSweeps, which is a list of tuples of Sweeps.
110
-
111
- A key in the dict may be a Parameter or a Setting; both will be converted to a Parameter.
112
- The values in the dict are converted with the following rules:
113
-
114
- * 1 is converted to an empty NdSweep, i.e., a scalar.
115
- * Other integers are converted to a :func:`.linear_index_sweep`
116
- * `Sweep` is converted to an NdSweep that contains only the sweep
117
- * NdSweep and None are not converted.
118
-
119
- Args:
120
- json_str: JSON representation of the ``return_parameters`` loaded
121
- from e.g. persistence
122
-
123
- Return:
124
- a reconstituted, typed ``return_parameters`` structure
125
-
126
- """
127
-
128
- def decode_key(key: str) -> Parameter:
129
- parameter_or_setting: dict[str, Any] = json.loads(key)
130
- parameter_dict = parameter_or_setting.get("parameter", parameter_or_setting)
131
- return ParameterModel(**parameter_dict).decode()
132
-
133
- raw: dict[str, Any] = _loads(json_str)
134
- decoded: dict[Setting, Union[NdSweep, Sweep, int]] = {decode_key(key): value for key, value in raw.items()}
135
- return _legacy_return_parameters_to_new_format(decoded)
136
-
137
-
138
- def decode_return_parameters(json_str: str) -> dict[Parameter, Optional[NdSweep]]:
88
+ def decode_return_parameters(json_str: str) -> dict[Parameter, NdSweep | None]:
139
89
  """Deserialize return parameters.
140
90
 
141
91
  For backwards compatibility, changes values of the return parameters dict to a new,
@@ -164,8 +114,7 @@ def decode_return_parameters(json_str: str) -> dict[Parameter, Optional[NdSweep]
164
114
  raise ValueError(f"Outer type is not list type when decoding: {json_str}")
165
115
 
166
116
  return_parameters = {
167
- ParameterModel(**param_and_sweeps["parameter"]).decode(): param_and_sweeps["hard_sweeps"]
168
- for param_and_sweeps in decoded
117
+ Parameter(**param_and_sweeps["parameter"]): param_and_sweeps["hard_sweeps"] for param_and_sweeps in decoded
169
118
  }
170
119
  return return_parameters
171
120
 
@@ -181,37 +130,8 @@ def decode_settings(json_str: str) -> SettingNode:
181
130
  deserialized settings
182
131
 
183
132
  """
184
- return SettingNodeModel(**json.loads(json_str)).decode()
185
-
186
-
187
- def _legacy_return_parameters_to_new_format(
188
- old: dict[Union[Parameter, Setting], Union[NdSweep, Sweep, int, None]],
189
- ) -> dict[Parameter, NdSweep]:
190
- """For backwards compatibility, changes values of the return parameters dict to a new,
191
- more general format: NdSweeps, which is a list of tuples of Sweeps.
192
-
193
- Args:
194
- old: return parameters in old format.
195
-
196
- Returns:
197
- `old` coerced to the new format.
198
-
199
- """
200
- new = {}
201
- for key, value in old.items():
202
- parameter = key.parameter if isinstance(key, Setting) else key
203
-
204
- # Previously, int meant "I don't know the numerical coordinates of this hard sweep, so
205
- # just give me a dummy sweep with integers from 0 to <coord>"
206
- if isinstance(value, int):
207
- # Length 1 means scalar, so no hard sweeps at all
208
- new_value = linear_index_sweep(parameter, value) if value != 1 else []
209
- elif isinstance(value, Sweep):
210
- new_value = [(value,)]
211
- else:
212
- new_value = value
213
- new[parameter] = new_value
214
- return new
133
+ json_loads = json.loads(json_str)
134
+ return SettingNode(**json_loads)
215
135
 
216
136
 
217
137
  def _loads(*args, **kwargs) -> Any:
@@ -228,12 +148,22 @@ def _loads(*args, **kwargs) -> Any:
228
148
  """
229
149
 
230
150
  def _decode_json(obj: Any) -> Any:
151
+ if isinstance(obj, dict) and "parameter" in obj:
152
+ # This is kind of a hack to provide backwards compatibility for old data.
153
+ # Pydantic doesn't allow extra attributes with the current setup,
154
+ # but old database data can have "parent_name" and "parent_label", which are not part of the model.
155
+ obj["parameter"].pop("parent_name", None)
156
+ obj["parameter"].pop("parent_label", None)
157
+
231
158
  if isinstance(obj, dict) and {"parameter", "data"}.issubset(obj):
232
- return SweepModel(**obj).decode()
233
- return decode_json(obj)
159
+ data = [json_helper.decode_json(d) for d in obj["data"]]
160
+ return Sweep(parameter=Parameter(**obj["parameter"]), data=data)
161
+ json_data_return = decode_json(obj)
162
+ return json_data_return
234
163
 
235
164
  kwargs.setdefault("object_hook", _decode_json)
236
- return json.loads(*args, **kwargs)
165
+ loads = json.loads(*args, **kwargs)
166
+ return loads
237
167
 
238
168
 
239
169
  class _SweepDataEncoder(json.JSONEncoder):
@@ -250,12 +180,14 @@ class _SweepDataEncoder(json.JSONEncoder):
250
180
 
251
181
  """
252
182
  if isinstance(obj, Sweep):
253
- return json.loads(SweepModel.encode(obj).model_dump_json())
254
- if isinstance(obj, Parameter):
255
- return json.loads(ParameterModel.encode(obj).model_dump_json())
256
- if isinstance(obj, tuple):
257
- return get_json_encoder()[tuple](obj)
258
- return super().default(obj)
183
+ obj = obj.model_copy().model_dump()
184
+ elif isinstance(obj, Parameter):
185
+ obj = obj.model_copy().model_dump()
186
+ elif isinstance(obj, tuple):
187
+ obj = get_json_encoder()[tuple](obj)
188
+ else:
189
+ obj = super().default(obj)
190
+ return obj
259
191
 
260
192
  # JSONEncoder doesn't call `default` method for tuple, because
261
193
  # it knows how to serialize it. In order to use custom encoder
exa/common/sweep/util.py CHANGED
@@ -16,7 +16,6 @@
16
16
  user-friendly format to canonic ones.
17
17
  """
18
18
 
19
- from exa.common.control.sweep.linear_sweep import LinearSweep
20
19
  from exa.common.control.sweep.option import StartStopOptions
21
20
  from exa.common.control.sweep.sweep import Sweep
22
21
  from exa.common.data.parameter import Parameter
@@ -75,7 +74,7 @@ def convert_sweeps_to_list_of_tuples(sweeps: Sweeps) -> NdSweep:
75
74
  return new_list
76
75
 
77
76
 
78
- def linear_index_sweep(parameter: Parameter, length: int) -> list[tuple[LinearSweep]]:
77
+ def linear_index_sweep(parameter: Parameter, length: int) -> list[tuple[Sweep]]:
79
78
  """Produce an NdSweep over a dummy index.
80
79
 
81
80
  Can be used in places where a "hardware sweep" is needed but not really meaningful.
@@ -91,9 +90,9 @@ def linear_index_sweep(parameter: Parameter, length: int) -> list[tuple[LinearSw
91
90
  """
92
91
  return [
93
92
  (
94
- LinearSweep(
95
- Parameter(name=parameter.name + "_index", label=parameter.label + " index"),
96
- StartStopOptions(0, length - 1, count=length),
93
+ Sweep(
94
+ parameter=Parameter(name=parameter.name + "_index", label=parameter.label + " index"),
95
+ data=StartStopOptions(0, length - 1, count=length).data,
97
96
  ),
98
97
  )
99
98
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-exa-common
3
- Version: 25.34
3
+ Version: 26.1
4
4
  Summary: Framework for control and measurement of superconducting qubits: common library
5
5
  Author-email: IQM Finland Oy <info@meetiqm.com>
6
6
  License: Apache License
@@ -215,7 +215,7 @@ Description-Content-Type: text/x-rst
215
215
  License-File: LICENSE.txt
216
216
  Requires-Dist: iqm-data-definitions <3.0,>=2.6
217
217
  Requires-Dist: numpy <3.0,>=1.25.2
218
- Requires-Dist: pydantic <3.0,>=2.9.2
218
+ Requires-Dist: pydantic <3.0,>=2.10.4
219
219
  Requires-Dist: python-dotenv ==0.21.1
220
220
  Requires-Dist: xarray ==2024.10.0
221
221
  Requires-Dist: requests ==2.32.3
@@ -0,0 +1,54 @@
1
+ exa/common/__init__.py,sha256=AqxwNht57urLqMxFblY7SgxjzkQYW7pRRUUPS1j1Gck,962
2
+ exa/common/api/__init__.py,sha256=PAYujWNG8CtSQX_8U9gnubDh5cwGRhtOfLr0r0xGx3M,587
3
+ exa/common/api/proto_serialization/__init__.py,sha256=Vn2C79OqovFu5wJus9EHsMtK3Of1JLJDcpg2QZKmXsY,1565
4
+ exa/common/api/proto_serialization/_parameter.py,sha256=W0EBrVs3uZ-jX1HnlOrAB7_PKrzi8D_qNM0_SBht8XY,2895
5
+ exa/common/api/proto_serialization/array.py,sha256=iht5WlfGEkzXM3PcOFDXxd2TgXWFyYNyPt44CMqXnl8,3110
6
+ exa/common/api/proto_serialization/datum.py,sha256=gFIAncWpOhy4V56DKYdKoasEIpGu1yUerSuRQf65unY,4828
7
+ exa/common/api/proto_serialization/nd_sweep.py,sha256=B36KY32wTNFJE3Bk2QlN4BeMO0Se7AtwOectlIh5SCM,2661
8
+ exa/common/api/proto_serialization/sequence.py,sha256=2_84ILndHsc9c9KPKvckySIPJHByoH2fXIF-fTjrzvI,2377
9
+ exa/common/api/proto_serialization/setting_node.py,sha256=KCNpwgwIrgyuXsgt-rAm3oEQqKlIxtN8JBUDFaQTJ48,3940
10
+ exa/common/control/__init__.py,sha256=00T_xV0lL20QZcEt__vWq81N1oGF0KpJMhTitfAI4VI,629
11
+ exa/common/control/sweep/__init__.py,sha256=GzKoQdQsLutcHhmrLPyPrW1n7Cpg766p3OWDHlRpuTs,607
12
+ exa/common/control/sweep/exponential_sweep.py,sha256=NjO0wiovyV4HTbS3hs0tptmPGSsQLNS9h-mYFQJzX8c,2039
13
+ exa/common/control/sweep/fixed_sweep.py,sha256=hfIv9-f-7WsIavs7JxwcBs-lSZTxV0D51Xv6gH3sywM,1411
14
+ exa/common/control/sweep/linear_sweep.py,sha256=Xn7gjysIQ2Xu_l15yBsqlUvnK5AJdN7KRaa3sNSjzd8,1884
15
+ exa/common/control/sweep/sweep.py,sha256=0ZzhbzcAQaByiX7dz5jDH0r1zmyEiW2B-v8edIyTDs8,3442
16
+ exa/common/control/sweep/sweep_values.py,sha256=pGvds0ZVgMIL6ztE6hGXEzC9E7rvAzeVwvHCG5v6XC8,2298
17
+ exa/common/control/sweep/option/__init__.py,sha256=Z01JS0FpchMvR8zfWBCs3jcPjh2H8X29YkN0SFxWLTY,906
18
+ exa/common/control/sweep/option/center_span_base_options.py,sha256=8F2HqHeq9RSMqEms6icuUqLlzkL6jT991eeRrKgikM8,2520
19
+ exa/common/control/sweep/option/center_span_options.py,sha256=3YI6DpBAXhon_DMRGzf-YugodSP1KX01MBtiqTvCJDM,2475
20
+ exa/common/control/sweep/option/constants.py,sha256=vdYrbi3EBlIST5mO498W2F6s-xqyoEVBAZ6zQEiHmmY,1417
21
+ exa/common/control/sweep/option/fixed_options.py,sha256=SyGSiEanD3xz4Wcy1rd9r2wj7hNaG3lQYH67WQDc72I,1047
22
+ exa/common/control/sweep/option/option_converter.py,sha256=RGNNQHNl8gTZUHO85IZseoo065s_kQSWP-AfrYhGbn4,3649
23
+ exa/common/control/sweep/option/start_stop_base_options.py,sha256=hZCIflh8NzK48cLLMer9U2yDRTM6mCEEuuF2zAZ2CYU,2361
24
+ exa/common/control/sweep/option/start_stop_options.py,sha256=HaQFNlhRPep2yrn_LuOkuZ0imwBEidpD0BTPWf-Svf4,3038
25
+ exa/common/control/sweep/option/sweep_options.py,sha256=BhKB7RHP0VXJ9iUQKVzeQOM4j_x9AsMhRJgoR3gkiaY,933
26
+ exa/common/data/__init__.py,sha256=F5SRe5QHBTjef4XJVQ63kO5Oxc_AiZnPbV560i7La0Y,644
27
+ exa/common/data/base_model.py,sha256=WWbQk5-9coz3qj4IzkEKvIkdcwHISi7XPb14K7ZTPHg,1936
28
+ exa/common/data/parameter.py,sha256=uUMyVt4wfKkwehd9CHbBPOGQ_PSnlI06pNMPjBySDGs,22999
29
+ exa/common/data/setting_node.py,sha256=WldawevXuOb2uN-bjZ04hWijKqX_MOdkyMsgxOZbrek,43190
30
+ exa/common/data/settingnode_v2.html.jinja2,sha256=mo-rlLLmU-Xxf6znJAisispAZK8sbV-2C13byKAtj_Q,3166
31
+ exa/common/data/value.py,sha256=etAYhIKyRmy30uzSd7MpzUhGhvCXcfhMq-PPteG8EcY,1893
32
+ exa/common/errors/__init__.py,sha256=ArMBdpmx1EUenBpzrSNG63kmUf7PM0gCqSYnaCnL9Qk,597
33
+ exa/common/errors/exa_error.py,sha256=eB_c-Qp1OchcBMr3LSyYitity4SochQh-nAghZmGLJU,975
34
+ exa/common/helpers/__init__.py,sha256=IgtVD3tojIFA4MTV2mT5uYM6jb2qny9kBIIhEZT2PuI,610
35
+ exa/common/helpers/data_helper.py,sha256=vhzJ63g1S2JqnCj0WJJuqWcuiIwKATnQeHdWw_3gkZg,1934
36
+ exa/common/helpers/json_helper.py,sha256=VTcYU8FRgv3tXPifuogUWmVAzt_4JoQ_laTHolyodtA,2672
37
+ exa/common/helpers/numpy_helper.py,sha256=KKKyZ_fD0O1gn7_InEQROYnX3WGMA6C1qHh8KzzjtUI,1062
38
+ exa/common/helpers/software_version_helper.py,sha256=kpuQer4p1p4cj9_CzwziBSCX7wuH-FvfNw8G8U-EI3Y,5162
39
+ exa/common/logger/__init__.py,sha256=1bIsGxHzfujXlkgtcAnWToKMkw3dpU5PEd_7LE_NpgQ,686
40
+ exa/common/logger/logger.py,sha256=qQOl2MEBlw69zKEKNWSPOFi7DSLOfsMXNmJYapqzlXY,5684
41
+ exa/common/qcm_data/__init__.py,sha256=VtsYkGoaniSjCkY0oQlqkcYJCtmC2sTDxfrIe_kpqZg,567
42
+ exa/common/qcm_data/chad_model.py,sha256=MQ1xuRODOA6uzb3GJ4fgYx9cXS8z1DeRGw6HYKA9Sio,11223
43
+ exa/common/qcm_data/chip_topology.py,sha256=OJU8-CXV7wfdxrn0HqryNZmxGRoffrg0vi0aMaiYbbY,19328
44
+ exa/common/qcm_data/file_adapter.py,sha256=U1XZm_PEswkW7kAztbWFLMufz4mPKPupWbh5yJXdZCI,2263
45
+ exa/common/qcm_data/immutable_base_model.py,sha256=QXmKIWQbsbWQvovXwKT1d9jtyf2LNJtjQquIwO52zOU,901
46
+ exa/common/qcm_data/qcm_data_client.py,sha256=tuNEosERVjtGYEq7RWaBzxST7OvRAWxN-VRYmhJLLN8,6094
47
+ exa/common/sweep/__init__.py,sha256=uEKk5AtzSgSnf8Y0geRPwUpqXIBIXpeCxsN64sX7F1o,591
48
+ exa/common/sweep/database_serialization.py,sha256=NUu1umxRQZpKtRmw1vNDsSbnofqbHvKFg_xQ2mdhY6k,7469
49
+ exa/common/sweep/util.py,sha256=-QE2AaH-WDkYAVH5-Z-30leLgY0x4efmby4kc1JTCgY,3732
50
+ iqm_exa_common-26.1.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
51
+ iqm_exa_common-26.1.dist-info/METADATA,sha256=d5as1iS3mrwzyUGIUrLxB13yjHEgfiP76prxvM_epQM,14548
52
+ iqm_exa_common-26.1.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
53
+ iqm_exa_common-26.1.dist-info/top_level.txt,sha256=Clphg2toaZ3_jSFRPhjMNEmLurkMNMc4lkK2EFYsSlM,4
54
+ iqm_exa_common-26.1.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- # Copyright 2024 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
-
15
- """Pydantic models for serializing control and data structures."""
@@ -1,111 +0,0 @@
1
- # Copyright 2024 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
-
15
- """Pydantic model for Parameter."""
16
-
17
- from __future__ import annotations
18
-
19
- from typing import Optional, Tuple
20
-
21
- from pydantic import BaseModel, ConfigDict
22
-
23
- from exa.common.data.parameter import CollectionType, DataType, Parameter
24
-
25
-
26
- class ParameterModel(BaseModel):
27
- """Pydantic parameter model""" # noqa: D200
28
-
29
- name: str
30
- parent_name: Optional[str] = None
31
- label: Optional[str] = None
32
- parent_label: Optional[str] = None
33
- unit: Optional[str] = None
34
- data_type: Optional[int | Tuple[int, ...]] = None
35
- collection_type: Optional[int] = None
36
- element_indices: Optional[int | list[int]] = None
37
-
38
- def __hash__(self):
39
- return hash(
40
- (
41
- self.name,
42
- self.parent_name,
43
- self.label,
44
- self.unit,
45
- self.data_type,
46
- self.collection_type,
47
- self.element_indices,
48
- )
49
- )
50
-
51
- def __eq__(self, other: ParameterModel):
52
- return isinstance(other, ParameterModel) and (
53
- (
54
- self.name,
55
- self.parent_name,
56
- self.label,
57
- self.parent_label,
58
- self.unit,
59
- self.data_type,
60
- self.collection_type,
61
- self.element_indices,
62
- )
63
- == (
64
- other.name,
65
- other.parent_name,
66
- other.label,
67
- other.parent_label,
68
- other.unit,
69
- other.data_type,
70
- other.collection_type,
71
- other.element_indices,
72
- )
73
- )
74
-
75
- model_config = ConfigDict(extra="allow")
76
-
77
- def decode(self) -> Parameter:
78
- """Creates instance of :class:`exa.common.data.parameter.Parameter` out of pydantic `ParameterModel`"""
79
- if self.data_type is not None:
80
- if isinstance(self.data_type, tuple):
81
- dt = tuple(DataType(dt) for dt in self.data_type)
82
- else:
83
- dt = DataType(self.data_type)
84
- else:
85
- dt = None
86
- ct = CollectionType(self.collection_type) if self.collection_type is not None else None
87
- if self.element_indices is None:
88
- return Parameter(self.name, self.label, self.unit, dt, ct)
89
- return Parameter(self.parent_name, self.parent_label, self.unit, dt, ct, self.element_indices)
90
-
91
- @classmethod
92
- def encode(cls, parameter: Parameter) -> ParameterModel:
93
- """Creates pydantic `ParameterModel` out of :class:`exa.common.data.parameter.Parameter` instance"""
94
- if parameter.data_type is not None:
95
- if isinstance(parameter.data_type, tuple):
96
- dt = tuple(dt.value for dt in parameter.data_type)
97
- else:
98
- dt = parameter.data_type.value
99
- else:
100
- dt = None
101
- ct = parameter.collection_type.value if parameter.collection_type is not None else None
102
- return ParameterModel(
103
- name=parameter.name,
104
- parent_name=parameter.parent_name,
105
- label=parameter.label,
106
- parent_label=parameter.parent_label,
107
- unit=parameter.unit,
108
- data_type=dt,
109
- collection_type=ct,
110
- element_indices=parameter.element_indices,
111
- )
@@ -1,63 +0,0 @@
1
- # Copyright 2024 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
-
15
- """Pydantic model for Setting."""
16
-
17
- from __future__ import annotations
18
-
19
- from typing import Any
20
-
21
- from pydantic import BaseModel, ConfigDict, field_serializer
22
-
23
- from exa.common.api.model.parameter_model import ParameterModel
24
- from exa.common.data.parameter import Setting
25
- from exa.common.helpers import json_helper
26
- from exa.common.helpers.numpy_helper import coerce_numpy_type_to_native
27
-
28
-
29
- class SettingModel(BaseModel):
30
- """Pydantic setting model""" # noqa: D200
31
-
32
- parameter: ParameterModel
33
- value: Any = None
34
-
35
- def __hash__(self):
36
- return hash((self.parameter, self.value))
37
-
38
- def __eq__(self, other: SettingModel):
39
- return isinstance(other, SettingModel) and ((self.parameter, self.value) == (other.parameter, other.value))
40
-
41
- model_config = ConfigDict(extra="allow")
42
-
43
- @field_serializer("value")
44
- def serialize_value(self, value: Any, _info):
45
- encoder = json_helper.get_json_encoder().get(type(value))
46
- if encoder:
47
- return encoder(value)
48
- return value
49
-
50
- def decode(self) -> Setting:
51
- """Creates instance of :class:`exa.common.data.parameter.Setting` out of pydantic `SettingModel`"""
52
- value = json_helper.decode_json(self.value)
53
- parameter = ParameterModel.decode(self.parameter)
54
- return Setting(parameter=parameter, value=value)
55
-
56
- @classmethod
57
- def encode(cls, setting: Setting) -> SettingModel:
58
- """Creates pydantic :class:`SettingModel` out of :class:`~exa.common.data.parameter.Setting` instance.
59
-
60
- Converts numpy scalars to native types to avoid problems with JSON encoding.
61
- """
62
- value = coerce_numpy_type_to_native(setting.value)
63
- return SettingModel(parameter=ParameterModel.encode(setting.parameter), value=value)