| 5 | |
| 6 | |
| 7 | class ModularLogger(UserDict): |
| 8 | def __init__(self, *args, **kwargs): |
| 9 | super().__init__(*args, **kwargs) |
| 10 | self._log_length = max(len(v) for _, v in self.items()) if len(self.data) else 0 |
| 11 | |
| 12 | def flush(self): |
| 13 | d = self.data.copy() |
| 14 | self.clear() |
| 15 | self._log_length = 0 |
| 16 | return d |
| 17 | |
| 18 | def log(self, log_dict=None, **log_items): |
| 19 | if log_items: |
| 20 | if log_dict: |
| 21 | raise TypeError('Cannot pass both positional and keyword arguments.') |
| 22 | |
| 23 | log_dict = log_items |
| 24 | |
| 25 | for key, value in log_dict.items(): |
| 26 | if key not in self: |
| 27 | self[key] = [] |
| 28 | |
| 29 | try: |
| 30 | self[key].append(value.item()) |
| 31 | except AttributeError: |
| 32 | self[key].append(value) |
| 33 | except ValueError: |
| 34 | raise ValueError('Only scalar values can be logged.') |
| 35 | |
| 36 | self._log_length += 1 |
| 37 | |
| 38 | def to_dict(self): |
| 39 | return self.data.copy() |
| 40 | |
| 41 | def raw(self): |
| 42 | return {k: list(map(float, v)) for k, v in self.data.items()} |
| 43 | |
| 44 | def to_frame(self): |
| 45 | return pd.DataFrame(self.data) |
| 46 | |
| 47 | def serialize(self, key): |
| 48 | return {key: self.to_frame()} if len(self) > 0 else {} |
| 49 | |
| 50 | def __len__(self): |
| 51 | return self._log_length |
| 52 | |
| 53 | @classmethod |
| 54 | def from_raw(cls, raw): |
| 55 | if raw is None: |
| 56 | return cls() |
| 57 | elif isinstance(raw, str): |
| 58 | raw = pd.read_csv(raw).to_dict() |
| 59 | return cls(raw) |