ophyd-async 0.1.0__py3-none-any.whl → 0.3a1__py3-none-any.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.
- ophyd_async/_version.py +2 -2
- ophyd_async/core/__init__.py +47 -12
- ophyd_async/core/_providers.py +66 -0
- ophyd_async/core/async_status.py +7 -5
- ophyd_async/core/detector.py +321 -0
- ophyd_async/core/device.py +184 -0
- ophyd_async/core/device_save_loader.py +286 -0
- ophyd_async/core/flyer.py +94 -0
- ophyd_async/core/{_device/_signal/signal.py → signal.py} +46 -18
- ophyd_async/core/{_device/_backend/signal_backend.py → signal_backend.py} +6 -2
- ophyd_async/core/{_device/_backend/sim_signal_backend.py → sim_signal_backend.py} +6 -2
- ophyd_async/core/{_device/standard_readable.py → standard_readable.py} +3 -3
- ophyd_async/core/utils.py +79 -29
- ophyd_async/epics/_backend/_aioca.py +38 -25
- ophyd_async/epics/_backend/_p4p.py +62 -27
- ophyd_async/epics/_backend/common.py +20 -0
- ophyd_async/epics/areadetector/__init__.py +10 -13
- ophyd_async/epics/areadetector/controllers/__init__.py +4 -0
- ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +52 -0
- ophyd_async/epics/areadetector/controllers/pilatus_controller.py +49 -0
- ophyd_async/epics/areadetector/drivers/__init__.py +15 -0
- ophyd_async/epics/areadetector/drivers/ad_base.py +111 -0
- ophyd_async/epics/areadetector/drivers/pilatus_driver.py +18 -0
- ophyd_async/epics/areadetector/single_trigger_det.py +4 -4
- ophyd_async/epics/areadetector/utils.py +91 -3
- ophyd_async/epics/areadetector/writers/__init__.py +5 -0
- ophyd_async/epics/areadetector/writers/_hdfdataset.py +10 -0
- ophyd_async/epics/areadetector/writers/_hdffile.py +54 -0
- ophyd_async/epics/areadetector/writers/hdf_writer.py +133 -0
- ophyd_async/epics/areadetector/{nd_file_hdf.py → writers/nd_file_hdf.py} +22 -5
- ophyd_async/epics/areadetector/writers/nd_plugin.py +30 -0
- ophyd_async/epics/demo/__init__.py +3 -2
- ophyd_async/epics/demo/demo_ad_sim_detector.py +35 -0
- ophyd_async/epics/motion/motor.py +2 -1
- ophyd_async/epics/pvi.py +70 -0
- ophyd_async/epics/signal/__init__.py +0 -2
- ophyd_async/epics/signal/signal.py +1 -1
- ophyd_async/panda/__init__.py +12 -8
- ophyd_async/panda/panda.py +43 -134
- ophyd_async/panda/panda_controller.py +41 -0
- ophyd_async/panda/table.py +158 -0
- ophyd_async/panda/utils.py +15 -0
- {ophyd_async-0.1.0.dist-info → ophyd_async-0.3a1.dist-info}/METADATA +49 -42
- ophyd_async-0.3a1.dist-info/RECORD +56 -0
- {ophyd_async-0.1.0.dist-info → ophyd_async-0.3a1.dist-info}/WHEEL +1 -1
- ophyd_async/core/_device/__init__.py +0 -0
- ophyd_async/core/_device/_backend/__init__.py +0 -0
- ophyd_async/core/_device/_signal/__init__.py +0 -0
- ophyd_async/core/_device/device.py +0 -60
- ophyd_async/core/_device/device_collector.py +0 -121
- ophyd_async/core/_device/device_vector.py +0 -14
- ophyd_async/epics/areadetector/ad_driver.py +0 -18
- ophyd_async/epics/areadetector/directory_provider.py +0 -18
- ophyd_async/epics/areadetector/hdf_streamer_det.py +0 -167
- ophyd_async/epics/areadetector/nd_plugin.py +0 -13
- ophyd_async/epics/signal/pvi_get.py +0 -22
- ophyd_async-0.1.0.dist-info/RECORD +0 -45
- {ophyd_async-0.1.0.dist-info → ophyd_async-0.3a1.dist-info}/LICENSE +0 -0
- {ophyd_async-0.1.0.dist-info → ophyd_async-0.3a1.dist-info}/entry_points.txt +0 -0
- {ophyd_async-0.1.0.dist-info → ophyd_async-0.3a1.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3a1
|
|
4
4
|
Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
|
|
5
5
|
Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -45,23 +45,17 @@ Requires-Dist: networkx >=2.0
|
|
|
45
45
|
Requires-Dist: numpy
|
|
46
46
|
Requires-Dist: packaging
|
|
47
47
|
Requires-Dist: pint
|
|
48
|
-
Requires-Dist: bluesky
|
|
48
|
+
Requires-Dist: bluesky >=1.13.0a3
|
|
49
49
|
Requires-Dist: event-model
|
|
50
50
|
Requires-Dist: p4p
|
|
51
|
+
Requires-Dist: pyyaml
|
|
51
52
|
Requires-Dist: typing-extensions ; python_version < "3.8"
|
|
52
53
|
Provides-Extra: ca
|
|
53
54
|
Requires-Dist: aioca >=1.6 ; extra == 'ca'
|
|
54
55
|
Provides-Extra: dev
|
|
55
56
|
Requires-Dist: ophyd-async[pva] ; extra == 'dev'
|
|
56
57
|
Requires-Dist: ophyd-async[ca] ; extra == 'dev'
|
|
57
|
-
Requires-Dist: attrs >=19.3.0 ; extra == 'dev'
|
|
58
58
|
Requires-Dist: black ; extra == 'dev'
|
|
59
|
-
Requires-Dist: bluesky >=1.11.0 ; extra == 'dev'
|
|
60
|
-
Requires-Dist: caproto[standard] >=0.4.2rc1 ; extra == 'dev'
|
|
61
|
-
Requires-Dist: pytest-codecov ; extra == 'dev'
|
|
62
|
-
Requires-Dist: databroker >=1.0.0b1 ; extra == 'dev'
|
|
63
|
-
Requires-Dist: doctr ; extra == 'dev'
|
|
64
|
-
Requires-Dist: epics-pypdb ; extra == 'dev'
|
|
65
59
|
Requires-Dist: flake8 ; extra == 'dev'
|
|
66
60
|
Requires-Dist: flake8-isort ; extra == 'dev'
|
|
67
61
|
Requires-Dist: Flake8-pyproject ; extra == 'dev'
|
|
@@ -74,6 +68,7 @@ Requires-Dist: mypy ; extra == 'dev'
|
|
|
74
68
|
Requires-Dist: myst-parser ; extra == 'dev'
|
|
75
69
|
Requires-Dist: numpydoc ; extra == 'dev'
|
|
76
70
|
Requires-Dist: ophyd ; extra == 'dev'
|
|
71
|
+
Requires-Dist: pickleshare ; extra == 'dev'
|
|
77
72
|
Requires-Dist: pipdeptree ; extra == 'dev'
|
|
78
73
|
Requires-Dist: pre-commit ; extra == 'dev'
|
|
79
74
|
Requires-Dist: pydata-sphinx-theme >=0.12 ; extra == 'dev'
|
|
@@ -90,55 +85,61 @@ Requires-Dist: sphinx-copybutton ; extra == 'dev'
|
|
|
90
85
|
Requires-Dist: sphinx-design ; extra == 'dev'
|
|
91
86
|
Requires-Dist: tox-direct ; extra == 'dev'
|
|
92
87
|
Requires-Dist: types-mock ; extra == 'dev'
|
|
88
|
+
Requires-Dist: types-pyyaml ; extra == 'dev'
|
|
93
89
|
Provides-Extra: pva
|
|
94
90
|
Requires-Dist: p4p ; extra == 'pva'
|
|
95
91
|
|
|
96
|
-
***********
|
|
97
92
|
Ophyd Async
|
|
98
|
-
|
|
93
|
+
===========
|
|
99
94
|
|
|
100
|
-
|
|
|
95
|
+
|code_ci| |docs_ci| |coverage| |pypi_version| |license|
|
|
101
96
|
|
|
102
|
-
|
|
103
|
-
abstraction layer that enables experiment orchestration and data acquisition
|
|
104
|
-
code to operate above the specifics of particular devices and control systems.
|
|
97
|
+
Asynchronous device abstraction framework, building on `Ophyd`_.
|
|
105
98
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
============== ==============================================================
|
|
100
|
+
PyPI ``pip install ophyd-async``
|
|
101
|
+
Source code https://github.com/bluesky/ophyd-async
|
|
102
|
+
Documentation https://blueskyproject.io/ophyd-async
|
|
103
|
+
============== ==============================================================
|
|
109
104
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
Python library for asynchronously interfacing with hardware, intended to
|
|
106
|
+
be used as an abstraction layer that enables experiment orchestration and data
|
|
107
|
+
acquisition code to operate above the specifics of particular devices and control
|
|
108
|
+
systems.
|
|
113
109
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
propagate into metadata.
|
|
120
|
-
* **Categorize** readings by "kind" (primary reading, configuration,
|
|
121
|
-
engineering/debugging) which can be read selectively.
|
|
110
|
+
Both ophyd and ophyd-async are typically used with the `Bluesky Run Engine`_ for
|
|
111
|
+
experiment orchestration and data acquisition. However, these libraries are
|
|
112
|
+
able to be used in a stand-alone fashion. For an example of how a facility defines
|
|
113
|
+
and uses ophyd-async devices, see `dls-dodal`_, which is currently using a
|
|
114
|
+
mixture of ophyd and ophyd-async devices.
|
|
122
115
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
116
|
+
While `EPICS`_ is the most common control system layer that ophyd-async can
|
|
117
|
+
interface with, other control systems like `Tango`_ are used by some facilities
|
|
118
|
+
also. In addition to the abstractions provided by ophyd, ophyd-async allows:
|
|
119
|
+
|
|
120
|
+
* Asynchronous signal access, opening the possibility for hardware-triggered
|
|
121
|
+
scanning (also known as fly-scanning)
|
|
122
|
+
* Simpler instantiation of devices (groupings of signals) with less reliance
|
|
123
|
+
upon complex class hierarchies
|
|
124
|
+
|
|
125
|
+
NOTE: ophyd-async is included on a provisional basis until the v1.0 release.
|
|
129
126
|
|
|
130
127
|
See the tutorials for usage examples.
|
|
131
128
|
|
|
132
|
-
.. |
|
|
133
|
-
:target: https://github.com/bluesky/ophyd/actions
|
|
134
|
-
:alt:
|
|
129
|
+
.. |code_ci| image:: https://github.com/bluesky/ophyd-async/actions/workflows/code.yml/badge.svg?branch=main
|
|
130
|
+
:target: https://github.com/bluesky/ophyd-async/actions/workflows/code.yml
|
|
131
|
+
:alt: Code CI
|
|
132
|
+
|
|
133
|
+
.. |docs_ci| image:: https://github.com/bluesky/ophyd-async/actions/workflows/docs.yml/badge.svg?branch=main
|
|
134
|
+
:target: https://github.com/bluesky/ophyd-async/actions/workflows/docs.yml
|
|
135
|
+
:alt: Docs CI
|
|
135
136
|
|
|
136
|
-
.. |coverage| image:: https://codecov.io/gh/bluesky/ophyd/branch/master/graph/badge.svg
|
|
137
|
-
:target: https://codecov.io/gh/bluesky/ophyd
|
|
137
|
+
.. |coverage| image:: https://codecov.io/gh/bluesky/ophyd-async/branch/master/graph/badge.svg
|
|
138
|
+
:target: https://codecov.io/gh/bluesky/ophyd-async
|
|
138
139
|
:alt: Test Coverage
|
|
139
140
|
|
|
140
|
-
.. |pypi_version| image:: https://img.shields.io/pypi/v/ophyd.svg
|
|
141
|
-
:target: https://pypi.org/project/ophyd
|
|
141
|
+
.. |pypi_version| image:: https://img.shields.io/pypi/v/ophyd-async.svg
|
|
142
|
+
:target: https://pypi.org/project/ophyd-async
|
|
142
143
|
:alt: Latest PyPI version
|
|
143
144
|
|
|
144
145
|
.. |license| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
|
|
@@ -147,8 +148,14 @@ See the tutorials for usage examples.
|
|
|
147
148
|
|
|
148
149
|
.. _Bluesky Run Engine: http://blueskyproject.io/bluesky
|
|
149
150
|
|
|
151
|
+
.. _Ophyd: http://blueskyproject.io/ophyd
|
|
152
|
+
|
|
153
|
+
.. _dls-dodal: https://github.com/DiamondLightSource/dodal
|
|
154
|
+
|
|
150
155
|
.. _EPICS: http://www.aps.anl.gov/epics/
|
|
151
156
|
|
|
157
|
+
.. _Tango: https://www.tango-controls.org/
|
|
158
|
+
|
|
152
159
|
..
|
|
153
160
|
Anything below this line is used when viewing README.rst and will be replaced
|
|
154
161
|
when included in index.rst
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
ophyd_async/__init__.py,sha256=WJoRU7gO-hRzyf7a-C952zF6-7zwPjP7qZ1Qu5GTUC8,124
|
|
2
|
+
ophyd_async/__main__.py,sha256=G-Zcv_G9zK7Nhx6o5L5w-wyhMxdl_WgyMELu8IMFqAE,328
|
|
3
|
+
ophyd_async/_version.py,sha256=nSi77MfFtahju9XLwmhCTVsEygz__it8HHOvmBHSgKI,408
|
|
4
|
+
ophyd_async/core/__init__.py,sha256=Vy0m53wHwRSQ8FVeqzyZ5c6qdWIkkLA4vmEwbdk7iqc,2121
|
|
5
|
+
ophyd_async/core/_providers.py,sha256=HJbXQGocNxGDr5fv13zOkONXN1JqCfqJ3P0pR_sIy1Y,2137
|
|
6
|
+
ophyd_async/core/async_status.py,sha256=-sfIf7VhwAP25kSVwKZjAIYOTROpfnh2jgkDw5_afSU,2801
|
|
7
|
+
ophyd_async/core/detector.py,sha256=-KttT_gPniRB5xalfh5xj2aH5nLV6KoDVLlXaM-d0rw,9989
|
|
8
|
+
ophyd_async/core/device.py,sha256=Ai5FRThlDeXnzKwTuVlmD8RFzlF_cq88Y6xcEiHOTho,5545
|
|
9
|
+
ophyd_async/core/device_save_loader.py,sha256=RXA3dPUPihAR2ZGDStlGiA-TAsr_xqL0snsCjMsMnfA,9138
|
|
10
|
+
ophyd_async/core/flyer.py,sha256=PBfxH9XMYqhFzNFqR2H6U_FxY2L5Un5mUD_3GMDZvdo,2780
|
|
11
|
+
ophyd_async/core/signal.py,sha256=PgoUzcmMaQczoBSlHDA4AmRKoDwoDH9uNmF_5DgJa6k,11800
|
|
12
|
+
ophyd_async/core/signal_backend.py,sha256=hwrDrwJK9rzOW4fsN_T2RFdCHhYwSFkR325i5L0lHE8,1363
|
|
13
|
+
ophyd_async/core/sim_signal_backend.py,sha256=h7if2Oqr4jNOLfQoD_sqJOZd3uyTNHpfn1oJ4apug84,5590
|
|
14
|
+
ophyd_async/core/standard_readable.py,sha256=9cBetIYttAho-7wOB3T1YgSJy0iWEFTAdn9jZkrGvLA,2560
|
|
15
|
+
ophyd_async/core/utils.py,sha256=10cGVTR73oa_05ZVfdNzdTlr3-s1VHxvgtT1PD5LJ8Q,4585
|
|
16
|
+
ophyd_async/epics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
ophyd_async/epics/pvi.py,sha256=BGhAXLyY2Z2e3ujyJ2ObnW19hogGvTZbHZY6Iq_nQeU,2331
|
|
18
|
+
ophyd_async/epics/_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
ophyd_async/epics/_backend/_aioca.py,sha256=0PmpDNohm52461plfrxirLJsyhZXgYIDJv12Y6zfQ0A,8731
|
|
20
|
+
ophyd_async/epics/_backend/_p4p.py,sha256=aikjxQUgBRqNmMNMzOx3-N0rPdn-D1E8P5vQwvmYIgM,11970
|
|
21
|
+
ophyd_async/epics/_backend/common.py,sha256=3zxGLNcBtss6WUGAwfAjxWnUF4YbFbYvpOUmoFJaG5Y,753
|
|
22
|
+
ophyd_async/epics/areadetector/__init__.py,sha256=oEOzL7gEVVSULeT2WkFrva8lUKeX0zmQD0tmwFz6L24,325
|
|
23
|
+
ophyd_async/epics/areadetector/single_trigger_det.py,sha256=q5mG-OUVagIjvXLb28lsrGj4eUSoH2pNW2rT4rQR8fA,1206
|
|
24
|
+
ophyd_async/epics/areadetector/utils.py,sha256=dez54oElIkGMnhSM9qghToUB1opSqjdWTV2vhHCgRMA,3133
|
|
25
|
+
ophyd_async/epics/areadetector/controllers/__init__.py,sha256=UG2-M5d2ykp2T8isQJCbAsGZF1aH0BtC_OPlzzPTjnA,149
|
|
26
|
+
ophyd_async/epics/areadetector/controllers/ad_sim_controller.py,sha256=mthZ6WxajMEgUKptq3bnkIctbLhjzTagV66i1auB8cg,1587
|
|
27
|
+
ophyd_async/epics/areadetector/controllers/pilatus_controller.py,sha256=TSWry-eWfDl4LqafMH75aVqYTrsdmSEbBzCLDUcR2aY,1552
|
|
28
|
+
ophyd_async/epics/areadetector/drivers/__init__.py,sha256=AOpIEYfoBhG9Nc4-SId99v4PpyEh4_RBXfNaqiXlwUI,315
|
|
29
|
+
ophyd_async/epics/areadetector/drivers/ad_base.py,sha256=ikfyNcZwJa5ah52DckjrBzkMMT_eDY1smM4XWfb6A6E,3689
|
|
30
|
+
ophyd_async/epics/areadetector/drivers/pilatus_driver.py,sha256=cn5WNz913UOnOttw2bssjV2Bo3p9SuJma3ckRyCdvw8,442
|
|
31
|
+
ophyd_async/epics/areadetector/writers/__init__.py,sha256=tpPcrYd1hs8WS7C0gmCnR2EBwjE5RzCljI7WwZ2V_LM,191
|
|
32
|
+
ophyd_async/epics/areadetector/writers/_hdfdataset.py,sha256=E0C9VgsPyY35h7k0mvcIhjsIVNavApLxizqNWlM388w,167
|
|
33
|
+
ophyd_async/epics/areadetector/writers/_hdffile.py,sha256=Zh7nWzK9-q0ASCi88tLAFUuWRL_rbz8XTNzKXwRmi88,1797
|
|
34
|
+
ophyd_async/epics/areadetector/writers/hdf_writer.py,sha256=lJHP1CzpXYH82GcgEA-D4qI27Uj1_W8pAVgexFSXmgk,5011
|
|
35
|
+
ophyd_async/epics/areadetector/writers/nd_file_hdf.py,sha256=rutCstILCGGwhP5pH_2lWM2QUcZ88-uxx5dTZIJUMWQ,1562
|
|
36
|
+
ophyd_async/epics/areadetector/writers/nd_plugin.py,sha256=l0yBBEazviyFsWJv_4_sfGn_YM_Iyd0_SlMdAmUlXDU,871
|
|
37
|
+
ophyd_async/epics/demo/__init__.py,sha256=DbVO4ufJWjQnZteilW8SBs5A8DN-Xajn0YibM0q8UkE,5500
|
|
38
|
+
ophyd_async/epics/demo/demo_ad_sim_detector.py,sha256=06y65yvaqXvL2rDocjYyLz9kTVzuwV-LeuPhEfExdOA,944
|
|
39
|
+
ophyd_async/epics/demo/mover.db,sha256=RFz0rxZue689Wh1sWTZwWeFMUrH04ttPq2u5xJH_Fp4,998
|
|
40
|
+
ophyd_async/epics/demo/sensor.db,sha256=AVtiydrdtwAz2EFurO2Ult9SSRtre3r0akOBbL98LT0,554
|
|
41
|
+
ophyd_async/epics/motion/__init__.py,sha256=tnmVRIwKa9PdN_xonJdAUD04UpEceh-hoD7XI62yDB0,46
|
|
42
|
+
ophyd_async/epics/motion/motor.py,sha256=lQcA3PSPxA6XOnk8y5VuJGnKTq2VjkcO6ldCrssGr3M,3392
|
|
43
|
+
ophyd_async/epics/signal/__init__.py,sha256=wb93RTqvSbGKVFQj8OHykbVLGLmwKHU72oi5xYu2UaY,188
|
|
44
|
+
ophyd_async/epics/signal/_epics_transport.py,sha256=DEIL0iYUAWssysVEgWGu1fHSM1l-ATV2kjUgPtDN9LY,858
|
|
45
|
+
ophyd_async/epics/signal/signal.py,sha256=7GnGa4CgFgTwyHeh4wYOJ2GEWwdXsC6vHD3z9LsaHaM,2543
|
|
46
|
+
ophyd_async/panda/__init__.py,sha256=rVM7PdHnON5h0Hcpz_49N5bVfcNmSH5V6ApdaGcBSno,533
|
|
47
|
+
ophyd_async/panda/panda.py,sha256=f_bEYUn7HwMCfVsZxPJ43e4Mo9FQrluHh7_vOHErwYE,8335
|
|
48
|
+
ophyd_async/panda/panda_controller.py,sha256=CK9TTXAGXne31C3HZfBo_grk9pIM1y9Lyo0lms37dLY,1236
|
|
49
|
+
ophyd_async/panda/table.py,sha256=dLoRP4zYNOkD_s0Vkp2wVYAwkjVG8nNdf8-FaXOTfPo,5655
|
|
50
|
+
ophyd_async/panda/utils.py,sha256=VHW5kPVISyEkmse_qQcyisBkkEwMO6GG2Ago-CH1AFA,487
|
|
51
|
+
ophyd_async-0.3a1.dist-info/LICENSE,sha256=pU5shZcsvWgz701EbT7yjFZ8rMvZcWgRH54CRt8ld_c,1517
|
|
52
|
+
ophyd_async-0.3a1.dist-info/METADATA,sha256=Ypyn4I7_5JESeLA3lNZUyld4MB3vNrWGw_bpTnYvq0g,7208
|
|
53
|
+
ophyd_async-0.3a1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
54
|
+
ophyd_async-0.3a1.dist-info/entry_points.txt,sha256=O0YNJTEufO0w9BozXi-JurTy2U1_o0ypeCgJLQ727Jk,58
|
|
55
|
+
ophyd_async-0.3a1.dist-info/top_level.txt,sha256=-hjorMsv5Rmjo3qrgqhjpal1N6kW5vMxZO3lD4iEaXs,12
|
|
56
|
+
ophyd_async-0.3a1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"""Base device"""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
from typing import Iterator, Optional, Tuple
|
|
5
|
-
|
|
6
|
-
from bluesky.protocols import HasName
|
|
7
|
-
|
|
8
|
-
from ..utils import wait_for_connection
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Device(HasName):
|
|
12
|
-
"""Common base class for all Ophyd Async Devices.
|
|
13
|
-
|
|
14
|
-
By default, names and connects all Device children.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
_name: str = ""
|
|
18
|
-
#: The parent Device if it exists
|
|
19
|
-
parent: Optional[Device] = None
|
|
20
|
-
|
|
21
|
-
def __init__(self, name: str = "") -> None:
|
|
22
|
-
self.set_name(name)
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def name(self) -> str:
|
|
26
|
-
"""Return the name of the Device"""
|
|
27
|
-
return self._name
|
|
28
|
-
|
|
29
|
-
def children(self) -> Iterator[Tuple[str, Device]]:
|
|
30
|
-
for attr_name, attr in self.__dict__.items():
|
|
31
|
-
if attr_name != "parent" and isinstance(attr, Device):
|
|
32
|
-
yield attr_name, attr
|
|
33
|
-
|
|
34
|
-
def set_name(self, name: str):
|
|
35
|
-
"""Set ``self.name=name`` and each ``self.child.name=name+"-child"``.
|
|
36
|
-
|
|
37
|
-
Parameters
|
|
38
|
-
----------
|
|
39
|
-
name:
|
|
40
|
-
New name to set
|
|
41
|
-
"""
|
|
42
|
-
self._name = name
|
|
43
|
-
for attr_name, child in self.children():
|
|
44
|
-
child_name = f"{name}-{attr_name.rstrip('_')}" if name else ""
|
|
45
|
-
child.set_name(child_name)
|
|
46
|
-
child.parent = self
|
|
47
|
-
|
|
48
|
-
async def connect(self, sim: bool = False):
|
|
49
|
-
"""Connect self and all child Devices.
|
|
50
|
-
|
|
51
|
-
Parameters
|
|
52
|
-
----------
|
|
53
|
-
sim:
|
|
54
|
-
If True then connect in simulation mode.
|
|
55
|
-
"""
|
|
56
|
-
coros = {
|
|
57
|
-
name: child_device.connect(sim) for name, child_device in self.children()
|
|
58
|
-
}
|
|
59
|
-
if coros:
|
|
60
|
-
await wait_for_connection(**coros)
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"""Interface for connecting and naming multiple devices"""
|
|
2
|
-
import asyncio
|
|
3
|
-
import logging
|
|
4
|
-
import sys
|
|
5
|
-
from contextlib import suppress
|
|
6
|
-
from typing import Any, Dict, Set
|
|
7
|
-
|
|
8
|
-
from bluesky.run_engine import call_in_bluesky_event_loop
|
|
9
|
-
|
|
10
|
-
from ..utils import NotConnected
|
|
11
|
-
from .device import Device
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class DeviceCollector:
|
|
15
|
-
"""Collector of top level Device instances to be used as a context manager
|
|
16
|
-
|
|
17
|
-
Parameters
|
|
18
|
-
----------
|
|
19
|
-
set_name:
|
|
20
|
-
If True, call ``device.set_name(variable_name)`` on all collected
|
|
21
|
-
Devices
|
|
22
|
-
connect:
|
|
23
|
-
If True, call ``device.connect(sim)`` in parallel on all
|
|
24
|
-
collected Devices
|
|
25
|
-
sim:
|
|
26
|
-
If True, connect Signals in simulation mode
|
|
27
|
-
timeout:
|
|
28
|
-
How long to wait for connect before logging an exception
|
|
29
|
-
|
|
30
|
-
Notes
|
|
31
|
-
-----
|
|
32
|
-
Example usage::
|
|
33
|
-
|
|
34
|
-
[async] with DeviceCollector():
|
|
35
|
-
t1x = motor.Motor("BLxxI-MO-TABLE-01:X")
|
|
36
|
-
t1y = motor.Motor("pva://BLxxI-MO-TABLE-01:Y")
|
|
37
|
-
# Names and connects devices here
|
|
38
|
-
assert t1x.comm.velocity.source
|
|
39
|
-
assert t1x.name == "t1x"
|
|
40
|
-
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def __init__(
|
|
44
|
-
self,
|
|
45
|
-
set_name=True,
|
|
46
|
-
connect=True,
|
|
47
|
-
sim=False,
|
|
48
|
-
timeout: float = 10.0,
|
|
49
|
-
):
|
|
50
|
-
self._set_name = set_name
|
|
51
|
-
self._connect = connect
|
|
52
|
-
self._sim = sim
|
|
53
|
-
self._timeout = timeout
|
|
54
|
-
self._names_on_enter: Set[str] = set()
|
|
55
|
-
self._objects_on_exit: Dict[str, Any] = {}
|
|
56
|
-
|
|
57
|
-
def _caller_locals(self):
|
|
58
|
-
"""Walk up until we find a stack frame that doesn't have us as self"""
|
|
59
|
-
try:
|
|
60
|
-
raise ValueError
|
|
61
|
-
except ValueError:
|
|
62
|
-
_, _, tb = sys.exc_info()
|
|
63
|
-
assert tb, "Can't get traceback, this shouldn't happen"
|
|
64
|
-
caller_frame = tb.tb_frame
|
|
65
|
-
while caller_frame.f_locals.get("self", None) is self:
|
|
66
|
-
caller_frame = caller_frame.f_back
|
|
67
|
-
return caller_frame.f_locals
|
|
68
|
-
|
|
69
|
-
def __enter__(self) -> "DeviceCollector":
|
|
70
|
-
# Stash the names that were defined before we were called
|
|
71
|
-
self._names_on_enter = set(self._caller_locals())
|
|
72
|
-
return self
|
|
73
|
-
|
|
74
|
-
async def __aenter__(self) -> "DeviceCollector":
|
|
75
|
-
return self.__enter__()
|
|
76
|
-
|
|
77
|
-
async def _on_exit(self) -> None:
|
|
78
|
-
# Name and kick off connect for devices
|
|
79
|
-
tasks: Dict[asyncio.Task, str] = {}
|
|
80
|
-
for name, obj in self._objects_on_exit.items():
|
|
81
|
-
if name not in self._names_on_enter and isinstance(obj, Device):
|
|
82
|
-
if self._set_name and not obj.name:
|
|
83
|
-
obj.set_name(name)
|
|
84
|
-
if self._connect:
|
|
85
|
-
task = asyncio.create_task(obj.connect(self._sim))
|
|
86
|
-
tasks[task] = name
|
|
87
|
-
# Wait for all the signals to have finished
|
|
88
|
-
if tasks:
|
|
89
|
-
await self._wait_for_tasks(tasks)
|
|
90
|
-
|
|
91
|
-
async def _wait_for_tasks(self, tasks: Dict[asyncio.Task, str]):
|
|
92
|
-
done, pending = await asyncio.wait(tasks, timeout=self._timeout)
|
|
93
|
-
if pending:
|
|
94
|
-
msg = f"{len(pending)} Devices did not connect:"
|
|
95
|
-
for t in pending:
|
|
96
|
-
t.cancel()
|
|
97
|
-
with suppress(Exception):
|
|
98
|
-
await t
|
|
99
|
-
e = t.exception()
|
|
100
|
-
msg += f"\n {tasks[t]}: {type(e).__name__}"
|
|
101
|
-
lines = str(e).splitlines()
|
|
102
|
-
if len(lines) <= 1:
|
|
103
|
-
msg += f": {e}"
|
|
104
|
-
else:
|
|
105
|
-
msg += "".join(f"\n {line}" for line in lines)
|
|
106
|
-
logging.error(msg)
|
|
107
|
-
raised = [t for t in done if t.exception()]
|
|
108
|
-
if raised:
|
|
109
|
-
logging.error(f"{len(raised)} Devices raised an error:")
|
|
110
|
-
for t in raised:
|
|
111
|
-
logging.exception(f" {tasks[t]}:", exc_info=t.exception())
|
|
112
|
-
if pending or raised:
|
|
113
|
-
raise NotConnected("Not all Devices connected")
|
|
114
|
-
|
|
115
|
-
async def __aexit__(self, type, value, traceback):
|
|
116
|
-
self._objects_on_exit = self._caller_locals()
|
|
117
|
-
await self._on_exit()
|
|
118
|
-
|
|
119
|
-
def __exit__(self, type_, value, traceback):
|
|
120
|
-
self._objects_on_exit = self._caller_locals()
|
|
121
|
-
return call_in_bluesky_event_loop(self._on_exit())
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"""Dictionary which can contain mappings between integers and devices."""
|
|
2
|
-
|
|
3
|
-
from typing import Dict, Generator, Tuple, TypeVar
|
|
4
|
-
|
|
5
|
-
from .device import Device
|
|
6
|
-
|
|
7
|
-
VT = TypeVar("VT", bound=Device)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class DeviceVector(Dict[int, VT], Device):
|
|
11
|
-
def children(self) -> Generator[Tuple[str, Device], None, None]:
|
|
12
|
-
for attr_name, attr in self.items():
|
|
13
|
-
if isinstance(attr, Device):
|
|
14
|
-
yield str(attr_name), attr
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from ophyd_async.core import Device
|
|
2
|
-
|
|
3
|
-
from ..signal.signal import epics_signal_rw
|
|
4
|
-
from .utils import ImageMode, ad_r, ad_rw
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ADDriver(Device):
|
|
8
|
-
def __init__(self, prefix: str) -> None:
|
|
9
|
-
# Define some signals
|
|
10
|
-
self.acquire = ad_rw(bool, prefix + "Acquire")
|
|
11
|
-
self.acquire_time = ad_rw(float, prefix + "AcquireTime")
|
|
12
|
-
self.num_images = ad_rw(int, prefix + "NumImages")
|
|
13
|
-
self.image_mode = ad_rw(ImageMode, prefix + "ImageMode")
|
|
14
|
-
self.array_counter = ad_rw(int, prefix + "ArrayCounter")
|
|
15
|
-
self.array_size_x = ad_r(int, prefix + "ArraySizeX")
|
|
16
|
-
self.array_size_y = ad_r(int, prefix + "ArraySizeY")
|
|
17
|
-
# There is no _RBV for this one
|
|
18
|
-
self.wait_for_plugins = epics_signal_rw(bool, prefix + "WaitForPlugins")
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import tempfile
|
|
2
|
-
from abc import abstractmethod
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Protocol
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class DirectoryProvider(Protocol):
|
|
8
|
-
@abstractmethod
|
|
9
|
-
async def get_directory(self) -> Path:
|
|
10
|
-
...
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TmpDirectoryProvider(DirectoryProvider):
|
|
14
|
-
def __init__(self) -> None:
|
|
15
|
-
self._directory = Path(tempfile.mkdtemp())
|
|
16
|
-
|
|
17
|
-
async def get_directory(self) -> Path:
|
|
18
|
-
return self._directory
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import collections
|
|
3
|
-
import time
|
|
4
|
-
from typing import Callable, Dict, Iterator, Optional, Sized
|
|
5
|
-
|
|
6
|
-
from bluesky.protocols import (
|
|
7
|
-
Asset,
|
|
8
|
-
Descriptor,
|
|
9
|
-
Flyable,
|
|
10
|
-
PartialEvent,
|
|
11
|
-
WritesExternalAssets,
|
|
12
|
-
)
|
|
13
|
-
from bluesky.utils import new_uid
|
|
14
|
-
from event_model import compose_stream_resource
|
|
15
|
-
|
|
16
|
-
from ophyd_async.core import (
|
|
17
|
-
DEFAULT_TIMEOUT,
|
|
18
|
-
AsyncStatus,
|
|
19
|
-
StandardReadable,
|
|
20
|
-
set_and_wait_for_value,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from .ad_driver import ADDriver
|
|
24
|
-
from .directory_provider import DirectoryProvider
|
|
25
|
-
from .nd_file_hdf import NDFileHDF
|
|
26
|
-
from .utils import FileWriteMode, ImageMode
|
|
27
|
-
|
|
28
|
-
# How long in seconds to wait between flushes of HDF datasets
|
|
29
|
-
FLUSH_PERIOD = 0.5
|
|
30
|
-
|
|
31
|
-
# How long to wait for new frames before timing out
|
|
32
|
-
FRAME_TIMEOUT = 120
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class _HDFResource:
|
|
36
|
-
def __init__(self) -> None:
|
|
37
|
-
# TODO: set to Deque[Asset] after protocols updated for stream*
|
|
38
|
-
# https://github.com/bluesky/bluesky/issues/1558
|
|
39
|
-
self.asset_docs = collections.deque() # type: ignore
|
|
40
|
-
self._last_emitted = 0
|
|
41
|
-
self._last_flush = time.monotonic()
|
|
42
|
-
self._compose_datum: Optional[Callable] = None
|
|
43
|
-
|
|
44
|
-
def _append_resource(self, full_file_name: str):
|
|
45
|
-
resource_doc, (self._compose_datum,) = compose_stream_resource(
|
|
46
|
-
spec="AD_HDF5_SWMR_SLICE",
|
|
47
|
-
root="/",
|
|
48
|
-
resource_path=full_file_name,
|
|
49
|
-
resource_kwargs={},
|
|
50
|
-
stream_names=["primary"],
|
|
51
|
-
)
|
|
52
|
-
self.asset_docs.append(("stream_resource", resource_doc))
|
|
53
|
-
|
|
54
|
-
def _append_datum(self, event_count: int):
|
|
55
|
-
assert self._compose_datum, "Resource not emitted yet"
|
|
56
|
-
datum_doc = self._compose_datum(
|
|
57
|
-
datum_kwargs={},
|
|
58
|
-
event_offset=self._last_emitted,
|
|
59
|
-
event_count=event_count,
|
|
60
|
-
)
|
|
61
|
-
self._last_emitted += event_count
|
|
62
|
-
self.asset_docs.append(("stream_datum", datum_doc))
|
|
63
|
-
|
|
64
|
-
async def flush_and_publish(self, hdf: NDFileHDF):
|
|
65
|
-
num_captured = await hdf.num_captured.get_value()
|
|
66
|
-
if num_captured:
|
|
67
|
-
if self._compose_datum is None:
|
|
68
|
-
self._append_resource(await hdf.full_file_name.get_value())
|
|
69
|
-
event_count = num_captured - self._last_emitted
|
|
70
|
-
if event_count:
|
|
71
|
-
self._append_datum(event_count)
|
|
72
|
-
await hdf.flush_now.set(True)
|
|
73
|
-
self._last_flush = time.monotonic()
|
|
74
|
-
if time.monotonic() - self._last_flush > FRAME_TIMEOUT:
|
|
75
|
-
raise TimeoutError(f"{hdf.name}: writing stalled on frame {num_captured}")
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
class HDFStreamerDet(StandardReadable, Flyable, WritesExternalAssets):
|
|
79
|
-
def __init__(
|
|
80
|
-
self, drv: ADDriver, hdf: NDFileHDF, dp: DirectoryProvider, name=""
|
|
81
|
-
) -> None:
|
|
82
|
-
self.drv = drv
|
|
83
|
-
self.hdf = hdf
|
|
84
|
-
self._dp = dp
|
|
85
|
-
self._resource = _HDFResource()
|
|
86
|
-
self._capture_status: Optional[AsyncStatus] = None
|
|
87
|
-
self._start_status: Optional[AsyncStatus] = None
|
|
88
|
-
self.set_readable_signals(config=[self.drv.acquire_time])
|
|
89
|
-
super().__init__(name)
|
|
90
|
-
|
|
91
|
-
@AsyncStatus.wrap
|
|
92
|
-
async def stage(self) -> None:
|
|
93
|
-
# Make a new resource for the new HDF file we're going to open
|
|
94
|
-
self._resource = _HDFResource()
|
|
95
|
-
await asyncio.gather(
|
|
96
|
-
self.drv.wait_for_plugins.set(True),
|
|
97
|
-
self.hdf.lazy_open.set(True),
|
|
98
|
-
self.hdf.swmr_mode.set(True),
|
|
99
|
-
self.hdf.file_path.set(str(await self._dp.get_directory())),
|
|
100
|
-
self.hdf.file_name.set(f"{self.name}-{new_uid()}"),
|
|
101
|
-
self.hdf.file_template.set("%s/%s.h5"),
|
|
102
|
-
# Go forever
|
|
103
|
-
self.hdf.num_capture.set(0),
|
|
104
|
-
self.hdf.file_write_mode.set(FileWriteMode.stream),
|
|
105
|
-
)
|
|
106
|
-
# Wait for it to start, stashing the status that tells us when it finishes
|
|
107
|
-
self._capture_status = await set_and_wait_for_value(self.hdf.capture, True)
|
|
108
|
-
await super().stage()
|
|
109
|
-
|
|
110
|
-
async def describe(self) -> Dict[str, Descriptor]:
|
|
111
|
-
datakeys = await super().describe()
|
|
112
|
-
# Insert a descriptor for the HDF resource, this will not appear
|
|
113
|
-
# in read() as it describes StreamResource outputs only
|
|
114
|
-
datakeys[self.name] = Descriptor(
|
|
115
|
-
source=self.hdf.full_file_name.source,
|
|
116
|
-
shape=await asyncio.gather(
|
|
117
|
-
self.drv.array_size_y.get_value(),
|
|
118
|
-
self.drv.array_size_x.get_value(),
|
|
119
|
-
),
|
|
120
|
-
dtype="array",
|
|
121
|
-
external="STREAM:",
|
|
122
|
-
)
|
|
123
|
-
return datakeys
|
|
124
|
-
|
|
125
|
-
# For step scan, take a single frame
|
|
126
|
-
@AsyncStatus.wrap
|
|
127
|
-
async def trigger(self):
|
|
128
|
-
await self.drv.image_mode.set(ImageMode.single)
|
|
129
|
-
frame_timeout = DEFAULT_TIMEOUT + await self.drv.acquire_time.get_value()
|
|
130
|
-
await self.drv.acquire.set(1, timeout=frame_timeout)
|
|
131
|
-
await self._resource.flush_and_publish(self.hdf)
|
|
132
|
-
|
|
133
|
-
def collect_asset_docs(self) -> Iterator[Asset]:
|
|
134
|
-
while self._resource.asset_docs:
|
|
135
|
-
yield self._resource.asset_docs.popleft()
|
|
136
|
-
|
|
137
|
-
# For flyscan, take the number of frames we wanted
|
|
138
|
-
@AsyncStatus.wrap
|
|
139
|
-
async def kickoff(self) -> None:
|
|
140
|
-
await self.drv.image_mode.set(ImageMode.multiple)
|
|
141
|
-
# Wait for it to start, stashing the status that tells us when it finishes
|
|
142
|
-
self._start_status = await set_and_wait_for_value(self.drv.acquire, True)
|
|
143
|
-
|
|
144
|
-
# Do the same thing for flyscans and step scans
|
|
145
|
-
async def describe_collect(self) -> Dict[str, Dict[str, Descriptor]]:
|
|
146
|
-
return {self.name: await self.describe()}
|
|
147
|
-
|
|
148
|
-
def collect(self) -> Iterator[PartialEvent]:
|
|
149
|
-
yield from iter([])
|
|
150
|
-
|
|
151
|
-
@AsyncStatus.wrap
|
|
152
|
-
async def complete(self) -> None:
|
|
153
|
-
done: Sized = ()
|
|
154
|
-
while not done:
|
|
155
|
-
assert self._start_status, "Kickoff not run"
|
|
156
|
-
done, _ = await asyncio.wait(
|
|
157
|
-
(self._start_status.task,), timeout=FLUSH_PERIOD
|
|
158
|
-
)
|
|
159
|
-
await self._resource.flush_and_publish(self.hdf)
|
|
160
|
-
|
|
161
|
-
@AsyncStatus.wrap
|
|
162
|
-
async def unstage(self) -> None:
|
|
163
|
-
# Already done a caput callback in _capture_status, so can't do one here
|
|
164
|
-
await self.hdf.capture.set(False, wait=False)
|
|
165
|
-
assert self._capture_status, "Stage not run"
|
|
166
|
-
await self._capture_status
|
|
167
|
-
await super().unstage()
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from ophyd_async.core import Device
|
|
2
|
-
|
|
3
|
-
from .utils import ad_r
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class NDPlugin(Device):
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class NDPluginStats(NDPlugin):
|
|
11
|
-
def __init__(self, prefix: str) -> None:
|
|
12
|
-
# Define some signals
|
|
13
|
-
self.unique_id = ad_r(int, prefix + "UniqueId")
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
from typing import Dict, TypedDict
|
|
2
|
-
|
|
3
|
-
from p4p.client.asyncio import Context
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class PVIEntry(TypedDict, total=False):
|
|
7
|
-
d: str
|
|
8
|
-
r: str
|
|
9
|
-
rw: str
|
|
10
|
-
w: str
|
|
11
|
-
x: str
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
async def pvi_get(pv: str, ctxt: Context, timeout: float = 5.0) -> Dict[str, PVIEntry]:
|
|
15
|
-
pv_info = ctxt.get(pv, timeout=timeout).get("pvi").todict()
|
|
16
|
-
|
|
17
|
-
result = {}
|
|
18
|
-
|
|
19
|
-
for attr_name, attr_info in pv_info.items():
|
|
20
|
-
result[attr_name] = PVIEntry(**attr_info) # type: ignore
|
|
21
|
-
|
|
22
|
-
return result
|