qcodes-loop 0.1.3__tar.gz → 0.2.1__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.
Files changed (63) hide show
  1. {qcodes_loop-0.1.3/src/qcodes_loop.egg-info → qcodes_loop-0.2.1}/PKG-INFO +12 -12
  2. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/pyproject.toml +14 -16
  3. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/setup.py +1 -0
  4. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/__init__.py +1 -0
  5. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/_version.py +1 -1
  6. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/actions.py +21 -19
  7. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/data_array.py +100 -75
  8. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/data_set.py +102 -87
  9. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/format.py +42 -35
  10. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/gnuplot_format.py +79 -53
  11. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/hdf5_format.py +145 -134
  12. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/hdf5_format_hickle.py +9 -10
  13. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/io.py +8 -9
  14. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/location.py +28 -25
  15. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/extensions/slack.py +2 -4
  16. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/loops.py +207 -124
  17. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/measure.py +28 -19
  18. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/plots/base.py +45 -27
  19. qcodes_loop-0.2.1/src/qcodes_loop/plots/colors.py +188 -0
  20. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/plots/pyqtgraph.py +138 -107
  21. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/plots/qcmatplotlib.py +100 -83
  22. qcodes_loop-0.2.1/src/qcodes_loop/sweep_values.py +515 -0
  23. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/common.py +3 -12
  24. qcodes_loop-0.2.1/src/qcodes_loop/tests/data_mocks.py +166 -0
  25. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_channels.py +278 -0
  26. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_combined_loop.py +129 -93
  27. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_data.py +157 -141
  28. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_format.py +104 -106
  29. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_generic_formatter.py +11 -9
  30. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_hdf5formatter.py +105 -92
  31. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_issequence.py +54 -0
  32. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_location_provider.py +120 -0
  33. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_loop.py +184 -152
  34. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_make_sweep.py +39 -0
  35. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_measure.py +30 -30
  36. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_permissive_range.py +33 -0
  37. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_plots.py +19 -13
  38. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_qcmatplotlib_functions.py +8 -16
  39. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_slack.py +97 -105
  40. qcodes_loop-0.2.1/src/qcodes_loop/tests/test_sweep_values.py +156 -0
  41. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_threading.py +4 -6
  42. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/utils/magic.py +31 -30
  43. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1/src/qcodes_loop.egg-info}/PKG-INFO +12 -12
  44. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop.egg-info/SOURCES.txt +5 -0
  45. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop.egg-info/requires.txt +6 -6
  46. qcodes_loop-0.1.3/src/qcodes_loop/plots/colors.py +0 -135
  47. qcodes_loop-0.1.3/src/qcodes_loop/tests/data_mocks.py +0 -150
  48. qcodes_loop-0.1.3/src/qcodes_loop/tests/test_channels.py +0 -296
  49. qcodes_loop-0.1.3/src/qcodes_loop/tests/test_location_provider.py +0 -118
  50. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/LICENSE +0 -0
  51. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/MANIFEST.in +0 -0
  52. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/README.rst +0 -0
  53. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/setup.cfg +0 -0
  54. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/data/__init__.py +0 -0
  55. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/extensions/__init__.py +0 -0
  56. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/plots/__init__.py +0 -0
  57. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/py.typed +0 -0
  58. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/__init__.py +0 -0
  59. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/tests/test_waitsecs.py +0 -0
  60. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/utils/__init__.py +0 -0
  61. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop/utils/qt_helpers.py +0 -0
  62. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop.egg-info/dependency_links.txt +0 -0
  63. {qcodes_loop-0.1.3 → qcodes_loop-0.2.1}/src/qcodes_loop.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: qcodes_loop
3
- Version: 0.1.3
3
+ Version: 0.2.1
4
4
  Summary: Features previously in QCoDeS
5
5
  Maintainer-email: QCoDeS Core Developers <qcodes-support@microsoft.com>
6
6
  License: MIT
