Coverage for src/extratools_core/crudl.py: 100%
51 statements
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-11 20:59 -0700
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-11 20:59 -0700
1from collections.abc import Callable, Iterable, Iterator, MutableMapping
2from typing import Any, cast
5class CRUDLWrapper[KT: Any, VT: Any]:
6 def __init__(self, mapping: MutableMapping[KT, VT]) -> None:
7 self.mapping = mapping
9 def create(self, key: KT, value: VT) -> VT:
10 if key in self.mapping:
11 raise KeyError
13 self.mapping[key] = value
14 return value
16 def read(self, key: KT) -> VT:
17 return self.mapping[key]
19 def update(self, key: KT, value: VT) -> VT:
20 if key not in self.mapping:
21 raise KeyError
23 self.mapping[key] = value
24 return value
26 def delete(self, key: KT) -> VT:
27 default = object()
28 value = self.mapping.pop(key, default)
29 if value == default:
30 raise KeyError
32 return cast("VT", value)
34 def list(self, filter_func: Callable[[KT], bool] | None = None) -> Iterable[tuple[KT, VT]]:
35 if filter_func is None:
36 yield from self.mapping.items()
37 else:
38 for key in filter(filter_func, self.mapping):
39 yield key, self.mapping[key]
42class CRUDLDict[KT: Any, VT: Any](MutableMapping[KT, VT]):
43 def __init__(
44 self,
45 *,
46 create_func: Callable[[KT | None, Any], VT | None],
47 read_func: Callable[[KT], VT],
48 update_func: Callable[[KT, Any], VT | None],
49 delete_func: Callable[[KT], VT | None],
50 list_func: Callable[[Any | None], Iterable[tuple[KT, VT | None]]],
51 ) -> None:
52 self.__create_func = create_func
53 self.__read_func = read_func
54 self.__update_func = update_func
55 self.__delete_func = delete_func
56 self.__list_func = list_func
58 def __delitem__(self, key: KT) -> None:
59 self.__delete_func(key)
61 def __getitem__(self, key: KT) -> VT:
62 return self.__read_func(key)
64 def __setitem__(self, key: KT | None, value: VT) -> None:
65 if key is None or key not in self:
66 self.__create_func(key, value)
67 else:
68 self.__update_func(key, value)
70 def __iter__(self) -> Iterator[KT]:
71 for key, _ in self.__list_func(None):
72 yield key
74 def __len__(self) -> int:
75 # Cannot use `count` in `toolz` as itself depends on this function
76 count = 0
77 for _ in self:
78 count += 1
79 return count