Compare commits

..

4 Commits

Author SHA1 Message Date
John Lancaster
1d2fcd13f9 abstractmethods 2026-02-21 22:30:50 -06:00
John Lancaster
428db7366e variable typing 2026-02-21 19:47:32 -06:00
John Lancaster
32ee15348b mutablenesting 2026-02-21 19:14:30 -06:00
John Lancaster
8d598ff135 mapping nested types 2026-02-21 19:11:55 -06:00
4 changed files with 71 additions and 21 deletions

View File

@@ -1,27 +1,39 @@
from collections.abc import Callable, MutableSequence from abc import ABC, abstractmethod
from typing import Generic, TypeVar from collections.abc import MutableMapping, MutableSequence
from typing import Generic, Protocol, TypeVar
from . import events as e from . import events as e
T = TypeVar("T") T = TypeVar("T")
type MutableNesting[T] = T | MutableSequence[T] | MutableMapping[T, MutableNesting[T]]
class HookedContainer(Generic[T]):
class HookFunction(Protocol):
def __call__(self, event: e.ChangeEvent[T]) -> None: ...
class HookedContainer(Generic[T], ABC):
_path: MutableSequence[int] _path: MutableSequence[int]
hook: Callable[[e.ChangeEvent[T]], None] | None hook: HookFunction
def __repr__(self): def __repr__(self):
return f"{self.__class__.__name__}({self._data!r})" return f"{self.__class__.__name__}({self._data!r})"
def __len__(self):
return len(self._data)
def __iter__(self): def __iter__(self):
return iter(self._data) return iter(self._data)
def __contains__(self, value): def __contains__(self, value):
return value in self._data return value in self._data
# MutableSequence Methods
def __len__(self):
return len(self._data)
@abstractmethod
def __getitem__(self, key): ...
def __setitem__(self, s, value): def __setitem__(self, s, value):
self._data[s] = value self._data[s] = value
if self.hook: if self.hook:
@@ -31,3 +43,6 @@ class HookedContainer(Generic[T]):
del self._data[s] del self._data[s]
if self.hook: if self.hook:
self.hook(e.RemoveItemEvent(index=s, item=self._data[s])) self.hook(e.RemoveItemEvent(index=s, item=self._data[s]))
@abstractmethod
def insert(self, index, value): ...

View File

@@ -7,6 +7,7 @@ T = TypeVar("T")
@dataclass(frozen=True) @dataclass(frozen=True)
class ChangeEvent(Generic[T]): class ChangeEvent(Generic[T]):
index: int index: int
item: T
@dataclass(frozen=True) @dataclass(frozen=True)

View File

@@ -1,20 +1,51 @@
from collections.abc import Callable, MutableMapping, MutableSequence, Sequence from collections.abc import MutableMapping, MutableSequence, Sequence
from typing import Generic, TypeVar from copy import copy
from typing import TypeVar
from . import events as e from .common import HookedContainer, MutableNesting
from .sequence import HookedList
T = TypeVar("T") T = TypeVar("T")
class HookedMapping(Generic[T], MutableMapping[T, T | MutableSequence[T], MutableMapping[T]]): class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
_data: MutableSequence[T] _data: MutableMapping[T, MutableNesting[T]]
_path: MutableSequence[int]
hook: Callable[[e.ChangeEvent[T]], None] | None
def __init__(self, hook, existing: MutableMapping[T], path: Sequence[int] | None = None): def __init__(
self,
hook,
existing: MutableMapping[T, MutableNesting[T]],
path: Sequence[int] | None = None,
):
self.hook = hook self.hook = hook
self._data = existing self._data = existing
self._path = list(path) if path is not None else [] self._path = list(path) if path is not None else []
def __setitem__(self, key): def __getitem__(self, key: T) -> MutableNesting[T]:
return value = self._data[key]
match value:
case MutableMapping() as mapping:
new_path = copy(self._path)
new_path.append(key)
return type(self)(self.hook, existing=mapping, path=new_path)
case MutableSequence() as seq:
new_path = copy(self._path)
new_path.append(key)
return HookedList(self.hook, existing=seq, path=new_path)
case _ as item:
return item
def __setitem__(self, key: T, value: MutableNesting[T]) -> None:
self._data[key] = value
if self.hook:
from . import events as e
self.hook(e.SetItemEvent(index=key, item=value))
def __delitem__(self, key: T) -> None:
item = self._data[key]
del self._data[key]
if self.hook:
from . import events as e
self.hook(e.RemoveItemEvent(index=key, item=item))

View File

@@ -1,19 +1,22 @@
from collections.abc import Iterable, MutableSequence, Sequence from collections.abc import MutableSequence
from copy import copy from copy import copy
from typing import TypeVar from typing import TypeVar
from . import events as e from . import events as e
from .common import HookedContainer from .common import HookedContainer, HookFunction
T = TypeVar("T") T = TypeVar("T")
class HookedList(HookedContainer[T], MutableSequence[T]): class HookedList(HookedContainer[T], MutableSequence[T]):
_data: MutableSequence[T] _data: MutableSequence[T]
path: MutableSequence[int]
def __init__(self, hook, existing: Iterable[T], path: Sequence[int] | None = None): def __init__(self, hook: HookFunction, existing: MutableSequence[T], path: MutableSequence[int] | None = None):
self.hook = hook self.hook = hook
match existing: match existing:
case HookedContainer(_data=seq):
self._data = seq
case MutableSequence() as seq: case MutableSequence() as seq:
self._data = seq self._data = seq
case _ as it: case _ as it:
@@ -27,7 +30,7 @@ class HookedList(HookedContainer[T], MutableSequence[T]):
new_path = copy(self._path) new_path = copy(self._path)
new_path.append(s) new_path.append(s)
# print(new_path) # print(new_path)
return HookedList(self.hook, existing=seq, path=new_path) return type(self)(self.hook, existing=seq, path=new_path)
case _ as item: case _ as item:
return item return item