@@ -12,19 +12,18 @@ Classifier: Development Status :: 3 - Alpha
12
12
  Classifier: Intended Audience :: Science/Research
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Programming Language :: Python :: 3 :: Only
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
19
18
  Classifier: Topic :: Scientific/Engineering
20
- Requires-Python: >=3.9
19
+ Requires-Python: >=3.12
21
20
  Description-Content-Type: text/x-rst
22
21
  License-File: LICENSE
23
22
  Requires-Dist: qcodes>=0.42.0
24
23
  Requires-Dist: h5py>=3.0.0
25
24
  Requires-Dist: lazy_loader>=0.1
26
25
  Requires-Dist: matplotlib>=3.3.0
27
- Requires-Dist: numpy>=1.21.0
26
+ Requires-Dist: numpy<2.5.0,>=1.21.0
28
27
  Requires-Dist: pandas>=1.0.0
29
28
  Requires-Dist: versioningit>=2.2.1
30
29
  Requires-Dist: xarray>=0.18.0
@@ -42,19 +41,20 @@ Requires-Dist: hypothesis>=5.49.0; extra == "test"
42
41
  Requires-Dist: pytest>=6.1.0; extra == "test"
43
42
  Requires-Dist: pytest-xdist>=2.0.0; extra == "test"
44
43
  Requires-Dist: pytest-mock>=3.0.0; extra == "test"
45
- Requires-Dist: pyqtgraph>=0.11.0; extra == "test"
46
- Requires-Dist: PyQt5>=5.15.0; extra == "test"
44
+ Requires-Dist: pyqtgraph>=0.13.0; extra == "test"
45
+ Requires-Dist: pyside6>=6.8.0; extra == "test"
47
46
  Requires-Dist: slack-sdk>=3.4.2; extra == "test"
48
47
  Requires-Dist: requests; extra == "test"
49
48
  Requires-Dist: urllib3; extra == "test"
50
49
  Provides-Extra: docs
51
50
  Requires-Dist: nbsphinx>=0.8.9; extra == "docs"
52
- Requires-Dist: PyQt5>=5.15.0; extra == "docs"
53
- Requires-Dist: pyqtgraph>=0.11.0; extra == "docs"
54
- Requires-Dist: sphinx<9.0.0,>=4.5.0; extra == "docs"
51
+ Requires-Dist: pyside6>=6.8.0; extra == "docs"
52
+ Requires-Dist: pyqtgraph>=0.13.0; extra == "docs"
53
+ Requires-Dist: sphinx<9.2.0,>=4.5.0; extra == "docs"
55
54
  Requires-Dist: slack-sdk>=3.4.2; extra == "docs"
56
55
  Requires-Dist: requests; extra == "docs"
57
56
  Requires-Dist: urllib3; extra == "docs"
57
+ Dynamic: license-file
58
58
 
59
59
  qcodes_loop
60
60
  ===========
@@ -14,20 +14,19 @@ classifiers = [
14
14
  "Intended Audience :: Science/Research",
15
15
  "License :: OSI Approved :: MIT License",
16
16
  "Programming Language :: Python :: 3 :: Only",
17
- "Programming Language :: Python :: 3.9",
18
- "Programming Language :: Python :: 3.10",
19
- "Programming Language :: Python :: 3.11",
20
17
  "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
21
20
  "Topic :: Scientific/Engineering",
22
21
  ]
23
22
  license = {text = "MIT"}
