Source code for bec_lib.scan_data

"""
This module contains the classes for storing scan data from scan_segments. 
"""

import collections
from typing import Any

from _collections_abc import dict_items, dict_keys, dict_values

from bec_lib import messages


[docs] class SignalData: """ SignalData is a container for storing signal data. """ def __init__(self): self.metadata = {} self.scan_id = None self.num_points = None self.data = {} def __getitem__(self, key: Any) -> Any: if isinstance(key, int): return self.data.get(key) if key in ["val", "value"]: return self.val if key == "timestamp": return self.timestamps return self.get(key) @property def val(self): """return a list of values of the signal data""" return [self.data.get(index, {}).get("value") for index in sorted(self.data.keys())] @property def timestamps(self): """return a list of timestamps of the signal data""" return [self.data.get(index, {}).get("timestamp") for index in sorted(self.data.keys())]
[docs] def get(self, index: Any, default=None) -> dict: """ Get the signal data at the given index. Args: index(int): the index of the scan point Returns: dict: the signal data at the given index """ if isinstance(index, int): return self.data.get(index, default) if index in ["val", "value"]: return self.val if index == "timestamp": return self.timestamps return self.get(index, default)
[docs] def set(self, index: Any, device_data: dict) -> None: """ Set the signal data at the given index to the given device data. Args: index(int): the index of the scan point device_data(dict): the device data to store """ self.data[index] = device_data
def __eq__(self, __value: object) -> bool: return self.data == __value def items(self) -> dict_items: return self.data.items() def keys(self) -> dict_keys: return self.data.keys() def values(self) -> dict_values: return self.data.values() def val_to_dict(self) -> dict: return {k: v.get("value") for k, v in self.data.items()} def __str__(self) -> str: return f"{self.data}" def __len__(self) -> int: return len(self.data)
[docs] class DeviceData(dict): """ DeviceData is a container for storing device data. """ def __init__(self): self.__signals = collections.defaultdict(SignalData) super().__init__() def __getitem__(self, key: Any) -> Any: if key in self.__signals: return self.__signals[key] if isinstance(key, int): return {signal: val.get(key) for signal, val in self.__signals.items()} return self.get(key) def __setattr__(self, attr: Any, value: Any) -> None: self.__setitem__(attr, value) def __setitem__(self, __key: Any, __value: Any) -> None: super().__setitem__(__key, __value) self.__dict__.update({__key: __value}) def __delitem__(self, __key: Any) -> None: super().__delitem__(__key) del self.__dict__[__key]
[docs] def get(self, index: Any, default=None) -> Any: if index in self.__signals: return self.__signals[index] if isinstance(index, int): return {signal: val.get(index) for signal, val in self.__signals.items()} return self.__signals.get(index, default)
def set(self, index: Any, signals: dict) -> None: for signal, signal_data in signals.items(): self.__signals[signal].set(index, signal_data) self.__setattr__(signal, self.__signals[signal]) def __str__(self) -> str: return f"{dict(self.__signals)}" def __eq__(self, ref_data: object) -> bool: return {name: self.__signals[name].data for name in self.__signals} == ref_data
[docs] def keys(self) -> dict_keys: return self.__signals.keys()
[docs] def items(self) -> dict_items: return self.__signals.items()
[docs] def values(self) -> dict_values: return self.__signals.values()
[docs] class ScanData(dict): """ ScanData is a container for storing scan data. """ def __init__(self, *args, **kwargs): self.devices = collections.defaultdict(DeviceData) self.messages = collections.defaultdict() super().__init__(*args, **kwargs)
[docs] def get(self, index: Any, default=None) -> Any: if index in self.devices: return self.devices.get(index, default) if isinstance(index, int) and index in self.messages: return self.messages.get(index) return self.devices.get(index, default)
def __getitem__(self, key: Any) -> Any: if key in self.devices: return self.devices[key] return self.get(key) def __contains__(self, key: Any) -> bool: if key in self.devices: return True return False def __eq__(self, __value: object) -> bool: return super().__eq__(__value) def __setattr__(self, attr: Any, value: Any) -> None: self.__setitem__(attr, value) def __setitem__(self, __key: Any, __value: Any) -> None: super().__setitem__(__key, __value) self.__dict__.update({__key: __value}) def __delitem__(self, __key: Any) -> None: super().__delitem__(__key) del self.__dict__[__key]
[docs] def set(self, index: Any, message: messages.BECMessage) -> None: """ Set the scan data at the given index to the values in the given content. Args: index(int): the index of the scan point content(dict): the content to store """ if not isinstance(index, int): raise TypeError("ScanData can only store data with integer indices.") self.messages[index] = message for dev, dev_data in message.content["data"].items(): self.devices[dev].set(index, dev_data) self.__setattr__(dev, self.devices[dev])
[docs] def keys(self) -> dict_keys: return self.devices.keys()
[docs] def items(self) -> dict_items: return self.devices.items()
[docs] def values(self) -> dict_values: return self.devices.values()
def __str__(self) -> str: return f"{dict(self.devices)}" def __len__(self) -> int: return len(self.messages)