#!/usr/bin/env python import collections import json import bisect import pandas class DictObject(): """Convert dictionnary into object""" def __init__(self, object_type = str, **dictionnary): self.__dict__.update(dictionnary) self.__type = object_type def __getitem__(self, key): return self.__dict__[key] def __str__(self): return json.dumps({key: self.__dict__[key] for key in self.__dict__.keys()}, default = vars) def get_type(self): return self.__type def keys(self): return list(self.__dict__.keys())[:-1] def append(self, key, value): __type_key = list(self.__dict__.keys())[-1] __type_value = self.__dict__.pop(__type_key) self.__dict__.update({key:value}) self.__dict__[__type_key] = __type_value class TimeStampedBuffer(collections.OrderedDict): """Ordered dictionary to handle timestamped data. ``` { timestamp1: data1, timestamp2: data2, ... } ``` """ def __new__(cls, args = None): return super(TimeStampedBuffer, cls).__new__(cls) def __setitem__(self, key: float, value): """Force key to be a number""" if type(key) != int and type(key) != float: raise KeyError('key must be a number') super().__setitem__(key, value) def __str__(self): return json.dumps(self, default=vars) def append(self, timestamped_buffer): """Append a timestamped buffer.""" for ts, value in timestamped_buffer.items(): self[ts] = value def pop_first(self): """Easing FIFO access mode""" return self.popitem(last=False) def pop_first_until(self, ts): """Pop all item until a given timestamped value and return the last poped item""" # get last timestamp before given timestamp earliest_ts = self.get_last_before(ts) # when no timestamped have been found if earliest_ts == None: raise ValueError popep_ts, poped_value = self.pop_first() while popep_ts != earliest_ts: popep_ts, poped_value = self.pop_first() return popep_ts, poped_value def pop_last(self): """Easing FIFO access mode""" return self.popitem(last=True) def get_last_before(self, ts): """Retreive last item timestamp before a given timestamp value.""" ts_list = list(self.keys()) last_before_index = bisect.bisect_left(ts_list, ts) - 1 if last_before_index >= 0: return ts_list[last_before_index] else: return None def export_as_json(self, filepath): """Write buffer content into a json file.""" try: with open(filepath, 'w', encoding='utf-8') as jsonfile: json.dump(self, jsonfile, ensure_ascii = False, default=vars) except: raise RuntimeError(f'Can\' write {filepath}') def as_dataframe(self, exclude=[]): """Convert buffer as pandas dataframe.""" df = pandas.DataFrame.from_dict(self.values()) df.drop(exclude, inplace=True, axis=True) df['timestamp'] = self.keys() df.set_index('timestamp', inplace=True) return df def export_as_csv(self, filepath, exclude=[]): """Write buffer content into a csv file.""" try: self.as_dataframe(exclude=exclude).to_csv(filepath, index=True) except: raise RuntimeError(f'Can\' write {filepath}')