from collections.abc import MutableMapping, MutableSequence from typing import TypeVar from . import events as e from .container import HookedContainer, HookFunction, MutableNesting T = TypeVar("T") class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]): _data: MutableMapping[T, MutableNesting[T]] def __init__( self, existing: MutableMapping[T, MutableNesting[T]], hook: HookFunction | None = None, path: MutableSequence[int] | None = None, ): self.hook = hook match existing: case HookedMapping(_data=seq): self._data = seq case MutableMapping() as seq: self._data = seq case _ as it: self._data = dict(it) self._data = existing self._path = list(path) if path is not None else [] # MutableMapping Methods def __iter__(self): return iter(self._data) def insert(self, key: T, value: MutableNesting[T]) -> None: self._data[key] = value if self.hook: self.hook(e.AddItemEvent(self.new_path(key), value)) # HookedContainer methods def __getitem__(self, key: T) -> MutableNesting[T]: if key not in self._data: self.insert(key, {}) return HookedMapping(self._data[key], hook=self.hook, path=self.new_path(key)) value = self._data[key] match value: case HookedMapping(_data=seq): return type(self)(seq, hook=self.hook, path=self.new_path(key)) case MutableMapping() as mapping: return HookedMapping(mapping, hook=self.hook, path=self.new_path(key)) case _ as item: return item def __setitem__(self, key: T, value: MutableNesting[T]) -> None: if key not in self._data: self.insert(key, value) else: self._data[key] = value if self.hook: self.hook(e.SetItemEvent(self.new_path(key), value)) def __delitem__(self, key: T) -> None: item = self._data[key] del self._data[key] if self.hook: self.hook(e.RemoveItemEvent(self.new_path(key), item))