Compare commits
5 Commits
842868c491
...
3281c7c1ea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3281c7c1ea | ||
|
|
071c3bd342 | ||
|
|
7c3e073c54 | ||
|
|
0980145b10 | ||
|
|
941e689c19 |
@@ -44,3 +44,12 @@ class HookedContainer(ABC, Sized, Iterable[T], Container[T]):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def insert(self, index, value): ...
|
def insert(self, index, value): ...
|
||||||
|
|
||||||
|
# Custom Methods
|
||||||
|
|
||||||
|
def get_nested(self, keys):
|
||||||
|
"""Recursively call __getitem__ with each key in the iterable."""
|
||||||
|
result = self
|
||||||
|
for key in keys:
|
||||||
|
result = result[key]
|
||||||
|
return result
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from collections.abc import MutableMapping, MutableSequence, Sequence
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
|
from . import events as e
|
||||||
from .common import HookedContainer, MutableNesting
|
from .common import HookedContainer, MutableNesting
|
||||||
from .sequence import HookedList
|
from .sequence import HookedList
|
||||||
|
|
||||||
@@ -23,29 +24,23 @@ class HookedMapping(HookedContainer[T], MutableMapping[T, MutableNesting[T]]):
|
|||||||
|
|
||||||
def __getitem__(self, key: T) -> MutableNesting[T]:
|
def __getitem__(self, key: T) -> MutableNesting[T]:
|
||||||
value = self._data[key]
|
value = self._data[key]
|
||||||
|
new_path = copy(self._path)
|
||||||
|
new_path.append(key)
|
||||||
match value:
|
match value:
|
||||||
case MutableMapping() as mapping:
|
case MutableMapping() as mapping:
|
||||||
new_path = copy(self._path)
|
return HookedMapping(hook=self.hook, existing=mapping, path=new_path)
|
||||||
new_path.append(key)
|
|
||||||
return type(self)(self.hook, existing=mapping, path=new_path)
|
|
||||||
case MutableSequence() as seq:
|
case MutableSequence() as seq:
|
||||||
new_path = copy(self._path)
|
return HookedList(hook=self.hook, existing=seq, path=new_path)
|
||||||
new_path.append(key)
|
|
||||||
return HookedList(self.hook, existing=seq, path=new_path)
|
|
||||||
case _ as item:
|
case _ as item:
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def __setitem__(self, key: T, value: MutableNesting[T]) -> None:
|
def __setitem__(self, key: T, value: MutableNesting[T]) -> None:
|
||||||
self._data[key] = value
|
self._data[key] = value
|
||||||
if self.hook:
|
if self.hook:
|
||||||
from . import events as e
|
|
||||||
|
|
||||||
self.hook(e.SetItemEvent(index=key, item=value))
|
self.hook(e.SetItemEvent(index=key, item=value))
|
||||||
|
|
||||||
def __delitem__(self, key: T) -> None:
|
def __delitem__(self, key: T) -> None:
|
||||||
item = self._data[key]
|
item = self._data[key]
|
||||||
del self._data[key]
|
del self._data[key]
|
||||||
if self.hook:
|
if self.hook:
|
||||||
from . import events as e
|
self.hook(e.RemoveItemEvent(index=key, item=item, path=self._path))
|
||||||
|
|
||||||
self.hook(e.RemoveItemEvent(index=key, item=item))
|
|
||||||
|
|||||||
@@ -12,27 +12,30 @@ class HookedList(HookedContainer[T], MutableSequence[T]):
|
|||||||
_data: MutableSequence[T]
|
_data: MutableSequence[T]
|
||||||
path: MutableSequence[int]
|
path: MutableSequence[int]
|
||||||
|
|
||||||
def __init__(self, hook: HookFunction, existing: MutableSequence[T], path: MutableSequence[int] | None = None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
existing: MutableSequence[T],
|
||||||
|
hook: HookFunction | None = None,
|
||||||
|
path: MutableSequence[int] | None = 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 HookedContainer(_data=seq):
|
||||||
|
self._data = seq
|
||||||
case _ as it:
|
case _ as it:
|
||||||
self._data = list(it)
|
self._data = list(it)
|
||||||
self._path = list(path) if path is not None else []
|
self._path = list(path) if path is not None else []
|
||||||
|
|
||||||
def __getitem__(self, s):
|
def __getitem__(self, s):
|
||||||
|
new_path = copy(self._path)
|
||||||
|
new_path.append(s)
|
||||||
match self._data[s]:
|
match self._data[s]:
|
||||||
case MutableSequence() as seq:
|
case MutableSequence() as seq:
|
||||||
new_path = copy(self._path)
|
return type(self)(seq, self.hook, path=new_path)
|
||||||
new_path.append(s)
|
|
||||||
return type(self)(self.hook, existing=seq, path=new_path)
|
|
||||||
case HookedContainer(_data=seq):
|
case HookedContainer(_data=seq):
|
||||||
new_path = copy(self._path)
|
return type(self)(seq, self.hook, path=new_path)
|
||||||
new_path.append(s)
|
|
||||||
return type(self)(self.hook, existing=seq, path=new_path)
|
|
||||||
case _ as item:
|
case _ as item:
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|||||||
@@ -12,59 +12,64 @@ def get_id(a: Any):
|
|||||||
class TestHookedList:
|
class TestHookedList:
|
||||||
class TestConstruction:
|
class TestConstruction:
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
lst = HookedList(None, existing=[])
|
lst = HookedList([])
|
||||||
assert list(lst) == []
|
assert list(lst) == []
|
||||||
|
|
||||||
def test_with_items(self):
|
def test_with_items(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
assert list(lst) == [1, 2, 3]
|
assert list(lst) == [1, 2, 3]
|
||||||
|
|
||||||
def test_recreation(self):
|
def test_recreation(self):
|
||||||
initial = [1, 2, 3]
|
initial = [1, 2, 3]
|
||||||
initial_id = id(initial)
|
initial_id = id(initial)
|
||||||
|
|
||||||
lst = HookedList(None, existing=initial)
|
lst = HookedList(initial)
|
||||||
assert id(lst._data) == initial_id
|
assert id(lst._data) == initial_id
|
||||||
|
|
||||||
lst2 = HookedList(None, existing=lst)
|
lst2 = HookedList(lst)
|
||||||
assert id(lst2._data) == initial_id
|
assert id(lst2._data) == initial_id
|
||||||
|
|
||||||
class TestSeqOps:
|
class TestSeqOps:
|
||||||
def test_len(self):
|
def test_len(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
assert len(lst) == 3
|
assert len(lst) == 3
|
||||||
|
|
||||||
def test_getitem(self):
|
def test_getitem(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
assert lst[0] == 1
|
assert lst[0] == 1
|
||||||
assert lst[1] == 2
|
assert lst[1] == 2
|
||||||
assert lst[-1] == 3
|
assert lst[-1] == 3
|
||||||
|
|
||||||
def test_contains(self):
|
def test_contains(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
assert 2 in lst
|
assert 2 in lst
|
||||||
assert 4 not in lst
|
assert 4 not in lst
|
||||||
|
|
||||||
def test_iter(self):
|
def test_iter(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
for i, item in enumerate(lst, start=1):
|
for i, item in enumerate(lst, start=1):
|
||||||
assert item == i
|
assert item == i
|
||||||
|
|
||||||
class TestMutableOps:
|
class TestMutableOps:
|
||||||
def test_setitem(self):
|
def test_setitem(self):
|
||||||
added = []
|
added = []
|
||||||
lst = HookedList(lambda e: added.append(e.item), existing=[1, 2, 3])
|
lst = HookedList(
|
||||||
|
[1, 2, [4, 5, [6, 7]]],
|
||||||
|
lambda e: added.append(e.item),
|
||||||
|
)
|
||||||
lst[0] = 10
|
lst[0] = 10
|
||||||
lst.append(20)
|
lst.append(20)
|
||||||
assert list(lst) == [10, 2, 3, 20]
|
|
||||||
assert added == [10, 20]
|
assert added == [10, 20]
|
||||||
|
|
||||||
|
lst[2][-1].append(8)
|
||||||
|
assert added == [10, 20, 8]
|
||||||
|
|
||||||
def test_delitem(self):
|
def test_delitem(self):
|
||||||
lst = HookedList(None, existing=[1, 2, 3])
|
lst = HookedList([1, 2, 3])
|
||||||
del lst[1]
|
del lst[1]
|
||||||
assert list(lst) == [1, 3]
|
assert list(lst) == [1, 3]
|
||||||
|
|
||||||
def test_insert(self):
|
def test_insert(self):
|
||||||
lst = HookedList(None, existing=[1, 3])
|
lst = HookedList([1, 3])
|
||||||
lst.insert(1, 2)
|
lst.insert(1, 2)
|
||||||
assert list(lst) == [1, 2, 3]
|
assert list(lst) == [1, 2, 3]
|
||||||
|
|||||||
Reference in New Issue
Block a user