24
- requires-python = ">=3.9"
23
+ requires-python = ">=3.12"
25
24
  dependencies = [
26
25
  "qcodes>=0.42.0",
27
26
  "h5py>=3.0.0",
28
27
  "lazy_loader>=0.1",
29
28
  "matplotlib>=3.3.0",
30
- "numpy>=1.21.0",
29
+ "numpy>=1.21.0,<2.5.0", # 2.4 removed support for assigning non scalar values to array elements. Code needs updating for this
31
30
  "pandas>=1.0.0",
32
31
  "versioningit>=2.2.1",
33
32
  "xarray>=0.18.0",
@@ -56,17 +55,17 @@ test = [
56
55
  "pytest>=6.1.0",
57
56
  "pytest-xdist>=2.0.0",
58
57
  "pytest-mock>=3.0.0",
59
- "pyqtgraph>=0.11.0", # pyqtgraph tests
60
- "PyQt5>=5.15.0", # pyqtgraph tests
58
+ "pyqtgraph>=0.13.0", # pyqtgraph tests
59
+ "pyside6>=6.8.0", # pyqtgraph tests
61
60
  "slack-sdk>=3.4.2", # slack tests and typecheck
62
61
  "requests", # slack tests and typecheck
63
62
  "urllib3", # slack tests and typecheck
64
63
  ]
65
64
  docs = [
66
65
  "nbsphinx>=0.8.9",
67
- "PyQt5>=5.15.0", # pyqtgraph examples
68
- "pyqtgraph>=0.11.0", # pyqtgraph examples
69
- "sphinx>=4.5.0,<9.0.0",
66
+ "pyside6>=6.8.0", # pyqtgraph examples
67
+ "pyqtgraph>=0.13.0", # pyqtgraph examples
68
+ "sphinx>=4.5.0,<9.2.0",
70
69
  "slack-sdk>=3.4.2", # slack docs
71
70
  "requests", # slack docs
72
71
  "urllib3", # slack docs
@@ -83,12 +82,6 @@ exclude_lines = [
83
82
  "if TYPE_CHECKING:",
84
83
  ]
85
84
 
86
- [tool.darker]
87
- isort = true
88
-
89
- [tool.isort]
90
- profile = "black"
91
-
92
85
  [tool.pytest.ini_options]
93
86
  minversion = "6.0"
94
87
  junit_family = "legacy"
@@ -104,6 +97,11 @@ filterwarnings = [
104
97
  "ignore:SelectableGroups dict interface is deprecated:DeprecationWarning"
105
98
  ]
106
99
 
100
+ [tool.ruff]
101
+
102
+ [tool.ruff.lint]
103
+
104
+ select = ["I","UP"]
107
105
  [tool.setuptools.cmdclass]
108
106
  sdist = "versioningit.cmdclass.sdist"
109
107
  build_py = "versioningit.cmdclass.build_py"
@@ -2,6 +2,7 @@
2
2
  This file only exists as a fallback for older versions of pip/setuptools
3
3
  All configuration is done in pyproject.toml
4
4
  """
5
+
5
6
  from setuptools import setup
6
7
 
7
8
  if __name__ == "__main__":
@@ -1,6 +1,7 @@
1
1
  import qcodes
2
2
 
3
3
  import qcodes_loop._version
4
+ from qcodes_loop.sweep_values import Sweeper, SweepFixedValues, SweepValues
4
5
 
5
6
  __version__ = qcodes_loop._version.__version__
6
7
 
@@ -9,4 +9,4 @@ def _get_version() -> str:
9
9
  return versioningit.get_version(project_dir=module_path.parent.parent)
10
10
 
11
11
 
12
- __version__ = "0.1.3"
12
+ __version__ = "0.2.1"
@@ -1,9 +1,10 @@
1
1
  """Actions, mainly to be executed in measurement Loops."""
2
+
2
3
  import time
3
4
 
4
5
  from qcodes.utils import is_function, thread_map
5
6
 
6
- _NO_SNAPSHOT = {'type': None, 'description': 'Action without snapshot'}
7
+ _NO_SNAPSHOT = {"type": None, "description": "Action without snapshot"}
7
8
 
8
9
 
9
10
  # exception when threading is attempted used to simultaneously
@@ -16,7 +17,7 @@ def _actions_snapshot(actions, update):
16
17
  """Make a list of snapshots from a list of actions."""
17
18
  snapshot = []
18
19
  for action in actions:
19
- if hasattr(action, 'snapshot'):
20
+ if hasattr(action, "snapshot"):
20
21
  snapshot.append(action.snapshot(update=update))
21
22
  else:
22
23
  snapshot.append(_NO_SNAPSHOT)
@@ -41,6 +42,7 @@ class Task:
41
42
  **kwargs: pass to func, after evaluation if callable
42
43
 
43
44
  """
45
+
44
46
  def __init__(self, func, *args, **kwargs):
45
47
  self.func = func
46
48
  self.args = args
@@ -62,7 +64,7 @@ class Task:
62
64
  Returns:
63
65
  dict: snapshot
64
66
  """
65
- return {'type': 'Task', 'func': repr(self.func)}
67
+ return {"type": "Task", "func": repr(self.func)}
66
68
 
67
69
 
68
70
  class Wait:
@@ -80,6 +82,7 @@ class Wait:
80
82
  Raises:
81
83
  ValueError: if delay is negative
82
84
  """
85
+
83
86
  def __init__(self, delay):
84
87
  if not delay >= 0:
85
88
  raise ValueError(f"delay must be > 0, not {repr(delay)}")
@@ -98,7 +101,7 @@ class Wait:
98
101
  Returns:
99
102
  dict: snapshot
100
103
  """
101
- return {'type': 'Wait', 'delay': self.delay}
104
+ return {"type": "Wait", "delay": self.delay}
102
105
 
103
106
 
104
107
  class _Measure:
@@ -107,6 +110,7 @@ class _Measure:
107
110
 
108
111
  This should not be constructed manually, only by an ActiveLoop.
109
112
  """
113
+
110
114
  def __init__(self, params_indices, data_set, use_threads):
111
115
  self.use_threads = use_threads and len(params_indices) > 1
112
116
  # the applicable DataSet.store function
@@ -124,7 +128,7 @@ class _Measure:
124
128
  if param._instrument:
125
129
  paramcheck.append((param, param._instrument))
126
130
 
127
- if hasattr(param, 'names'):
131
+ if hasattr(param, "names"):
128
132
  part_ids = []
129
133
  for i in range(len(param.names)):
130
134
  param_id = data_set.action_id_map[action_indices + (i,)]
@@ -138,14 +142,16 @@ class _Measure:
138
142
 
139
143
  if self.use_threads:
140
144
  insts = [p[1] for p in paramcheck]
141
- if (len(set(insts)) != len(insts)):
145
+ if len(set(insts)) != len(insts):
142
146
  duplicates = [p for p in paramcheck if insts.count(p[1]) > 1]
143
- raise UnsafeThreadingException('Can not use threading to '
144
- 'read '
145
- 'several things from the same '
146
- 'instrument. Specifically, you '
147
- 'asked for'
148
- ' {}.'.format(duplicates))
147
+ raise UnsafeThreadingException(
148
+ "Can not use threading to "
149
+ "read "
150
+ "several things from the same "
151
+ "instrument. Specifically, you "
152
+ "asked for"
153
+ f" {duplicates}."
154
+ )
149
155
 
150
156
  def __call__(self, loop_indices, **ignore_kwargs):
151
157
  out_dict = {}
@@ -154,8 +160,7 @@ class _Measure:
154
160
  else:
155
161
  out = [g() for g in self.getters]
156
162
 
157
- for param_out, param_id, composite in zip(out, self.param_ids,
158
- self.composite):
163
+ for param_out, param_id, composite in zip(out, self.param_ids, self.composite):
159
164
  if composite:
160
165
  for val, part_id in zip(param_out, composite):
161
166
  out_dict[part_id] = val
@@ -166,7 +171,6 @@ class _Measure:
166
171
 
167
172
 
168
173
  class _Nest:
169
-
170
174
  """
171
175
  Wrapper to make a callable nested ActiveLoop.
172
176
 
@@ -182,7 +186,6 @@ class _Nest:
182
186
 
183
187
 
184
188
  class BreakIf:
185
-
186
189
  """
187
190
  Loop action that breaks out of the loop if a condition is truthy.
188
191
 
@@ -198,8 +201,7 @@ class BreakIf:
198
201
 
199
202
  def __init__(self, condition):
200
203
  if not is_function(condition, 0):
201
- raise TypeError('BreakIf condition must be a callable with '
202
- 'no arguments')
204
+ raise TypeError("BreakIf condition must be a callable with no arguments")
203
205
  self.condition = condition
204
206
 
205
207
  def __call__(self, **ignore_kwargs):
@@ -216,7 +218,7 @@ class BreakIf:
216
218
  dict: snapshot
217
219
 
218
220
  """
219
- return {'type': 'BreakIf', 'condition': repr(self.condition)}
221
+ return {"type": "BreakIf", "condition": repr(self.condition)}
220
222
 
221
223
 
222
224
  class _QcodesBreak(Exception):
@@ -1,5 +1,5 @@
1
1
  import collections.abc
2
- from typing import TYPE_CHECKING, Any, Dict, Optional
2
+ from typing import TYPE_CHECKING, Any, Optional
3
3
 
4
4
  import numpy as np
5
5
 
@@ -12,8 +12,8 @@ from qcodes.utils import DelegateAttributes, full_class
12
12
 
13
13
  _LOG = logging.getLogger(__name__)
14
14
 
15
- class DataArray(DelegateAttributes):
16
15
 
16
+ class DataArray(DelegateAttributes):
17
17
  """
18
18
  A container for one parameter in a measurement loop.
19
19
 
@@ -91,35 +91,46 @@ class DataArray(DelegateAttributes):
91
91
 
92
92
  # attributes of self to include in the snapshot
93
93
  SNAP_ATTRS = (
94
- 'array_id',
95
- 'name',
96
- 'shape',
97
- 'unit',
98
- 'label',
99
- 'action_indices',
100
- 'is_setpoint')
94
+ "array_id",
95
+ "name",
96
+ "shape",
97
+ "unit",
98
+ "label",
99
+ "action_indices",
100
+ "is_setpoint",
101
+ )
101
102
 
102
103
  # attributes of the parameter (or keys in the incoming snapshot)
103
104
  # to copy to DataArray attributes, if they aren't set some other way
104
- COPY_ATTRS_FROM_INPUT = (
105
- 'name',
106
- 'label',
107
- 'unit')
105
+ COPY_ATTRS_FROM_INPUT = ("name", "label", "unit")
108
106
 
109
107
  # keys in the parameter snapshot to omit from our snapshot
110
108
  SNAP_OMIT_KEYS = (
111
- 'ts',
112
- 'value',
113
- '__class__',
114
- 'set_arrays',
115
- 'shape',
116
- 'array_id',
117
- 'action_indices')
118
-
119
- def __init__(self, parameter=None, name=None, full_name=None, label=None,
120
- snapshot=None, array_id=None, set_arrays=(), shape=None,
121
- action_indices=(), unit=None, units=None, is_setpoint=False,
122
- preset_data=None):
109
+ "ts",
110
+ "value",
111
+ "__class__",
112
+ "set_arrays",
113
+ "shape",
114
+ "array_id",
115
+ "action_indices",
116
+ )
117
+
118
+ def __init__(
119
+ self,
120
+ parameter=None,
121
+ name=None,
122
+ full_name=None,
123
+ label=None,
124
+ snapshot=None,
125
+ array_id=None,
126
+ set_arrays=(),
127
+ shape=None,
128
+ action_indices=(),
129
+ unit=None,
130
+ units=None,
131
+ is_setpoint=False,
132
+ preset_data=None,
133
+ ):
123
134
  self.name = name
