Skip to content

Instantly share code, notes, and snippets.

@strikaco
Created April 1, 2022 18:31
Show Gist options
  • Save strikaco/fd235c5cbb872ee599671cb2cb80af46 to your computer and use it in GitHub Desktop.
Save strikaco/fd235c5cbb872ee599671cb2cb80af46 to your computer and use it in GitHub Desktop.
Python - Component dataclasses as class properties
from dataclasses import dataclass, field, fields, replace, asdict
_MISSING = object()
@dataclass
class Component(object):
"""
Collection of attributes.
"""
_key: str = field(default=None, hash=False, repr=False, compare=False)
_entity:object = field(default=None, hash=False, repr=False, compare=False)
autosave:bool = field(default=False, hash=False, repr=False, compare=False)
def __set_name__(self, owner, name):
self._key = name
def __get__(self, instance, owner):
# Try getting existing component object
obj = getattr(instance.ndb, self._key, _MISSING)
if obj and isinstance(obj, self.__class__):
return obj
# Try getting data from db
data = getattr(instance.db, self._key, {})
# Create and save new object to ndb
obj = replace(self, _entity=instance, **data)
setattr(instance.ndb, self._key, obj)
return obj
def __setattr__(self, key, value):
super().__setattr__(key, value)
if self.autosave: self.save()
def save(self):
base_fields = tuple(f.name for f in fields(Component))
data = {k:v for k,v in asdict(self).items() if k not in base_fields}
setattr(self._entity.db, self._key, data)
@dataclass
class Geometry(Component):
height:float = 0.0
width:float = 0.0
depth:float = 0.0
class DB(object): pass
class Object(object):
geom = Geometry(depth=16)
def __init__(self):
self.db = DB()
self.ndb = DB()
o = Object()
o.geom.height = 5.0
print(o, o.geom, o.geom.height)
o.geom.save()
print(o.db.geom)
o3 = Object()
print(o3.geom)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment