adiumentum 0.1.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
adiumentum/merge.py ADDED
@@ -0,0 +1,113 @@
1
+ from collections.abc import Callable, Hashable, Iterable
2
+ from functools import reduce
3
+ from typing import TypeVar
4
+
5
+ T = TypeVar("T")
6
+ H = TypeVar("H", bound=Hashable)
7
+ TPost = TypeVar("TPost")
8
+ TPre = TypeVar("TPre")
9
+ K = TypeVar("K", bound=Hashable)
10
+ V = TypeVar("V")
11
+ type Filterer[T] = Callable[[T], bool]
12
+
13
+ type IterableVal = list["ValType"] | set[Hashable] | tuple["ValType", ...]
14
+ type ValType = Hashable | IterableVal | dict[Hashable, "ValType"]
15
+ type IterReturnType = list[ValType] | set[Hashable] | tuple[ValType]
16
+ type Mergeable[K, T] = str | object | list[T] | set[T] | tuple[T] | dict[K, "Mergeable"]
17
+
18
+
19
+ def make_hashable(ob: object) -> Hashable:
20
+ def make_sequence_hashable(ob: list[T] | set[T]) -> tuple[T, ...]:
21
+ return tuple(ob)
22
+
23
+ def make_dict_hashable(ob: dict[K, V]) -> tuple[tuple[K, V], ...]:
24
+ return tuple(ob.items())
25
+
26
+ if isinstance(ob, Hashable):
27
+ return ob
28
+ if isinstance(ob, list | set):
29
+ return make_sequence_hashable(ob)
30
+ if isinstance(ob, dict):
31
+ return make_dict_hashable(ob)
32
+ return str(ob)
33
+
34
+
35
+ def join_as_sequence( # noqa: C901,PLR0911
36
+ lv: ValType,
37
+ rv: ValType,
38
+ default_new_type: type[list] | type[tuple] | type[set] = tuple,
39
+ add_duplicates: bool = True,
40
+ ) -> IterableVal:
41
+ def keep_duplicates(a: Iterable, _) -> Iterable:
42
+ return a
43
+
44
+ def remove_duplicates(a: Iterable, b) -> Iterable:
45
+ compare = set(b) if isinstance(b, list | set | tuple) else {b}
46
+ return filter(lambda x: x not in compare, a)
47
+
48
+ filtr = keep_duplicates if add_duplicates else remove_duplicates
49
+
50
+ if isinstance(lv, list):
51
+ if isinstance(rv, list | set | tuple):
52
+ return lv + list(filtr(rv, lv))
53
+ else:
54
+ return lv if rv in lv else [*lv, rv]
55
+ if isinstance(lv, tuple):
56
+ if isinstance(rv, list | set | tuple):
57
+ return (*lv, *filtr(rv, lv))
58
+ else:
59
+ return lv if rv in lv else (*lv, rv)
60
+ if isinstance(lv, set):
61
+ if isinstance(rv, list | set | tuple):
62
+ return {*lv, *filtr(map(make_hashable, rv), lv)}
63
+ else:
64
+ return lv if make_hashable(rv) in lv else {*lv, make_hashable(rv)}
65
+
66
+ if isinstance(rv, list):
67
+ return [lv, *filtr(rv, lv)]
68
+ if isinstance(rv, tuple):
69
+ return (lv, *filtr(rv, lv))
70
+ if isinstance(rv, set):
71
+ return {make_hashable(lv), *filtr(rv, make_hashable(lv))}
72
+
73
+ return default_new_type((lv, rv))
74
+
75
+
76
+ def merge_dicts(
77
+ *dicts: dict[Hashable, ValType],
78
+ default_new_sequence: type[list] | type[tuple] | type[set] = tuple,
79
+ add_duplicates: bool = True,
80
+ ) -> dict[Hashable, ValType]:
81
+ def merge_values(right_val: ValType, left_val: ValType) -> ValType: # noqa: PLR0911
82
+ if left_val == right_val:
83
+ return left_val
84
+ if isinstance(left_val, dict) and isinstance(right_val, dict):
85
+ return merge_dicts(left_val, right_val, default_new_sequence=default_new_sequence)
86
+ if left_val is None:
87
+ return right_val
88
+ if right_val is None:
89
+ return left_val
90
+ if isinstance(left_val, dict):
91
+ return left_val
92
+ if isinstance(right_val, dict):
93
+ return right_val
94
+ return join_as_sequence(
95
+ left_val,
96
+ right_val,
97
+ default_new_type=default_new_sequence,
98
+ add_duplicates=add_duplicates,
99
+ )
100
+
101
+ def merge(
102
+ left: dict[Hashable, ValType], right: dict[Hashable, ValType]
103
+ ) -> dict[Hashable, ValType]:
104
+ common_keys: set[Hashable] = set(left).intersection(set(right))
105
+ common: dict[Hashable, ValType] = {}
106
+ for key in common_keys:
107
+ lv, rv = left[key], right[key]
108
+ new_dict: dict[Hashable, ValType] = {key: merge_values(lv, rv)}
109
+ common.update(new_dict)
110
+
111
+ return left | right | common
112
+
113
+ return reduce(merge, dicts)
@@ -0,0 +1,19 @@
1
+ from abc import abstractmethod
2
+ from pathlib import Path
3
+ from typing import Self
4
+
5
+
6
+ class PathsManager:
7
+ @abstractmethod
8
+ def setup(self) -> None: ...
9
+
10
+ @classmethod
11
+ @abstractmethod
12
+ def auto(cls, root_dir: Path): ...
13
+
14
+ @classmethod
15
+ @abstractmethod
16
+ def read(cls, config_file_path: Path) -> Self: ...
17
+
18
+ @abstractmethod
19
+ def write(self, config_file_path: Path) -> None: ...