Skip to content

Commit fb6f5fb

Browse files
authored
Merge pull request #208 from BCDA-APS/202-spec2ophyd
add labels attribute to enable wa and ct magic commands
2 parents d977736 + 8349afc commit fb6f5fb

File tree

4 files changed

+117
-50
lines changed

4 files changed

+117
-50
lines changed

CHANGES.rst

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44
Change History
55
##############
66

7+
:1.1.10: release *tba* : updates & bug fix
8+
9+
* `#207 <https://github.com/BCDA-APS/apstools/issues/207>`_
10+
``show_ophyd_symbols`` also shows labels
11+
* `#206 <https://github.com/BCDA-APS/apstools/issues/206>`_
12+
new: ``apstools.utils.APS_utils.list_recent_scans()``
13+
* `#205 <https://github.com/BCDA-APS/apstools/issues/205>`_
14+
``show_ophyd_symbols`` uses ipython shell's namespace
15+
* `#202 <https://github.com/BCDA-APS/apstools/issues/202>`_
16+
add ``labels`` attribute to enable ``wa`` and ``ct`` magic commands
17+
718
:1.1.9: released *2019-07-28* : updates & bug fix
819

920
* `#203 <https://github.com/BCDA-APS/apstools/issues/203>`_
@@ -28,13 +39,10 @@ Change History
2839

2940
:1.1.7: released 2019-07-04
3041

31-
.. note:: DEPRECATION:
42+
* `DEPRECATION <https://github.com/BCDA-APS/apstools/issues/90#issuecomment-483405890>`_
3243
`apstools.plans.run_blocker_in_plan()` will be removed by 2019-12-31.
3344
`Do not write blocking code in bluesky plans.
34-
<https://github.com/BCDA-APS/apstools/issues/90#issuecomment-483405890>`_
35-
36-
.. note:: Dropped python 3.5 from supported versions
37-
45+
* Dropped python 3.5 from supported versions
3846
* `#175 <https://github.com/BCDA-APS/apstools/issues/175>`_
3947
move `plans.run_in_thread()` to `utils.run_in_thread()`
4048
* `#168 <https://github.com/BCDA-APS/apstools/issues/168>`_

apstools/migration/spec2ophyd.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ def setDevice(self, devices):
120120
self.ignore = True
121121

122122
def ophyd_config(self):
123-
s = f"{self.mne} = {self.signal_name}('{self.pvname}', name='{self.mne}')"
123+
s = f"{self.mne} = {self.signal_name}('{self.pvname}', name='{self.mne}', labels=('detectors',))"
124124
suffix = None
125125
if "misc_par_1" in self.cntpar:
126126
suffix = self.cntpar.pop("misc_par_1")
127127
pvname = f"{self.device.prefix}{suffix}"
128-
s = f"{self.mne} = EpicsSignal('{pvname}', name='{self.mne}')"
128+
s = f"{self.mne} = EpicsSignal('{pvname}', name='{self.mne}', labels=('detectors',))"
129129
if self.mne != self.name:
130130
s += f" # {self.name}"
131131
if self.ignore:
@@ -200,12 +200,12 @@ def setDevice(self, devices):
200200
self.ignore = True
201201

202202
def ophyd_config(self):
203-
s = f"{self.mne} = EpicsMotor('{self.pvname}', name='{self.mne}')"
203+
s = f"{self.mne} = EpicsMotor('{self.pvname}', name='{self.mne}', labels=('motor',))"
204204
suffix = None
205205
if "misc_par_1" in self.motpar:
206206
suffix = self.motpar.pop("misc_par_1")
207207
pvname = f"{self.device.prefix}{suffix}"
208-
s = f"{self.mne} = EpicsMotor('{pvname}', name='{self.mne}')"
208+
s = f"{self.mne} = EpicsMotor('{pvname}', name='{self.mne}', labels=('motor',))"
209209
if self.pvname is None:
210210
if self.macro_prefix is not None:
211211
s = f"# Macro Motor: {self}"
@@ -288,7 +288,7 @@ def ophyd_config(self):
288288
if "misc_par_1" in self.cntpar:
289289
suffix = self.cntpar.pop("misc_par_1")
290290
pvname = f"{self.device.prefix}{suffix}"
291-
s = f"{self.mne} = EpicsSignal('{pvname}', name='{self.mne}')"
291+
s = f"{self.mne} = EpicsSignal('{pvname}', name='{self.mne}', labels=('detectors',))"
292292
if self.ignore:
293293
s = f"# {self.config_line}: {self.raw}"
294294
if len(self.cntpar) > 0:

