iqm-exa-common 26.25.0__tar.gz → 26.27.0__tar.gz
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.
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/CHANGELOG.rst +16 -0
- {iqm_exa_common-26.25.0/src/iqm_exa_common.egg-info → iqm_exa_common-26.27.0}/PKG-INFO +1 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/center_span_options.py +1 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/start_stop_base_options.py +5 -9
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/start_stop_options.py +1 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/sweep_values.py +3 -4
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/base_model.py +2 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/parameter.py +49 -27
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/setting_node.py +48 -23
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/data_helper.py +4 -2
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/software_version_helper.py +1 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/chad_model.py +3 -2
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/chip_topology.py +7 -7
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/qcm_data_client.py +1 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0/src/iqm_exa_common.egg-info}/PKG-INFO +1 -1
- iqm_exa_common-26.27.0/version.txt +1 -0
- iqm_exa_common-26.25.0/version.txt +0 -1
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/LICENSE.txt +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/MANIFEST.in +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/README.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/API.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/Makefile +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_static/.gitignore +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_static/css/custom.css +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_static/images/favicon.ico +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_static/images/logo.png +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_templates/autosummary-class-template.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_templates/autosummary-module-template.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/changelog.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/conf.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/index.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/license.rst +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/pyproject.toml +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/requirements/base.in +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/requirements/base.txt +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/setup.cfg +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/setup.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/_parameter.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/array.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/datum.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/nd_sweep.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/sequence.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/setting_node.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/exponential_sweep.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/fixed_sweep.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/linear_sweep.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/center_span_base_options.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/constants.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/fixed_options.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/option_converter.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/sweep_options.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/sweep.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/settingnode_v2.html.jinja2 +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/value.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/errors/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/errors/exa_error.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/errors/station_control_errors.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/deprecation.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/json_helper.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/numpy_helper.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/yaml_helper.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/logger/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/logger/logger.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/file_adapter.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/immutable_base_model.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/sweep/__init__.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/sweep/database_serialization.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/sweep/util.py +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/iqm_exa_common.egg-info/SOURCES.txt +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/iqm_exa_common.egg-info/dependency_links.txt +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/iqm_exa_common.egg-info/requires.txt +0 -0
- {iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/iqm_exa_common.egg-info/top_level.txt +0 -0
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
Version 26.27.0 (2025-07-04)
|
|
6
|
+
============================
|
|
7
|
+
|
|
8
|
+
Features
|
|
9
|
+
--------
|
|
10
|
+
|
|
11
|
+
- Setting now has a private field _source and an associated property which can be used to store e.g. the observation that is the source of the Setting's value.
|
|
12
|
+
|
|
13
|
+
Version 26.26.0 (2025-07-02)
|
|
14
|
+
============================
|
|
15
|
+
|
|
16
|
+
Bug fixes
|
|
17
|
+
---------
|
|
18
|
+
|
|
19
|
+
- Fix type errors raised by mypy.
|
|
20
|
+
|
|
5
21
|
Version 26.25.0 (2025-06-17)
|
|
6
22
|
============================
|
|
7
23
|
|
|
@@ -40,7 +40,7 @@ class CenterSpanOptions(SweepOptions):
|
|
|
40
40
|
#: :const:`exa.common.control.sweep.option.constants.DEFAULT_COUNT`.
|
|
41
41
|
count: int | None = None
|
|
42
42
|
#: Size of spacing between values.
|
|
43
|
-
step: int | float | complex = None
|
|
43
|
+
step: int | float | complex | None = None
|
|
44
44
|
#: Order of generated values. Default to ascending
|
|
45
45
|
asc: bool | None = None
|
|
46
46
|
|
|
@@ -35,26 +35,22 @@ class StartStopBaseOptions(SweepOptions):
|
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
37
|
#: The power for the start of the interval.
|
|
38
|
-
start: int | float
|
|
38
|
+
start: int | float
|
|
39
39
|
#: The power for the end of the interval.
|
|
40
|
-
stop: int | float
|
|
40
|
+
stop: int | float
|
|
41
41
|
#: Number of values to generate. Default to
|
|
42
42
|
#: :const:`exa.common.control.sweep.option.constants.DEFAULT_COUNT`.
|
|
43
|
-
count: int
|
|
43
|
+
count: int = DEFAULT_COUNT
|
|
44
44
|
#: Number, that is raised to the power `start` or `stop`. Default to
|
|
45
45
|
#: :const:`exa.common.control.sweep.option.constants.DEFAULT_BASE`.
|
|
46
|
-
base: int
|
|
46
|
+
base: int = DEFAULT_BASE
|
|
47
47
|
|
|
48
48
|
def __post_init__(self):
|
|
49
|
-
if self.count is None:
|
|
50
|
-
object.__setattr__(self, "count", DEFAULT_COUNT)
|
|
51
|
-
if self.base is None:
|
|
52
|
-
object.__setattr__(self, "base", DEFAULT_BASE)
|
|
53
49
|
if self.start == 0 or self.stop == 0:
|
|
54
50
|
raise ValueError("Exponential range sweep start and stop values must not be zero.")
|
|
55
51
|
|
|
56
52
|
@property
|
|
57
|
-
def data(self) -> list[int | float
|
|
53
|
+
def data(self) -> list[int | float]:
|
|
58
54
|
logger.debug(f"EXPONENTS: ({self.start}, {self.stop}) with base {self.base}")
|
|
59
55
|
start = math.pow(self.base, self.start)
|
|
60
56
|
stop = math.pow(self.base, self.stop)
|
|
@@ -65,7 +65,7 @@ class StartStopOptions(SweepOptions):
|
|
|
65
65
|
count = 1 + math.ceil(abs(self.stop - self.start) / float(np.abs(self.step)))
|
|
66
66
|
data = self._generate_by_count(count)
|
|
67
67
|
else:
|
|
68
|
-
data = self._generate_by_count(self.count)
|
|
68
|
+
data = self._generate_by_count(self.count if self.count is not None else DEFAULT_COUNT)
|
|
69
69
|
return data
|
|
70
70
|
|
|
71
71
|
def _generate_by_count(self, count: int) -> SweepValues:
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/sweep_values.py
RENAMED
|
@@ -28,9 +28,8 @@ def validate_sweep_values(sweep_values: Any) -> Any:
|
|
|
28
28
|
if isinstance(sweep_values, np.ndarray):
|
|
29
29
|
sweep_values = sweep_values.tolist()
|
|
30
30
|
for index, value in enumerate(sweep_values):
|
|
31
|
-
if isinstance(value, dict):
|
|
32
|
-
|
|
33
|
-
sweep_values[index] = complex(value["real"], value["imag"])
|
|
31
|
+
if isinstance(value, dict) and "__complex__" in value:
|
|
32
|
+
sweep_values[index] = complex(value["real"], value["imag"])
|
|
34
33
|
return sweep_values
|
|
35
34
|
|
|
36
35
|
|
|
@@ -51,7 +50,7 @@ def serialize_sweep_values(sweep_values: Any) -> Any:
|
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
SweepValues = Annotated[
|
|
54
|
-
list[Any] | np.ndarray
|
|
53
|
+
list[Any] | np.ndarray,
|
|
55
54
|
PlainValidator(validate_sweep_values),
|
|
56
55
|
PlainSerializer(serialize_sweep_values),
|
|
57
56
|
WithJsonSchema(core_schema.any_schema()),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from typing import Any, Self
|
|
2
3
|
|
|
3
4
|
import pydantic
|
|
@@ -24,7 +25,7 @@ class BaseModel(pydantic.BaseModel):
|
|
|
24
25
|
frozen=True, # This makes instances of the model potentially hashable if all the attributes are hashable
|
|
25
26
|
)
|
|
26
27
|
|
|
27
|
-
def model_copy(self, *, update:
|
|
28
|
+
def model_copy(self, *, update: Mapping[str, Any] | None = None, deep: bool = True) -> Self:
|
|
28
29
|
"""Returns a copy of the model.
|
|
29
30
|
|
|
30
31
|
Overrides the Pydantic default 'model_copy' to set 'deep=True' by default.
|
|
@@ -61,7 +61,7 @@ import ast
|
|
|
61
61
|
from collections.abc import Hashable
|
|
62
62
|
import copy
|
|
63
63
|
from enum import IntEnum
|
|
64
|
-
from typing import Any, Self
|
|
64
|
+
from typing import Any, Self, TypeAlias
|
|
65
65
|
import warnings
|
|
66
66
|
|
|
67
67
|
import numpy as np
|
|
@@ -73,7 +73,9 @@ from exa.common.data.base_model import BaseModel
|
|
|
73
73
|
from exa.common.data.value import ObservationValue
|
|
74
74
|
from exa.common.errors.station_control_errors import ValidationError
|
|
75
75
|
|
|
76
|
-
CastType = str | list["CastType"] | None
|
|
76
|
+
CastType: TypeAlias = str | list["CastType"] | None
|
|
77
|
+
SourceType: TypeAlias = None | BaseModel | dict[str, Any]
|
|
78
|
+
"""Type for Setting sources."""
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
class DataType(IntEnum):
|
|
@@ -116,7 +118,7 @@ class DataType(IntEnum):
|
|
|
116
118
|
else:
|
|
117
119
|
return False
|
|
118
120
|
|
|
119
|
-
def _cast(self, value: str) -> Any: # noqa: PLR0911
|
|
121
|
+
def _cast(self, value: str | None) -> Any: # noqa: PLR0911
|
|
120
122
|
if value is None:
|
|
121
123
|
return None
|
|
122
124
|
elif self in [DataType.FLOAT, DataType.NUMBER]:
|
|
@@ -135,7 +137,7 @@ class DataType(IntEnum):
|
|
|
135
137
|
raise TypeError("Boolean data types can only be 'false', 'true, '0' or '1' (case-insensitive)")
|
|
136
138
|
elif self is DataType.STRING:
|
|
137
139
|
return value
|
|
138
|
-
else:
|
|
140
|
+
else: # TODO: can this be removed?
|
|
139
141
|
try:
|
|
140
142
|
return ast.literal_eval(value)
|
|
141
143
|
except (SyntaxError, ValueError): # if the value can not be evaluated, return the original value
|
|
@@ -238,13 +240,12 @@ class Parameter(BaseModel):
|
|
|
238
240
|
raise ValidationError("Parameter 'element_indices' must be one or more ints.")
|
|
239
241
|
object.__setattr__(self, "element_indices", idxs)
|
|
240
242
|
# there may be len(idxs) num of "__" separated indices at the end, remove those to get the parent name
|
|
241
|
-
|
|
243
|
+
seperated_indices = "__".join([str(idx) for idx in idxs])
|
|
244
|
+
parent_name = self.name.replace("__" + seperated_indices, "")
|
|
242
245
|
object.__setattr__(self, "_parent_name", parent_name)
|
|
243
246
|
object.__setattr__(self, "_parent_label", self.label.replace(f" {idxs}", ""))
|
|
244
247
|
object.__setattr__(self, "label", f"{self._parent_label} {idxs}")
|
|
245
|
-
name =
|
|
246
|
-
for index in idxs:
|
|
247
|
-
name += f"__{index}"
|
|
248
|
+
name = parent_name + "__" + seperated_indices
|
|
248
249
|
object.__setattr__(self, "name", name)
|
|
249
250
|
|
|
250
251
|
@property
|
|
@@ -272,7 +273,7 @@ class Parameter(BaseModel):
|
|
|
272
273
|
def build_data_set(
|
|
273
274
|
variables: list[tuple[Parameter, list[Any]]],
|
|
274
275
|
data: tuple[Parameter, SweepValues],
|
|
275
|
-
attributes: dict[str, Any] = None,
|
|
276
|
+
attributes: dict[str, Any] | None = None,
|
|
276
277
|
extra_variables: list[tuple[str, int]] | None = None,
|
|
277
278
|
):
|
|
278
279
|
"""Build an xarray Dataset, where the only DataArray is given by `results` and coordinates are given by
|
|
@@ -289,9 +290,9 @@ class Parameter(BaseModel):
|
|
|
289
290
|
extra_variables: Valueless dimensions and their sizes.
|
|
290
291
|
|
|
291
292
|
"""
|
|
292
|
-
variable_names = []
|
|
293
|
-
variable_sizes = []
|
|
294
|
-
variable_data_arrays = {}
|
|
293
|
+
variable_names: list[str] = []
|
|
294
|
+
variable_sizes: list[int] = []
|
|
295
|
+
variable_data_arrays: dict[str, xr.DataArray] = {}
|
|
295
296
|
for variable in variables:
|
|
296
297
|
variable_names.append(variable[0].name)
|
|
297
298
|
variable_sizes.append(len(variable[1]))
|
|
@@ -326,9 +327,9 @@ class Parameter(BaseModel):
|
|
|
326
327
|
def build_data_array(
|
|
327
328
|
self,
|
|
328
329
|
data: np.ndarray,
|
|
329
|
-
dimensions: list[Hashable] = None,
|
|
330
|
-
coords: dict[Hashable, Any] = None,
|
|
331
|
-
metadata: dict[str, Any] = None,
|
|
330
|
+
dimensions: list[str] | list[Hashable] | None = None,
|
|
331
|
+
coords: dict[Hashable, Any] | None = None,
|
|
332
|
+
metadata: dict[str, Any] | None = None,
|
|
332
333
|
) -> xr.DataArray:
|
|
333
334
|
"""Attach Parameter information to a numerical array.
|
|
334
335
|
|
|
@@ -365,7 +366,7 @@ class Parameter(BaseModel):
|
|
|
365
366
|
da = xr.DataArray(name=self.name, data=data, attrs=attrs, dims=dimensions, coords=coords)
|
|
366
367
|
# copying the coordinate metadata, if present, to the new DataArray coordinates
|
|
367
368
|
if coords:
|
|
368
|
-
for key in [k for k in coords
|
|
369
|
+
for key in [k for k in coords if isinstance(coords[k], xr.DataArray)]:
|
|
369
370
|
da[key].attrs = coords[key].attrs
|
|
370
371
|
return da
|
|
371
372
|
|
|
@@ -408,12 +409,19 @@ class Setting(BaseModel):
|
|
|
408
409
|
path: str = ""
|
|
409
410
|
"""Path in the settings tree (starting from the root ``SettingNode``) for this setting."""
|
|
410
411
|
|
|
412
|
+
_source: SourceType = None
|
|
413
|
+
"""The source for this Setting value. May contain an observation (ObservationDefinition or ObservationData)
|
|
414
|
+
or a source-dict (e.g. ``{"type": "configuration_source", "configurator": "defaults_from_yml"}``). By default,
|
|
415
|
+
``None``, which denotes the source not being specified (e.g. hardcoded defaults). The source is stored in a private
|
|
416
|
+
attribute and thus is never serialized (the source field can contain non-serializable data such as Callables)."""
|
|
417
|
+
|
|
411
418
|
def __init__(
|
|
412
419
|
self,
|
|
413
420
|
parameter: Parameter | None = None,
|
|
414
421
|
value: ObservationValue | None = None,
|
|
415
422
|
read_only: bool = False,
|
|
416
423
|
path: str = "",
|
|
424
|
+
source: SourceType = None,
|
|
417
425
|
**kwargs,
|
|
418
426
|
) -> None:
|
|
419
427
|
super().__init__(
|
|
@@ -423,6 +431,7 @@ class Setting(BaseModel):
|
|
|
423
431
|
path=path,
|
|
424
432
|
**kwargs,
|
|
425
433
|
)
|
|
434
|
+
self._source = source
|
|
426
435
|
|
|
427
436
|
@model_validator(mode="after")
|
|
428
437
|
def validate_parameter_value_after(self) -> Self:
|
|
@@ -436,8 +445,17 @@ class Setting(BaseModel):
|
|
|
436
445
|
raise ValidationError(f"Invalid value '{self.value}' for parameter '{self.parameter}'.")
|
|
437
446
|
return self
|
|
438
447
|
|
|
439
|
-
def update(self, value: ObservationValue) -> Setting:
|
|
440
|
-
"""Create a new setting object with updated
|
|
448
|
+
def update(self, value: ObservationValue, source: SourceType = None) -> Setting:
|
|
449
|
+
"""Create a new setting object with updated value and source.
|
|
450
|
+
|
|
451
|
+
Args:
|
|
452
|
+
value: New value for the setting.
|
|
453
|
+
source: New source for the setting.
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
Copy of ``self`` with modified properties.
|
|
457
|
+
|
|
458
|
+
"""
|
|
441
459
|
if self.read_only:
|
|
442
460
|
raise ValueError(
|
|
443
461
|
f"Can't update the value of {self.parameter.name} to {value} since the setting is read-only."
|
|
@@ -446,7 +464,7 @@ class Setting(BaseModel):
|
|
|
446
464
|
value = np.array(value)
|
|
447
465
|
# Need to create a new Setting here instead of using Pydantic model_copy().
|
|
448
466
|
# model_copy() can't handle backdoor settings without errors, i.e. values with a list of 2 elements.
|
|
449
|
-
return Setting(self.parameter, value, self.read_only, self.path)
|
|
467
|
+
return Setting(self.parameter, value, self.read_only, self.path, source=source)
|
|
450
468
|
|
|
451
469
|
@property
|
|
452
470
|
def name(self):
|
|
@@ -474,24 +492,28 @@ class Setting(BaseModel):
|
|
|
474
492
|
return self.parameter.unit
|
|
475
493
|
|
|
476
494
|
@property
|
|
477
|
-
def element_indices(self) ->
|
|
495
|
+
def element_indices(self) -> int | list[int] | None:
|
|
478
496
|
"""Element-wise indices of the parameter in ``self``."""
|
|
479
497
|
return self.parameter.element_indices
|
|
480
498
|
|
|
499
|
+
@property
|
|
500
|
+
def source(self) -> SourceType:
|
|
501
|
+
"""Return the source for this Setting's value."""
|
|
502
|
+
return self._source
|
|
503
|
+
|
|
481
504
|
@staticmethod
|
|
482
505
|
def get_by_name(name: str, values: set[Setting]) -> Setting | None:
|
|
483
506
|
return next((setting for setting in values if setting.parameter.name == name), None)
|
|
484
507
|
|
|
485
508
|
@staticmethod
|
|
486
|
-
def remove_by_name(name: str, values: set[Setting]
|
|
487
|
-
if values is None:
|
|
488
|
-
values = set()
|
|
509
|
+
def remove_by_name(name: str, values: set[Setting]) -> set[Setting]:
|
|
489
510
|
removed = copy.deepcopy(values)
|
|
490
|
-
|
|
511
|
+
if setting := Setting.get_by_name(name, values):
|
|
512
|
+
removed.discard(setting)
|
|
491
513
|
return removed
|
|
492
514
|
|
|
493
515
|
@staticmethod
|
|
494
|
-
def replace(settings: Setting | list[Setting], values: set[Setting] = None) -> set[Setting]:
|
|
516
|
+
def replace(settings: Setting | list[Setting], values: set[Setting] | None = None) -> set[Setting]:
|
|
495
517
|
if values is None:
|
|
496
518
|
values = set()
|
|
497
519
|
if not isinstance(settings, list):
|
|
@@ -518,7 +540,7 @@ class Setting(BaseModel):
|
|
|
518
540
|
diff = first.difference(second)
|
|
519
541
|
for s in first.intersection(second):
|
|
520
542
|
a, b = [Setting.get_by_name(s.parameter.name, group) for group in [first, second]]
|
|
521
|
-
if a.value != b.value:
|
|
543
|
+
if a is not None and b is not None and a.value != b.value:
|
|
522
544
|
diff.add(a)
|
|
523
545
|
return diff
|
|
524
546
|
|
|
@@ -555,7 +577,7 @@ class Setting(BaseModel):
|
|
|
555
577
|
def __hash__(self):
|
|
556
578
|
return hash(self.parameter)
|
|
557
579
|
|
|
558
|
-
def __eq__(self, other:
|
|
580
|
+
def __eq__(self, other: Any) -> bool:
|
|
559
581
|
if not (isinstance(other, Setting) and self.parameter == other.parameter):
|
|
560
582
|
return False
|
|
561
583
|
if isinstance(self.value, np.ndarray):
|
|
@@ -217,19 +217,19 @@ import jinja2
|
|
|
217
217
|
import numpy as np
|
|
218
218
|
|
|
219
219
|
from exa.common.data.base_model import BaseModel
|
|
220
|
-
from exa.common.data.parameter import CollectionType, Parameter, Setting
|
|
220
|
+
from exa.common.data.parameter import CollectionType, Parameter, Setting, SourceType
|
|
221
221
|
from exa.common.errors.exa_error import UnknownSettingError
|
|
222
222
|
from exa.common.qcm_data.chip_topology import sort_components
|
|
223
223
|
|
|
224
224
|
logger = logging.getLogger(__name__)
|
|
225
225
|
|
|
226
226
|
|
|
227
|
-
def _fix_path_recursive(node: SettingNode
|
|
227
|
+
def _fix_path_recursive(node: SettingNode, path: str) -> SettingNode:
|
|
228
228
|
"""Recursively travel the settings tree and fix the ``path``attribute (also aligns ``name``,
|
|
229
229
|
based on the node type). Deep copies all the child nodes.
|
|
230
230
|
"""
|
|
231
|
-
settings = {}
|
|
232
|
-
subtrees = {}
|
|
231
|
+
settings: dict[str, Setting] = {}
|
|
232
|
+
subtrees: dict[str, SettingNode] = {}
|
|
233
233
|
for key, setting in node.settings.items():
|
|
234
234
|
child_path = f"{path}.{key}"
|
|
235
235
|
update_dict = {"path": child_path}
|
|
@@ -305,8 +305,8 @@ class SettingNode(BaseModel):
|
|
|
305
305
|
generate_paths: bool = True,
|
|
306
306
|
**kwargs,
|
|
307
307
|
):
|
|
308
|
-
settings
|
|
309
|
-
subtrees
|
|
308
|
+
settings = settings or {}
|
|
309
|
+
subtrees = subtrees or {}
|
|
310
310
|
|
|
311
311
|
for key, child in kwargs.items():
|
|
312
312
|
if isinstance(child, Setting):
|
|
@@ -603,7 +603,7 @@ class SettingNode(BaseModel):
|
|
|
603
603
|
"""
|
|
604
604
|
for key, item in other.settings.items():
|
|
605
605
|
if key in self.settings and (prioritize_other or (self[key].value is None)):
|
|
606
|
-
self.settings[key] = Setting(self.settings[key].parameter, item.value)
|
|
606
|
+
self.settings[key] = Setting(self.settings[key].parameter, item.value, source=self.settings[key].source)
|
|
607
607
|
for key, item in other.subtrees.items():
|
|
608
608
|
if key in self.subtrees:
|
|
609
609
|
self.subtrees[key].merge_values(copy(item), prioritize_other)
|
|
@@ -650,7 +650,7 @@ class SettingNode(BaseModel):
|
|
|
650
650
|
append_lines(self, lines, [])
|
|
651
651
|
print("\n", "\n".join(lines))
|
|
652
652
|
|
|
653
|
-
def __eq__(self, other:
|
|
653
|
+
def __eq__(self, other: Any) -> bool:
|
|
654
654
|
return isinstance(other, SettingNode) and (
|
|
655
655
|
(self.name, self.settings, self.subtrees) == (other.name, other.settings, other.subtrees)
|
|
656
656
|
)
|
|
@@ -678,16 +678,22 @@ class SettingNode(BaseModel):
|
|
|
678
678
|
new.subtrees[key] = cls.transform_node_types(subnode)
|
|
679
679
|
return new
|
|
680
680
|
|
|
681
|
-
def set_from_dict(
|
|
681
|
+
def set_from_dict(
|
|
682
|
+
self,
|
|
683
|
+
dct: dict[str, Any],
|
|
684
|
+
strict: bool = False,
|
|
685
|
+
source: SourceType = None,
|
|
686
|
+
) -> None:
|
|
682
687
|
"""Recursively set values to Settings, taking values from a dictionary that has similar tree structure.
|
|
683
|
-
Keys that are not found in self are ignored, unless
|
|
688
|
+
Keys that are not found in self are ignored, unless ``strict`` is True.
|
|
684
689
|
|
|
685
690
|
Args:
|
|
686
691
|
dct: Dictionary containing the new values to use.
|
|
687
|
-
strict: If True, will raise error if
|
|
692
|
+
strict: If True, will raise error if ``dct`` contains a setting that is not found in ``self``.
|
|
693
|
+
source: Source for the settings (this same source is applied to all settings from the dict).
|
|
688
694
|
|
|
689
695
|
Raises:
|
|
690
|
-
UnknownSettingError: If the condition of
|
|
696
|
+
UnknownSettingError: If the condition of ``strict`` happens.
|
|
691
697
|
|
|
692
698
|
"""
|
|
693
699
|
for key, value in dct.items():
|
|
@@ -704,13 +710,17 @@ class SettingNode(BaseModel):
|
|
|
704
710
|
self.settings[key].name,
|
|
705
711
|
self.settings[key].parameter.data_type.cast(value),
|
|
706
712
|
path=self.settings[key].path,
|
|
713
|
+
source=source,
|
|
707
714
|
)
|
|
708
715
|
else:
|
|
709
|
-
self.settings[key] = self.settings[key].update(value)
|
|
716
|
+
self.settings[key] = self.settings[key].update(value, source=source)
|
|
710
717
|
|
|
711
|
-
def setting_with_path_name(self, setting: Setting) -> Setting:
|
|
718
|
+
def setting_with_path_name(self, setting: Setting) -> Setting | None:
|
|
712
719
|
"""Get a copy of a setting with its name replaced with the path name."""
|
|
713
|
-
|
|
720
|
+
first_item = self.find_by_name(setting.name)
|
|
721
|
+
if isinstance(first_item, Setting):
|
|
722
|
+
return first_item.with_path_name()
|
|
723
|
+
return None
|
|
714
724
|
|
|
715
725
|
def diff(self, other: SettingNode, *, path: str = "") -> list[str]:
|
|
716
726
|
"""Recursive diff between two SettingNodes.
|
|
@@ -855,6 +865,7 @@ class SettingNode(BaseModel):
|
|
|
855
865
|
nodes: Iterable[Setting | Parameter | SettingNode] | dict[str, Setting | Parameter | SettingNode],
|
|
856
866
|
path: str,
|
|
857
867
|
override_values: dict[str, Any] | None = None,
|
|
868
|
+
override_source: SourceType = None,
|
|
858
869
|
) -> None:
|
|
859
870
|
"""Add nodes to ``self`` while creating the missing nodes in-between.
|
|
860
871
|
|
|
@@ -870,6 +881,8 @@ class SettingNode(BaseModel):
|
|
|
870
881
|
found in self, the associated nodes will be created automatically.
|
|
871
882
|
override_values: Optionally override the values for the `Settings` corresponding to ``nodes``. This dict
|
|
872
883
|
should have the same structure as ``nodes``, including matching names.
|
|
884
|
+
override_source: Optionally override the source for the ``Settings`` corresponding to ``nodes``. All the
|
|
885
|
+
settings will then have this same source.
|
|
873
886
|
|
|
874
887
|
"""
|
|
875
888
|
override_values = override_values or {}
|
|
@@ -888,7 +901,7 @@ class SettingNode(BaseModel):
|
|
|
888
901
|
latest_node[fragment] = SettingNode(name=fragment, align_name=latest_node.align_name)
|
|
889
902
|
latest_node = latest_node[fragment]
|
|
890
903
|
# finally add the nodes
|
|
891
|
-
nodes_to_add = nodes.values() if isinstance(nodes, dict) else nodes
|
|
904
|
+
nodes_to_add: Iterable[Setting | Parameter | SettingNode] = nodes.values() if isinstance(nodes, dict) else nodes
|
|
892
905
|
nodes_keys = list(nodes.keys()) if isinstance(nodes, dict) else []
|
|
893
906
|
for idx, node in enumerate(nodes_to_add):
|
|
894
907
|
key = nodes_keys[idx] if isinstance(nodes, dict) else node.name.split(".")[-1]
|
|
@@ -896,9 +909,10 @@ class SettingNode(BaseModel):
|
|
|
896
909
|
latest_node[key] = node
|
|
897
910
|
else:
|
|
898
911
|
default_value = node.value if isinstance(node, Setting) else None
|
|
912
|
+
source = override_source or (node.source if isinstance(node, Setting) else None)
|
|
899
913
|
parameter = node.parameter if isinstance(node, Setting) else node
|
|
900
914
|
value = override_values.get(node.name) if override_values.get(node.name) is not None else default_value
|
|
901
|
-
latest_node[key] = Setting(parameter, value)
|
|
915
|
+
latest_node[key] = Setting(parameter, value, source=source)
|
|
902
916
|
|
|
903
917
|
def get_default_implementation_name(self, gate: str, locus: str | Iterable[str]) -> str:
|
|
904
918
|
"""Get the default implementation name for a given gate and locus.
|
|
@@ -926,10 +940,7 @@ class SettingNode(BaseModel):
|
|
|
926
940
|
):
|
|
927
941
|
if isinstance(locus, str):
|
|
928
942
|
locus = locus.split("__")
|
|
929
|
-
if gate_settings.symmetric.value
|
|
930
|
-
loci = list(permutations(locus))
|
|
931
|
-
else:
|
|
932
|
-
loci = [tuple(locus)]
|
|
943
|
+
loci = list(permutations(locus)) if gate_settings.symmetric.value else [tuple(locus)]
|
|
933
944
|
for permuted_locus in loci:
|
|
934
945
|
locus_str = "__".join(permuted_locus)
|
|
935
946
|
if locus_str in gate_settings[impl].override_default_for_loci.value:
|
|
@@ -987,7 +998,7 @@ class SettingNode(BaseModel):
|
|
|
987
998
|
The locus node (string) paths corresponding to this gate.
|
|
988
999
|
|
|
989
1000
|
"""
|
|
990
|
-
node_paths = []
|
|
1001
|
+
node_paths: list[str] = []
|
|
991
1002
|
if "gates" not in self.children or gate not in self.gates.children:
|
|
992
1003
|
return node_paths
|
|
993
1004
|
if implementations is not None:
|
|
@@ -1034,7 +1045,21 @@ class SettingNode(BaseModel):
|
|
|
1034
1045
|
|
|
1035
1046
|
raise ValueError(f"Locus {locus} cannot be found in the gate properties characterization settings.")
|
|
1036
1047
|
|
|
1037
|
-
def
|
|
1048
|
+
def set_source(self, source: SourceType, ignore_nones: bool = True) -> None:
|
|
1049
|
+
"""Set source recursively to all Settings in ``self``.
|
|
1050
|
+
|
|
1051
|
+
Args:
|
|
1052
|
+
source: The source to set.
|
|
1053
|
+
ignore_nones: If ``True``, the source will not be set for Settings with ``None`` value.
|
|
1054
|
+
|
|
1055
|
+
"""
|
|
1056
|
+
for setting in self.settings.values():
|
|
1057
|
+
if not ignore_nones or setting.value is not None:
|
|
1058
|
+
setting._source = source
|
|
1059
|
+
for subtree in self.subtrees.values():
|
|
1060
|
+
subtree.set_source(source, ignore_nones=ignore_nones)
|
|
1061
|
+
|
|
1062
|
+
def _get_symmetric_loci(self, gate: str, implementation: str, locus: str | Iterable[str]) -> list[str]:
|
|
1038
1063
|
if not isinstance(locus, str):
|
|
1039
1064
|
if self.gate_definitions[gate][implementation].symmetric.value:
|
|
1040
1065
|
str_loci = ["__".join(sort_components(locus))]
|
|
@@ -13,13 +13,15 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
from collections.abc import Hashable
|
|
17
|
+
|
|
16
18
|
import xarray as xr
|
|
17
19
|
|
|
18
20
|
"""Helper methods for data manipulation.
|
|
19
21
|
"""
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
def add_data_array(ds: xr.Dataset, da: xr.DataArray, name:
|
|
24
|
+
def add_data_array(ds: xr.Dataset, da: xr.DataArray, name: Hashable | None = None) -> xr.Dataset:
|
|
23
25
|
"""Add data array `da` to dataset `ds`.
|
|
24
26
|
|
|
25
27
|
Unlike the default xarray command, preserves metadata of the dataset.
|
|
@@ -50,7 +52,7 @@ def add_data_array(ds: xr.Dataset, da: xr.DataArray, name: str | None = None) ->
|
|
|
50
52
|
ds[name] = da
|
|
51
53
|
for key in ds.coords:
|
|
52
54
|
if attributes.get(key):
|
|
53
|
-
ds.coords[key].attrs = attributes.get(key)
|
|
55
|
+
ds.coords[key].attrs = attributes.get(key) # type:ignore[assignment]
|
|
54
56
|
for key in ds.data_vars:
|
|
55
57
|
if attributes.get(key):
|
|
56
58
|
ds.data_vars[key].attrs = attributes[key]
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/helpers/software_version_helper.py
RENAMED
|
@@ -30,7 +30,7 @@ def _is_editable(pkg_name: str) -> bool:
|
|
|
30
30
|
``importlib.metadata``, so it might break anytime.
|
|
31
31
|
"""
|
|
32
32
|
dist = distribution(pkg_name)
|
|
33
|
-
return dist.files and dist.files[0].name.startswith("__editable__.")
|
|
33
|
+
return dist.files is not None and dist.files[0].name.startswith("__editable__.")
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def get_all_software_versions(reload_module: bool = False) -> dict[str, str]:
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
from collections.abc import Collection
|
|
18
18
|
from functools import cached_property
|
|
19
19
|
import re
|
|
20
|
+
from typing import Any
|
|
20
21
|
|
|
21
22
|
from pydantic import Field, field_validator
|
|
22
23
|
|
|
23
24
|
from exa.common.qcm_data.immutable_base_model import ImmutableBaseModel
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
def _natural_sort_key(name: str) -> tuple[int, ...]:
|
|
27
|
+
def _natural_sort_key(name: str) -> tuple[int | str | Any, ...]:
|
|
27
28
|
return tuple(int(item) if item.isdigit() else item.lower() for item in re.split(r"(\d+)", name))
|
|
28
29
|
|
|
29
30
|
|
|
@@ -76,7 +77,7 @@ class Components(ImmutableBaseModel):
|
|
|
76
77
|
|
|
77
78
|
@cached_property
|
|
78
79
|
def all(self) -> dict[str, Component]:
|
|
79
|
-
components: tuple[Qubit
|
|
80
|
+
components: tuple[Qubit | Coupler | ProbeLine | Launcher | ComputationalResonator, ...] = (
|
|
80
81
|
self.qubits + self.couplers + self.probe_lines + self.launchers + self.computational_resonators
|
|
81
82
|
)
|
|
82
83
|
return {component.name: component for component in components}
|
|
@@ -109,7 +109,7 @@ class ChipTopology:
|
|
|
109
109
|
coupler: tuple(sort_components(components)) for coupler, components in couplers.items()
|
|
110
110
|
}
|
|
111
111
|
"""Map from each coupler to all other components it connects to. The values are sorted."""
|
|
112
|
-
component_to_couplers = {}
|
|
112
|
+
component_to_couplers: dict = {}
|
|
113
113
|
for coupler, components in couplers.items():
|
|
114
114
|
for c in components:
|
|
115
115
|
component_to_couplers.setdefault(c, set()).add(coupler)
|
|
@@ -128,7 +128,7 @@ class ChipTopology:
|
|
|
128
128
|
Components without connection to a probe line don't appear.
|
|
129
129
|
"""
|
|
130
130
|
|
|
131
|
-
self._locus_mappings: dict[
|
|
131
|
+
self._locus_mappings: dict[str, dict[Locus, tuple[str, ...]]] = {
|
|
132
132
|
DEFAULT_1QB_MAPPING: {(qubit,): (qubit,) for qubit in self.qubits_sorted},
|
|
133
133
|
DEFAULT_2QB_MAPPING: {
|
|
134
134
|
frozenset(comps): (coupler,)
|
|
@@ -244,7 +244,7 @@ class ChipTopology:
|
|
|
244
244
|
"""Get probelines that are connected to any of the given components."""
|
|
245
245
|
return {self.component_to_probe_line[c] for c in components if c in self.component_to_probe_line}
|
|
246
246
|
|
|
247
|
-
def get_connected_coupler_map(self, components: Collection[str]) ->
|
|
247
|
+
def get_connected_coupler_map(self, components: Collection[str]) -> dict[str, tuple[str, ...]]:
|
|
248
248
|
"""Returns a `ComponentMap`, including only the couplers between components that both are in the given subset.
|
|
249
249
|
|
|
250
250
|
Args:
|
|
@@ -261,7 +261,7 @@ class ChipTopology:
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
@staticmethod
|
|
264
|
-
def limit_values(dct: ComponentMap, limit_to: Collection[str]) ->
|
|
264
|
+
def limit_values(dct: ComponentMap, limit_to: Collection[str]) -> dict[str, Collection[str]]:
|
|
265
265
|
"""Prunes the given dictionary (e.g. a coupler-to-qubits map) to a subset of values.
|
|
266
266
|
|
|
267
267
|
Used to prune e.g. :attr:`coupler_to_components` to a subset of relevant elements.
|
|
@@ -313,7 +313,7 @@ class ChipTopology:
|
|
|
313
313
|
self._validate_locus_mapping(mapping)
|
|
314
314
|
self._locus_mappings[name] = mapping
|
|
315
315
|
|
|
316
|
-
def _validate_locus_mapping(self, mapping: dict[
|
|
316
|
+
def _validate_locus_mapping(self, mapping: dict[Locus, tuple[str, ...]]) -> None:
|
|
317
317
|
"""Validate that the components given in mapping are found in self and the mapping is correctly formed."""
|
|
318
318
|
for locus, mapped in mapping.items():
|
|
319
319
|
if not isinstance(locus, tuple) and not isinstance(locus, frozenset):
|
|
@@ -325,7 +325,7 @@ class ChipTopology:
|
|
|
325
325
|
if locus_component not in self.all_components:
|
|
326
326
|
raise ValueError(f"Locus component {locus_component} is not found in this ChipTopology.")
|
|
327
327
|
|
|
328
|
-
def map_locus(self, locus: Locus, name: str | None = None) -> str | tuple[str] | None:
|
|
328
|
+
def map_locus(self, locus: Locus, name: str | None = None) -> str | tuple[str, ...] | None:
|
|
329
329
|
"""Returns the mapped components for the given locus and the given gate.
|
|
330
330
|
|
|
331
331
|
If the locus or the gate is not found from the locus mappings of self, returns None.
|
|
@@ -388,7 +388,7 @@ class ChipTopology:
|
|
|
388
388
|
name = DEFAULT_1QB_MAPPING
|
|
389
389
|
elif default_mapping_dimension == 2:
|
|
390
390
|
name = DEFAULT_2QB_MAPPING
|
|
391
|
-
return
|
|
391
|
+
return list(self._locus_mappings.get(name, {}))
|
|
392
392
|
|
|
393
393
|
def get_common_computational_resonator(self, first_qubit: str, second_qubit: str) -> str:
|
|
394
394
|
"""Convenience method for getting the name of a computational resonator which is connected to both specified
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/qcm_data_client.py
RENAMED
|
@@ -62,7 +62,7 @@ class QCMDataClient:
|
|
|
62
62
|
# Make the cache containers local to the instances so that the reference from cache to the instance
|
|
63
63
|
# gets scraped off with the instance
|
|
64
64
|
# https://rednafi.github.io/reflections/dont-wrap-instance-methods-with-functoolslru_cache-decorator-in-python.html
|
|
65
|
-
self._send_request = cache(self._send_request)
|
|
65
|
+
self._send_request = cache(self._send_request) # type:ignore[method-assign]
|
|
66
66
|
|
|
67
67
|
@property
|
|
68
68
|
def root_url(self) -> str:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
26.27.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
26.25.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_templates/autosummary-class-template.rst
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/docs/_templates/autosummary-module-template.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/array.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/datum.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/nd_sweep.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/api/proto_serialization/sequence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/exponential_sweep.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/fixed_sweep.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/linear_sweep.py
RENAMED
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/control/sweep/option/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/data/settingnode_v2.html.jinja2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/errors/station_control_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/qcm_data/immutable_base_model.py
RENAMED
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/exa/common/sweep/database_serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iqm_exa_common-26.25.0 → iqm_exa_common-26.27.0}/src/iqm_exa_common.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|