From 66b4c1274fab27dc818eb04d6541d35509248f56 Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sun, 22 Feb 2026 21:44:06 -0600 Subject: [PATCH] wrap_sub --- src/hooked_containers/events.py | 9 ++++++--- src/hooked_containers/mapping.py | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/hooked_containers/events.py b/src/hooked_containers/events.py index 1da2798..88d0975 100644 --- a/src/hooked_containers/events.py +++ b/src/hooked_containers/events.py @@ -1,15 +1,18 @@ +from __future__ import annotations + from collections.abc import MutableSequence 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") @dataclass(frozen=True) class ChangeEvent(Generic[T]): - root: MutableNesting[T] = field(repr=False) + root: HookedMapping[T] = field(repr=False) path: MutableSequence[int] item: T diff --git a/src/hooked_containers/mapping.py b/src/hooked_containers/mapping.py index 6327cf7..63878e4 100644 --- a/src/hooked_containers/mapping.py +++ b/src/hooked_containers/mapping.py @@ -15,6 +15,7 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]): self, existing: MutableMapping[T, MutableNesting[T]], hook: HookFunction | None = None, + root: MutableMapping[T] | None = None, path: MutableSequence[int] | None = None, ): match existing: @@ -27,15 +28,19 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]): # self._data = dict(it) self._data = existing 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 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] match value: 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: return item @@ -47,7 +52,11 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]): suppress_hook: bool = False, ) -> MutableNesting[T] | None: 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: case HookedMapping(_data=value): self._data[key] = value @@ -60,4 +69,4 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]): def __delitem__(self, key: T) -> None: item = self._data.pop(key) if self.hook: - self.hook(e.RemoveItemEvent(self, self.new_path(key), item)) + self.hook(e.RemoveItemEvent(self._root, self.new_path(key), item))