from collections.abc import MutableMapping from collections.abc import MutableSequence from . import events as e from .container import HookedContainer from .container import MutableNesting from .events import HookFunction from .mixins import MutableMappingMixin class HookedMapping[T](MutableMappingMixin[T, MutableNesting[T]], HookedContainer[T]): _data: MutableMapping[T, MutableNesting[T]] def __init__( self, existing: MutableMapping[T, MutableNesting[T]], hook: HookFunction | None = None, root: MutableMapping[T] | None = None, path: MutableSequence[int] | None = None, ): match existing: case HookedMapping(_data=seq): self._data = seq case MutableMapping() as seq: self._data = seq case _: raise TypeError(f"Expected a mapping, got {type(existing)}") # self._data = dict(it) self.hook = hook self._root = root if root is not None else self self._path = list(path) if path is not None else [] def __wrap_sub__(self, other, **kwargs): return HookedMapping(other, hook=self.hook, root=self._root, **kwargs) def __getitem__(self, key: T) -> MutableNesting[T]: if key not in self._data: return self.__wrap_sub__(self.__setitem__(key, {}), path=self.new_path(key)) value = self._data[key] match value: case MutableMapping() as mapping: return self.__wrap_sub__(mapping, path=self.new_path(key)) case _ as item: return item def __setitem__( self, key: T, value: MutableNesting[T], *, suppress_hook: bool = False, ) -> MutableNesting[T] | None: match value: case HookedMapping(_data=data): event_type = e.SetItemEvent if key in self._data else e.AddItemEvent self._data[key] = data if not suppress_hook: self._notify(event_type, key, value) return data case _: if suppress_hook: self._data[key] = value else: super().__setitem__(key, value) return value