Files
hooked-containers/src/hooked_containers/mapping.py
T
2026-10-08 20:50:03 -05:00

66 lines
2.2 KiB
Python

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