QuLab 2.0.1__cp310-cp310-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. QuLab-2.0.1.dist-info/LICENSE +21 -0
  2. QuLab-2.0.1.dist-info/METADATA +95 -0
  3. QuLab-2.0.1.dist-info/RECORD +82 -0
  4. QuLab-2.0.1.dist-info/WHEEL +5 -0
  5. QuLab-2.0.1.dist-info/entry_points.txt +2 -0
  6. QuLab-2.0.1.dist-info/top_level.txt +1 -0
  7. qulab/__init__.py +1 -0
  8. qulab/__main__.py +24 -0
  9. qulab/fun.cp310-win_amd64.pyd +0 -0
  10. qulab/monitor/__init__.py +1 -0
  11. qulab/monitor/__main__.py +8 -0
  12. qulab/monitor/config.py +41 -0
  13. qulab/monitor/dataset.py +77 -0
  14. qulab/monitor/event_queue.py +54 -0
  15. qulab/monitor/mainwindow.py +234 -0
  16. qulab/monitor/monitor.py +93 -0
  17. qulab/monitor/ploter.py +123 -0
  18. qulab/monitor/qt_compat.py +16 -0
  19. qulab/monitor/toolbar.py +265 -0
  20. qulab/scan/__init__.py +4 -0
  21. qulab/scan/base.py +548 -0
  22. qulab/scan/dataset.py +0 -0
  23. qulab/scan/expression.py +472 -0
  24. qulab/scan/optimize.py +0 -0
  25. qulab/scan/scanner.py +270 -0
  26. qulab/scan/transforms.py +16 -0
  27. qulab/scan/utils.py +37 -0
  28. qulab/storage/__init__.py +0 -0
  29. qulab/storage/__main__.py +51 -0
  30. qulab/storage/backend/__init__.py +0 -0
  31. qulab/storage/backend/redis.py +204 -0
  32. qulab/storage/base_dataset.py +352 -0
  33. qulab/storage/chunk.py +60 -0
  34. qulab/storage/dataset.py +127 -0
  35. qulab/storage/file.py +273 -0
  36. qulab/storage/models/__init__.py +22 -0
  37. qulab/storage/models/base.py +4 -0
  38. qulab/storage/models/config.py +28 -0
  39. qulab/storage/models/file.py +89 -0
  40. qulab/storage/models/ipy.py +58 -0
  41. qulab/storage/models/models.py +88 -0
  42. qulab/storage/models/record.py +161 -0
  43. qulab/storage/models/report.py +22 -0
  44. qulab/storage/models/tag.py +93 -0
  45. qulab/storage/storage.py +95 -0
  46. qulab/sys/__init__.py +0 -0
  47. qulab/sys/chat.py +688 -0
  48. qulab/sys/device/__init__.py +3 -0
  49. qulab/sys/device/basedevice.py +221 -0
  50. qulab/sys/device/loader.py +86 -0
  51. qulab/sys/device/utils.py +46 -0
  52. qulab/sys/drivers/FakeInstrument.py +52 -0
  53. qulab/sys/drivers/__init__.py +0 -0
  54. qulab/sys/ipy_events.py +125 -0
  55. qulab/sys/net/__init__.py +0 -0
  56. qulab/sys/net/bencoder.py +205 -0
  57. qulab/sys/net/cli.py +169 -0
  58. qulab/sys/net/dhcp.py +543 -0
  59. qulab/sys/net/dhcpd.py +176 -0
  60. qulab/sys/net/kad.py +1142 -0
  61. qulab/sys/net/kcp.py +192 -0
  62. qulab/sys/net/nginx.py +192 -0
  63. qulab/sys/progress.py +190 -0
  64. qulab/sys/rpc/__init__.py +0 -0
  65. qulab/sys/rpc/client.py +0 -0
  66. qulab/sys/rpc/exceptions.py +96 -0
  67. qulab/sys/rpc/msgpack.py +1052 -0
  68. qulab/sys/rpc/msgpack.pyi +41 -0
  69. qulab/sys/rpc/rpc.py +412 -0
  70. qulab/sys/rpc/serialize.py +139 -0
  71. qulab/sys/rpc/server.py +29 -0
  72. qulab/sys/rpc/socket.py +29 -0
  73. qulab/sys/rpc/utils.py +25 -0
  74. qulab/sys/rpc/worker.py +0 -0
  75. qulab/version.py +1 -0
  76. qulab/visualization/__init__.py +188 -0
  77. qulab/visualization/__main__.py +71 -0
  78. qulab/visualization/_autoplot.py +457 -0
  79. qulab/visualization/plot_layout.py +408 -0
  80. qulab/visualization/plot_seq.py +90 -0
  81. qulab/visualization/qdat.py +152 -0
  82. qulab/visualization/widgets.py +86 -0
