diff options
Diffstat (limited to 'src/argaze/DataFeatures.py')
-rw-r--r-- | src/argaze/DataFeatures.py | 91 |
1 files changed, 52 insertions, 39 deletions
diff --git a/src/argaze/DataFeatures.py b/src/argaze/DataFeatures.py index cf7566a..ac3000c 100644 --- a/src/argaze/DataFeatures.py +++ b/src/argaze/DataFeatures.py @@ -7,7 +7,7 @@ __credits__ = [] __copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" __license__ = "BSD" -from typing import TypeVar, Tuple +from typing import TypeVar, Tuple, Any from dataclasses import dataclass, field import importlib from inspect import getmembers @@ -103,13 +103,6 @@ class JsonEncoder(json.JSONEncoder): return public_dict -class DataDictionary(dict): - """Enable dot.notation access to dictionary attributes""" - - __getattr__ = dict.get - __setattr__ = dict.__setitem__ - __delattr__ = dict.__delitem__ - class SharedObject(): """Enable multiple threads sharing.""" @@ -180,37 +173,6 @@ class SharedObject(): self._token = token self._lock.release() -TimeStampedDataLoggerType = TypeVar('TimeStampedDataLogger', bound="TimeStampedDataLogger") -# Type definition for type annotation convenience - -@dataclass -class TimeStampedDataLogger(): - """Abstract class to define what should provide a timestamped data logger.""" - - selector: str = field(default='data') - """Code evaluated to select data. Default 'data' string means that all incoming data will be written.""" - - @classmethod - def from_dict(self, logger_module_path: str, logger_parameters: dict) -> TimeStampedDataLoggerType: - """Load timestamped data logger from dictionary. - - Parameters: - logger_module_path: class name to load - logger_parameters: attributes to load - """ - - # Prepend argaze.DataLog path when a single name is provided - if len(logger_module_path.split('.')) == 1: - logger_module_path = f'argaze.DataLog.{logger_module_path}' - - logger_module = importlib.import_module(logger_module_path) - return logger_module.TimeStampedDataLogger(**logger_parameters) - - def emit(self, timestamp: TimeStampType, data: DataDictionary): - """Emit timestamped data dictionary to a specific log destination.""" - - raise NotImplementedError('emit() method not implemented') - class TimeStampedBuffer(collections.OrderedDict): """Ordered dictionary to handle timestamped data. ``` @@ -458,3 +420,54 @@ class TimeStampedBuffer(collections.OrderedDict): legend_patches.append(mpatches.Patch(color=color, label=name.upper())) return legend_patches + +class DataDictionary(dict): + """Enable dot.notation access to dictionary attributes""" + + __getattr__ = dict.get + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + +# Import libraries that can be used in selector or formatter codes +from argaze import GazeFeatures + +TimeStampedDataLoggerType = TypeVar('TimeStampedDataLogger', bound="TimeStampedDataLogger") +# Type definition for type annotation convenience + +@dataclass +class TimeStampedDataLogger(): + """Abstract class to define what should provide a timestamped data logger.""" + + selector: str = field(default='True') + """Code evaluated to select data under a condition. Default 'True' string means that all incoming data will be accepted.""" + + formatter: str|list = field(default='timestamp, data') + """Code (or list of codes) evaluated to format timestamp and data to emit. Default 'timestamp, data' string means that all incoming timestamp and data values will be emitted.""" + + @classmethod + def from_dict(self, logger_module_path: str, logger_parameters: dict) -> TimeStampedDataLoggerType: + """Load timestamped data logger from dictionary. + + Parameters: + logger_module_path: class name to load + logger_parameters: attributes to load + """ + + # Prepend argaze.DataLog path when a single name is provided + if len(logger_module_path.split('.')) == 1: + logger_module_path = f'argaze.DataLog.{logger_module_path}' + + logger_module = importlib.import_module(logger_module_path) + return logger_module.TimeStampedDataLogger(**logger_parameters) + + def __call__(self, timestamp: TimeStampType, data: DataDictionary) -> Any: + """Apply selector code to decide if data have to be logged, then apply formatter code before to call specific logger emit method.""" + + if eval(self.selector): + + return self.emit(eval(self.formatter)) + + def emit(self, formatted_log: any): + """Emit formatted log to a destination.""" + + raise NotImplementedError('handle() method not implemented') |