Coverage for src/extratools_core/crudl.py: 100%

48 statements  

« prev     ^ index     » next       coverage.py v7.8.1, created at 2025-06-11 07:53 -0700

1from collections.abc import Callable, Iterable, Iterator, MutableMapping 

2from typing import Any, cast 

3 

4 

5class CRUDLWrapper[KT: Any, VT: Any]: 

6 def __init__(self, mapping: MutableMapping[KT, VT]) -> None: 

7 self.mapping = mapping 

8 

9 def create(self, key: KT, value: VT) -> VT: 

10 if key in self.mapping: 

11 raise KeyError 

12 

13 self.mapping[key] = value 

14 return value 

15 

16 def read(self, key: KT) -> VT: 

17 return self.mapping[key] 

18 

19 def update(self, key: KT, value: VT) -> VT: 

20 if key not in self.mapping: 

21 raise KeyError 

22 

23 self.mapping[key] = value 

24 return value 

25 

26 def delete(self, key: KT) -> VT: 

27 default = object() 

28 value = self.mapping.pop(key, default) 

29 if value == default: 

30 raise KeyError 

31 

32 return cast("VT", value) 

33 

34 def list(self) -> Iterable[tuple[KT, VT]]: 

35 return self.mapping.items() 

36 

37 

38class CRUDLDict[KT: Any, VT: Any](MutableMapping[KT, VT]): 

39 def __init__( 

40 self, 

41 *, 

42 create_func: Callable[[KT | None, Any], VT | None], 

43 read_func: Callable[[KT], VT], 

44 update_func: Callable[[KT, Any], VT | None], 

45 delete_func: Callable[[KT], VT | None], 

46 list_func: Callable[[], Iterable[tuple[KT, VT | None]]], 

47 ) -> None: 

48 self.__create_func = create_func 

49 self.__read_func = read_func 

50 self.__update_func = update_func 

51 self.__delete_func = delete_func 

52 self.__list_func = list_func 

53 

54 def __delitem__(self, key: KT) -> None: 

55 self.__delete_func(key) 

56 

57 def __getitem__(self, key: KT) -> VT: 

58 return self.__read_func(key) 

59 

60 def __setitem__(self, key: KT | None, value: VT) -> None: 

61 if key is None or key not in self: 

62 self.__create_func(key, value) 

63 else: 

64 self.__update_func(key, value) 

65 

66 def __iter__(self) -> Iterator[KT]: 

67 for key, _ in self.__list_func(): 

68 yield key 

69 

70 def __len__(self) -> int: 

71 # Cannot use `count` in `toolz` as itself depends on this function 

72 count = 0 

73 for _ in self: 

74 count += 1 

75 return count