Source code for tango.utils._events
# SPDX-FileCopyrightText: All Contributors to the PyTango project
# SPDX-License-Identifier: LGPL-3.0-or-later
"""Event callbacks that print what they receive, for interactive use."""
import sys
from tango import (
AttrConfEventData,
DataReadyEventData,
DevIntrChangeEventData,
EventData,
EventReason,
)
[docs]
class EventCallback:
"""
Useful event callback for test purposes
Usage::
>>> dev = tango.DeviceProxy(dev_name)
>>> cb = tango.utils.EventCallback()
>>> id = dev.subscribe_event("state", tango.EventType.CHANGE_EVENT, cb, [])
2011-04-06 15:33:18.910474 sys/tg_test/1 STATE CHANGE [ATTR_VALID] ON
Allowed format keys are:
- date (event timestamp)
- reception_date (event reception timestamp)
- type (event type)
- reason (event subscription reason)
- dev_name (device name)
- name (attribute name)
- value (event value)
.. versionadded:: 7.1.4
"""
def __init__(
self,
format="{date} {dev_name} {name} {type} {reason} {value}",
fd=sys.stdout,
max_buf=100,
):
self._msg = format
self._fd = fd
self._evts = []
self._max_buf = max_buf
[docs]
def get_events(self):
"""Returns the list of events received by this callback
:return: the list of events received by this callback
:rtype: sequence<obj>
"""
return self._evts
[docs]
def push_event(self, evt):
"""Internal usage only"""
try:
self._push_event(evt)
except Exception as e:
print(f"Unexpected error in callback for {evt}: {e}", file=self._fd)
def _push_event(self, evt):
"""Internal usage only"""
self._append(evt)
import datetime
now = datetime.datetime.now()
try:
date = self._get_date(evt)
except Exception:
date = now
try:
reception_date = evt.reception_date.todatetime()
except Exception:
reception_date = now
try:
evt_type = evt.event.upper()
except Exception:
evt_type = "<UNKNOWN>"
try:
evt_reason = str(evt.event_reason).upper()
except Exception:
evt_reason = "<UNKNOWN>"
try:
dev_name = evt.device.dev_name().upper()
except Exception:
dev_name = "<UNKNOWN>"
try:
if hasattr(evt, "attr_name"):
attr_name = evt.attr_name.split("/")[-1].upper()
attr_name = attr_name.removesuffix("#DBASE=NO")
else:
attr_name = "<N/A>"
except Exception:
attr_name = "<UNKNOWN>"
try:
value = self._get_value(evt)
except Exception as e:
value = f"Unexpected exception in getting event value: {e}"
d = {
"date": date,
"reception_date": reception_date,
"type": evt_type,
"reason": evt_reason,
"dev_name": dev_name,
"name": attr_name,
"value": value,
}
print(self._msg.format(**d), file=self._fd)
def _append(self, evt):
"""Internal usage only"""
evts = self._evts
while evts and len(evts) >= self._max_buf:
evts.pop(0)
if self._max_buf > 0:
evts.append(evt)
def _get_date(self, evt):
if isinstance(evt, EventData):
return evt.attr_value.time.todatetime()
else:
return evt.get_date().todatetime()
def _get_value(self, evt):
"""Internal usage only"""
if evt.err:
e = evt.errors[0]
return f"[{e.reason}] {e.desc}"
if isinstance(evt, EventData):
if evt.attr_value is None and evt.event_reason == EventReason.SubSuccess:
return "<N/A>" # assume EventSubMode.Async which provides no value
else:
return f"[{evt.attr_value.quality}] {evt.attr_value.value}"
elif isinstance(evt, AttrConfEventData):
cfg = evt.attr_conf
return f"label='{cfg.label}'; unit='{cfg.unit}'"
elif isinstance(evt, DataReadyEventData):
return f"ctr={evt.ctr}"
elif isinstance(evt, DevIntrChangeEventData):
return f"dev_started={evt.dev_started}; {len(evt.cmd_list)} commands; {len(evt.att_list)} attrs"
return repr(evt)
class AsyncEventCallback(EventCallback):
async def push_event(self, evt):
"""Internal usage only"""
try:
self._push_event(evt)
except Exception as e:
print(f"Unexpected error in callback for {evt}: {e}", file=self._fd)