apstools/utils.py

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
~ExcelDatabaseFileBase
1313
~ExcelDatabaseFileGeneric
1414
~ExcelReadError
15+
~ipython_profile_name
1516
~itemizer
1617
~json_export
1718
~json_import
18-
~ipython_profile_name
19+
~list_recent_scans
1920
~pairwise
2021
~print_snapshot_list
2122
~print_RE_md
@@ -140,7 +141,7 @@ def dictionary_table(dictionary, fmt="simple"):
140141
141142
default: ``simple``
142143
143-
.. [#] *pyRestTable* : https://pyresttable.readthedocs.io/en/latest/examples/index.html#examples
144+
.. [#] *pyRestTable* : https://pyresttable.readthedocs.io/en/latest/examples/index.html#examples
144145
145146
RETURNS
146147
@@ -181,6 +182,65 @@ def itemizer(fmt, items):
181182
return [fmt % k for k in items]
182183

183184

185+
def list_recent_scans(num=20, keys=[], printing=True, db=None):
186+
"""
187+
make a table of the most recent scans
188+
189+
PARAMETERS
190+
191+
num : int (default: ``20``)
192+
Make the table include the ``num`` most recent scans.
193+
keys : [str] (default: ``[]``)
194+
Include these additional keys from the start document.
195+
printing : bool (default: ``True``)
196+
If True, print the table to stdout
197+
db : object (default: ``db`` from the IPython shell)
198+
Instance of ``databroker.Broker()``
199+
200+
RETURNS
201+
202+
object:
203+
Instance of `pyRestTable.Table()``
204+
205+
EXAMPLE::
206+
207+
In [7]: APS_utils.list_recent_scans(num=5, keys=["proposal_id","pid"])
208+
========= ========================== ======= ========= =========== =====
209+
short_uid date/time scan_id plan_name proposal_id pid
210+
========= ========================== ======= ========= =========== =====
211+
235cc8e 2019-07-26 19:59:57.377210 156 scan testing 31185
212+
82406dd 2019-07-26 19:57:30.607125 155 scan testing 31185
213+
f6249d8 2019-07-25 16:45:36.114533 151 count testing 15321
214+
9457fa4 2019-07-25 16:19:07.410803 150 count testing 4845
215+
f17f026 2019-07-25 16:19:04.929030 149 count testing 4845
216+
========= ========================== ======= ========= =========== =====
217+
218+
"""
219+
try:
220+
from IPython import get_ipython
221+
global_db = get_ipython().user_ns["db"]
222+
except AttributeError as _exc:
223+
global_db = None
224+
db = db or global_db
225+
226+
keys.insert(0, "plan_name")
227+
keys.insert(0, "scan_id")
228+
229+
table = pyRestTable.Table()
230+
table.labels = "short_uid date/time".split() + keys
231+
232+
for h in db[-abs(num):]:
233+
row = [
234+
h.start["uid"][:7],
235+
datetime.datetime.fromtimestamp(h.start['time']),
236+
] + [h.start.get(k, "") for k in keys]
237+
table.addRow(row)
238+
239+
if printing:
240+
print(table)
241+
return table
242+
243+
184244
def print_RE_md(dictionary=None, fmt="simple", printing=True):
185245
"""
186246
custom print the RunEngine metadata in a table
@@ -210,7 +270,11 @@ def print_RE_md(dictionary=None, fmt="simple", printing=True):
210270
======================== ===================================
211271
212272
"""
213-
global RE
273+
try:
274+
from IPython import get_ipython
275+
RE = get_ipython().user_ns["RE"]
276+
except AttributeError as _exc:
277+
RE = None
214278
dictionary = dictionary or RE.md
215279
md = dict(dictionary) # copy of input for editing
216280
v = dictionary_table(md["versions"], fmt=fmt) # sub-table
@@ -279,30 +343,13 @@ def show_ophyd_symbols(show_pv=True, printing=True, verbose=False, symbols=None)
279343
If True, also show ``str(obj``.
280344
symbols: dict (default: `globals()`)
281345
If None, use global symbol table.
282-
If not None, use provided dictionary.
283-
284-
**TIP** ``globals()`` only gets the module's globals
285-
286-
To get ``globals()`` from the global namespace, need to
287-
pass that from the global namespace into this function.
288-
Define this function *in* the global namespace::
289-
290-
from apstools import utils as APS_utils
291-
292-
def show_ophyd_symbols(
293-
show_pv=True,
294-
printing=True,
295-
verbose=False,
296-
symbols=None
297-
):
298-
symbols = symbols or globals()
299-
return APS_utils.show_ophyd_symbols(
300-
show_pv=show_pv,
301-
printing=printing,
302-
verbose=verbose,
303-
symbols=symbols
304-
)
346+
If not None, use provided dictionary.
305347
348+
RETURNS
349+
350+
object:
351+
Instance of `pyRestTable.Table()``
352+
306353
EXAMPLE::
307354
308355
In [1]: show_ophyd_symbols()
@@ -333,7 +380,13 @@ def show_ophyd_symbols(
333380
table.addLabel("EPICS PV")
334381
if verbose:
335382
table.addLabel("object representation")
336-
g = symbols or globals()
383+
table.addLabel("label(s)")
384+
try:
385+
from IPython import get_ipython
386+
g = get_ipython().user_ns
387+
except AttributeError as _exc:
388+
g = globals()
389+
g = symbols or g
337390
for k, v in sorted(g.items()):
338391
if isinstance(v, (ophyd.Signal, ophyd.Device)):
339392
row = [k, v.__class__.__name__]
@@ -346,6 +399,7 @@ def show_ophyd_symbols(
346399
row.append("")
347400
if verbose:
348401
row.append(str(v))
402+
row.append(' '.join(v._ophyd_labels_))
349403
table.addRow(row)
350404
if printing:
351405
print(table)

tests/test_utils.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,26 @@ def test_print_RE_md(self):
108108

109109
expected = [
110110
'RunEngine metadata dictionary:',
111-
'========= ================================',
112-
'key value ',
113-
'========= ================================',
114-
'purpose testing ',
115-
'something else ',
116-
'versions ======== =======================',
117-
' key value ',
118-
' ======== =======================',
111+
'========= ===============================',
112+
'key value ',
113+
'========= ===============================',
114+
'purpose testing ',
115+
'something else ',
116+
'versions ======== ======================',
117+
' key value ',
118+
' ======== ======================',
119119
f' apstools {APS__version__}',
120-
' ======== =======================',
121-
'========= ================================',
120+
' ======== ======================',
121+
'========= ===============================',
122122
''
123123
]
124-
for r, e in zip(received, expected):
125-
self.assertEqual(r, e)
124+
self.assertEqual(len(received), len(expected))
125+
self.assertEqual(received[4].strip(), expected[4].strip())
126+
self.assertEqual(received[5].strip(), expected[5].strip())
127+
self.assertEqual(
128+
received[9].strip(),
129+
expected[9].strip()
130+
)
126131

127132
def test_pairwise(self):
128133
items = [1.0, 1.1, 1.01, 1.001, 1.0001, 1.00001, 2]
@@ -160,7 +165,7 @@ def test_show_ophyd_symbols(self):
160165
kk = sorted(sims.keys())
161166
# sims hardware not found by show_ophyd_symbols() in globals!
162167
table = APS_utils.show_ophyd_symbols(symbols=sims, printing=False)
163-
self.assertEqual(3, len(table.labels))
168+
self.assertEqual(4, len(table.labels))
164169
rr = [r[0] for r in table.rows]
165170
for k in kk:
166171
msg = f"{k} not found"

0 commit comments

Comments
 (0)