PyroLab 0.3.1__tar.gz → 0.4.0__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.
- pyrolab-0.4.0/MANIFEST.in +4 -0
- {PyroLab-0.3.1 → pyrolab-0.4.0}/NOTICE.txt +1 -1
- pyrolab-0.4.0/PKG-INFO +299 -0
- {PyroLab-0.3.1 → pyrolab-0.4.0}/README.md +18 -8
- {PyroLab-0.3.1 → pyrolab-0.4.0}/pyproject.toml +33 -14
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/__init__.py +56 -7
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/api.py +6 -6
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/cli.py +220 -98
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/configure.py +109 -71
- pyrolab-0.4.0/pyrolab/data/wordlist.txt +9890 -0
- pyrolab-0.4.0/pyrolab/drivers/VISAResourceExtensions.py +273 -0
- pyrolab-0.4.0/pyrolab/drivers/__init__.py +162 -0
- pyrolab-0.4.0/pyrolab/drivers/arduino/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/arduino/arduino.py +190 -0
- pyrolab-0.4.0/pyrolab/drivers/cameras/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/cameras/amcam.py +61 -0
- pyrolab-0.4.0/pyrolab/drivers/cameras/sciTSI.py +215 -0
- pyrolab-0.4.0/pyrolab/drivers/cameras/thorcam.py +611 -0
- pyrolab-0.4.0/pyrolab/drivers/cameras/uc480.py +420 -0
- pyrolab-0.4.0/pyrolab/drivers/fpgas/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/fpgas/analogdiscovery.py +310 -0
- pyrolab-0.4.0/pyrolab/drivers/function_generators/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/function_generators/smcv100b.py +389 -0
- pyrolab-0.4.0/pyrolab/drivers/lasers/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/lasers/ppcl55x.py +653 -0
- pyrolab-0.4.0/pyrolab/drivers/lasers/sachertec.py +108 -0
- pyrolab-0.4.0/pyrolab/drivers/lasers/tsl550.py +1540 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/KMTS25E.py +92 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/kinesis/__init__.py +65 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/kinesis/bpc303.py +465 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/kinesis/kdc101.py +819 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/max31x.py +247 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/prm1z8.py +54 -0
- pyrolab-0.4.0/pyrolab/drivers/motion/z8xx.py +144 -0
- pyrolab-0.4.0/pyrolab/drivers/sample.py +300 -0
- pyrolab-0.4.0/pyrolab/drivers/scopes/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/scopes/rohdeschwarz.py +579 -0
- pyrolab-0.4.0/pyrolab/drivers/smu/__init__.py +16 -0
- pyrolab-0.4.0/pyrolab/drivers/smu/keysight.py +397 -0
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/manager.py +138 -85
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/nameserver.py +28 -16
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/pyrolabd.py +37 -19
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/server.py +69 -57
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/service.py +13 -7
- {PyroLab-0.3.1/src → pyrolab-0.4.0}/pyrolab/utils.py +13 -5
- pyrolab-0.4.0/pyrolab.egg-info/PKG-INFO +299 -0
- pyrolab-0.4.0/pyrolab.egg-info/SOURCES.txt +62 -0
- {PyroLab-0.3.1/src/PyroLab.egg-info → pyrolab-0.4.0/pyrolab.egg-info}/entry_points.txt +0 -1
- pyrolab-0.4.0/pyrolab.egg-info/requires.txt +46 -0
- pyrolab-0.4.0/pyrolab.egg-info/top_level.txt +1 -0
- pyrolab-0.4.0/tests/test_code_interface.py +29 -0
- pyrolab-0.4.0/tests/test_configure.py +150 -0
- pyrolab-0.4.0/tests/test_daemon.py +24 -0
- pyrolab-0.4.0/tests/test_errors.py +0 -0
- pyrolab-0.4.0/tests/test_manager.py +0 -0
- pyrolab-0.4.0/tests/test_nameserver.py +0 -0
- pyrolab-0.4.0/tests/test_pyrolabd.py +0 -0
- pyrolab-0.4.0/tests/test_service.py +0 -0
- pyrolab-0.4.0/tests/test_utils.py +0 -0
- pyrolab-0.4.0/tests/testsrv.py +21 -0
- PyroLab-0.3.1/AUTHORS.txt +0 -20
- PyroLab-0.3.1/MANIFEST.in +0 -1
- PyroLab-0.3.1/PKG-INFO +0 -930
- PyroLab-0.3.1/src/PyroLab.egg-info/PKG-INFO +0 -930
- PyroLab-0.3.1/src/PyroLab.egg-info/SOURCES.txt +0 -26
- PyroLab-0.3.1/src/PyroLab.egg-info/requires.txt +0 -33
- PyroLab-0.3.1/src/PyroLab.egg-info/top_level.txt +0 -2
- PyroLab-0.3.1/src/pyromonitor/__init__.py +0 -68
- PyroLab-0.3.1/src/pyromonitor/cli.py +0 -77
- PyroLab-0.3.1/src/pyromonitor/config.py +0 -19
- PyroLab-0.3.1/src/pyromonitor/lister.py +0 -131
- {PyroLab-0.3.1 → pyrolab-0.4.0}/LICENSE +0 -0
- {PyroLab-0.3.1/src/PyroLab.egg-info → pyrolab-0.4.0/pyrolab.egg-info}/dependency_links.txt +0 -0
- {PyroLab-0.3.1 → pyrolab-0.4.0}/setup.cfg +0 -0
|
@@ -31,7 +31,7 @@ PPCL55X
|
|
|
31
31
|
The code found in the following files were included in Pyrolab with some
|
|
32
32
|
modifications:
|
|
33
33
|
|
|
34
|
-
pyrolab/drivers/lasers/
|
|
34
|
+
pyrolab/drivers/lasers/ppcl55x.py
|
|
35
35
|
|
|
36
36
|
The original source is available at
|
|
37
37
|
https://www.pure-photonics.com/s/ITLA_v3-CUSTOMER.PY
|
pyrolab-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyrolab
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A framework for using remote lab instruments as local resources built on Pyro5.
|
|
5
|
+
Author-email: Sequoia Ploeg <sequoiap4@gmail.com>, BYU CamachoLab <camacho@byu.edu>
|
|
6
|
+
Maintainer-email: Sequoia Ploeg <sequoiap4@gmail.com>, BYU CamachoLab <camacho@byu.edu>
|
|
7
|
+
License: GPL-3.0+
|
|
8
|
+
Project-URL: Homepage, https://pyrolab.readthedocs.io/en/latest/
|
|
9
|
+
Project-URL: Documentation, https://pyrolab.readthedocs.io/en/latest/
|
|
10
|
+
Project-URL: Source, https://github.com/BYUCamachoLab/pyrolab
|
|
11
|
+
Project-URL: Bug Reports, https://github.com/BYUCamachoLab/pyrolab/issues
|
|
12
|
+
Project-URL: Research Group, https://camacholab.byu.edu/
|
|
13
|
+
Keywords: PyroLab,Pyro5,Pyro,lab,instrument,remote,resources,framework,laboratory,instrumentation,hardware,science,remote,network,integration
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Education
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
27
|
+
Classifier: Operating System :: MacOS
|
|
28
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
29
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
30
|
+
Classifier: Operating System :: OS Independent
|
|
31
|
+
Requires-Python: >=3.9
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
License-File: LICENSE
|
|
34
|
+
License-File: NOTICE.txt
|
|
35
|
+
Requires-Dist: numpy
|
|
36
|
+
Requires-Dist: scipy
|
|
37
|
+
Requires-Dist: Pyro5
|
|
38
|
+
Requires-Dist: pydantic<2.0.0,>=1.9.1
|
|
39
|
+
Requires-Dist: pyyaml
|
|
40
|
+
Requires-Dist: deprecation
|
|
41
|
+
Requires-Dist: typer
|
|
42
|
+
Requires-Dist: colorama
|
|
43
|
+
Requires-Dist: tabulate
|
|
44
|
+
Requires-Dist: requests
|
|
45
|
+
Requires-Dist: packaging>=23.0
|
|
46
|
+
Provides-Extra: tsl550
|
|
47
|
+
Requires-Dist: pyserial; extra == "tsl550"
|
|
48
|
+
Provides-Extra: ppcl55x
|
|
49
|
+
Requires-Dist: pyserial; extra == "ppcl55x"
|
|
50
|
+
Provides-Extra: rto
|
|
51
|
+
Requires-Dist: pyvisa; extra == "rto"
|
|
52
|
+
Requires-Dist: pyvisa-py; extra == "rto"
|
|
53
|
+
Provides-Extra: arduino
|
|
54
|
+
Requires-Dist: pyfirmata; extra == "arduino"
|
|
55
|
+
Provides-Extra: test
|
|
56
|
+
Requires-Dist: pytest; extra == "test"
|
|
57
|
+
Requires-Dist: coverage; extra == "test"
|
|
58
|
+
Provides-Extra: dev
|
|
59
|
+
Requires-Dist: notebook; extra == "dev"
|
|
60
|
+
Requires-Dist: pytest; extra == "dev"
|
|
61
|
+
Requires-Dist: mypy; extra == "dev"
|
|
62
|
+
Requires-Dist: coverage; extra == "dev"
|
|
63
|
+
Requires-Dist: flake8>=4.0.1; extra == "dev"
|
|
64
|
+
Requires-Dist: isort>=5.10.1; extra == "dev"
|
|
65
|
+
Requires-Dist: black>=22.1.0; extra == "dev"
|
|
66
|
+
Requires-Dist: autopep8>=1.6.0; extra == "dev"
|
|
67
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
68
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
69
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
70
|
+
Requires-Dist: bump2version~=1.0.1; extra == "dev"
|
|
71
|
+
Provides-Extra: docs
|
|
72
|
+
Requires-Dist: jupyter-book==1.0.3; extra == "docs"
|
|
73
|
+
Requires-Dist: numpydoc==1.5.0; extra == "docs"
|
|
74
|
+
Dynamic: license-file
|
|
75
|
+
|
|
76
|
+
<p align="center">
|
|
77
|
+
<img src="https://raw.githubusercontent.com/BYUCamachoLab/pyrolab/master/docs/_static/images/pyrolab_logo.svg" width="40%" alt="PyroLab">
|
|
78
|
+
</p>
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
<p align="center">
|
|
83
|
+
<img alt="Development version" src="https://img.shields.io/badge/master-v0.4.0-informational">
|
|
84
|
+
<a href="https://pypi.python.org/pypi/pyrolab"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/pyrolab.svg"></a>
|
|
85
|
+
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pyrolab">
|
|
86
|
+
<a href="https://pyrolab.readthedocs.io/"><img alt="Documentation Status" src="https://readthedocs.org/projects/pyrolab/badge/?version=latest"></a>
|
|
87
|
+
<a href="https://pypi.python.org/pypi/pyrolab/"><img alt="License" src="https://img.shields.io/pypi/l/pyrolab.svg"></a>
|
|
88
|
+
<a href="https://github.com/BYUCamachoLab/pyrolab/commits/master"><img alt="Latest Commit" src="https://img.shields.io/github/last-commit/BYUCamachoLab/pyrolab.svg"></a>
|
|
89
|
+
</p>
|
|
90
|
+
|
|
91
|
+
A framework for using remote lab instruments as local resources, built on Pyro5.
|
|
92
|
+
|
|
93
|
+
Developed by Sequoia Ploeg (for [CamachoLab](https://camacholab.byu.edu/),
|
|
94
|
+
Brigham Young University).
|
|
95
|
+
|
|
96
|
+
## About
|
|
97
|
+
This project aims to allow all laboratory instruments to be accessed as
|
|
98
|
+
local objects from a remote machine. Instruments that don't natively
|
|
99
|
+
support such access, such as those required to be connected by a USB cable
|
|
100
|
+
(or similar), are wrapped with a Pyro5 interface. However, this library may
|
|
101
|
+
contain other instruments that are already internet-capable and don't rely
|
|
102
|
+
on Pyro5. That's alright; we're just trying to create a minimal-dependency,
|
|
103
|
+
one-stop-shop for laboratory instruments!
|
|
104
|
+
|
|
105
|
+
**Note:** while the software says "OS Independent", some of the servers *are*
|
|
106
|
+
OS-specific. For example, ThorLabs DLL's only work on Windows. However, you could
|
|
107
|
+
use PyroLab to connect to those devices from any operating system.
|
|
108
|
+
|
|
109
|
+
## Installation
|
|
110
|
+
|
|
111
|
+
PyroLab is pip installable:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
pip install pyrolab
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
PyroLab declares several "extras", depending on which instruments you need
|
|
118
|
+
to support:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
pip install pyrolab[tsl550, oscope]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The full list of supported extras is:
|
|
125
|
+
- ``tsl550`` (Santec lasers)
|
|
126
|
+
- ``ppcl55x`` (PurePhotonics lasers)
|
|
127
|
+
- ``rto`` (Rohde & Schwarz oscilloscopes)
|
|
128
|
+
- ``arduino`` (Arduino)
|
|
129
|
+
- ``test`` (PyroLab unit testing)
|
|
130
|
+
<!-- - ``thorlabs`` (ThorLabs motion controllers) -->
|
|
131
|
+
<!-- - ``adiscovery`` (Analog Discovery boards from Digilent) -->
|
|
132
|
+
<!-- - ``monitor`` (PyroMonitor web application) -->
|
|
133
|
+
|
|
134
|
+
You can also clone the repository, navigate to the toplevel, and install in
|
|
135
|
+
editable mode (make sure you have pip >= 21.1):
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
pip install -e .
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Web Monitor
|
|
142
|
+
|
|
143
|
+
There's a web application that can monitor your PyroLab nameserver and
|
|
144
|
+
provide an easy-to-access status board. It's a Flask app that can be served
|
|
145
|
+
using a production grade server. Install it using pip:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
pip install pyromonitor
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
To run:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
pyromonitor up
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Example
|
|
158
|
+
|
|
159
|
+
### Local Instruments
|
|
160
|
+
|
|
161
|
+
Locally available instruments just import drivers without using any of the
|
|
162
|
+
other features of PyroLab.
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
from pyrolab.drivers.lasers.tsl550 import TSL550
|
|
166
|
+
|
|
167
|
+
laser = TSL550("COM4")
|
|
168
|
+
laser.on()
|
|
169
|
+
laser.power_dBm(12)
|
|
170
|
+
laser.open_shutter()
|
|
171
|
+
laser.sweep_set_mode(continuous=True, twoway=True, trigger=False, const_freq_step=False)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Remote Instruments
|
|
175
|
+
|
|
176
|
+
First, make sure all configurations on the nameserver computer, instrument
|
|
177
|
+
server computer, and client are correct (with the proper keys, if configured,
|
|
178
|
+
etc.).
|
|
179
|
+
|
|
180
|
+
Run a nameserver:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from pyrolab.api import start_ns_loop
|
|
184
|
+
start_ns_loop()
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Provide a service:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from pyrolab.api import Daemon, locate_ns
|
|
191
|
+
from pyrolab.drivers.sample import SampleService
|
|
192
|
+
|
|
193
|
+
daemon = Daemon()
|
|
194
|
+
ns = locate_ns(host="localhost")
|
|
195
|
+
uri = daemon.register(SampleService)
|
|
196
|
+
ns.register("test.SampleService", uri)
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
daemon.requestLoop()
|
|
200
|
+
finally:
|
|
201
|
+
ns.remove("test.SampleService")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Connect using a remote client:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from pyrolab.api import locate_ns, Proxy
|
|
208
|
+
|
|
209
|
+
ns = locate_ns(host="localhost")
|
|
210
|
+
uri = ns.lookup("test.SampleService")
|
|
211
|
+
|
|
212
|
+
with Proxy(uri) as service:
|
|
213
|
+
resp = service.echo("Hello, server!")
|
|
214
|
+
print(type(resp), resp)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Instrument Server Configuration
|
|
218
|
+
|
|
219
|
+
PyroLab stores information about instruments and servers when it closes. This
|
|
220
|
+
means that once PyroLab has been configured once, each time it is restarted,
|
|
221
|
+
it will remember and reload the previous configuration. Hence, once a server
|
|
222
|
+
is set up, unless the available instruments, nameserver, or other
|
|
223
|
+
configurations change, PyroLab will automatically work when started, every
|
|
224
|
+
time!
|
|
225
|
+
|
|
226
|
+
For an example of how a new PyroLab instrument server should be configured the
|
|
227
|
+
first time it's run, see ``examples/library-catalog/config.yaml``.
|
|
228
|
+
|
|
229
|
+
## FAQ's
|
|
230
|
+
1. **Another instrument library? What about all the others?**
|
|
231
|
+
In our experience, many of the other libraries are buggy or have difficulty
|
|
232
|
+
with network connections. So, our approach was to rely on a well developed
|
|
233
|
+
and time-tested framework (Pyro) instead of worrying about developing and
|
|
234
|
+
supporting our own custom set of servers.
|
|
235
|
+
|
|
236
|
+
2. **Is this a standalone software that automatically supports all the advertised
|
|
237
|
+
instruments?**
|
|
238
|
+
No; many of these instruments depend on other software already being
|
|
239
|
+
installed. In particular, ThorLabs equipment depends on ThorLabs software
|
|
240
|
+
already being installed on the computer connected to the physical hardware
|
|
241
|
+
(but not on the remote computer!). As much as possible, though, we try to
|
|
242
|
+
make the drivers standalone capable.
|
|
243
|
+
|
|
244
|
+
## For Developers
|
|
245
|
+
|
|
246
|
+
Since the passing of data is, by definition, between hosts and over IP, PyroLab
|
|
247
|
+
avoids the use of complex Python objects for return values that will be
|
|
248
|
+
transmitted to remote machines. Since serialization is complicated, and
|
|
249
|
+
security is even harder, we resort to using only basic Python types when
|
|
250
|
+
interfacing with hardware (i.e., Python lists, ints, tuples, and not NumPy
|
|
251
|
+
arrays, matplotlib plot objects, custom objects, etc.).
|
|
252
|
+
|
|
253
|
+
## Releasing
|
|
254
|
+
|
|
255
|
+
Make sure you have committed a changelog file under ``docs/changelog`` titled
|
|
256
|
+
``<major>.<minor>.<patch>-changelog.md`` before bumping version. Also, the git
|
|
257
|
+
directory should be clean (no uncommitted changes).
|
|
258
|
+
|
|
259
|
+
To bump version prior to a release, run one of the following commands:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
bumpversion major
|
|
263
|
+
bumpversion minor
|
|
264
|
+
bumpversion patch
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
This will automatically create a git tag in the repository with the
|
|
268
|
+
corrresponding version number and commit the modified files (where version
|
|
269
|
+
numbers were updated). Pushing the tags (a manual process) to the remote will
|
|
270
|
+
automatically create a new release. Releases are automatically published to
|
|
271
|
+
PyPI and GitHub when git tags matching the "v*" pattern are created
|
|
272
|
+
(e.g. "v0.4.0"), as bumpversion does.
|
|
273
|
+
|
|
274
|
+
After bumping version, you can view the tags on the local machine by running
|
|
275
|
+
``git tag``. To push the tags to the remote server and trigger the release
|
|
276
|
+
workflow, you can run ``git push origin <tagname>``.
|
|
277
|
+
|
|
278
|
+
For code quality, please run isort and black before committing (note that the
|
|
279
|
+
latest release of isort may not work through VSCode's integrated terminal, and
|
|
280
|
+
it's safest to run it separately through another terminal).
|
|
281
|
+
|
|
282
|
+
## Building the Docs
|
|
283
|
+
|
|
284
|
+
Much of the API documentation is autogenerated from the source code. Gitignores
|
|
285
|
+
are in place to prevent you from committing autogenerated pages.
|
|
286
|
+
|
|
287
|
+
To build the docs, navigate to the ``docs/`` directory and run:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
pip install -r requirements.txt
|
|
291
|
+
make html
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Building the Package
|
|
295
|
+
|
|
296
|
+
You can test the build and view the bundled artifacts using
|
|
297
|
+
[build](https://pypi.org/project/build/). It's recommended you build locally
|
|
298
|
+
before pushing to PyPI. In particular, double check the included files and make
|
|
299
|
+
sure only the required files are there by modifying MANIFEST.in as necessary.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img alt="Development version" src="https://img.shields.io/badge/master-v0.
|
|
8
|
+
<img alt="Development version" src="https://img.shields.io/badge/master-v0.4.0-informational">
|
|
9
9
|
<a href="https://pypi.python.org/pypi/pyrolab"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/pyrolab.svg"></a>
|
|
10
10
|
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pyrolab">
|
|
11
11
|
<a href="https://pyrolab.readthedocs.io/"><img alt="Documentation Status" src="https://readthedocs.org/projects/pyrolab/badge/?version=latest"></a>
|
|
@@ -47,10 +47,14 @@ pip install pyrolab[tsl550, oscope]
|
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
The full list of supported extras is:
|
|
50
|
-
- tsl550
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
50
|
+
- ``tsl550`` (Santec lasers)
|
|
51
|
+
- ``ppcl55x`` (PurePhotonics lasers)
|
|
52
|
+
- ``rto`` (Rohde & Schwarz oscilloscopes)
|
|
53
|
+
- ``arduino`` (Arduino)
|
|
54
|
+
- ``test`` (PyroLab unit testing)
|
|
55
|
+
<!-- - ``thorlabs`` (ThorLabs motion controllers) -->
|
|
56
|
+
<!-- - ``adiscovery`` (Analog Discovery boards from Digilent) -->
|
|
57
|
+
<!-- - ``monitor`` (PyroMonitor web application) -->
|
|
54
58
|
|
|
55
59
|
You can also clone the repository, navigate to the toplevel, and install in
|
|
56
60
|
editable mode (make sure you have pip >= 21.1):
|
|
@@ -61,9 +65,15 @@ pip install -e .
|
|
|
61
65
|
|
|
62
66
|
## Web Monitor
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
There's a web application that can monitor your PyroLab nameserver and
|
|
65
69
|
provide an easy-to-access status board. It's a Flask app that can be served
|
|
66
|
-
using a production grade server.
|
|
70
|
+
using a production grade server. Install it using pip:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
pip install pyromonitor
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To run:
|
|
67
77
|
|
|
68
78
|
```
|
|
69
79
|
pyromonitor up
|
|
@@ -184,7 +194,7 @@ corrresponding version number and commit the modified files (where version
|
|
|
184
194
|
numbers were updated). Pushing the tags (a manual process) to the remote will
|
|
185
195
|
automatically create a new release. Releases are automatically published to
|
|
186
196
|
PyPI and GitHub when git tags matching the "v*" pattern are created
|
|
187
|
-
(e.g. "v0.
|
|
197
|
+
(e.g. "v0.4.0"), as bumpversion does.
|
|
188
198
|
|
|
189
199
|
After bumping version, you can view the tags on the local machine by running
|
|
190
200
|
``git tag``. To push the tags to the remote server and trigger the release
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
|
-
name = "
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "A framework for using remote lab instruments as local resources built on Pyro5"
|
|
2
|
+
name = "pyrolab"
|
|
3
|
+
version = "0.4.0"
|
|
4
|
+
description = "A framework for using remote lab instruments as local resources built on Pyro5."
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
7
|
-
license = {
|
|
6
|
+
requires-python = ">=3.9"
|
|
7
|
+
license = {text = "GPL-3.0+"}
|
|
8
8
|
keywords = [
|
|
9
9
|
"PyroLab",
|
|
10
10
|
"Pyro5",
|
|
@@ -47,11 +47,11 @@ classifiers = [
|
|
|
47
47
|
"Topic :: Scientific/Engineering",
|
|
48
48
|
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
49
49
|
"Programming Language :: Python :: 3",
|
|
50
|
-
"Programming Language :: Python :: 3.7",
|
|
51
|
-
"Programming Language :: Python :: 3.8",
|
|
52
50
|
"Programming Language :: Python :: 3.9",
|
|
53
51
|
"Programming Language :: Python :: 3.10",
|
|
54
52
|
"Programming Language :: Python :: 3.11",
|
|
53
|
+
"Programming Language :: Python :: 3.12",
|
|
54
|
+
"Programming Language :: Python :: 3.13",
|
|
55
55
|
"Programming Language :: Python :: 3 :: Only",
|
|
56
56
|
"Operating System :: MacOS",
|
|
57
57
|
"Operating System :: Microsoft :: Windows",
|
|
@@ -63,7 +63,7 @@ dependencies = [
|
|
|
63
63
|
"numpy",
|
|
64
64
|
"scipy",
|
|
65
65
|
"Pyro5",
|
|
66
|
-
"pydantic",
|
|
66
|
+
"pydantic >= 1.9.1, < 2.0.0",
|
|
67
67
|
"pyyaml",
|
|
68
68
|
"deprecation",
|
|
69
69
|
"typer",
|
|
@@ -81,10 +81,34 @@ dependencies = [
|
|
|
81
81
|
[project.optional-dependencies]
|
|
82
82
|
tsl550 = ["pyserial"]
|
|
83
83
|
ppcl55x = ["pyserial"]
|
|
84
|
+
# thorlabs = ["thorlabs_kinesis@git+https://github.com/BYUCamachoLab/thorlabs-kinesis"]
|
|
84
85
|
rto = ["pyvisa", "pyvisa-py"]
|
|
85
86
|
arduino = ["pyfirmata"]
|
|
86
|
-
|
|
87
|
+
# adiscovery = ["WF_SDK@git+https://github.com/Digilent/WaveForms-SDK-Getting-Started-PY#egg=WF_SDK"]
|
|
88
|
+
# monitor = ["pyromonitor@git+https://github.com/BYUCamachoLab/pyromonitor"]
|
|
87
89
|
test = ["pytest", "coverage"]
|
|
90
|
+
dev = [
|
|
91
|
+
"notebook",
|
|
92
|
+
"pytest",
|
|
93
|
+
"mypy",
|
|
94
|
+
"coverage",
|
|
95
|
+
"flake8 >= 4.0.1",
|
|
96
|
+
"isort >= 5.10.1",
|
|
97
|
+
"black >= 22.1.0",
|
|
98
|
+
"autopep8 >= 1.6.0",
|
|
99
|
+
"twine >= 4.0.0",
|
|
100
|
+
"build >= 0.10.0",
|
|
101
|
+
"pre-commit",
|
|
102
|
+
"bump2version ~= 1.0.1",
|
|
103
|
+
]
|
|
104
|
+
docs = [
|
|
105
|
+
"jupyter-book == 1.0.3",
|
|
106
|
+
"numpydoc==1.5.0",
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
[tool.setuptools.packages.find]
|
|
110
|
+
include = ["pyrolab"]
|
|
111
|
+
namespaces = false
|
|
88
112
|
|
|
89
113
|
[project.urls]
|
|
90
114
|
"Homepage" = "https://pyrolab.readthedocs.io/en/latest/"
|
|
@@ -95,11 +119,6 @@ test = ["pytest", "coverage"]
|
|
|
95
119
|
|
|
96
120
|
[project.scripts]
|
|
97
121
|
pyrolab = "pyrolab.cli:app"
|
|
98
|
-
pyromonitor = "pyromonitor.cli:app"
|
|
99
|
-
|
|
100
|
-
[tool.setuptools.packages.find]
|
|
101
|
-
where = ["src"]
|
|
102
|
-
include = ["pyrolab", "pyromonitor"]
|
|
103
122
|
|
|
104
123
|
[tool.pytest.ini_options]
|
|
105
124
|
minversion = "6.0"
|
|
@@ -27,6 +27,12 @@ import os
|
|
|
27
27
|
import pathlib
|
|
28
28
|
import platform
|
|
29
29
|
import sys
|
|
30
|
+
import atexit
|
|
31
|
+
import fileinput
|
|
32
|
+
import re
|
|
33
|
+
from typing import Callable, Iterable
|
|
34
|
+
from time import strptime
|
|
35
|
+
from pathlib import Path
|
|
30
36
|
|
|
31
37
|
# Check if Python version is supported
|
|
32
38
|
pyversion = sys.version_info
|
|
@@ -42,11 +48,11 @@ if pyversion < (3, 7, 0):
|
|
|
42
48
|
__name__ = "PyroLab"
|
|
43
49
|
__author__ = "CamachoLab"
|
|
44
50
|
__copyright__ = "Copyright 2020, The PyroLab Project"
|
|
45
|
-
__version__ = "0.
|
|
51
|
+
__version__ = "0.4.0"
|
|
46
52
|
__license__ = "GPLv3+"
|
|
47
53
|
__maintainer__ = "Sequoia Ploeg"
|
|
48
54
|
__maintainer_email__ = "sequoia.ploeg@byu.edu"
|
|
49
|
-
__status__ = "Development"
|
|
55
|
+
__status__ = "Development" # "Production"
|
|
50
56
|
__project_url__ = "https://github.com/sequoiap/pyrolab"
|
|
51
57
|
__forum_url__ = "https://github.com/sequoiap/pyrolab/issues"
|
|
52
58
|
__website_url__ = "https://camacholab.byu.edu/"
|
|
@@ -66,6 +72,7 @@ if pyversion < (3, 9, 0):
|
|
|
66
72
|
base_path = pathlib.Path(__file__).resolve().parent
|
|
67
73
|
else:
|
|
68
74
|
from importlib.resources import files
|
|
75
|
+
|
|
69
76
|
base_path = files("pyrolab")
|
|
70
77
|
base_path = base_path / "data" / "local"
|
|
71
78
|
|
|
@@ -78,6 +85,7 @@ NAMESERVER_STORAGE.mkdir(parents=True, exist_ok=True)
|
|
|
78
85
|
|
|
79
86
|
PYROLAB_LOGDIR = PYROLAB_DATA_DIR / "logs"
|
|
80
87
|
PYROLAB_LOGDIR.mkdir(parents=True, exist_ok=True)
|
|
88
|
+
PYROLAB_MASTERLOG = PYROLAB_LOGDIR / "pyrolab.log"
|
|
81
89
|
|
|
82
90
|
LOCKFILE = PYROLAB_DATA_DIR / "pyrolabd.lock"
|
|
83
91
|
USER_CONFIG_FILE = PYROLAB_DATA_DIR / "user_configuration.yaml"
|
|
@@ -98,11 +106,14 @@ def get_loglevel() -> int:
|
|
|
98
106
|
return loglevel
|
|
99
107
|
|
|
100
108
|
|
|
101
|
-
if len(logging.root.handlers) == 0:
|
|
109
|
+
if len(logging.root.handlers) == 0:
|
|
102
110
|
logfile = PYROLAB_LOGDIR / f"pyrolab_{os.getpid()}.log"
|
|
103
111
|
root = logging.getLogger()
|
|
104
|
-
h = logging.handlers.RotatingFileHandler(logfile,
|
|
105
|
-
f = logging.Formatter(
|
|
112
|
+
h = logging.handlers.RotatingFileHandler(logfile, "a", 30000, 10)
|
|
113
|
+
f = logging.Formatter(
|
|
114
|
+
"[%(asctime)s.%(msecs)03d] %(levelname)-8s %(process)-5s %(processName)-16s %(name)-20s %(message)s",
|
|
115
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
116
|
+
)
|
|
106
117
|
h.setFormatter(f)
|
|
107
118
|
root.addHandler(h)
|
|
108
119
|
root.setLevel(get_loglevel())
|
|
@@ -124,10 +135,10 @@ try:
|
|
|
124
135
|
|
|
125
136
|
url = "https://pypi.org/pypi/pyrolab/json"
|
|
126
137
|
with requests.Session() as s:
|
|
127
|
-
s.mount(
|
|
138
|
+
s.mount("https://pypi.org", HTTPAdapter(max_retries=3))
|
|
128
139
|
resp = s.get(url).text
|
|
129
140
|
|
|
130
|
-
v = json.loads(resp)[
|
|
141
|
+
v = json.loads(resp)["info"]["version"]
|
|
131
142
|
curver = parse(__version__)
|
|
132
143
|
latest = parse(v)
|
|
133
144
|
|
|
@@ -139,3 +150,41 @@ try:
|
|
|
139
150
|
log.info(message)
|
|
140
151
|
except:
|
|
141
152
|
pass
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def try_itr(func: Callable, itr: Iterable, *exceptions, **kwargs):
|
|
156
|
+
"""
|
|
157
|
+
Tests a function on an iterable, yields iterable if no exception is raised.
|
|
158
|
+
"""
|
|
159
|
+
for elem in itr:
|
|
160
|
+
try:
|
|
161
|
+
func(elem, **kwargs)
|
|
162
|
+
yield elem
|
|
163
|
+
except exceptions:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# @atexit.register
|
|
168
|
+
# def condense_logs():
|
|
169
|
+
# """
|
|
170
|
+
# Cleans up the logfile directory every once in a while.
|
|
171
|
+
|
|
172
|
+
# Runs at exit or when "pyrolab down" is called. Condenses all process log
|
|
173
|
+
# files into a single logfile that is sorted by timestamp.
|
|
174
|
+
# """
|
|
175
|
+
# f_names = list(PYROLAB_LOGDIR.glob("*.*"))
|
|
176
|
+
# lines = list(fileinput.input(f_names))
|
|
177
|
+
# t_fmt = "%Y-%m-%d %H:%M:%S.%f" # format of time stamps
|
|
178
|
+
# t_pat = re.compile(r"\[(.+?)\]") # pattern to extract timestamp
|
|
179
|
+
# lines = list(
|
|
180
|
+
# try_itr(
|
|
181
|
+
# lambda l: strptime(t_pat.search(l).group(1), t_fmt), lines, AttributeError
|
|
182
|
+
# )
|
|
183
|
+
# )
|
|
184
|
+
# with PYROLAB_MASTERLOG.open(mode="w") as f:
|
|
185
|
+
# for l in sorted(lines, key=lambda l: strptime(t_pat.search(l).group(1), t_fmt)):
|
|
186
|
+
# f.write(l)
|
|
187
|
+
# if PYROLAB_MASTERLOG in f_names:
|
|
188
|
+
# f_names.remove(PYROLAB_MASTERLOG)
|
|
189
|
+
# for f in f_names:
|
|
190
|
+
# f.unlink()
|
|
@@ -14,11 +14,11 @@ from Pyro5.core import locate_ns
|
|
|
14
14
|
from Pyro5.server import behavior, expose, oneway, serve
|
|
15
15
|
from pyrolab import USER_CONFIG_FILE
|
|
16
16
|
from pyrolab.configure import (
|
|
17
|
-
PyroLabConfiguration,
|
|
18
|
-
NameServerConfiguration,
|
|
19
|
-
DaemonConfiguration,
|
|
20
|
-
ServiceConfiguration,
|
|
21
|
-
reset_config,
|
|
17
|
+
PyroLabConfiguration,
|
|
18
|
+
NameServerConfiguration,
|
|
19
|
+
DaemonConfiguration,
|
|
20
|
+
ServiceConfiguration,
|
|
21
|
+
reset_config,
|
|
22
22
|
update_config,
|
|
23
23
|
)
|
|
24
24
|
from pyrolab.server import Daemon, LockableDaemon
|
|
@@ -47,7 +47,7 @@ __all__ = [
|
|
|
47
47
|
]
|
|
48
48
|
|
|
49
49
|
# If a user config file exists, load the first listed nameserver by default,
|
|
50
|
-
# so that locate_ns "just works."
|
|
50
|
+
# so that locate_ns "just works."
|
|
51
51
|
if USER_CONFIG_FILE.exists():
|
|
52
52
|
cfg = PyroLabConfiguration.from_file(USER_CONFIG_FILE)
|
|
53
53
|
nscfg = next(iter(cfg.nameservers.values()))
|