QuLab 2.10.10__cp313-cp313-macosx_10_13_universal2.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.
- qulab/__init__.py +33 -0
- qulab/__main__.py +4 -0
- qulab/cli/__init__.py +0 -0
- qulab/cli/commands.py +30 -0
- qulab/cli/config.py +170 -0
- qulab/cli/decorators.py +28 -0
- qulab/dicttree.py +523 -0
- qulab/executor/__init__.py +5 -0
- qulab/executor/analyze.py +188 -0
- qulab/executor/cli.py +434 -0
- qulab/executor/load.py +563 -0
- qulab/executor/registry.py +185 -0
- qulab/executor/schedule.py +543 -0
- qulab/executor/storage.py +615 -0
- qulab/executor/template.py +259 -0
- qulab/executor/utils.py +194 -0
- qulab/expression.py +827 -0
- qulab/fun.cpython-313-darwin.so +0 -0
- qulab/monitor/__init__.py +1 -0
- qulab/monitor/__main__.py +8 -0
- qulab/monitor/config.py +41 -0
- qulab/monitor/dataset.py +77 -0
- qulab/monitor/event_queue.py +54 -0
- qulab/monitor/mainwindow.py +234 -0
- qulab/monitor/monitor.py +115 -0
- qulab/monitor/ploter.py +123 -0
- qulab/monitor/qt_compat.py +16 -0
- qulab/monitor/toolbar.py +265 -0
- qulab/scan/__init__.py +2 -0
- qulab/scan/curd.py +221 -0
- qulab/scan/models.py +554 -0
- qulab/scan/optimize.py +76 -0
- qulab/scan/query.py +387 -0
- qulab/scan/record.py +603 -0
- qulab/scan/scan.py +1166 -0
- qulab/scan/server.py +450 -0
- qulab/scan/space.py +213 -0
- qulab/scan/utils.py +234 -0
- qulab/storage/__init__.py +0 -0
- qulab/storage/__main__.py +51 -0
- qulab/storage/backend/__init__.py +0 -0
- qulab/storage/backend/redis.py +204 -0
- qulab/storage/base_dataset.py +352 -0
- qulab/storage/chunk.py +60 -0
- qulab/storage/dataset.py +127 -0
- qulab/storage/file.py +273 -0
- qulab/storage/models/__init__.py +22 -0
- qulab/storage/models/base.py +4 -0
- qulab/storage/models/config.py +28 -0
- qulab/storage/models/file.py +89 -0
- qulab/storage/models/ipy.py +58 -0
- qulab/storage/models/models.py +88 -0
- qulab/storage/models/record.py +161 -0
- qulab/storage/models/report.py +22 -0
- qulab/storage/models/tag.py +93 -0
- qulab/storage/storage.py +95 -0
- qulab/sys/__init__.py +2 -0
- qulab/sys/chat.py +688 -0
- qulab/sys/device/__init__.py +3 -0
- qulab/sys/device/basedevice.py +255 -0
- qulab/sys/device/loader.py +86 -0
- qulab/sys/device/utils.py +79 -0
- qulab/sys/drivers/FakeInstrument.py +68 -0
- qulab/sys/drivers/__init__.py +0 -0
- qulab/sys/ipy_events.py +125 -0
- qulab/sys/net/__init__.py +0 -0
- qulab/sys/net/bencoder.py +205 -0
- qulab/sys/net/cli.py +169 -0
- qulab/sys/net/dhcp.py +543 -0
- qulab/sys/net/dhcpd.py +176 -0
- qulab/sys/net/kad.py +1142 -0
- qulab/sys/net/kcp.py +192 -0
- qulab/sys/net/nginx.py +194 -0
- qulab/sys/progress.py +190 -0
- qulab/sys/rpc/__init__.py +0 -0
- qulab/sys/rpc/client.py +0 -0
- qulab/sys/rpc/exceptions.py +96 -0
- qulab/sys/rpc/msgpack.py +1052 -0
- qulab/sys/rpc/msgpack.pyi +41 -0
- qulab/sys/rpc/router.py +35 -0
- qulab/sys/rpc/rpc.py +412 -0
- qulab/sys/rpc/serialize.py +139 -0
- qulab/sys/rpc/server.py +29 -0
- qulab/sys/rpc/socket.py +29 -0
- qulab/sys/rpc/utils.py +25 -0
- qulab/sys/rpc/worker.py +0 -0
- qulab/sys/rpc/zmq_socket.py +227 -0
- qulab/tools/__init__.py +0 -0
- qulab/tools/connection_helper.py +39 -0
- qulab/typing.py +2 -0
- qulab/utils.py +95 -0
- qulab/version.py +1 -0
- qulab/visualization/__init__.py +188 -0
- qulab/visualization/__main__.py +71 -0
- qulab/visualization/_autoplot.py +464 -0
- qulab/visualization/plot_circ.py +319 -0
- qulab/visualization/plot_layout.py +408 -0
- qulab/visualization/plot_seq.py +242 -0
- qulab/visualization/qdat.py +152 -0
- qulab/visualization/rot3d.py +23 -0
- qulab/visualization/widgets.py +86 -0
- qulab-2.10.10.dist-info/METADATA +110 -0
- qulab-2.10.10.dist-info/RECORD +107 -0
- qulab-2.10.10.dist-info/WHEEL +5 -0
- qulab-2.10.10.dist-info/entry_points.txt +2 -0
- qulab-2.10.10.dist-info/licenses/LICENSE +21 -0
- qulab-2.10.10.dist-info/top_level.txt +1 -0
@@ -0,0 +1,255 @@
|
|
1
|
+
import copy
|
2
|
+
import itertools
|
3
|
+
import logging
|
4
|
+
import re
|
5
|
+
import string
|
6
|
+
from collections import defaultdict
|
7
|
+
from functools import partial
|
8
|
+
from typing import Any, Callable, Literal, NamedTuple
|
9
|
+
|
10
|
+
log = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
Decorator = Callable[[Callable], Callable]
|
13
|
+
|
14
|
+
_buildin_set = set
|
15
|
+
|
16
|
+
|
17
|
+
class Source():
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class Sink():
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
def action(key: str,
|
26
|
+
method: Literal['get', 'set', 'post', 'delete'] = 'get',
|
27
|
+
**kwds) -> Decorator:
|
28
|
+
|
29
|
+
if any(c in key for c in ",()[]<>"):
|
30
|
+
raise ValueError('Invalid key: ' + key)
|
31
|
+
|
32
|
+
def decorator(func):
|
33
|
+
func.__action__ = key, method, kwds
|
34
|
+
return func
|
35
|
+
|
36
|
+
return decorator
|
37
|
+
|
38
|
+
|
39
|
+
def get(key: str, **kwds) -> Decorator:
|
40
|
+
return action(key, 'get', **kwds)
|
41
|
+
|
42
|
+
|
43
|
+
def set(key: str, **kwds) -> Decorator:
|
44
|
+
return action(key, 'set', **kwds)
|
45
|
+
|
46
|
+
|
47
|
+
def post(key: str, **kwds) -> Decorator:
|
48
|
+
return action(key, 'post', **kwds)
|
49
|
+
|
50
|
+
|
51
|
+
def delete(key: str, **kwds) -> Decorator:
|
52
|
+
return action(key, 'delete', **kwds)
|
53
|
+
|
54
|
+
|
55
|
+
class _Exclusion(NamedTuple):
|
56
|
+
keys: list
|
57
|
+
|
58
|
+
|
59
|
+
def exclude(sections: list):
|
60
|
+
return _Exclusion(sections)
|
61
|
+
|
62
|
+
|
63
|
+
def _add_action(attrs: dict, key: str, method: str, func: Callable, doc: dict,
|
64
|
+
sections: dict) -> None:
|
65
|
+
try:
|
66
|
+
mapping = attrs[f'__{method}_actions__']
|
67
|
+
except KeyError:
|
68
|
+
raise ValueError('Invalid method: ' + method)
|
69
|
+
arguments = re.findall(r'\{(\w+)\}', key)
|
70
|
+
doc[method][key] = func.__doc__
|
71
|
+
matrix = {}
|
72
|
+
for arg in arguments:
|
73
|
+
if (arg not in attrs and arg not in sections or arg in sections
|
74
|
+
and arg not in attrs and isinstance(sections[arg], _Exclusion)
|
75
|
+
or arg in sections and arg in attrs
|
76
|
+
and isinstance(sections[arg], _Exclusion) and len(
|
77
|
+
_buildin_set(attrs[arg]) -
|
78
|
+
_buildin_set(sections[arg].keys)) == 0):
|
79
|
+
raise ValueError(
|
80
|
+
f'Undefined section: {arg!r} in @action({key!r}, {method!r})')
|
81
|
+
if arg in sections and not isinstance(sections[arg], _Exclusion):
|
82
|
+
matrix[arg] = sections[arg]
|
83
|
+
else:
|
84
|
+
if arg in sections:
|
85
|
+
matrix[arg] = [
|
86
|
+
k for k in attrs[arg] if k not in sections[arg].keys
|
87
|
+
]
|
88
|
+
else:
|
89
|
+
matrix[arg] = attrs[arg]
|
90
|
+
for values in itertools.product(*[matrix[arg] for arg in arguments]):
|
91
|
+
kwds = dict(zip(arguments, values))
|
92
|
+
# mapping[key.format(**kwds)] = partial(func, **kwds)
|
93
|
+
mapping[string.Template(key).substitute(kwds)] = partial(func, **kwds)
|
94
|
+
|
95
|
+
|
96
|
+
def _build_docs(mapping: dict, attrs: dict) -> str:
|
97
|
+
docs = []
|
98
|
+
for key, doc in mapping.items():
|
99
|
+
if not doc:
|
100
|
+
doc = "No documentation."
|
101
|
+
docs.append(f"key = \"{key}\"")
|
102
|
+
lines = doc.strip().split('\n')
|
103
|
+
docs.extend(lines)
|
104
|
+
docs.append("")
|
105
|
+
return '\n'.join(docs)
|
106
|
+
|
107
|
+
|
108
|
+
class DeviceMeta(type):
|
109
|
+
|
110
|
+
def __new__(cls, name, bases, attrs):
|
111
|
+
doc = defaultdict(dict)
|
112
|
+
for method in ['get', 'set', 'post', 'delete']:
|
113
|
+
attrs.setdefault(f'__{method}_actions__', {})
|
114
|
+
for attr in attrs.values():
|
115
|
+
if hasattr(attr, '__action__'):
|
116
|
+
key, method, kwds = attr.__action__
|
117
|
+
_add_action(attrs, key, method, attr, doc, kwds)
|
118
|
+
new_class = super().__new__(cls, name, bases, attrs)
|
119
|
+
|
120
|
+
for method in ['get', 'set', 'post', 'delete']:
|
121
|
+
getattr(new_class,
|
122
|
+
method).__doc__ = f"{method.upper()}\n\n" + _build_docs(
|
123
|
+
doc[method], attrs)
|
124
|
+
return new_class
|
125
|
+
|
126
|
+
|
127
|
+
class BaseDevice(metaclass=DeviceMeta):
|
128
|
+
__log__ = None
|
129
|
+
|
130
|
+
def __init__(self, address: str = None, **options):
|
131
|
+
self._state = {}
|
132
|
+
self._status = "NOT CONNECTED"
|
133
|
+
self.address = address
|
134
|
+
self.options = options
|
135
|
+
|
136
|
+
def __del__(self):
|
137
|
+
try:
|
138
|
+
self.close()
|
139
|
+
except Exception:
|
140
|
+
pass
|
141
|
+
|
142
|
+
@property
|
143
|
+
def log(self):
|
144
|
+
if self.__log__ is None:
|
145
|
+
self.__log__ = logging.getLogger(
|
146
|
+
f"{self.__class__.__module__}.{self.__class__.__name__}")
|
147
|
+
return self.__log__
|
148
|
+
|
149
|
+
@property
|
150
|
+
def state(self):
|
151
|
+
return copy.deepcopy(self._state)
|
152
|
+
|
153
|
+
def get_state(self, key: str, default=None) -> Any:
|
154
|
+
return self._state.get(key, default)
|
155
|
+
|
156
|
+
@property
|
157
|
+
def status(self):
|
158
|
+
return self._status
|
159
|
+
|
160
|
+
def open(self) -> None:
|
161
|
+
self._status = "CONNECTED"
|
162
|
+
|
163
|
+
def close(self) -> None:
|
164
|
+
self._status = "NOT CONNECTED"
|
165
|
+
self._state.clear()
|
166
|
+
|
167
|
+
def reset(self) -> None:
|
168
|
+
self._state.clear()
|
169
|
+
|
170
|
+
def get(self, key: str, default: Any = None) -> Any:
|
171
|
+
self.log.info(f'Get {key!r}')
|
172
|
+
if key in self.__get_actions__:
|
173
|
+
result = self.__get_actions__[key](self)
|
174
|
+
self._state[key] = result
|
175
|
+
return result
|
176
|
+
else:
|
177
|
+
return self._state.get(key, default)
|
178
|
+
|
179
|
+
def set(self, key: str, value: Any = None) -> None:
|
180
|
+
self.log.info(f'Set {key!r} = {value!r}')
|
181
|
+
self.__set_actions__[key](self, value)
|
182
|
+
self._state[key] = value
|
183
|
+
|
184
|
+
def post(self, key: str, value: Any = None) -> Any:
|
185
|
+
self.log.info(f'Post {key!r} = {value!r}')
|
186
|
+
return self.__post_actions__[key](self, value)
|
187
|
+
|
188
|
+
def delete(self, key: str) -> None:
|
189
|
+
self.log.info(f'Delete {key!r}')
|
190
|
+
self.__delete_actions__[key](self)
|
191
|
+
del self._state[key]
|
192
|
+
|
193
|
+
def __repr__(self) -> str:
|
194
|
+
return f'{self.__class__.__name__}({self.address!r})'
|
195
|
+
|
196
|
+
|
197
|
+
class VisaDevice(BaseDevice):
|
198
|
+
|
199
|
+
error_query = 'SYST:ERR?'
|
200
|
+
|
201
|
+
def open(self) -> None:
|
202
|
+
import pyvisa
|
203
|
+
kwds = self.options.copy()
|
204
|
+
if 'backend' in kwds:
|
205
|
+
rm = pyvisa.ResourceManager(kwds.pop('backend'))
|
206
|
+
else:
|
207
|
+
rm = pyvisa.ResourceManager()
|
208
|
+
self.resource = rm.open_resource(self.address, **kwds)
|
209
|
+
self.errors = []
|
210
|
+
super().open()
|
211
|
+
|
212
|
+
def close(self) -> None:
|
213
|
+
super().close()
|
214
|
+
self.resource.close()
|
215
|
+
|
216
|
+
def reset(self) -> None:
|
217
|
+
super().reset()
|
218
|
+
self.resource.write('*RST')
|
219
|
+
|
220
|
+
def check_error(self):
|
221
|
+
if self.error_query:
|
222
|
+
while True:
|
223
|
+
error = self.resource.query(self.error_query)
|
224
|
+
error_code = int(error.split(',')[0])
|
225
|
+
if error_code == 0:
|
226
|
+
break
|
227
|
+
self.errors.append(error)
|
228
|
+
|
229
|
+
@get('idn')
|
230
|
+
def get_idn(self) -> str:
|
231
|
+
"""Get instrument identification."""
|
232
|
+
return self.resource.query('*IDN?')
|
233
|
+
|
234
|
+
@get('opc')
|
235
|
+
def get_opc(self) -> bool:
|
236
|
+
"""Get operation complete."""
|
237
|
+
return bool(int(self.resource.query('*OPC?')))
|
238
|
+
|
239
|
+
@get('errors')
|
240
|
+
def get_errors(self) -> list[str]:
|
241
|
+
"""Get error queue."""
|
242
|
+
self.check_error()
|
243
|
+
errors = self.errors
|
244
|
+
self.errors = []
|
245
|
+
return errors
|
246
|
+
|
247
|
+
@set('timeout')
|
248
|
+
def set_timeout(self, value: float) -> None:
|
249
|
+
"""Set timeout in seconds."""
|
250
|
+
self.resource.timeout = round(value * 1000)
|
251
|
+
|
252
|
+
@get('timeout')
|
253
|
+
def get_timeout(self) -> float:
|
254
|
+
"""Get timeout in seconds."""
|
255
|
+
return self.resource.timeout / 1000
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import importlib
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Type
|
4
|
+
|
5
|
+
from .basedevice import BaseDevice
|
6
|
+
|
7
|
+
path = {}
|
8
|
+
|
9
|
+
|
10
|
+
def _make_device(module, args, kwds) -> BaseDevice:
|
11
|
+
importlib.reload(module)
|
12
|
+
try:
|
13
|
+
return module.device(*args, **kwds)
|
14
|
+
except AttributeError:
|
15
|
+
return module.Device(*args, **kwds)
|
16
|
+
|
17
|
+
|
18
|
+
def create_device_from_file(filepath: str | Path, package_name: str, args,
|
19
|
+
kwds) -> BaseDevice:
|
20
|
+
"""
|
21
|
+
Create a device from a file.
|
22
|
+
|
23
|
+
Parameters
|
24
|
+
----------
|
25
|
+
filepath : str | Path
|
26
|
+
The path to the driver file.
|
27
|
+
package_name : str
|
28
|
+
The name of the package in which .filepath is located.
|
29
|
+
args : tuple
|
30
|
+
The positional arguments to pass to the device maker.
|
31
|
+
kwds : dict
|
32
|
+
The keyword arguments to pass to the device maker.
|
33
|
+
"""
|
34
|
+
filepath = Path(filepath)
|
35
|
+
if not filepath.exists():
|
36
|
+
raise RuntimeError(f"File {filepath} does not exist")
|
37
|
+
module_name = f"{package_name}.{filepath.stem}"
|
38
|
+
spec = importlib.util.spec_from_file_location(module_name, filepath)
|
39
|
+
module = importlib.util.module_from_spec(spec)
|
40
|
+
return _make_device(module, args, kwds)
|
41
|
+
|
42
|
+
|
43
|
+
def create_device_from_module(module_name: str, args, kwds) -> BaseDevice:
|
44
|
+
"""
|
45
|
+
Create a device from a module.
|
46
|
+
|
47
|
+
Parameters
|
48
|
+
----------
|
49
|
+
module_name : str
|
50
|
+
The name of the module to import.
|
51
|
+
args : tuple
|
52
|
+
The positional arguments to pass to the device maker.
|
53
|
+
kwds : dict
|
54
|
+
The keyword arguments to pass to the device maker.
|
55
|
+
"""
|
56
|
+
module = importlib.import_module(module_name)
|
57
|
+
return _make_device(module, args, kwds)
|
58
|
+
|
59
|
+
|
60
|
+
def create_device(driver_name: str, *args, **kwds) -> BaseDevice:
|
61
|
+
"""
|
62
|
+
Create a device from a driver.
|
63
|
+
|
64
|
+
Parameters
|
65
|
+
----------
|
66
|
+
driver_name : str
|
67
|
+
The name of the driver to use.
|
68
|
+
args : tuple
|
69
|
+
The positional arguments to pass to the device maker.
|
70
|
+
kwds : dict
|
71
|
+
The keyword arguments to pass to the device maker.
|
72
|
+
"""
|
73
|
+
try:
|
74
|
+
for package_name, p in path.items():
|
75
|
+
try:
|
76
|
+
dev = create_device_from_file(
|
77
|
+
Path(p) / f"{driver_name}.py", package_name, args, kwds)
|
78
|
+
return dev
|
79
|
+
except:
|
80
|
+
pass
|
81
|
+
|
82
|
+
dev = create_device_from_module(f"qulab.sys.drivers.{driver_name}",
|
83
|
+
args, kwds)
|
84
|
+
return dev
|
85
|
+
except:
|
86
|
+
raise RuntimeError(f"Can not find driver {driver_name!r}")
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import struct
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
types = {
|
6
|
+
"b" : ( int, 'b'), "B" : ( int, 'B'),
|
7
|
+
"h" : ( int, 'h'), "H" : ( int, 'H'),
|
8
|
+
"i" : ( int, 'i'), "I" : ( int, 'I'),
|
9
|
+
"q" : ( int, 'q'), "Q" : ( int, 'Q'),
|
10
|
+
"f" : (float, 'f'), "d" : (float, 'd'),
|
11
|
+
"int8" : ( int, 'b'), "uint8" : ( int, 'B'),
|
12
|
+
"int16" : ( int, 'h'), "uint16" : ( int, 'H'),
|
13
|
+
"int32" : ( int, 'i'), "uint32" : ( int, 'I'),
|
14
|
+
"int64" : ( int, 'q'), "uint64" : ( int, 'Q'),
|
15
|
+
"float" : (float, 'f'), "double" : (float, 'd'),
|
16
|
+
"float32": (float, 'f'), "float64": (float, 'd')
|
17
|
+
} # yapf: disable
|
18
|
+
|
19
|
+
|
20
|
+
def IEEE_488_2_BinBlock(datalist, dtype="int16", is_big_endian=True):
|
21
|
+
"""
|
22
|
+
将一组数据打包成 IEEE 488.2 标准二进制块
|
23
|
+
|
24
|
+
Args:
|
25
|
+
datalist : 要打包的数字列表
|
26
|
+
dtype : 数据类型
|
27
|
+
endian : 字节序
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
binblock, header
|
31
|
+
二进制块, 以及其 'header'
|
32
|
+
"""
|
33
|
+
if isinstance(datalist, bytes):
|
34
|
+
datablock = datalist
|
35
|
+
else:
|
36
|
+
datalist = np.asarray(datalist)
|
37
|
+
datalist.astype(types[dtype][0])
|
38
|
+
if is_big_endian:
|
39
|
+
endianc = '>'
|
40
|
+
else:
|
41
|
+
endianc = '<'
|
42
|
+
datablock = struct.pack(
|
43
|
+
'%s%d%s' % (endianc, len(datalist), types[dtype][1]), *datalist)
|
44
|
+
size = '%d' % len(datablock)
|
45
|
+
header = '#%d%s' % (len(size), size)
|
46
|
+
|
47
|
+
return header.encode() + datablock
|
48
|
+
|
49
|
+
|
50
|
+
def decode_IEEE_488_2_BinBlock(data, dtype="int16", is_big_endian=True):
|
51
|
+
"""
|
52
|
+
解析 IEEE 488.2 标准二进制块
|
53
|
+
|
54
|
+
Args:
|
55
|
+
data : 二进制块
|
56
|
+
dtype : 数据类型
|
57
|
+
endian : 字节序
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
datalist
|
61
|
+
"""
|
62
|
+
if isinstance(data, bytes):
|
63
|
+
header = data[:2]
|
64
|
+
size = int(data[2:2 + int(header[1:2])])
|
65
|
+
assert size == len(data) - 2 - int(header[1:2]), "data size error"
|
66
|
+
datablock = data[2 + int(header[1:2]):size + 2 + int(header[1:2])]
|
67
|
+
else:
|
68
|
+
raise ValueError("data must be bytes")
|
69
|
+
|
70
|
+
if is_big_endian:
|
71
|
+
endianc = '>'
|
72
|
+
else:
|
73
|
+
endianc = '<'
|
74
|
+
datalist = list(
|
75
|
+
struct.unpack(
|
76
|
+
'%s%d%s' % (endianc, size // struct.calcsize(types[dtype][1]),
|
77
|
+
types[dtype][1]), datablock))
|
78
|
+
|
79
|
+
return datalist
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
from qulab.sys import BaseDevice, exclude, get, set
|
4
|
+
|
5
|
+
|
6
|
+
class Device(BaseDevice):
|
7
|
+
|
8
|
+
channel = [
|
9
|
+
'X1', 'X2', 'X3', 'X4', 'Y1', 'Y2', 'Y3', 'Y4', 'Z1', 'Z2', 'Z3', 'Z4',
|
10
|
+
'M1', 'M2'
|
11
|
+
]
|
12
|
+
|
13
|
+
@get('IDN')
|
14
|
+
def get_idn(self) -> str:
|
15
|
+
return 'Fake Instrument'
|
16
|
+
|
17
|
+
@get('${channel_type}${channel_num}.SampleRate',
|
18
|
+
channel_type=['X', 'Y'],
|
19
|
+
channel_num=[1, 2, 3, 4])
|
20
|
+
def get_sample_rate_DDS(self, channel_type: str,
|
21
|
+
channel_num: int) -> float:
|
22
|
+
return 6e9
|
23
|
+
|
24
|
+
@get('${channel}.SampleRate', channel=['Z1', 'Z2', 'Z3', 'Z4'])
|
25
|
+
def get_sample_rate_Z(self, channel: str) -> float:
|
26
|
+
return 2e9
|
27
|
+
|
28
|
+
@get('${channel}.SampleRate', channel=['M1', 'M2'])
|
29
|
+
def get_sample_rate_AD(self, channel: str) -> float:
|
30
|
+
return 1e9
|
31
|
+
|
32
|
+
@set('${channel}.Vpp', channel=exclude(['M1', 'M2']))
|
33
|
+
def set_voltage(self, value: float, channel: str) -> None:
|
34
|
+
self.log.info(f'Set {channel} Vpp to {value}')
|
35
|
+
|
36
|
+
# @get('${channel}.Vpp', channel=exclude(['M1', 'M2']))
|
37
|
+
# def get_voltage(self, channel: str, default=0.0) -> float:
|
38
|
+
# return self._state.get(f'{channel}.Vpp', default)
|
39
|
+
|
40
|
+
@set('${channel}.Offset', channel=exclude(['M1', 'M2']))
|
41
|
+
def set_offset(
|
42
|
+
self,
|
43
|
+
value: float,
|
44
|
+
channel: str,
|
45
|
+
) -> None:
|
46
|
+
self.log.info(f'Set {channel} offset to {value}')
|
47
|
+
|
48
|
+
# @get('${channel}.Offset', channel=exclude(['M1', 'M2']))
|
49
|
+
# def get_offset(self, channel: str, default=0.0) -> float:
|
50
|
+
# return self._state.get(f'{channel}.Offset', default)
|
51
|
+
|
52
|
+
@set('${channel}.Waveform', channel=exclude(['M1', 'M2']))
|
53
|
+
def set_waveform(self, value, channel: str) -> None:
|
54
|
+
self.log.info(f'Set {channel} waveform to {value!r}')
|
55
|
+
|
56
|
+
# @get('${channel}.Waveform', channel=exclude(['M1', 'M2']))
|
57
|
+
# def get_waveform(self, channel: str, default=None) -> str:
|
58
|
+
# return self._state.get(f'{channel}.Waveform', default)
|
59
|
+
|
60
|
+
@set('${channel}.Size', channel=['M1', 'M2'])
|
61
|
+
def set_size(self, value, channel: str) -> None:
|
62
|
+
self.log.info(f'Set {channel} size to {value!r}')
|
63
|
+
|
64
|
+
@get('${channel}.Trace', channel=['M1', 'M2'])
|
65
|
+
def get_random_data(self, channel: str) -> np.ndarray:
|
66
|
+
size = self._state.get(f'{channel}.Size', 1024)
|
67
|
+
shots = self._state.get(f'{channel}.Shots', 128)
|
68
|
+
return np.random.randn(shots, size)
|
File without changes
|
qulab/sys/ipy_events.py
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
import contextlib
|
2
|
+
import time
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
from .storage.crud import create_cell, create_notebook
|
6
|
+
from .storage.models import Notebook
|
7
|
+
|
8
|
+
__current_notebook_id = None
|
9
|
+
|
10
|
+
|
11
|
+
def _get_current_notebook(session):
|
12
|
+
global __current_notebook_id
|
13
|
+
if __current_notebook_id is None:
|
14
|
+
notebook = create_notebook(session, 'Untitled')
|
15
|
+
session.commit()
|
16
|
+
__current_notebook_id = notebook.id
|
17
|
+
else:
|
18
|
+
notebook = session.query(Notebook).filter(
|
19
|
+
Notebook.id == __current_notebook_id).one()
|
20
|
+
return notebook
|
21
|
+
|
22
|
+
|
23
|
+
def _get_current_cell(session):
|
24
|
+
notebook = _get_current_notebook(session)
|
25
|
+
if notebook.cells:
|
26
|
+
return notebook.cells[-1]
|
27
|
+
else:
|
28
|
+
return None
|
29
|
+
|
30
|
+
|
31
|
+
def _save_inputCells(session, inputCells=None):
|
32
|
+
notebook = _get_current_notebook(session)
|
33
|
+
aready_saved = len(notebook.cells)
|
34
|
+
if inputCells:
|
35
|
+
for cell in inputCells[aready_saved:]:
|
36
|
+
create_cell(session, notebook, cell)
|
37
|
+
|
38
|
+
|
39
|
+
def _update_inputCells(session):
|
40
|
+
cell = _get_current_cell(session)
|
41
|
+
if cell:
|
42
|
+
cell.ftime = datetime.utcnow()
|
43
|
+
session.add(cell)
|
44
|
+
|
45
|
+
|
46
|
+
__sessionmaker = None
|
47
|
+
|
48
|
+
|
49
|
+
@contextlib.contextmanager
|
50
|
+
def get_session():
|
51
|
+
global __session
|
52
|
+
if __sessionmaker is None:
|
53
|
+
raise RuntimeError('Sessionmaker is not set')
|
54
|
+
session = __sessionmaker()
|
55
|
+
try:
|
56
|
+
yield session
|
57
|
+
session.commit()
|
58
|
+
except:
|
59
|
+
session.rollback()
|
60
|
+
|
61
|
+
|
62
|
+
def set_sessionmaker(sessionmaker):
|
63
|
+
global __sessionmaker
|
64
|
+
__sessionmaker = sessionmaker
|
65
|
+
|
66
|
+
|
67
|
+
def get_current_notebook(session=None):
|
68
|
+
try:
|
69
|
+
if session is None:
|
70
|
+
with get_session() as session:
|
71
|
+
return _get_current_notebook(session)
|
72
|
+
else:
|
73
|
+
return _get_current_notebook(session)
|
74
|
+
except RuntimeError:
|
75
|
+
return None
|
76
|
+
|
77
|
+
|
78
|
+
def get_current_cell_id(session=None):
|
79
|
+
try:
|
80
|
+
if session is None:
|
81
|
+
with get_session() as session:
|
82
|
+
return _get_current_cell(session).id
|
83
|
+
else:
|
84
|
+
return _get_current_cell(session).id
|
85
|
+
except RuntimeError as e:
|
86
|
+
return None
|
87
|
+
|
88
|
+
|
89
|
+
def get_inputCells():
|
90
|
+
try:
|
91
|
+
from IPython import get_ipython
|
92
|
+
|
93
|
+
return get_ipython().user_ns['In']
|
94
|
+
except Exception as e:
|
95
|
+
# raise e
|
96
|
+
return ['']
|
97
|
+
|
98
|
+
|
99
|
+
def autosave_cells(ipython):
|
100
|
+
try:
|
101
|
+
with get_session() as session:
|
102
|
+
_save_inputCells(session, get_inputCells())
|
103
|
+
except:
|
104
|
+
pass
|
105
|
+
|
106
|
+
|
107
|
+
def update_timestamp(ipython):
|
108
|
+
try:
|
109
|
+
with get_session() as session:
|
110
|
+
_update_inputCells(session)
|
111
|
+
except:
|
112
|
+
pass
|
113
|
+
|
114
|
+
|
115
|
+
def setup_ipy_events():
|
116
|
+
try:
|
117
|
+
from IPython import get_ipython
|
118
|
+
|
119
|
+
ipython = get_ipython()
|
120
|
+
|
121
|
+
if ipython is not None:
|
122
|
+
ipython.events.register('pre_run_cell', autosave_cells)
|
123
|
+
ipython.events.register('post_run_cell', update_timestamp)
|
124
|
+
except:
|
125
|
+
pass
|
File without changes
|