QuLab 2.0.1__tar.gz → 2.0.2__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 (100) hide show
  1. {QuLab-2.0.1 → qulab-2.0.2}/PKG-INFO +4 -1
  2. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/PKG-INFO +4 -1
  3. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/SOURCES.txt +7 -5
  4. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/requires.txt +3 -0
  5. {QuLab-2.0.1 → qulab-2.0.2}/pyproject.toml +4 -1
  6. {QuLab-2.0.1 → qulab-2.0.2}/qulab/__main__.py +2 -0
  7. qulab-2.0.2/qulab/scan/__init__.py +3 -0
  8. qulab-2.0.2/qulab/scan/curd.py +144 -0
  9. {QuLab-2.0.1 → qulab-2.0.2}/qulab/scan/expression.py +34 -1
  10. qulab-2.0.2/qulab/scan/models.py +540 -0
  11. qulab-2.0.2/qulab/scan/optimize.py +69 -0
  12. qulab-2.0.2/qulab/scan/query_record.py +361 -0
  13. qulab-2.0.2/qulab/scan/recorder.py +447 -0
  14. qulab-2.0.2/qulab/scan/scan.py +701 -0
  15. qulab-2.0.2/qulab/sys/rpc/zmq_socket.py +209 -0
  16. qulab-2.0.2/qulab/version.py +1 -0
  17. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/_autoplot.py +11 -5
  18. qulab-2.0.2/tests/test_scan.py +2 -0
  19. QuLab-2.0.1/qulab/scan/__init__.py +0 -4
  20. QuLab-2.0.1/qulab/scan/base.py +0 -548
  21. QuLab-2.0.1/qulab/scan/dataset.py +0 -0
  22. QuLab-2.0.1/qulab/scan/optimize.py +0 -0
  23. QuLab-2.0.1/qulab/scan/scanner.py +0 -270
  24. QuLab-2.0.1/qulab/scan/transforms.py +0 -16
  25. QuLab-2.0.1/qulab/version.py +0 -1
  26. QuLab-2.0.1/tests/test_scan_iter.py +0 -375
  27. {QuLab-2.0.1 → qulab-2.0.2}/LICENSE +0 -0
  28. {QuLab-2.0.1 → qulab-2.0.2}/MANIFEST.in +0 -0
  29. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/dependency_links.txt +0 -0
  30. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/entry_points.txt +0 -0
  31. {QuLab-2.0.1 → qulab-2.0.2}/QuLab.egg-info/top_level.txt +0 -0
  32. {QuLab-2.0.1 → qulab-2.0.2}/README.md +0 -0
  33. {QuLab-2.0.1 → qulab-2.0.2}/qulab/__init__.py +0 -0
  34. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/__init__.py +0 -0
  35. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/__main__.py +0 -0
  36. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/config.py +0 -0
  37. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/dataset.py +0 -0
  38. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/event_queue.py +0 -0
  39. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/mainwindow.py +0 -0
  40. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/monitor.py +0 -0
  41. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/ploter.py +0 -0
  42. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/qt_compat.py +0 -0
  43. {QuLab-2.0.1 → qulab-2.0.2}/qulab/monitor/toolbar.py +0 -0
  44. {QuLab-2.0.1 → qulab-2.0.2}/qulab/scan/utils.py +0 -0
  45. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/__init__.py +0 -0
  46. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/__main__.py +0 -0
  47. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/backend/__init__.py +0 -0
  48. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/backend/redis.py +0 -0
  49. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/base_dataset.py +0 -0
  50. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/chunk.py +0 -0
  51. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/dataset.py +0 -0
  52. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/file.py +0 -0
  53. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/__init__.py +0 -0
  54. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/base.py +0 -0
  55. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/config.py +0 -0
  56. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/file.py +0 -0
  57. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/ipy.py +0 -0
  58. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/models.py +0 -0
  59. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/record.py +0 -0
  60. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/report.py +0 -0
  61. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/models/tag.py +0 -0
  62. {QuLab-2.0.1 → qulab-2.0.2}/qulab/storage/storage.py +0 -0
  63. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/__init__.py +0 -0
  64. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/chat.py +0 -0
  65. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/device/__init__.py +0 -0
  66. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/device/basedevice.py +0 -0
  67. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/device/loader.py +0 -0
  68. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/device/utils.py +0 -0
  69. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/drivers/FakeInstrument.py +0 -0
  70. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/drivers/__init__.py +0 -0
  71. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/ipy_events.py +0 -0
  72. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/__init__.py +0 -0
  73. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/bencoder.py +0 -0
  74. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/cli.py +0 -0
  75. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/dhcp.py +0 -0
  76. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/dhcpd.py +0 -0
  77. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/kad.py +0 -0
  78. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/kcp.py +0 -0
  79. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/net/nginx.py +0 -0
  80. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/progress.py +0 -0
  81. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/__init__.py +0 -0
  82. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/client.py +0 -0
  83. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/exceptions.py +0 -0
  84. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/msgpack.py +0 -0
  85. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/msgpack.pyi +0 -0
  86. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/rpc.py +0 -0
  87. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/serialize.py +0 -0
  88. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/server.py +0 -0
  89. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/socket.py +0 -0
  90. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/utils.py +0 -0
  91. {QuLab-2.0.1 → qulab-2.0.2}/qulab/sys/rpc/worker.py +0 -0
  92. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/__init__.py +0 -0
  93. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/__main__.py +0 -0
  94. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/plot_layout.py +0 -0
  95. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/plot_seq.py +0 -0
  96. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/qdat.py +0 -0
  97. {QuLab-2.0.1 → qulab-2.0.2}/qulab/visualization/widgets.py +0 -0
  98. {QuLab-2.0.1 → qulab-2.0.2}/setup.cfg +0 -0
  99. {QuLab-2.0.1 → qulab-2.0.2}/setup.py +0 -0
  100. {QuLab-2.0.1 → qulab-2.0.2}/src/qulab.h +0 -0
