This commit is contained in:
John Lancaster
2026-02-22 21:44:06 -06:00
parent 0c3dfde336
commit 66b4c1274f
2 changed files with 19 additions and 7 deletions

View File

@@ -1,15 +1,18 @@
from __future__ import annotations
from collections.abc import MutableSequence from collections.abc import MutableSequence
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Generic, Protocol, TypeVar from typing import TYPE_CHECKING, Generic, Protocol, TypeVar
from .types import MutableNesting if TYPE_CHECKING:
from .mapping import HookedMapping
T = TypeVar("T") T = TypeVar("T")
@dataclass(frozen=True) @dataclass(frozen=True)
class ChangeEvent(Generic[T]): class ChangeEvent(Generic[T]):
root: MutableNesting[T] = field(repr=False) root: HookedMapping[T] = field(repr=False)
path: MutableSequence[int] path: MutableSequence[int]
item: T item: T

View File

@@ -15,6 +15,7 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
self, self,
existing: MutableMapping[T, MutableNesting[T]], existing: MutableMapping[T, MutableNesting[T]],
hook: HookFunction | None = None, hook: HookFunction | None = None,
root: MutableMapping[T] | None = None,
path: MutableSequence[int] | None = None, path: MutableSequence[int] | None = None,
): ):
match existing: match existing:
@@ -27,15 +28,19 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
# self._data = dict(it) # self._data = dict(it)
self._data = existing self._data = existing
self.hook = hook self.hook = hook
self._root = root if root is not None else self
self._path = list(path) if path is not None else [] 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]: def __getitem__(self, key: T) -> MutableNesting[T]:
if key not in self._data: if key not in self._data:
return HookedMapping(self.__setitem__(key, {}), hook=self.hook, path=self.new_path(key)) return self.__wrap_sub__(self.__setitem__(key, {}), path=self.new_path(key))
value = self._data[key] value = self._data[key]
match value: match value:
case MutableMapping() as mapping: case MutableMapping() as mapping:
return HookedMapping(mapping, hook=self.hook, path=self.new_path(key)) return self.__wrap_sub__(mapping, path=self.new_path(key))
case _ as item: case _ as item:
return item return item
@@ -47,7 +52,11 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
suppress_hook: bool = False, suppress_hook: bool = False,
) -> MutableNesting[T] | None: ) -> MutableNesting[T] | None:
new_path = self.new_path(key) new_path = self.new_path(key)
event = e.SetItemEvent(self, new_path, value) if key in self._data else e.AddItemEvent(self, new_path, value) event = (
e.SetItemEvent(self._root, new_path, value)
if key in self._data
else e.AddItemEvent(self._root, new_path, value)
)
match value: match value:
case HookedMapping(_data=value): case HookedMapping(_data=value):
self._data[key] = value self._data[key] = value
@@ -60,4 +69,4 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
def __delitem__(self, key: T) -> None: def __delitem__(self, key: T) -> None:
item = self._data.pop(key) item = self._data.pop(key)
if self.hook: if self.hook:
self.hook(e.RemoveItemEvent(self, self.new_path(key), item)) self.hook(e.RemoveItemEvent(self._root, self.new_path(key), item))