@@ -0,0 +1,221 @@
1
+ import itertools
2
+ import logging
3
+ import re
4
+ from collections import defaultdict
5
+ from functools import partial
6
+ from typing import Any, Callable, Literal, NamedTuple
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+ Decorator = Callable[[Callable], Callable]
11
+
12
+ _buildin_set = set
13
+
14
+
15
+ def action(key: str,
16
+ method: Literal['get', 'set', 'post', 'delete'] = 'get',
17
+ **kwds) -> Decorator:
18
+
19
+ if any(c in key for c in ",()[]<>"):
20
+ raise ValueError('Invalid key: ' + key)
21
+
22
+ def decorator(func):
23
+ func.__action__ = key, method, kwds
24
+ return func
25
+
26
+ return decorator
27
+
28
+
29
+ def get(key: str, **kwds) -> Decorator:
30
+ return action(key, 'get', **kwds)
31
+
32
+
33
+ def set(key: str, **kwds) -> Decorator:
34
+ return action(key, 'set', **kwds)
35
+
36
+
37
+ def post(key: str, **kwds) -> Decorator:
38
+ return action(key, 'post', **kwds)
39
+
40
+
41
+ def delete(key: str, **kwds) -> Decorator:
42
+ return action(key, 'delete', **kwds)
43
+
44
+
45
+ class _Exclusion(NamedTuple):
46
+ keys: list
47
+
48
+
49
+ def exclude(sections: list):
50
+ return _Exclusion(sections)
51
+
52
+
53
+ def _add_action(attrs: dict, key: str, method: str, func: Callable, doc: dict,
54
+ sections: dict) -> None:
55
+ try:
56
+ mapping = attrs[f'__{method}_actions__']
57
+ except KeyError:
58
+ raise ValueError('Invalid method: ' + method)
59
+ arguments = re.findall(r'\{(\w+)\}', key)
60
+ doc[method][key] = func.__doc__
61
+ matrix = {}
62
+ for arg in arguments:
63
+ if (arg not in attrs and arg not in sections or arg in sections
64
+ and arg not in attrs and isinstance(sections[arg], _Exclusion)
65
+ or arg in sections and arg in attrs
66
+ and isinstance(sections[arg], _Exclusion) and len(
67
+ _buildin_set(attrs[arg]) -
68
+ _buildin_set(sections[arg].keys)) == 0):
69
+ raise ValueError(
70
+ f'Undefined section: {arg!r} in @action({key!r}, {method!r})')
71
+ if arg in sections and not isinstance(sections[arg], _Exclusion):
72
+ matrix[arg] = sections[arg]
73
+ else:
74
+ if arg in sections:
75
+ matrix[arg] = [
76
+ k for k in attrs[arg] if k not in sections[arg].keys
77
+ ]
78
+ else:
79
+ matrix[arg] = attrs[arg]
80
+ for values in itertools.product(*[matrix[arg] for arg in arguments]):
81
+ kwds = dict(zip(arguments, values))
82
+ mapping[key.format(**kwds)] = partial(func, **kwds)
83
+
84
+
85
+ def _build_docs(mapping: dict, attrs: dict) -> str:
86
+ docs = []
87
+ for key, doc in mapping.items():
88
+ if not doc:
89
+ doc = "No documentation."
90
+ docs.append(f"key = \"{key}\"")
91
+ lines = doc.strip().split('\n')
92
+ docs.extend(lines)
93
+ docs.append("")
94
+ return '\n'.join(docs)
95
+
96
+
97
+ class DeviceMeta(type):
98
+
99
+ def __new__(cls, name, bases, attrs):
100
+ doc = defaultdict(dict)
101
+ for method in ['get', 'set', 'post', 'delete']:
102
+ attrs.setdefault(f'__{method}_actions__', {})
103
+ for attr in attrs.values():
104
+ if hasattr(attr, '__action__'):
105
+ key, method, kwds = attr.__action__
106
+ _add_action(attrs, key, method, attr, doc, kwds)
107
+ new_class = super().__new__(cls, name, bases, attrs)
108
+
109
+ for method in ['get', 'set', 'post', 'delete']:
110
+ getattr(new_class,
111
+ method).__doc__ = f"{method.upper()}\n\n" + _build_docs(
112
+ doc[method], attrs)
113
+ return new_class
114
+
115
+
116
+ class BaseDevice(metaclass=DeviceMeta):
117
+ __log__ = None
118
+
119
+ def __init__(self, address: str = None, **options):
120
+ self._status = {}
121
+ self.address = address
122
+ self.options = options
123
+
124
+ def __del__(self):
125
+ try:
126
+ self.close()
127
+ except Exception:
128
+ pass
129
+
130
+ @property
131
+ def log(self):
132
+ if self.__log__ is None:
133
+ self.__log__ = logging.getLogger(
134
+ f"{self.__class__.__module__}.{self.__class__.__name__}")
135
+ return self.__log__
136
+
137
+ def open(self) -> None:
138
+ pass
139
+
140
+ def close(self) -> None:
141
+ pass
142
+
143
+ def reset(self) -> None:
144
+ self._status.clear()
145
+
146
+ def get(self, key: str, default: Any = None) -> Any:
147
+ self.log.info(f'Get {key!r}')
148
+ if key in self.__get_actions__:
149
+ result = self.__get_actions__[key](self)
150
+ self._status[key] = result
151
+ return result
152
+ else:
153
+ return self._status.get(key, default)
154
+
155
+ def set(self, key: str, value: Any = None) -> None:
156
+ self.log.info(f'Set {key!r} = {value!r}')
157
+ self.__set_actions__[key](self, value)
158
+ self._status[key] = value
159
+
160
+ def post(self, key: str, value: Any = None) -> Any:
161
+ self.log.info(f'Post {key!r} = {value!r}')
162
+ return self.__post_actions__[key](self, value)
163
+
164
+ def delete(self, key: str) -> None:
165
+ self.log.info(f'Delete {key!r}')
166
+ self.__delete_actions__[key](self)
167
+ del self._status[key]
168
+
169
+ def __repr__(self) -> str:
170
+ return f'{self.__class__.__name__}({self.address!r})'
171
+
172
+
173
+ class VisaDevice(BaseDevice):
174
+
175
+ def open(self) -> None:
176
+ import pyvisa
177
+ kwds = self.options.copy()
178
+ if 'backend' in kwds:
179
+ rm = pyvisa.ResourceManager(kwds.pop('backend'))
180
+ else:
181
+ rm = pyvisa.ResourceManager()
182
+ self.resource = rm.open_resource(self.address, **kwds)
183
+
184
+ def close(self) -> None:
185
+ self.resource.close()
186
+
187
+ def reset(self) -> None:
188
+ super().reset()
189
+ self.resource.write('*RST')
190
+
191
+ @get('idn')
192
+ def get_idn(self) -> str:
193
+ """Get instrument identification."""
194
+ return self.resource.query('*IDN?')
195
+
196
+ @get('opc')
197
+ def get_opc(self) -> bool:
198
+ """Get operation complete."""
199
+ return bool(int(self.resource.query('*OPC?')))
200
+
201
+ @get('errors')
202
+ def get_errors(self) -> list[str]:
203
+ """Get error queue."""
204
+ errors = []
205
+ while True:
206
+ error = self.resource.query('SYST:ERR?')
207
+ error_code = int(error.split(',')[0])
208
+ if error_code == 0:
209
+ break
210
+ errors.append(error)
211
+ return errors
212
+
213
+ @set('timeout')
214
+ def set_timeout(self, value: float) -> None:
215
+ """Set timeout in seconds."""
216
+ self.resource.timeout = round(value * 1000)
217
+
218
+ @get('timeout')
219
+ def get_timeout(self) -> float:
220
+ """Get timeout in seconds."""
221
+ 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"waveforms.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,46 @@
1
+ import struct
2
+
3
+ import numpy as np
4
+
5
+
6
+ def IEEE_488_2_BinBlock(datalist, dtype="int16", is_big_endian=True):
7
+ """
8
+ 将一组数据打包成 IEEE 488.2 标准二进制块
9
+
10
+ Args:
11
+ datalist : 要打包的数字列表
12
+ dtype : 数据类型
13
+ endian : 字节序
14
+
15
+ Returns:
16
+ binblock, header
17
+ 二进制块, 以及其 'header'
18
+ """
19
+ types = {"b" : ( int, 'b'), "B" : ( int, 'B'),
20
+ "h" : ( int, 'h'), "H" : ( int, 'H'),
21
+ "i" : ( int, 'i'), "I" : ( int, 'I'),
22
+ "q" : ( int, 'q'), "Q" : ( int, 'Q'),
23
+ "f" : (float, 'f'), "d" : (float, 'd'),
24
+ "int8" : ( int, 'b'), "uint8" : ( int, 'B'),
25
+ "int16" : ( int, 'h'), "uint16" : ( int, 'H'),
26
+ "int32" : ( int, 'i'), "uint32" : ( int, 'I'),
27
+ "int64" : ( int, 'q'), "uint64" : ( int, 'Q'),
28
+ "float" : (float, 'f'), "double" : (float, 'd'),
29
+ "float32": (float, 'f'), "float64": (float, 'd')
30
+ } # yapf: disable
31
+
32
+ if isinstance(datalist, bytes):
33
+ datablock = datalist
34
+ else:
35
+ datalist = np.asarray(datalist)
36
+ datalist.astype(types[dtype][0])
37
+ if is_big_endian:
38
+ endianc = '>'
39
+ else:
40
+ endianc = '<'
41
+ datablock = struct.pack(
42
+ '%s%d%s' % (endianc, len(datalist), types[dtype][1]), *datalist)
43
+ size = '%d' % len(datablock)
44
+ header = '#%d%s' % (len(size), size)
45
+
46
+ return header.encode() + datablock
@@ -0,0 +1,52 @@
1
+ from waveforms.sys.device import BaseDevice, exclude, get, set
2
+
3
+
4
+ class Device(BaseDevice):
5
+
6
+ channel = [
7
+ 'X1', 'X2', 'X3', 'X4', 'Y1', 'Y2', 'Y3', 'Y4', 'Z1', 'Z2', 'Z3', 'Z4',
8
+ 'M1', 'M2'
9
+ ]
10
+
11
+ @get('IDN')
12
+ def get_idn(self) -> str:
13
+ return 'Fake Instrument'
14
+
15
+ @set('{channel}.Vpp', channel=exclude(['M1', 'M2']))
16
+ def set_voltage(self, value: float, channel: str) -> None:
17
+ self.log.info(f'Set {channel} Vpp to {value}')
18
+
19
+ @get('{channel}.Vpp', channel=exclude(['M1', 'M2']))
20
+ def get_voltage(self, channel: str, default=0.0) -> float:
21
+ return self._status.get(f'{channel}.Vpp', default)
22
+
23
+ @set('{channel}.Offset', channel=exclude(['M1', 'M2']))
24
+ def set_frequency(
25
+ self,
26
+ value: float,
27
+ channel: str,
28
+ ) -> None:
29
+ self.log.info(f'Set {channel} offset to {value}')
30
+
31
+ @get('{channel}.Offset', channel=exclude(['M1', 'M2']))
32
+ def get_frequency(self, channel: str, default=0.0) -> float:
33
+ return self._status.get(f'{channel}.Offset', default)
34
+
35
+ @set('{channel}.Waveform', channel=exclude(['M1', 'M2']))
36
+ def set_waveform(self, value, channel: str) -> None:
37
+ self.log.info(f'Set {channel} waveform to {value!r}')
38
+
39
+ @get('{channel}.Waveform', channel=exclude(['M1', 'M2']))
40
+ def get_waveform(self, channel: str, default=None) -> str:
41
+ return self._status.get(f'{channel}.Waveform', default)
42
+
43
+ @set('{channel}.Size', channel=['M1', 'M2'])
44
+ def set_size(self, value, channel: str) -> None:
45
+ self.log.info(f'Set {channel} size to {value!r}')
46
+
47
+ @get('{channel}.Trace', channel=['M1', 'M2'])
48
+ def get_size(self, channel: str) -> str:
49
+ import numpy as np
50
+ size = self._status.get(f'{channel}.Size', 1024)
51
+ shots = self._status.get(f'{channel}.Shots', 128)
52
+ return np.random.randn(shots, size)
File without changes
@@ -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