- @classmethod
- def get_cached(cls: type[BaseModelInstance],
- id_: BaseModelId) -> BaseModelInstance | None:
- """Get object of id_ from class's cache, or None if not found."""
- # pylint: disable=consider-iterating-dictionary
- cache = cls.get_cache()
- if id_ in cache.keys():
- obj = cache[id_]
- assert isinstance(obj, cls)
- return obj
- return None
+ @property
+ def as_dict(self) -> dict[str, object]:
+ """Return self as (json.dumps-coompatible) dict."""
+ d: dict[str, object] = {'id': self.id_}
+ if len(self.to_save_versioned) > 0:
+ d['_versioned'] = {}
+ for k in self.to_save:
+ attr = getattr(self, k)
+ if hasattr(attr, 'as_dict'):
+ d[k] = attr.as_dict
+ d[k] = attr
+ for k in self.to_save_versioned:
+ attr = getattr(self, k)
+ assert isinstance(d['_versioned'], dict)
+ d['_versioned'][k] = attr.history
+ for r in self.to_save_relations:
+ attr_name = r[2]
+ d[attr_name] = [x.as_dict for x in getattr(self, attr_name)]
+ return d
+
+ # cache management
+ # (we primarily use the cache to ensure we work on the same object in
+ # memory no matter where and how we retrieve it, e.g. we don't want
+ # .by_id() calls to create a new object each time, but rather a pointer
+ # to the one already instantiated)
+
+ def __getattribute__(self, name: str) -> Any:
+ """Ensure fail if ._disappear() was called, except to check ._exists"""
+ if name != '_exists' and not super().__getattribute__('_exists'):
+ raise HandledException('Object does not exist.')
+ return super().__getattribute__(name)
+
+ def _disappear(self) -> None:
+ """Invalidate object, make future use raise exceptions."""
+ assert self.id_ is not None
+ if self._get_cached(self.id_):
+ self._uncache()
+ to_kill = list(self.__dict__.keys())
+ for attr in to_kill:
+ delattr(self, attr)
+ self._exists = False