63 lines
1.8 KiB
Python
63 lines
1.8 KiB
Python
# scopes.shape
|
|
|
|
"""really abstract basic data shape definitions"""
|
|
|
|
from scopes.util import keywords as k
|
|
|
|
class Record:
|
|
|
|
headFields: tuple[str, ...] = () # to be defined by subclass
|
|
headFieldsAsKeywords: set[str] = set()
|
|
defaultHeadValue = ''
|
|
|
|
def __init__(self, *headValues, data=None, **kw):
|
|
self.head = dict((k, self.defaultHeadValue) for k in self.headFields)
|
|
for k, v in kw.items():
|
|
self.set(k, v)
|
|
for ix, hv in enumerate(headValues):
|
|
self.set(self.headFields[ix], hv)
|
|
self.data = data or {}
|
|
|
|
def __getattr__(self, k):
|
|
raise AttributeError(k)
|
|
|
|
@property
|
|
def headValues(self):
|
|
return [self.head[k] for k in self.headFields]
|
|
|
|
def set(self, attr, value):
|
|
if attr in self.headFields:
|
|
if value is None:
|
|
value = self.defaultHeadValue
|
|
elif attr in self.headFieldsAsKeywords:
|
|
value = k[value]
|
|
self.head[attr] = value
|
|
setattr(self, attr, value)
|
|
else:
|
|
raise AttributeError(attr)
|
|
|
|
def update(self, data, overwrite=False):
|
|
if data is None:
|
|
return
|
|
if overwrite:
|
|
self.data = data
|
|
else:
|
|
self.data.update(data)
|
|
|
|
def __repr__(self):
|
|
return f'<{self.__class__.__name__}: {self.headValues}, {self.data}>'
|
|
|
|
def asDict(self, flatten=False):
|
|
if flatten:
|
|
return self.head | self.data
|
|
return dict(head=self.head, data=self.data)
|
|
|
|
def toObject(self, cls):
|
|
return cls(**self.asDict(flatten=True))
|
|
|
|
@classmethod
|
|
def fromObject(cls, obj):
|
|
inp = obj.model_dump()
|
|
headValues = [inp.pop(hf) for hf in cls.headFields]
|
|
return cls(*headValues, data=inp)
|
|
|