124
135
  self.full_name = full_name or name
125
136
  self.label = label
@@ -152,25 +163,23 @@ class DataArray(DelegateAttributes):
152
163
  self._snapshot_input = {}
153
164
 
154
165
  if parameter is not None:
155
- param_full_name = getattr(parameter, 'full_name', None)
166
+ param_full_name = getattr(parameter, "full_name", None)
156
167
  if param_full_name and not full_name:
157
168
  self.full_name = parameter.full_name
158
169
 
159
- if hasattr(parameter, 'snapshot') and not snapshot:
170
+ if hasattr(parameter, "snapshot") and not snapshot:
160
171
  snapshot = parameter.snapshot()
161
172
  else:
162
173
  # TODO: why is this in an else clause?
163
174
  for attr in self.COPY_ATTRS_FROM_INPUT:
164
- if (hasattr(parameter, attr) and
165
- not getattr(self, attr, None)):
175
+ if hasattr(parameter, attr) and not getattr(self, attr, None):
166
176
  setattr(self, attr, getattr(parameter, attr))
167
177
 
168
178
  for key, value in snapshot.items():
169
179
  if key not in self.SNAP_OMIT_KEYS:
170
180
  self._snapshot_input[key] = value
171
181
 
172
- if (key in self.COPY_ATTRS_FROM_INPUT and
173
- not getattr(self, key, None)):
182
+ if key in self.COPY_ATTRS_FROM_INPUT and not getattr(self, key, None):
174
183
  setattr(self, key, value)
