apsbits 1.0.0rc2__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.
- apsbits/__init__.py +18 -0
- apsbits/_version.py +21 -0
- apsbits/core/__init__.py +11 -0
- apsbits/core/best_effort_init.py +38 -0
- apsbits/core/catalog_init.py +29 -0
- apsbits/core/run_engine_init.py +71 -0
- apsbits/demo_instrument/README.md +1 -0
- apsbits/demo_instrument/__init__.py +3 -0
- apsbits/demo_instrument/callbacks/__init__.py +1 -0
- apsbits/demo_instrument/callbacks/nexus_data_file_writer.py +60 -0
- apsbits/demo_instrument/callbacks/spec_data_file_writer.py +93 -0
- apsbits/demo_instrument/configs/__init__.py +1 -0
- apsbits/demo_instrument/configs/devices.yml +52 -0
- apsbits/demo_instrument/configs/devices_aps_only.yml +6 -0
- apsbits/demo_instrument/configs/iconfig.yml +81 -0
- apsbits/demo_instrument/configs/logging.yml +41 -0
- apsbits/demo_instrument/devices/__init__.py +1 -0
- apsbits/demo_instrument/plans/__init__.py +8 -0
- apsbits/demo_instrument/plans/dm_plans.py +111 -0
- apsbits/demo_instrument/plans/sim_plans.py +69 -0
- apsbits/demo_instrument/startup.py +63 -0
- apsbits/tests/__init__.py +1 -0
- apsbits/tests/conftest.py +32 -0
- apsbits/tests/test_device_factories.py +44 -0
- apsbits/tests/test_general.py +83 -0
- apsbits/tests/test_stored_dict.py +139 -0
- apsbits/utils/__init__.py +1 -0
- apsbits/utils/aps_functions.py +67 -0
- apsbits/utils/config_loaders.py +61 -0
- apsbits/utils/context_aware.py +187 -0
- apsbits/utils/controls_setup.py +113 -0
- apsbits/utils/create_new_instrument.py +144 -0
- apsbits/utils/helper_functions.py +113 -0
- apsbits/utils/logging_setup.py +211 -0
- apsbits/utils/make_devices_yaml.py +127 -0
- apsbits/utils/metadata.py +101 -0
- apsbits/utils/sim_creator.py +199 -0
- apsbits/utils/stored_dict.py +192 -0
- apsbits-1.0.0rc2.dist-info/LICENSE +48 -0
- apsbits-1.0.0rc2.dist-info/METADATA +349 -0
- apsbits-1.0.0rc2.dist-info/RECORD +44 -0
- apsbits-1.0.0rc2.dist-info/WHEEL +5 -0
- apsbits-1.0.0rc2.dist-info/entry_points.txt +2 -0
- apsbits-1.0.0rc2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Storage-backed Dictionary
|
|
3
|
+
=========================
|
|
4
|
+
|
|
5
|
+
A dictionary that writes its contents to YAML file.
|
|
6
|
+
|
|
7
|
+
Replaces ``bluesky.utils.PersistentDict``.
|
|
8
|
+
|
|
9
|
+
* Contents must be JSON serializable.
|
|
10
|
+
* Contents stored in a single human-readable YAML file.
|
|
11
|
+
* Sync to disk shortly after dictionary is updated.
|
|
12
|
+
|
|
13
|
+
.. autosummary::
|
|
14
|
+
|
|
15
|
+
~StoredDict
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
__all__ = ["StoredDict"]
|
|
19
|
+
|
|
20
|
+
import collections.abc
|
|
21
|
+
import datetime
|
|
22
|
+
import inspect
|
|
23
|
+
import json
|
|
24
|
+
import logging
|
|
25
|
+
import pathlib
|
|
26
|
+
import threading
|
|
27
|
+
import time
|
|
28
|
+
|
|
29
|
+
import yaml
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
logger.bsdev(__file__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StoredDict(collections.abc.MutableMapping):
|
|
36
|
+
"""
|
|
37
|
+
Dictionary that syncs to storage.
|
|
38
|
+
|
|
39
|
+
.. autosummary::
|
|
40
|
+
|
|
41
|
+
~flush
|
|
42
|
+
~popitem
|
|
43
|
+
~reload
|
|
44
|
+
|
|
45
|
+
.. rubric:: Static methods
|
|
46
|
+
|
|
47
|
+
All support for the YAML format is implemented in the static methods.
|
|
48
|
+
|
|
49
|
+
.. autosummary::
|
|
50
|
+
|
|
51
|
+
~dump
|
|
52
|
+
~load
|
|
53
|
+
|
|
54
|
+
----
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, file, delay=5, title=None, serializable=True):
|
|
58
|
+
"""
|
|
59
|
+
StoredDict : Dictionary that syncs to storage
|
|
60
|
+
|
|
61
|
+
PARAMETERS
|
|
62
|
+
|
|
63
|
+
file : str or pathlib.Path
|
|
64
|
+
Name of file to store dictionary contents.
|
|
65
|
+
delay : number
|
|
66
|
+
Time delay (s) since last dictionary update to write to storage.
|
|
67
|
+
Default: 5 seconds.
|
|
68
|
+
title : str or None
|
|
69
|
+
Comment to write at top of file.
|
|
70
|
+
Default: "Written by StoredDict."
|
|
71
|
+
serializable : bool
|
|
72
|
+
If True, validate new dictionary entries are JSON serializable.
|
|
73
|
+
"""
|
|
74
|
+
self._file = pathlib.Path(file)
|
|
75
|
+
self._delay = max(0, delay)
|
|
76
|
+
self._title = title or f"Written by {self.__class__.__name__}."
|
|
77
|
+
self.test_serializable = serializable
|
|
78
|
+
|
|
79
|
+
self.sync_in_progress = False
|
|
80
|
+
self._sync_deadline = time.time()
|
|
81
|
+
self._sync_key = f"sync_agent_{id(self):x}"
|
|
82
|
+
self._sync_loop_period = 0.005
|
|
83
|
+
|
|
84
|
+
self._cache = {}
|
|
85
|
+
self.reload()
|
|
86
|
+
|
|
87
|
+
def __delitem__(self, key):
|
|
88
|
+
"""Delete dictionary value by key."""
|
|
89
|
+
del self._cache[key]
|
|
90
|
+
|
|
91
|
+
def __getitem__(self, key):
|
|
92
|
+
"""Get dictionary value by key."""
|
|
93
|
+
return self._cache[key]
|
|
94
|
+
|
|
95
|
+
def __iter__(self):
|
|
96
|
+
"""Iterate over the dictionary keys."""
|
|
97
|
+
yield from self._cache
|
|
98
|
+
|
|
99
|
+
def __len__(self):
|
|
100
|
+
"""Number of keys in the dictionary."""
|
|
101
|
+
return len(self._cache)
|
|
102
|
+
|
|
103
|
+
def __repr__(self):
|
|
104
|
+
"""representation of this object."""
|
|
105
|
+
return f"<{self.__class__.__name__} {dict(self)!r}>"
|
|
106
|
+
|
|
107
|
+
def __setitem__(self, key, value):
|
|
108
|
+
"""Write to the dictionary."""
|
|
109
|
+
outermost_frame = inspect.getouterframes(inspect.currentframe())[-1]
|
|
110
|
+
if "sphinx-build" in outermost_frame.filename:
|
|
111
|
+
# Seems that Sphinx is building the documentation.
|
|
112
|
+
# Ignore all the objects it tries to add.
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
if self.test_serializable:
|
|
116
|
+
json.dumps({key: value})
|
|
117
|
+
|
|
118
|
+
self._cache[key] = value # Store the new (or revised) content.
|
|
119
|
+
|
|
120
|
+
# Reset the deadline.
|
|
121
|
+
self._sync_deadline = time.time() + self._delay
|
|
122
|
+
logger.debug("new sync deadline in %f s.", self._delay)
|
|
123
|
+
|
|
124
|
+
if not self.sync_in_progress:
|
|
125
|
+
# Start the sync_agent (thread).
|
|
126
|
+
self._delayed_sync_to_storage()
|
|
127
|
+
|
|
128
|
+
def _delayed_sync_to_storage(self):
|
|
129
|
+
"""
|
|
130
|
+
Sync the metadata to storage.
|
|
131
|
+
|
|
132
|
+
Start a time-delay thread. New writes to the metadata dictionary will
|
|
133
|
+
extend the deadline. Sync once the deadline is reached.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
def sync_agent():
|
|
137
|
+
"""Threaded task."""
|
|
138
|
+
logger.debug("Starting sync_agent...")
|
|
139
|
+
self.sync_in_progress = True
|
|
140
|
+
while time.time() < self._sync_deadline:
|
|
141
|
+
time.sleep(self._sync_loop_period)
|
|
142
|
+
logger.debug("Sync waiting period ended")
|
|
143
|
+
self.sync_in_progress = False
|
|
144
|
+
|
|
145
|
+
StoredDict.dump(self._file, self._cache, title=self._title)
|
|
146
|
+
|
|
147
|
+
thred = threading.Thread(target=sync_agent)
|
|
148
|
+
thred.start()
|
|
149
|
+
|
|
150
|
+
def flush(self):
|
|
151
|
+
"""Force a write of the dictionary to disk"""
|
|
152
|
+
logger.debug("flush()")
|
|
153
|
+
if not self.sync_in_progress:
|
|
154
|
+
StoredDict.dump(self._file, self._cache, title=self._title)
|
|
155
|
+
self._sync_deadline = time.time()
|
|
156
|
+
self.sync_in_progress = False
|
|
157
|
+
|
|
158
|
+
def popitem(self):
|
|
159
|
+
"""
|
|
160
|
+
Remove and return a (key, value) pair as a 2-tuple.
|
|
161
|
+
|
|
162
|
+
Pairs are returned in LIFO (last-in, first-out) order.
|
|
163
|
+
Raises KeyError if the dict is empty.
|
|
164
|
+
"""
|
|
165
|
+
return self._cache.popitem()
|
|
166
|
+
|
|
167
|
+
def reload(self):
|
|
168
|
+
"""Read dictionary from storage."""
|
|
169
|
+
logger.debug("reload()")
|
|
170
|
+
self._cache = StoredDict.load(self._file)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def dump(file, contents, title=None):
|
|
174
|
+
"""Write dictionary to YAML file."""
|
|
175
|
+
logger.debug("_dump(): file='%s', contents=%r, title=%r", file, contents, title)
|
|
176
|
+
with open(file, "w") as f:
|
|
177
|
+
if isinstance(title, str) and len(title) > 0:
|
|
178
|
+
f.write(f"# {title}\n")
|
|
179
|
+
f.write(f"# Dictionary contents written: {datetime.datetime.now()}\n\n")
|
|
180
|
+
f.write(yaml.dump(contents, indent=2))
|
|
181
|
+
|
|
182
|
+
@staticmethod
|
|
183
|
+
def load(file):
|
|
184
|
+
"""Read dictionary from YAML file."""
|
|
185
|
+
from .config_loaders import load_config_yaml
|
|
186
|
+
|
|
187
|
+
file = pathlib.Path(file)
|
|
188
|
+
logger.debug("_load('%s')", file)
|
|
189
|
+
md = None
|
|
190
|
+
if file.exists():
|
|
191
|
+
md = load_config_yaml(file)
|
|
192
|
+
return md or {} # In case file is empty.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Copyright (c) 2023-2025, UChicago Argonne, LLC
|
|
2
|
+
|
|
3
|
+
All Rights Reserved
|
|
4
|
+
|
|
5
|
+
BITS
|
|
6
|
+
|
|
7
|
+
BCDA, Advanced Photon Source, Argonne National Laboratory
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
OPEN SOURCE LICENSE
|
|
11
|
+
|
|
12
|
+
Redistribution and use in source and binary forms, with or without
|
|
13
|
+
modification, are permitted provided that the following conditions are met:
|
|
14
|
+
|
|
15
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
16
|
+
this list of conditions and the following disclaimer. Software changes,
|
|
17
|
+
modifications, or derivative works, should be noted with comments and
|
|
18
|
+
the author and organization's name.
|
|
19
|
+
|
|
20
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
21
|
+
this list of conditions and the following disclaimer in the documentation
|
|
22
|
+
and/or other materials provided with the distribution.
|
|
23
|
+
|
|
24
|
+
3. Neither the names of UChicago Argonne, LLC or the Department of Energy
|
|
25
|
+
nor the names of its contributors may be used to endorse or promote
|
|
26
|
+
products derived from this software without specific prior written
|
|
27
|
+
permission.
|
|
28
|
+
|
|
29
|
+
4. The software and the end-user documentation included with the
|
|
30
|
+
redistribution, if any, must include the following acknowledgment:
|
|
31
|
+
|
|
32
|
+
"This product includes software produced by UChicago Argonne, LLC
|
|
33
|
+
under Contract No. DE-AC02-06CH11357 with the Department of Energy."
|
|
34
|
+
|
|
35
|
+
****************************************************************************
|
|
36
|
+
|
|
37
|
+
DISCLAIMER
|
|
38
|
+
|
|
39
|
+
THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND.
|
|
40
|
+
|
|
41
|
+
Neither the United States GOVERNMENT, nor the United States Department
|
|
42
|
+
of Energy, NOR uchicago argonne, LLC, nor any of their employees, makes
|
|
43
|
+
any warranty, express or implied, or assumes any legal liability or
|
|
44
|
+
responsibility for the accuracy, completeness, or usefulness of any
|
|
45
|
+
information, data, apparatus, product, or process disclosed, or
|
|
46
|
+
represents that its use would not infringe privately owned rights.
|
|
47
|
+
|
|
48
|
+
****************************************************************************
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: apsbits
|
|
3
|
+
Version: 1.0.0rc2
|
|
4
|
+
Summary: Model of a Bluesky Data Acquisition Instrument in console, notebook, & queueserver.
|
|
5
|
+
Author-email: Eric Codrea <ecodrea@anl.gov>, Pete Jemian <prjemian+instrument@gmail.com>, Rafael Vescovi <rvescovi@anl.gov>
|
|
6
|
+
Maintainer-email: Eric Codrea <ecodrea@anl.gov>, Pete Jemian <prjemian+instrument@gmail.com>, Rafael Vescovi <rvescovi@anl.gov>
|
|
7
|
+
License: Copyright (c) 2023-2025, UChicago Argonne, LLC
|
|
8
|
+
|
|
9
|
+
All Rights Reserved
|
|
10
|
+
|
|
11
|
+
BITS
|
|
12
|
+
|
|
13
|
+
BCDA, Advanced Photon Source, Argonne National Laboratory
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
OPEN SOURCE LICENSE
|
|
17
|
+
|
|
18
|
+
Redistribution and use in source and binary forms, with or without
|
|
19
|
+
modification, are permitted provided that the following conditions are met:
|
|
20
|
+
|
|
21
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
22
|
+
this list of conditions and the following disclaimer. Software changes,
|
|
23
|
+
modifications, or derivative works, should be noted with comments and
|
|
24
|
+
the author and organization's name.
|
|
25
|
+
|
|
26
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
27
|
+
this list of conditions and the following disclaimer in the documentation
|
|
28
|
+
and/or other materials provided with the distribution.
|
|
29
|
+
|
|
30
|
+
3. Neither the names of UChicago Argonne, LLC or the Department of Energy
|
|
31
|
+
nor the names of its contributors may be used to endorse or promote
|
|
32
|
+
products derived from this software without specific prior written
|
|
33
|
+
permission.
|
|
34
|
+
|
|
35
|
+
4. The software and the end-user documentation included with the
|
|
36
|
+
redistribution, if any, must include the following acknowledgment:
|
|
37
|
+
|
|
38
|
+
"This product includes software produced by UChicago Argonne, LLC
|
|
39
|
+
under Contract No. DE-AC02-06CH11357 with the Department of Energy."
|
|
40
|
+
|
|
41
|
+
****************************************************************************
|
|
42
|
+
|
|
43
|
+
DISCLAIMER
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND.
|
|
46
|
+
|
|
47
|
+
Neither the United States GOVERNMENT, nor the United States Department
|
|
48
|
+
of Energy, NOR uchicago argonne, LLC, nor any of their employees, makes
|
|
49
|
+
any warranty, express or implied, or assumes any legal liability or
|
|
50
|
+
responsibility for the accuracy, completeness, or usefulness of any
|
|
51
|
+
information, data, apparatus, product, or process disclosed, or
|
|
52
|
+
represents that its use would not infringe privately owned rights.
|
|
53
|
+
|
|
54
|
+
****************************************************************************
|
|
55
|
+
|
|
56
|
+
Project-URL: Homepage, https://BCDA-APS.github.io/APSBITS/
|
|
57
|
+
Project-URL: Bug Tracker, https://github.com/BCDA-APS/APSBITS/issues
|
|
58
|
+
Keywords: bluesky,queueserver
|
|
59
|
+
Classifier: Development Status :: 6 - Mature
|
|
60
|
+
Classifier: Environment :: Console
|
|
61
|
+
Classifier: Intended Audience :: Developers
|
|
62
|
+
Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
63
|
+
Classifier: License :: Freely Distributable
|
|
64
|
+
Classifier: License :: Public Domain
|
|
65
|
+
Classifier: Programming Language :: Python
|
|
66
|
+
Classifier: Programming Language :: Python :: 3
|
|
67
|
+
Classifier: Topic :: Utilities
|
|
68
|
+
Requires-Python: >=3.11
|
|
69
|
+
Description-Content-Type: text/markdown
|
|
70
|
+
License-File: LICENSE
|
|
71
|
+
Requires-Dist: apstools>=1.7.2
|
|
72
|
+
Requires-Dist: bluesky-queueserver-api
|
|
73
|
+
Requires-Dist: bluesky-queueserver
|
|
74
|
+
Requires-Dist: bluesky-widgets
|
|
75
|
+
Requires-Dist: bluesky
|
|
76
|
+
Requires-Dist: caproto
|
|
77
|
+
Requires-Dist: databroker==1.2.5
|
|
78
|
+
Requires-Dist: guarneri
|
|
79
|
+
Requires-Dist: ipython
|
|
80
|
+
Requires-Dist: jupyterlab
|
|
81
|
+
Requires-Dist: ophyd-registry
|
|
82
|
+
Requires-Dist: ophyd
|
|
83
|
+
Requires-Dist: PyQt5>5.15
|
|
84
|
+
Requires-Dist: pyRestTable
|
|
85
|
+
Requires-Dist: pysumreg
|
|
86
|
+
Requires-Dist: qtpy
|
|
87
|
+
Requires-Dist: toml
|
|
88
|
+
Provides-Extra: dev
|
|
89
|
+
Requires-Dist: build; extra == "dev"
|
|
90
|
+
Requires-Dist: isort; extra == "dev"
|
|
91
|
+
Requires-Dist: mypy; extra == "dev"
|
|
92
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
93
|
+
Requires-Dist: pytest; extra == "dev"
|
|
94
|
+
Requires-Dist: ruff; extra == "dev"
|
|
95
|
+
Provides-Extra: doc
|
|
96
|
+
Requires-Dist: babel; extra == "doc"
|
|
97
|
+
Requires-Dist: ipykernel; extra == "doc"
|
|
98
|
+
Requires-Dist: jinja2; extra == "doc"
|
|
99
|
+
Requires-Dist: markupsafe; extra == "doc"
|
|
100
|
+
Requires-Dist: myst_parser; extra == "doc"
|
|
101
|
+
Requires-Dist: nbsphinx; extra == "doc"
|
|
102
|
+
Requires-Dist: pydata-sphinx-theme; extra == "doc"
|
|
103
|
+
Requires-Dist: pygments-ipython-console; extra == "doc"
|
|
104
|
+
Requires-Dist: pygments; extra == "doc"
|
|
105
|
+
Requires-Dist: sphinx-design; extra == "doc"
|
|
106
|
+
Requires-Dist: sphinx-tabs; extra == "doc"
|
|
107
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
108
|
+
Provides-Extra: all
|
|
109
|
+
Requires-Dist: apsbits[dev,doc]; extra == "all"
|
|
110
|
+
|
|
111
|
+
# APSBITS: Template Package for Bluesky Instruments
|
|
112
|
+
|
|
113
|
+
| PyPI | Coverage |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
[](https://pypi.python.org/pypi/apsbits) | [](https://coveralls.io/github/BCDA-APS/BITS) |
|
|
116
|
+
|
|
117
|
+
BITS: **B**luesky **I**nstrument **T**emplate**S**
|
|
118
|
+
|
|
119
|
+
Template of a Bluesky Data Acquisition Instrument in console, notebook, &
|
|
120
|
+
queueserver.
|
|
121
|
+
|
|
122
|
+
## Create repository from this template.
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template
|
|
127
|
+
|
|
128
|
+
Creating a repository from a template
|
|
129
|
+
On GitHub, navigate to the main page of the repository.
|
|
130
|
+
|
|
131
|
+
Above the file list, click Use this template.
|
|
132
|
+
|
|
133
|
+
Select Create a new repository.
|
|
134
|
+
|
|
135
|
+

|
|
137
|
+
|
|
138
|
+
Alternatively, you can open the template in a codespace and publish your work to a new repository later. For more information, see Creating a codespace from a template.
|
|
139
|
+
|
|
140
|
+
Use the Owner dropdown menu to select the account you want to own the repository.
|
|
141
|
+
|
|
142
|
+
Screenshot of the owner menu for a new GitHub repository. The menu shows two options, octocat and github.
|
|
143
|
+
Type a name for your repository, and an optional description.
|
|
144
|
+
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
Screenshot of a the first step in creating a repository. The "Repository name" field contains the text "hello-world" and is outlined in orange.
|
|
149
|
+
Choose a repository visibility. For more information, see About repositories.
|
|
150
|
+
|
|
151
|
+

|
|
152
|
+
|
|
153
|
+
Optionally, to include the directory structure and files from all branches in the template, and not just the default branch, select Include all branches.
|
|
154
|
+
|
|
155
|
+
Optionally, if the personal account or organization in which you're creating uses any GitHub Apps from GitHub Marketplace, select any apps you'd like to use in the repository.
|
|
156
|
+
|
|
157
|
+
Click Create repository from template.
|
|
158
|
+
|
|
159
|
+
## Installing your own BITS instrument
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
export ENV_NAME=BITS_env
|
|
163
|
+
|
|
164
|
+
conda create -y -n $ENV_NAME python=3.11 pyepics
|
|
165
|
+
conda activate $ENV_NAME
|
|
166
|
+
pip install -e ."[all]"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
## Edit your instrument
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
## IPython console Start
|
|
175
|
+
|
|
176
|
+
To start the bluesky instrument session in a ipython execute the next command in a terminal:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
ipython
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Jupyter Notebook Start
|
|
183
|
+
Start JupyterLab, a Jupyter notebook server, or a notebook, VSCode.
|
|
184
|
+
|
|
185
|
+
## Starting the BITS Package
|
|
186
|
+
|
|
187
|
+
```py
|
|
188
|
+
from instrument.startup import *
|
|
189
|
+
RE(make_devices()) # create all the ophyd-style control devices
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Run Sim Plan Demo
|
|
193
|
+
|
|
194
|
+
To run some simulated plans that ensure the installation worked as expected
|
|
195
|
+
please run the next commands inside an ipython session or a jupyter notebook
|
|
196
|
+
after starting the data acquisition:
|
|
197
|
+
|
|
198
|
+
```py
|
|
199
|
+
RE(sim_print_plan())
|
|
200
|
+
RE(sim_count_plan())
|
|
201
|
+
RE(sim_rel_scan_plan())
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
See this [example](./docs/source/demo.ipynb).
|
|
205
|
+
|
|
206
|
+
## Configuration files
|
|
207
|
+
|
|
208
|
+
The files that can be configured to adhere to your preferences are:
|
|
209
|
+
|
|
210
|
+
- `configs/iconfig.yml` - configuration for data collection
|
|
211
|
+
- `configs/logging.yml` - configuration for session logging to console and/or files
|
|
212
|
+
- `qserver/qs-config.yml` - contains all configuration of the QS host process. See the [documentation](https://blueskyproject.io/bluesky-queueserver/manager_config.html) for more details of the configuration.
|
|
213
|
+
|
|
214
|
+
## queueserver
|
|
215
|
+
|
|
216
|
+
The queueserver has a host process that manages a RunEngine. Client sessions
|
|
217
|
+
will interact with that host process.
|
|
218
|
+
|
|
219
|
+
### Run a queueserver host process
|
|
220
|
+
|
|
221
|
+
Use the queueserver host management script to start the QS host process. The
|
|
222
|
+
`restart` option stops the server (if it is running) and then starts it. This is
|
|
223
|
+
the usual way to (re)start the QS host process. Using `restart`, the process
|
|
224
|
+
runs in the background.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
./qserver/qs_host.sh restart
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Run a queueserver client GUI
|
|
231
|
+
|
|
232
|
+
To run the gui client for the queueserver you can use the next command inside the terminal:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
queue-monitor &
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Shell script explained
|
|
239
|
+
|
|
240
|
+
A [shell script](./qserver/qs_host.sh) is used to start the QS host process. Below
|
|
241
|
+
are all the command options, and what they do.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
(bstest) $ ./qserver/qs_host.sh help
|
|
245
|
+
Usage: qs_host.sh {start|stop|restart|status|checkup|console|run} [NAME]
|
|
246
|
+
|
|
247
|
+
COMMANDS
|
|
248
|
+
console attach to process console if process is running in screen
|
|
249
|
+
checkup check that process is running, restart if not
|
|
250
|
+
restart restart process
|
|
251
|
+
run run process in console (not screen)
|
|
252
|
+
start start process
|
|
253
|
+
status report if process is running
|
|
254
|
+
stop stop process
|
|
255
|
+
|
|
256
|
+
OPTIONAL TERMS
|
|
257
|
+
NAME name of process (default: bluesky_queueserver-)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Alternatively, run the QS host's startup command directly within the `./qserver/`
|
|
261
|
+
subdirectory.
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
cd ./qserver
|
|
265
|
+
start-re-manager --config=./qs-config.yml
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Testing
|
|
269
|
+
|
|
270
|
+
Use this command to run the test suite locally:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
pytest -vvv --lf ./src
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Documentation
|
|
277
|
+
|
|
278
|
+
<details>
|
|
279
|
+
<summary>prerequisite</summary>
|
|
280
|
+
|
|
281
|
+
To build the documentation locally, install [`pandoc`](https://pandoc.org/) in
|
|
282
|
+
your conda environment:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
conda install conda-forge::pandoc
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
</details>
|
|
289
|
+
|
|
290
|
+
Use this command to build the documentation locally:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
make -C docs clean html
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Once the documentation builds, view the HTML pages using your web browser:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
BROWSER ./docs/build/html/index.html &
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Adding to the documentation source
|
|
303
|
+
|
|
304
|
+
The documentation source is located in files and directories under
|
|
305
|
+
`./docs/source`. Various examples are provided.
|
|
306
|
+
|
|
307
|
+
Documentation can be added in these formats:
|
|
308
|
+
[`.rst`](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html)
|
|
309
|
+
(reStructured text), [`.md`](https://en.wikipedia.org/wiki/Markdown) (markdown),
|
|
310
|
+
and [`.ipynb`](https://jupyter.org/) (Jupyter notebook). For more information,
|
|
311
|
+
see the [Sphinx](https://www.sphinx-doc.org/) documentation.
|
|
312
|
+
|
|
313
|
+
## Warnings
|
|
314
|
+
|
|
315
|
+
### Bluesky Queueserver
|
|
316
|
+
|
|
317
|
+
The QS host process writes files into the `qserver/` directory. This directory can be
|
|
318
|
+
relocated. However, it should not be moved into the instrument package since
|
|
319
|
+
that might be installed into a read-only directory.
|
|
320
|
+
|
|
321
|
+
## How-To Guides
|
|
322
|
+
### How to use the template
|
|
323
|
+
|
|
324
|
+
Consider renaming this `instrument` package to be more clear that is specific to *this*
|
|
325
|
+
instrument. This will be the name by which it is `pip` installed and also used with
|
|
326
|
+
`import`. Let's use an example instrument package name `my_instrument` below to show which parts are edited.
|
|
327
|
+
|
|
328
|
+
1) Click on use as template button
|
|
329
|
+
2) Adjust the following parameters in the following files:
|
|
330
|
+
- `pyproject.toml`
|
|
331
|
+
- `[project]` `name =` *example: `my_instrument`*
|
|
332
|
+
- `[project.urls]` *change URLs for your repo*
|
|
333
|
+
- `[tool.setuptools]` `package-dir = {"instrument" = "src/instrument"}` *example: `{"my_instrument" = "src/instrument"}`*
|
|
334
|
+
- `src/instrument/init.py`
|
|
335
|
+
- `__package__ = "instrument"` *example: `"my_instrument"`*
|
|
336
|
+
- `src/instrument/configs/iconfig.yml`
|
|
337
|
+
- `DATABROKER_CATALOG:` *change from `temp` to your catalog's name*
|
|
338
|
+
- `beamline_id:` *one word beamline name (such as known by APS scheduling system)*
|
|
339
|
+
- `instrument_name:` *descriptive name of your beamline*
|
|
340
|
+
- `DM_SETUP_FILE:` *Path to DM bash setup file, comment out if you do not have*
|
|
341
|
+
- `BEC:` *adjust for your preferences*
|
|
342
|
+
- `qserver/qs-config.yml`
|
|
343
|
+
- `startup_module: instrument.startup` *example: `my_instrument.startup`*
|
|
344
|
+
- `docs/source/conf.py`
|
|
345
|
+
- `import instrument` *example `import my_instrument`*
|
|
346
|
+
- `project = "instrument"` *example: `"my_instrument"`*
|
|
347
|
+
- `version = instrument.__version__` *example: `my_instrument.__version__`*
|
|
348
|
+
|
|
349
|
+
- [APS Data Management Plans](./docs/source/guides/dm.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
apsbits/__init__.py,sha256=aC6iFpu22_zSzmQDjkrd3FcthCgjoD1SUiZ-7j_TwuY,442
|
|
2
|
+
apsbits/_version.py,sha256=M6t-LPFvXIty3cmb1PuSyyBXUrQKwdDeD11Ht_y2eKY,521
|
|
3
|
+
apsbits/core/__init__.py,sha256=CmmaJwx5aAUf2d-svOMw9paMlKnCSz_xvEPBAW8e5nA,266
|
|
4
|
+
apsbits/core/best_effort_init.py,sha256=FJ53pcywdhsTloDXbxsbV9eMLyNxWjm7pFKjLS7Mnv8,938
|
|
5
|
+
apsbits/core/catalog_init.py,sha256=rhvTgnTN0cGUCWqF2zwq22MrCq5jKbvQ2EHMLG4t6yQ,588
|
|
6
|
+
apsbits/core/run_engine_init.py,sha256=gXWGj25mAy6acRiK0tA7yR1lGqF7Fhg2fZn9fwp0wZ4,2070
|
|
7
|
+
apsbits/demo_instrument/README.md,sha256=fLZWnARxJxOZSwrb1eIN4UtRpxrLgKeApU5xJ5jGNWs,19
|
|
8
|
+
apsbits/demo_instrument/__init__.py,sha256=FvRPlH1kNyvOzRV6K-ELCQgGYBzUEsrU--yr29x8Zx4,69
|
|
9
|
+
apsbits/demo_instrument/startup.py,sha256=cbgiVKXr8h_UH4xtXhnIwy1USYy6sOAPKOEcgc4q6Nw,2272
|
|
10
|
+
apsbits/demo_instrument/callbacks/__init__.py,sha256=UlYegbF9GbziD1UzgscoGo9T5aFPvs-upwXxPQmBEjY,35
|
|
11
|
+
apsbits/demo_instrument/callbacks/nexus_data_file_writer.py,sha256=3pwLL7E8tzKrmSRQ9iTLJUpdZss-x1l9t0qT1Wn8ihQ,1519
|
|
12
|
+
apsbits/demo_instrument/callbacks/spec_data_file_writer.py,sha256=D58A-Th7sSJasAmkFNg_Ab3v3TUjOf9uKw_9HK_Ne9M,2641
|
|
13
|
+
apsbits/demo_instrument/configs/__init__.py,sha256=mhZO8bz7uexqBJx0PrILGQM6ssHPbCx8fld7EtRy6so,46
|
|
14
|
+
apsbits/demo_instrument/configs/devices.yml,sha256=sbAyUSqCF2CeCp_KKmCBEuOj3gT1h8OP_eR5uqROby0,1305
|
|
15
|
+
apsbits/demo_instrument/configs/devices_aps_only.yml,sha256=XR9ZB-RaVpG-rghDSYKL8A16wETuOi7mzlx7U8LBCTg,136
|
|
16
|
+
apsbits/demo_instrument/configs/iconfig.yml,sha256=YAz2FCv6VlvBEz9n-u7KymF9n-tfrSW4JWiyDjK_NFo,2271
|
|
17
|
+
apsbits/demo_instrument/configs/logging.yml,sha256=ydODRE8cUqzZvI7xxTB9jT6hEQci8jKrshF8mwRV9fo,836
|
|
18
|
+
apsbits/demo_instrument/devices/__init__.py,sha256=3nhJy2BDR_nelXjxWw5_1Ppg7zStO6v2vJNpvO06IYU,27
|
|
19
|
+
apsbits/demo_instrument/plans/__init__.py,sha256=Qjo7AYRIReo-x5i9rkpiYs86F5C8adDchn_Ghe-Qn1A,356
|
|
20
|
+
apsbits/demo_instrument/plans/dm_plans.py,sha256=SeZMKQeQGlQ-abpv3Ccfe9BgQDHMxFQq0pEgsiZCeb4,3445
|
|
21
|
+
apsbits/demo_instrument/plans/sim_plans.py,sha256=er9Dekkh9ob6t-GBR0tb2EIBdgr3JqRdIfr2xTi_l-Y,1963
|
|
22
|
+
apsbits/tests/__init__.py,sha256=ZqbT_R0daJUQAawNOy472d-DOwwYxmZQKuZp3jivZDM,48
|
|
23
|
+
apsbits/tests/conftest.py,sha256=mEErfrzLO_27WIergnHD5gC8iYLf7R_TRQPKhJ8UJbM,868
|
|
24
|
+
apsbits/tests/test_device_factories.py,sha256=Uoq3V6zugCLCqNagln81N3d7dk_e8bTAsH5ZwEKpVrI,1364
|
|
25
|
+
apsbits/tests/test_general.py,sha256=KoGchanPPOg8E1n7KhJxLuclKCgoDgxr0s11Wj7ySrM,2646
|
|
26
|
+
apsbits/tests/test_stored_dict.py,sha256=BmJAXnQFtkqdXloiMdzUXDxZ1SH-wwNyQmgmWOyhQkI,4248
|
|
27
|
+
apsbits/utils/__init__.py,sha256=2ZlHuOIAtb-kEBwQoabNVWD5QOVtDBORgdy1BzI8NS8,45
|
|
28
|
+
apsbits/utils/aps_functions.py,sha256=o4ZQ0GCdftpCRJnVcjKrx5WnQNV0gwnA_oXS8rBhGN0,2135
|
|
29
|
+
apsbits/utils/config_loaders.py,sha256=ZVUu0WgfxAwgy8ICULhjNNhg3xsowUeD6kZFIEQYjnY,1712
|
|
30
|
+
apsbits/utils/context_aware.py,sha256=Aepj9Zxctc1hZg7Uv-rltObFHGLFEHySTa4pE1SiY-k,5627
|
|
31
|
+
apsbits/utils/controls_setup.py,sha256=HA4P2NNohEOfK_MUkELuxjoMAC8UPjHX52PmbzF5dNM,3395
|
|
32
|
+
apsbits/utils/create_new_instrument.py,sha256=DQddRosANfvfmndftNW52Z_Xi0_9Y3HnD7XYS-bHvxA,4546
|
|
33
|
+
apsbits/utils/helper_functions.py,sha256=KUbTdRIkhIeEtAOxiqKTzV4fv97bn6HEpcPvly3XOAw,3126
|
|
34
|
+
apsbits/utils/logging_setup.py,sha256=lDThArGcwq9v0ClRJs__thQG13xITx7-pQbmxdR6FsU,7034
|
|
35
|
+
apsbits/utils/make_devices_yaml.py,sha256=x9qp_bRMo4p0HdKHYFhZlVEcCoQrTl8-srwCnrCfefg,3614
|
|
36
|
+
apsbits/utils/metadata.py,sha256=aiEVHFK13Zu1XCbFALrfFxIJzDHtmPEAj9xO5QAKs9g,2629
|
|
37
|
+
apsbits/utils/sim_creator.py,sha256=OUs0vS0shaEQRJZVRS9j9TE496YjGr8zqKQzZJl1DYE,5275
|
|
38
|
+
apsbits/utils/stored_dict.py,sha256=ACqlB81YSMjHITBb0bAX5BMp_hPGOGPLiueQdsqjDAw,5530
|
|
39
|
+
apsbits-1.0.0rc2.dist-info/LICENSE,sha256=VRL4rXRDmRe62o4ci_VPKWl_z8_96c-U6DUqelNBgI0,1927
|
|
40
|
+
apsbits-1.0.0rc2.dist-info/METADATA,sha256=KxfP9_A5b3mCZfs5-602bYJYbztrnJz3M_Sa-u7G3dQ,12544
|
|
41
|
+
apsbits-1.0.0rc2.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
42
|
+
apsbits-1.0.0rc2.dist-info/entry_points.txt,sha256=iLl4F8OZNqN7wb-wmKSBY8_LDK7B2CnGWbPMNIt8QEA,73
|
|
43
|
+
apsbits-1.0.0rc2.dist-info/top_level.txt,sha256=K0KyAyPka1k4prJJFWALbX0gcUL3i4kiflTvSeM_6O4,8
|
|
44
|
+
apsbits-1.0.0rc2.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
apsbits
|