Compare commits
2 Commits
1d2fcd13f9
...
54e2febf3b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54e2febf3b | ||
|
|
58ab0aae6c |
@@ -19,6 +19,9 @@ dev = [
|
|||||||
"rich>=14.3.3",
|
"rich>=14.3.3",
|
||||||
"ruff>=0.15.2",
|
"ruff>=0.15.2",
|
||||||
]
|
]
|
||||||
|
test = [
|
||||||
|
"pytest>=9.0.2",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
|
|||||||
@@ -20,19 +20,17 @@ class HookedContainer(Generic[T], ABC):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}({self._data!r})"
|
return f"{self.__class__.__name__}({self._data!r})"
|
||||||
|
|
||||||
def __iter__(self):
|
# Sequence Methods
|
||||||
return iter(self._data)
|
# __contains__, __iter__, __reversed__, index, and count
|
||||||
|
|
||||||
def __contains__(self, value):
|
@abstractmethod
|
||||||
return value in self._data
|
def __getitem__(self, key): ...
|
||||||
|
|
||||||
# MutableSequence Methods
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@abstractmethod
|
# MutableSequence Methods
|
||||||
def __getitem__(self, key): ...
|
# append, reverse, extend, pop, remove, and __iadd__
|
||||||
|
|
||||||
def __setitem__(self, s, value):
|
def __setitem__(self, s, value):
|
||||||
self._data[s] = value
|
self._data[s] = value
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class HookedList(HookedContainer[T], MutableSequence[T]):
|
|||||||
def __getitem__(self, s):
|
def __getitem__(self, s):
|
||||||
# print("Getting item:", s)
|
# print("Getting item:", s)
|
||||||
match self._data[s]:
|
match self._data[s]:
|
||||||
case MutableSequence() as seq:
|
case HookedContainer(_data=seq):
|
||||||
new_path = copy(self._path)
|
new_path = copy(self._path)
|
||||||
new_path.append(s)
|
new_path.append(s)
|
||||||
# print(new_path)
|
# print(new_path)
|
||||||
|
|||||||
22
src/hooked_containers/state.py
Normal file
22
src/hooked_containers/state.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from .mapping import HookedMapping
|
||||||
|
|
||||||
|
|
||||||
|
class DomainState(HookedMapping[str]):
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
super().__setitem__(key, value)
|
||||||
|
super().__setitem__("last_changed", datetime.now())
|
||||||
|
|
||||||
|
|
||||||
|
class NameSpaceState(HookedMapping[str]):
|
||||||
|
_data: DomainState
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
super().__setitem__(key, value)
|
||||||
|
# print("ns SetItem")
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
val = super().__getitem__(key)
|
||||||
|
# print("ns GetItem")
|
||||||
|
return DomainState(self.hook, existing=val, path=self._path + [key])
|
||||||
70
tests/test_sequence.py
Normal file
70
tests/test_sequence.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from hooked_containers.sequence import HookedList
|
||||||
|
|
||||||
|
|
||||||
|
def get_id(a: Any):
|
||||||
|
return str(hex(id(a)))
|
||||||
|
|
||||||
|
|
||||||
|
class TestHookedList:
|
||||||
|
class TestConstruction:
|
||||||
|
def test_empty(self):
|
||||||
|
lst = HookedList(None, existing=[])
|
||||||
|
assert list(lst) == []
|
||||||
|
|
||||||
|
def test_with_items(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
assert list(lst) == [1, 2, 3]
|
||||||
|
|
||||||
|
def test_recreation(self):
|
||||||
|
initial = [1, 2, 3]
|
||||||
|
initial_id = id(initial)
|
||||||
|
|
||||||
|
lst = HookedList(None, existing=initial)
|
||||||
|
assert id(lst._data) == initial_id
|
||||||
|
|
||||||
|
lst2 = HookedList(None, existing=lst)
|
||||||
|
assert id(lst2._data) == initial_id
|
||||||
|
|
||||||
|
class TestSeqOps:
|
||||||
|
def test_len(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
assert len(lst) == 3
|
||||||
|
|
||||||
|
def test_getitem(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
assert lst[0] == 1
|
||||||
|
assert lst[1] == 2
|
||||||
|
assert lst[-1] == 3
|
||||||
|
|
||||||
|
def test_contains(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
assert 2 in lst
|
||||||
|
assert 4 not in lst
|
||||||
|
|
||||||
|
def test_iter(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
for i, item in enumerate(lst, start=1):
|
||||||
|
assert item == i
|
||||||
|
|
||||||
|
class TestMutableOps:
|
||||||
|
def test_setitem(self):
|
||||||
|
added = []
|
||||||
|
lst = HookedList(lambda e: added.append(e.item), existing=[1, 2, 3])
|
||||||
|
lst[0] = 10
|
||||||
|
lst.append(20)
|
||||||
|
assert list(lst) == [10, 2, 3, 20]
|
||||||
|
assert added == [10, 20]
|
||||||
|
|
||||||
|
def test_delitem(self):
|
||||||
|
lst = HookedList(None, existing=[1, 2, 3])
|
||||||
|
del lst[1]
|
||||||
|
assert list(lst) == [1, 3]
|
||||||
|
|
||||||
|
def test_insert(self):
|
||||||
|
lst = HookedList(None, existing=[1, 3])
|
||||||
|
lst.insert(1, 2)
|
||||||
|
assert list(lst) == [1, 2, 3]
|
||||||
38
uv.lock
generated
38
uv.lock
generated
@@ -145,6 +145,9 @@ dev = [
|
|||||||
{ name = "rich" },
|
{ name = "rich" },
|
||||||
{ name = "ruff" },
|
{ name = "ruff" },
|
||||||
]
|
]
|
||||||
|
test = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
|
|
||||||
@@ -154,6 +157,16 @@ dev = [
|
|||||||
{ name = "rich", specifier = ">=14.3.3" },
|
{ name = "rich", specifier = ">=14.3.3" },
|
||||||
{ name = "ruff", specifier = ">=0.15.2" },
|
{ name = "ruff", specifier = ">=0.15.2" },
|
||||||
]
|
]
|
||||||
|
test = [{ name = "pytest", specifier = ">=9.0.2" }]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipykernel"
|
name = "ipykernel"
|
||||||
@@ -334,6 +347,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
|
{ url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prompt-toolkit"
|
name = "prompt-toolkit"
|
||||||
version = "3.0.52"
|
version = "3.0.52"
|
||||||
@@ -410,6 +432,22 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "9.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "iniconfig" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pluggy" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
version = "2.9.0.post0"
|
||||||
|
|||||||
Reference in New Issue
Block a user