175
184
 
176
185
  if not self.label:
@@ -193,10 +202,12 @@ class DataArray(DelegateAttributes):
193
202
 
194
203
  @data_set.setter
195
204
  def data_set(self, new_data_set):
196
- if (self._data_set is not None and
197
- new_data_set is not None and
198
- self._data_set != new_data_set):
199
- raise RuntimeError('A DataArray can only be part of one DataSet')
205
+ if (
206
+ self._data_set is not None
207
+ and new_data_set is not None
208
+ and self._data_set != new_data_set
209
+ ):
210
+ raise RuntimeError("A DataArray can only be part of one DataSet")
200
211
  self._data_set = new_data_set
201
212
 
202
213
  def nest(self, size, action_index=None, set_array=None):
@@ -225,20 +236,21 @@ class DataArray(DelegateAttributes):
225
236
  chained method calls.
226
237
  """
227
238
  if self.ndarray is not None and not self._preset:
228
- raise RuntimeError('Only preset arrays can be nested after data '
229
- 'is initialized! {}'.format(self))
239
+ raise RuntimeError(
240
+ f"Only preset arrays can be nested after data is initialized! {self}"
241
+ )
230
242
 
231
243
  if set_array is None:
232
244
  if self.set_arrays:
233
- raise TypeError('a setpoint array must be its own inner loop')
245
+ raise TypeError("a setpoint array must be its own inner loop")
234
246
  set_array = self
235
247
 
236
- self.shape = (size, ) + self.shape
248
+ self.shape = (size,) + self.shape
237
249
 
238
250
  if action_index is not None:
239
- self.action_indices = (action_index, ) + self.action_indices
251
+ self.action_indices = (action_index,) + self.action_indices
240
252
 
241
- self.set_arrays = (set_array, ) + self.set_arrays
253
+ self.set_arrays = (set_array,) + self.set_arrays
242
254
 
243
255
  if self._preset:
244
256
  inner_data = self.ndarray
@@ -289,9 +301,12 @@ class DataArray(DelegateAttributes):
289
301
  if self.shape is None:
290
302
  self.shape = data.shape
291
303
  elif data.shape != self.shape:
292
- raise ValueError('preset data must be a sequence '
293
- 'with shape matching the array shape',
294
- data.shape, self.shape)
304
+ raise ValueError(
305
+ "preset data must be a sequence "
306
+ "with shape matching the array shape",
307
+ data.shape,
308
+ self.shape,
309
+ )
295
310
  self.ndarray = data
296
311
  self._preset = True
297
312
 
@@ -300,8 +315,10 @@ class DataArray(DelegateAttributes):
300
315
 
301
316
  elif self.ndarray is not None:
302
317
  if self.ndarray.shape != self.shape:
303
- raise ValueError('data has already been initialized, '
304
- 'but its shape doesn\'t match self.shape')
318
+ raise ValueError(
319
+ "data has already been initialized, "
320
+ "but its shape doesn't match self.shape"
321
+ )
305
322
  return
306
323
  else:
307
324
  self.ndarray = np.ndarray(self.shape)
@@ -319,7 +336,7 @@ class DataArray(DelegateAttributes):
319
336
  # what people want anyway.
320
337
  if self.ndarray.dtype != float:
321
338
  self.ndarray = self.ndarray.astype(float)
322
- self.ndarray.fill(float('nan'))
339
+ self.ndarray.fill(float("nan"))
323
340
 
324
341
  def __setitem__(self, loop_indices, value):
325
342
  """
