QuLab 2.0.1__cp311-cp311-macosx_10_9_universal2.whl → 2.0.2__cp311-cp311-macosx_10_9_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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -30,10 +30,13 @@ Requires-Dist: dill >=0.3.6
30
30
  Requires-Dist: GitPython >=3.1.14
31
31
  Requires-Dist: ipython >=7.4.0
32
32
  Requires-Dist: ipywidgets >=7.4.2
33
+ Requires-Dist: loguru >=0.7.2
33
34
  Requires-Dist: matplotlib >=3.7.2
34
35
  Requires-Dist: numpy >=1.13.3
35
36
  Requires-Dist: ply >=3.11
37
+ Requires-Dist: pyzmq >=25.1.0
36
38
  Requires-Dist: scipy >=1.0.0
39
+ Requires-Dist: watchdog >=4.0.0
37
40
 
38
41
  # QuLab
39
42
  [![View build status](https://travis-ci.org/feihoo87/QuLab.svg?branch=master)](https://travis-ci.org/feihoo87/QuLab)
@@ -1,7 +1,7 @@
1
1
  qulab/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
2
- qulab/__main__.py,sha256=HnWr_0eErzaJUkjeTpeR7-l5FASfYK-h0VtqQI-eVoc,371
3
- qulab/fun.cpython-311-darwin.so,sha256=yZONlFl41M9Z37UygNHeMFNtyeHskCbAPtrJuxncif0,160422
4
- qulab/version.py,sha256=pMl7p0vBanIg04EfboBE80RyG_KP7M0m9V3-qTl0YLQ,21
2
+ qulab/__main__.py,sha256=h84t4vjTH6Gu7SrBhudkzvbqfH1oNudDtM11LIY1h4Q,430
3
+ qulab/fun.cpython-311-darwin.so,sha256=vZyZMkbS3DVPFrFumYWuPDPi3hZbXUQhiri3D_3OxyA,159616
4
+ qulab/version.py,sha256=xARS6PXiulA1Bog5UZUM6hqQfydeRzKLyWtOyUBL-Ss,21
5
5
  qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
6
6
  qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
7
7
  qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
@@ -12,13 +12,14 @@ qulab/monitor/monitor.py,sha256=7E4bnTsO6qC85fs2ONrccGHfaYKv7SW74mtXzv6QjVc,2305
12
12
  qulab/monitor/ploter.py,sha256=CbiIjmohgtwDDTVeGzhXEGVo3XjytMdhLwU9VUkg9vo,3601
13
13
  qulab/monitor/qt_compat.py,sha256=OK71_JSO_iyXjRIKHANmaK4Lx4bILUzmXI-mwKg3QeI,788
14
14
  qulab/monitor/toolbar.py,sha256=WEag6cxAtEsOLL14XvM7pSE56EA3MO188_JuprNjdBs,7948
15
- qulab/scan/__init__.py,sha256=yT_L9Rdr9lwxds-uq-sC_lhnTQxJgIkSzQkiX9PYmug,216
16
- qulab/scan/base.py,sha256=SAmv-QRPHcN_FlfKeMykbBatm5Qo5DS76PFt5h2xtWY,17143
17
- qulab/scan/dataset.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- qulab/scan/expression.py,sha256=J0F7jFyCkMKcHieT5ok6alivjrnHXPqQ0Xil5czGDuI,14781
19
- qulab/scan/optimize.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- qulab/scan/scanner.py,sha256=H5wXarVeJab6pNVfLEWB6jCmpeIdpUu6igR9vlaQ-wc,7802
21
- qulab/scan/transforms.py,sha256=ReUuG57B_1GEgOwZZaxYbOTappG7yY9ERvagc2v48Pg,252
15
+ qulab/scan/__init__.py,sha256=BflmtNkyV72f4jqkeXoO_gi7kf8CHyk-AmKHjNXwe1A,124
16
+ qulab/scan/curd.py,sha256=ntpK62ArZiF2mrDDewcw227VMR1E_8no0yLJSrgdgng,4518
17
+ qulab/scan/expression.py,sha256=-aTYbjFQNI1mwOcoSBztqhKfGJpu_n4a1QnWro_xnTU,15694
18
+ qulab/scan/models.py,sha256=S8Q9hC8nOzxyoNB10EYg-miDKqoNMnjyAECjD-TuORw,17117
19
+ qulab/scan/optimize.py,sha256=vErjRTCtn2MwMF5Xyhs1P4gHF2IFHv_EqxsUvH_4y7k,2287
20
+ qulab/scan/query_record.py,sha256=ed40efBQxtkwUxZHT0zB9SYlMxgNUFqOtCiseOCeBe0,11521
21
+ qulab/scan/recorder.py,sha256=jIkFY-Mirvkpyvh-8nKFiTqrLbGAgp9h9kBX25q_RIs,15402
22
+ qulab/scan/scan.py,sha256=hWKDSosn7_eOAiiA548vdBRYu34OvvWPEtfXLk7fxcY,23030
22
23
  qulab/scan/utils.py,sha256=2bj7ggTNTK5LXwBDi8w7IzFqFjchoE6EhgSASC0fpDQ,1024
23
24
  qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
25
  qulab/storage/__main__.py,sha256=3emxxRry8BB0m8hUZvJ_oBqkPy7ksV7flHB_KEDXZuI,1692
@@ -67,16 +68,17 @@ qulab/sys/rpc/server.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
67
68
  qulab/sys/rpc/socket.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
68
69
  qulab/sys/rpc/utils.py,sha256=6YGFOkY7o09lkA_I1FIP9_1Up3k2F1KOkftvu0_8lxo,594
69
70
  qulab/sys/rpc/worker.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
+ qulab/sys/rpc/zmq_socket.py,sha256=fuW86N7O1X-TmFO0ona7GC47jsg5mLp7kBcO42kpCKk,7926
70
72
  qulab/visualization/__init__.py,sha256=26cuHt3QIJXUb3VaMxlJx3IQTOUVJFKlYBZr7WMP53M,6129
71
73
  qulab/visualization/__main__.py,sha256=9zKK3yZFy0leU40ou6BpRC1Fsetfc1gjjFzIZYIwP6Y,1639
72
- qulab/visualization/_autoplot.py,sha256=p4jzsJFgtOhnU0iuZJvjTT2ar6fvGd9VmxBr5dx1JC8,13777
74
+ qulab/visualization/_autoplot.py,sha256=jddg40dX48Wd8G6NLFA_Kf7z1QxdrZBDS99Xx2GLMqs,14099
73
75
  qulab/visualization/plot_layout.py,sha256=clNw9QjE_kVNpIIx2Ob4YhAz2fucPGMuzkoIrOJo_Y8,13533
74
76
  qulab/visualization/plot_seq.py,sha256=lphYF4VhkEdc_wWr1kFBwrx2yujkyFPFaJ3pjr61awI,2693
75
77
  qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
76
78
  qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
77
- QuLab-2.0.1.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
78
- QuLab-2.0.1.dist-info/METADATA,sha256=9lh5a31NtQa3tADAUrr94sSw38Mzza_1BSzEkHJVtPY,3385
79
- QuLab-2.0.1.dist-info/WHEEL,sha256=eupBwbXGAhwNAPJSvj5BiShZwdZO8jnQ5yHfv-9aUGw,115
80
- QuLab-2.0.1.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
81
- QuLab-2.0.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
82
- QuLab-2.0.1.dist-info/RECORD,,
79
+ QuLab-2.0.2.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
80
+ QuLab-2.0.2.dist-info/METADATA,sha256=cIK74-RBs-jNnttEcwVdgMtNd4WAh7OmcVn2ShZBIt4,3477
81
+ QuLab-2.0.2.dist-info/WHEEL,sha256=eupBwbXGAhwNAPJSvj5BiShZwdZO8jnQ5yHfv-9aUGw,115
82
+ QuLab-2.0.2.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
83
+ QuLab-2.0.2.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
84
+ QuLab-2.0.2.dist-info/RECORD,,
qulab/__main__.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import click
2
2
 
3
3
  from .monitor.__main__ import main as monitor
4
+ from .scan.recorder import record
4
5
  from .sys.net.cli import dht
5
6
  from .visualization.__main__ import plot
6
7
 
@@ -19,6 +20,7 @@ def hello():
19
20
  main.add_command(monitor)
20
21
  main.add_command(plot)
21
22
  main.add_command(dht)
23
+ main.add_command(record)
22
24
 
23
25
  if __name__ == '__main__':
24
26
  main()
Binary file
qulab/scan/__init__.py CHANGED
@@ -1,4 +1,3 @@
1
- from .base import (BaseOptimizer, Begin, End, OptimizerConfig, StepStatus,
2
- Tracker, scan_iters)
3
1
  from .expression import Expression, Symbol
4
- from .scanner import Atom, Optimizer, OptimizeSpace, Scan
2
+ from .query_record import get_record, lookup, lookup_list
3
+ from .scan import Scan
qulab/scan/curd.py ADDED
@@ -0,0 +1,144 @@
1
+ from datetime import date, datetime, timezone
2
+ from typing import Sequence, Type, Union
3
+
4
+ from sqlalchemy.orm import Query, Session, aliased
5
+ from sqlalchemy.orm.exc import NoResultFound
6
+ from sqlalchemy.orm.session import Session
7
+ from waveforms.dicttree import foldDict
8
+
9
+ from .models import Comment, Record, Report, Sample, Tag
10
+
11
+
12
+ def tag(session: Session, tag_text: str) -> Tag:
13
+ """Get a tag from the database or create a new if not exists."""
14
+ try:
15
+ return session.query(Tag).filter(Tag.text == tag_text).one()
16
+ except NoResultFound:
17
+ tag = Tag(text=tag_text)
18
+ return tag
19
+
20
+
21
+ def tag_it(session: Session, tag_text: str, obj: Union[Sample, Record,
22
+ Report]) -> Tag:
23
+ """Tag an object."""
24
+ if obj.id is None:
25
+ session.add(obj)
26
+ obj.tags.append(tag(session, tag_text))
27
+ else:
28
+ session.query(type(obj)).filter(
29
+ type(obj).id == obj.id).one().tags.append(tag(session, tag_text))
30
+ session.commit()
31
+
32
+
33
+ def get_object_with_tags(session: Session,
34
+ cls: Union[Type[Comment], Type[Sample], Type[Record],
35
+ Type[Report]], *tags: str) -> Query:
36
+ """
37
+ Query objects with the given tags.
38
+
39
+ Parameters
40
+ ----------
41
+ session : :class:`sqlalchemy.orm.Session`
42
+ The database session.
43
+ cls : :class:`sqlalchemy.orm.Mapper`
44
+ The object class.
45
+ tags : str
46
+ The tags.
47
+
48
+ Returns
49
+ -------
50
+ :class:`sqlalchemy.orm.Query`
51
+ The query.
52
+ """
53
+ if isinstance(session, Query):
54
+ q = session
55
+ else:
56
+ q = session.query(cls)
57
+ if not hasattr(cls, 'tags'):
58
+ return []
59
+
60
+ aliase = {tag: aliased(Tag) for tag in tags}
61
+
62
+ for tag, a in aliase.items():
63
+ q = q.join(a, cls.tags)
64
+ if '*' in tag:
65
+ q = q.filter(a.text.like(tag.replace('*', '%')))
66
+ else:
67
+ q = q.filter(a.text == tag)
68
+ return q
69
+
70
+
71
+ def query_record(session: Session,
72
+ offset: int = 0,
73
+ limit: int = 10,
74
+ app: str | None = None,
75
+ tags: Sequence[str] = (),
76
+ before: datetime | date | None = None,
77
+ after: datetime | date | None = None):
78
+ tz_offset = datetime.now(timezone.utc).astimezone().utcoffset()
79
+ table = {'header': ['ID', 'App', 'tags', 'created time'], 'body': []}
80
+ apps = sorted(
81
+ set([
82
+ n for n, *_ in get_object_with_tags(session.query(Record.app),
83
+ Record, *tags).all()
84
+ ]))
85
+ apps = foldDict(dict([(app, None) for app in apps]))
86
+
87
+ query = get_object_with_tags(session, Record, *tags)
88
+
89
+ if app is not None:
90
+ if app.endswith('*'):
91
+ query = query.filter(Record.app.like(app[:-1] + '%'))
92
+ else:
93
+ query = query.filter(Record.app == app)
94
+ if before is not None:
95
+ if isinstance(before, date):
96
+ before = datetime(before.year, before.month, before.day)
97
+ query = query.filter(Record.ctime <= before - tz_offset)
98
+ if after is not None:
99
+ if isinstance(after, date):
100
+ after = datetime(after.year, after.month, after.day)
101
+ query = query.filter(Record.ctime >= after - tz_offset)
102
+ total = query.count()
103
+ for r in query.order_by(Record.ctime.desc()).limit(limit).offset(offset):
104
+ tags = sorted([t.text for t in r.tags])
105
+ ctime = r.ctime + tz_offset
106
+ row = [r.id, r.app, tags, ctime]
107
+ table['body'].append(row)
108
+
109
+ return total, apps, table
110
+
111
+
112
+ def update_tags(session: Session,
113
+ record_id: int,
114
+ tags: Sequence[str],
115
+ append: bool = False):
116
+ record = session.get(Record, record_id)
117
+ if record is None:
118
+ return False
119
+ if append:
120
+ old = [t.text for t in record.tags]
121
+ for t in old:
122
+ if t not in tags:
123
+ tags.append(t)
124
+ record.tags = [tag(session, t) for t in tags]
125
+ try:
126
+ session.commit()
127
+ except Exception:
128
+ session.rollback()
129
+ return False
130
+ return True
131
+
132
+
133
+ def remove_tags(session: Session, record_id: int, tags: Sequence[str]):
134
+ record = session.get(Record, record_id)
135
+ if record is None:
136
+ return False
137
+ old = [t.text for t in record.tags]
138
+ record.tags = [tag(session, t) for t in old if t not in tags]
139
+ try:
140
+ session.commit()
141
+ except Exception:
142
+ session.rollback()
143
+ return False
144
+ return True
qulab/scan/expression.py CHANGED
@@ -323,6 +323,14 @@ class UnaryExpression(Expression):
323
323
  self.a = a
324
324
  self.op = op
325
325
 
326
+ def __getstate__(self) -> dict:
327
+ return {'a': self.a, 'op': self.op}
328
+
329
+ def __setstate__(self, state: dict):
330
+ self.a = state['a']
331
+ self.op = state['op']
332
+ self.cache = _empty
333
+
326
334
  def symbols(self) -> list[str]:
327
335
  if isinstance(self.a, Expression):
328
336
  return self.a.symbols()
@@ -362,6 +370,15 @@ class BinaryExpression(Expression):
362
370
  self.b = b
363
371
  self.op = op
364
372
 
373
+ def __getstate__(self) -> dict:
374
+ return {'a': self.a, 'b': self.b, 'op': self.op}
375
+
376
+ def __setstate__(self, state: dict):
377
+ self.a = state['a']
378
+ self.b = state['b']
379
+ self.op = state['op']
380
+ self.cache = _empty
381
+
365
382
  def symbols(self) -> list[str]:
366
383
  symbs = set()
367
384
  if isinstance(self.a, Expression):
@@ -419,6 +436,15 @@ class ObjectMethod(Expression):
419
436
  self.method = method
420
437
  self.args = args
421
438
 
439
+ def __getstate__(self) -> dict:
440
+ return {'obj': self.obj, 'method': self.method, 'args': self.args}
441
+
442
+ def __setstate__(self, state: dict):
443
+ self.obj = state['obj']
444
+ self.method = state['method']
445
+ self.args = state['args']
446
+ self.cache = _empty
447
+
422
448
  def symbols(self) -> list[str]:
423
449
  symbs = set()
424
450
  if isinstance(self.obj, Expression):
@@ -439,7 +465,7 @@ class ObjectMethod(Expression):
439
465
  return ObjectMethod(obj, self.method, *args)
440
466
  else:
441
467
  return getattr(obj, self.method)(*args)
442
-
468
+
443
469
  def __repr__(self):
444
470
  if self.method == '__call__':
445
471
  return f"{self.obj!r}({', '.join(map(repr, self.args))})"
@@ -453,6 +479,13 @@ class Symbol(Expression):
453
479
  super().__init__()
454
480
  self.name = name
455
481
 
482
+ def __getstate__(self) -> dict:
483
+ return {'name': self.name}
484
+
485
+ def __setstate__(self, state: dict):
486
+ self.name = state['name']
487
+ self.cache = _empty
488
+
456
489
  def symbols(self) -> list[str]:
457
490
  return [self.name]
458
491