- self._dict: dict[str, ClientDbType] = {}
- self._confirmeds: list[str] = []
-
- def __getattr__(self, key: str) -> Optional[ClientDbType]:
- if key in self._dict and key in self._confirmeds:
- value = self._dict[key]
- self._typecheck(key, value)
- return value
- return None
-
- def __setattr__(self, key: str, *args, **kwargs) -> None:
- if key[:1] == '_':
- super().__setattr__(key, *args, **kwargs)
- else:
- raise CrashingException(
- 'no direct attribute setting, use .set() etc.')
-
- @classmethod
- def _type_for(cls, key):
- candidates = [c.__annotations__[key] for c in cls.__mro__
- if c is not object and key in c.__annotations__]
- if not candidates:
- raise CrashingException(f'{cls} lacks annotation for {key}')
- return candidates[0]
-
- @classmethod
- def _typecheck(cls, key: str, value: ClientDbType) -> None:
- type_ = cls._type_for(key)
- fail = True
- type_found = str(type(value))
- if not isinstance(type_, type): # gotta be GenericAlias, …
- assert hasattr(type_, '__origin__') # … which, if for list …
- assert type_.__origin__ is list # … (only probable …
- if isinstance(value, type_.__origin__): # … candidate so far), …
- fail = False # be ok if list emtpy # … stores members' …
- assert hasattr(type_, '__args__') # … types at .__args__
- subtypes_found = set()
- for subtype in type_.__args__:
- for x in [x for x in value if not isinstance(x, subtype)]:
- fail = True
- subtypes_found.add(str(type(x)))
- type_found = f'{type_.__origin__}: ' + '|'.join(subtypes_found)
- elif isinstance(value, type_):
- return
- if fail:
- raise CrashingException(
- f'wrong type for {key}: {type_found} (should be: {type_}, '
- f'provided value: {value})')
+ annos = {}
+ for c in self.__class__.__mro__:
+ if hasattr(c, '__annotations__'):
+ for k in [k for k in c.__annotations__ if k not in annos]:
+ annos[k] = c.__annotations__[k]
+ for name, type_ in annos.items():
+ if type_ is int:
+ setattr(self, name, 0)
+ elif type_ is str:
+ setattr(self, name, '')
+ elif hasattr(type_, '__origin__') and type_.__origin__ is list:
+ setattr(self, name, [])
+ else:
+ setattr(self, name, {})
+ self._confirmeds: set[str] = set()