@@ -342,8 +359,7 @@ class DataArray(DelegateAttributes):
342
359
  if isinstance(index, slice):
343
360
  start, stop, step = index.indices(self.shape[i])
344
361
  min_indices[i] = start
345
- max_indices[i] = start + (
346
- ((stop - start - 1)//step) * step)
362
+ max_indices[i] = start + (((stop - start - 1) // step) * step)
347
363
 
348
364
  min_li = self.flat_index(min_indices, self._min_indices)
349
365
  max_li = self.flat_index(max_indices, self._max_indices)
@@ -354,7 +370,7 @@ class DataArray(DelegateAttributes):
354
370
  def __getitem__(self, loop_indices):
355
371
  return self.ndarray[loop_indices]
356
372
 
357
- delegate_attr_objects = ['ndarray']
373
+ delegate_attr_objects = ["ndarray"]
358
374
 
359
375
  def __len__(self):
360
376
  """
@@ -385,13 +401,15 @@ class DataArray(DelegateAttributes):
385
401
  int: the resulting flat index.
386
402
  """
387
403
  if len(indices) < len(self.shape):
388
- indices = indices + index_fill[len(indices):]
404
+ indices = indices + index_fill[len(indices) :]
389
405
  return np.ravel_multi_index(tuple(zip(indices)), self.shape)[0]
390
406
 
391
407
  def _update_modified_range(self, low, high):
392
408
  if self.modified_range:
393
- self.modified_range = (min(self.modified_range[0], low),
394
- max(self.modified_range[1], high))
409
+ self.modified_range = (
410
+ min(self.modified_range[0], low),
411
+ max(self.modified_range[1], high),
412
+ )
395
413
  else:
396
414
  self.modified_range = (low, high)
397
415
 
@@ -410,9 +428,10 @@ class DataArray(DelegateAttributes):
410
428
  if last_saved_index >= self.modified_range[1]:
411
429
  self.modified_range = None
412
430
  else:
413
- self.modified_range = (max(self.modified_range[0],
414
- last_saved_index + 1),
415
- self.modified_range[1])
431
+ self.modified_range = (
432
+ max(self.modified_range[0], last_saved_index + 1),
433
+ self.modified_range[1],
434
+ )
416
435
  self.last_saved_index = last_saved_index
417
436
 
418
437
  def clear_save(self):
@@ -438,7 +457,7 @@ class DataArray(DelegateAttributes):
438
457
  int: the last flat index which has been synced from the server,
439
458
  or -1 if no data has been synced.
440
459
  """
441
- if not hasattr(self, 'synced_index'):
460
+ if not hasattr(self, "synced_index"):
442
461
  self.init_data()
443
462
  self.synced_index = -1
444
463
 
@@ -471,11 +490,7 @@ class DataArray(DelegateAttributes):
471
490
  ]
472
491
 
473
492
  if vals:
474
- return {
475
- 'start': synced_index + 1,
476
- 'stop': latest_index,
477
- 'vals': vals
478
- }
493
+ return {"start": synced_index + 1, "stop": latest_index, "vals": vals}
479
494
 
480
495
  def apply_changes(self, start, stop, vals):
481
496
  """
@@ -497,14 +512,17 @@ class DataArray(DelegateAttributes):
497
512
  self.synced_index = stop
498
513
 
499
514
  def __repr__(self):
500
- array_id_or_none = f' {self.array_id}' if self.array_id else ''
501
- return '{}[{}]:{}\n{}'.format(self.__class__.__name__,
502
- ','.join(map(str, self.shape)),
503
- array_id_or_none, repr(self.ndarray))
515
+ array_id_or_none = f" {self.array_id}" if self.array_id else ""
516
+ return "{}[{}]:{}\n{}".format(
517
+ self.__class__.__name__,
518
+ ",".join(map(str, self.shape)),
519
+ array_id_or_none,
520
+ repr(self.ndarray),
521
+ )
504
522
 
505
523
  def snapshot(self, update=False):
506
524
  """JSON representation of this DataArray."""
507
- snap = {'__class__': full_class(self)}
525
+ snap = {"__class__": full_class(self)}
508
526
 
509
527
  snap.update(self._snapshot_input)
510
528
 
@@ -531,25 +549,26 @@ class DataArray(DelegateAttributes):
531
549
  last_index = max(last_index, self.last_saved_index)
532
550
  if self.modified_range is not None:
533
551
  last_index = max(last_index, self.modified_range[1])
534
- if getattr(self, 'synced_index', None) is not None:
552
+ if getattr(self, "synced_index", None) is not None:
535
553
  last_index = max(last_index, self.synced_index)
536
554
 
537
555
  return (last_index + 1) / self.ndarray.size
538
556
 
539
557
  def to_xarray(self) -> "xr.DataArray":
540
- """ Return this DataArray as an xarray dataarray
558
+ """Return this DataArray as an xarray dataarray
541
559
 
542
560
  Returns:
543
561
  DataArray in xarray format
544
562
  """
545
563
  import xarray as xr
564
+
546
565
  xarray_dictionary = data_array_to_xarray_dictionary(self)
547
566
  xarray_dataarray = xr.DataArray.from_dict(xarray_dictionary)
548
567
  return xarray_dataarray
549
568
 
550
569
  @classmethod
551
570
  def from_xarray(
552
- cls, xarray_dataarray: "xr.DataArray", array_id: Optional[str] = None
571
+ cls, xarray_dataarray: "xr.DataArray", array_id: str | None = None
553
572
  ) -> "DataArray":
554
573
  """Create a DataArray from an xarray DataArray
555
574
 
@@ -560,12 +579,14 @@ class DataArray(DelegateAttributes):
560
579
  """
561
580
  xarray_dict = xarray_dataarray.to_dict()
562
581
  if array_id is None:
563
- array_id = list(xarray_dict['dims'])[0]
564
- data_array = xarray_data_array_dictionary_to_data_array(array_id, xarray_dict, is_setpoint=False)
582
+ array_id = list(xarray_dict["dims"])[0]
583
+ data_array = xarray_data_array_dictionary_to_data_array(
584
+ array_id, xarray_dict, is_setpoint=False
585
+ )
565
586
  return data_array
566
587
 
567
588
 
568
- def data_array_to_xarray_dictionary(data_array: DataArray) -> Dict[str, Any]:
589
+ def data_array_to_xarray_dictionary(data_array: DataArray) -> dict[str, Any]:
569
590
  """Convert DataArray to a dictionary in xarray format.
570
591
 
571
592
  Args:
@@ -576,7 +597,7 @@ def data_array_to_xarray_dictionary(data_array: DataArray) -> Dict[str, Any]:
576
597
  """
577
598
  key_mapping = {"unit": "units", "name": "name", "label": "long_name"}
578
599
 
579
- data_dictionary: Dict[str, Any] = {"name": data_array.array_id}
600
+ data_dictionary: dict[str, Any] = {"name": data_array.array_id}
580
601
  data_dictionary["attrs"] = {
581
602
  target_key: getattr(data_array, key) for key, target_key in key_mapping.items()
582
603
  }
@@ -598,7 +619,11 @@ def data_array_to_xarray_dictionary(data_array: DataArray) -> Dict[str, Any]:
598
619
 
599
620
 
600
621
  def xarray_data_array_dictionary_to_data_array(
601
- array_id: str, array_dictionary: Dict[str, Any], is_setpoint: bool = False, preset_data=None):
622
+ array_id: str,
623
+ array_dictionary: dict[str, Any],
624
+ is_setpoint: bool = False,
625
+ preset_data=None,
626
+ ):
602
627
  """Convert xarray dictionary to a DataArray
603
628
 
604
629
  This conversion is for bith the data array and the the internal xarray structure, e.g. the datavars and coords.