@@ -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,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)
@@ -23,12 +23,13 @@ qulab/monitor/ploter.py
23
23
  qulab/monitor/qt_compat.py
24
24
  qulab/monitor/toolbar.py
25
25
  qulab/scan/__init__.py
26
- qulab/scan/base.py
27
- qulab/scan/dataset.py
26
+ qulab/scan/curd.py
28
27
  qulab/scan/expression.py
28
+ qulab/scan/models.py
29
29
  qulab/scan/optimize.py
30
- qulab/scan/scanner.py
31
- qulab/scan/transforms.py
30
+ qulab/scan/query_record.py
31
+ qulab/scan/recorder.py
32
+ qulab/scan/scan.py
32
33
  qulab/scan/utils.py
33
34
  qulab/storage/__init__.py
34
35
  qulab/storage/__main__.py
@@ -77,6 +78,7 @@ qulab/sys/rpc/server.py
77
78
  qulab/sys/rpc/socket.py
78
79
  qulab/sys/rpc/utils.py
79
80
  qulab/sys/rpc/worker.py
81
+ qulab/sys/rpc/zmq_socket.py
80
82
  qulab/visualization/__init__.py
81
83
  qulab/visualization/__main__.py
82
84
  qulab/visualization/_autoplot.py
@@ -85,4 +87,4 @@ qulab/visualization/plot_seq.py
85
87
  qulab/visualization/qdat.py
86
88
  qulab/visualization/widgets.py
87
89
  src/qulab.h
88
- tests/test_scan_iter.py
90
+ tests/test_scan.py
@@ -4,7 +4,10 @@ dill>=0.3.6
4
4
  GitPython>=3.1.14
5
5
  ipython>=7.4.0
6
6
  ipywidgets>=7.4.2
7
+ loguru>=0.7.2
7
8
  matplotlib>=3.7.2
8
9
  numpy>=1.13.3
9
10
  ply>=3.11
11
+ pyzmq>=25.1.0
10
12
  scipy>=1.0.0
13
+ watchdog>=4.0.0
@@ -34,10 +34,13 @@ dependencies = [
34
34
  "GitPython>=3.1.14",
35
35
  "ipython>=7.4.0",
36
36
  "ipywidgets>=7.4.2",
37
+ "loguru>=0.7.2",
37
38
  "matplotlib>=3.7.2",
38
39
  "numpy>=1.13.3",
39
40
  "ply>=3.11",
40
- "scipy>=1.0.0"
41
+ "pyzmq>=25.1.0",
42
+ "scipy>=1.0.0",
43
+ "watchdog>=4.0.0"
41
44
  ]
42
45
  dynamic = ["version"]
43
46
 
@@ -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()
@@ -0,0 +1,3 @@
1
+ from .expression import Expression, Symbol
2
+ from .query_record import get_record, lookup, lookup_list
3
+ from .scan import Scan
@@ -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
@@ -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