omlish 0.0.0.dev1__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +7 -0
- omlish/__init__.py +0 -0
- omlish/argparse.py +223 -0
- omlish/asyncs/__init__.py +17 -0
- omlish/asyncs/anyio.py +23 -0
- omlish/asyncs/asyncio.py +19 -0
- omlish/asyncs/asyncs.py +76 -0
- omlish/asyncs/futures.py +179 -0
- omlish/asyncs/trio.py +11 -0
- omlish/c3.py +173 -0
- omlish/cached.py +9 -0
- omlish/check.py +231 -0
- omlish/collections/__init__.py +63 -0
- omlish/collections/_abc.py +156 -0
- omlish/collections/_io_abc.py +78 -0
- omlish/collections/cache/__init__.py +11 -0
- omlish/collections/cache/descriptor.py +188 -0
- omlish/collections/cache/impl.py +485 -0
- omlish/collections/cache/types.py +37 -0
- omlish/collections/coerce.py +337 -0
- omlish/collections/frozen.py +148 -0
- omlish/collections/identity.py +106 -0
- omlish/collections/indexed.py +75 -0
- omlish/collections/mappings.py +127 -0
- omlish/collections/ordered.py +81 -0
- omlish/collections/persistent.py +36 -0
- omlish/collections/skiplist.py +193 -0
- omlish/collections/sorted.py +126 -0
- omlish/collections/treap.py +228 -0
- omlish/collections/treapmap.py +144 -0
- omlish/collections/unmodifiable.py +174 -0
- omlish/collections/utils.py +110 -0
- omlish/configs/__init__.py +0 -0
- omlish/configs/flattening.py +147 -0
- omlish/configs/props.py +64 -0
- omlish/dataclasses/__init__.py +83 -0
- omlish/dataclasses/impl/__init__.py +6 -0
- omlish/dataclasses/impl/api.py +260 -0
- omlish/dataclasses/impl/as_.py +76 -0
- omlish/dataclasses/impl/exceptions.py +2 -0
- omlish/dataclasses/impl/fields.py +148 -0
- omlish/dataclasses/impl/frozen.py +55 -0
- omlish/dataclasses/impl/hashing.py +85 -0
- omlish/dataclasses/impl/init.py +173 -0
- omlish/dataclasses/impl/internals.py +118 -0
- omlish/dataclasses/impl/main.py +150 -0
- omlish/dataclasses/impl/metaclass.py +126 -0
- omlish/dataclasses/impl/metadata.py +74 -0
- omlish/dataclasses/impl/order.py +47 -0
- omlish/dataclasses/impl/params.py +150 -0
- omlish/dataclasses/impl/processing.py +16 -0
- omlish/dataclasses/impl/reflect.py +173 -0
- omlish/dataclasses/impl/replace.py +40 -0
- omlish/dataclasses/impl/repr.py +34 -0
- omlish/dataclasses/impl/simple.py +92 -0
- omlish/dataclasses/impl/slots.py +80 -0
- omlish/dataclasses/impl/utils.py +167 -0
- omlish/defs.py +193 -0
- omlish/dispatch/__init__.py +3 -0
- omlish/dispatch/dispatch.py +137 -0
- omlish/dispatch/functions.py +52 -0
- omlish/dispatch/methods.py +162 -0
- omlish/docker.py +149 -0
- omlish/dynamic.py +220 -0
- omlish/graphs/__init__.py +0 -0
- omlish/graphs/dot/__init__.py +19 -0
- omlish/graphs/dot/items.py +162 -0
- omlish/graphs/dot/rendering.py +147 -0
- omlish/graphs/dot/utils.py +30 -0
- omlish/graphs/trees.py +249 -0
- omlish/http/__init__.py +0 -0
- omlish/http/consts.py +20 -0
- omlish/http/wsgi.py +34 -0
- omlish/inject/__init__.py +85 -0
- omlish/inject/binder.py +12 -0
- omlish/inject/bindings.py +49 -0
- omlish/inject/eagers.py +21 -0
- omlish/inject/elements.py +43 -0
- omlish/inject/exceptions.py +49 -0
- omlish/inject/impl/__init__.py +0 -0
- omlish/inject/impl/bindings.py +19 -0
- omlish/inject/impl/elements.py +154 -0
- omlish/inject/impl/injector.py +182 -0
- omlish/inject/impl/inspect.py +98 -0
- omlish/inject/impl/private.py +109 -0
- omlish/inject/impl/providers.py +132 -0
- omlish/inject/impl/scopes.py +198 -0
- omlish/inject/injector.py +40 -0
- omlish/inject/inspect.py +14 -0
- omlish/inject/keys.py +43 -0
- omlish/inject/managed.py +24 -0
- omlish/inject/overrides.py +18 -0
- omlish/inject/private.py +29 -0
- omlish/inject/providers.py +111 -0
- omlish/inject/proxy.py +48 -0
- omlish/inject/scopes.py +84 -0
- omlish/inject/types.py +21 -0
- omlish/iterators.py +184 -0
- omlish/json.py +194 -0
- omlish/lang/__init__.py +112 -0
- omlish/lang/cached.py +267 -0
- omlish/lang/classes/__init__.py +24 -0
- omlish/lang/classes/abstract.py +74 -0
- omlish/lang/classes/restrict.py +137 -0
- omlish/lang/classes/simple.py +120 -0
- omlish/lang/classes/test/__init__.py +0 -0
- omlish/lang/classes/test/test_abstract.py +89 -0
- omlish/lang/classes/test/test_restrict.py +71 -0
- omlish/lang/classes/test/test_simple.py +58 -0
- omlish/lang/classes/test/test_virtual.py +72 -0
- omlish/lang/classes/virtual.py +130 -0
- omlish/lang/clsdct.py +67 -0
- omlish/lang/cmp.py +63 -0
- omlish/lang/contextmanagers.py +249 -0
- omlish/lang/datetimes.py +67 -0
- omlish/lang/descriptors.py +52 -0
- omlish/lang/functions.py +126 -0
- omlish/lang/imports.py +153 -0
- omlish/lang/iterables.py +54 -0
- omlish/lang/maybes.py +136 -0
- omlish/lang/objects.py +103 -0
- omlish/lang/resolving.py +50 -0
- omlish/lang/strings.py +128 -0
- omlish/lang/typing.py +92 -0
- omlish/libc.py +532 -0
- omlish/logs/__init__.py +9 -0
- omlish/logs/_abc.py +247 -0
- omlish/logs/configs.py +62 -0
- omlish/logs/filters.py +9 -0
- omlish/logs/formatters.py +67 -0
- omlish/logs/utils.py +20 -0
- omlish/marshal/__init__.py +52 -0
- omlish/marshal/any.py +25 -0
- omlish/marshal/base.py +201 -0
- omlish/marshal/base64.py +25 -0
- omlish/marshal/dataclasses.py +115 -0
- omlish/marshal/datetimes.py +90 -0
- omlish/marshal/enums.py +43 -0
- omlish/marshal/exceptions.py +7 -0
- omlish/marshal/factories.py +129 -0
- omlish/marshal/global_.py +33 -0
- omlish/marshal/iterables.py +57 -0
- omlish/marshal/mappings.py +66 -0
- omlish/marshal/naming.py +17 -0
- omlish/marshal/objects.py +106 -0
- omlish/marshal/optionals.py +49 -0
- omlish/marshal/polymorphism.py +147 -0
- omlish/marshal/primitives.py +43 -0
- omlish/marshal/registries.py +57 -0
- omlish/marshal/standard.py +80 -0
- omlish/marshal/utils.py +23 -0
- omlish/marshal/uuids.py +29 -0
- omlish/marshal/values.py +30 -0
- omlish/math.py +184 -0
- omlish/os.py +32 -0
- omlish/reflect.py +359 -0
- omlish/replserver/__init__.py +5 -0
- omlish/replserver/__main__.py +4 -0
- omlish/replserver/console.py +247 -0
- omlish/replserver/server.py +146 -0
- omlish/runmodule.py +28 -0
- omlish/stats.py +342 -0
- omlish/term.py +222 -0
- omlish/testing/__init__.py +7 -0
- omlish/testing/pydevd.py +225 -0
- omlish/testing/pytest/__init__.py +8 -0
- omlish/testing/pytest/helpers.py +35 -0
- omlish/testing/pytest/inject/__init__.py +1 -0
- omlish/testing/pytest/inject/harness.py +159 -0
- omlish/testing/pytest/plugins/__init__.py +20 -0
- omlish/testing/pytest/plugins/_registry.py +6 -0
- omlish/testing/pytest/plugins/logging.py +13 -0
- omlish/testing/pytest/plugins/pycharm.py +54 -0
- omlish/testing/pytest/plugins/repeat.py +19 -0
- omlish/testing/pytest/plugins/skips.py +32 -0
- omlish/testing/pytest/plugins/spacing.py +19 -0
- omlish/testing/pytest/plugins/switches.py +70 -0
- omlish/testing/testing.py +102 -0
- omlish/text/__init__.py +0 -0
- omlish/text/delimit.py +171 -0
- omlish/text/indent.py +50 -0
- omlish/text/parts.py +265 -0
- omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
- omlish-0.0.0.dev1.dist-info/METADATA +17 -0
- omlish-0.0.0.dev1.dist-info/RECORD +187 -0
- omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
- omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
K = ta.TypeVar('K')
|
|
6
|
+
V = ta.TypeVar('V')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OverweightException(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Eviction: ta.TypeAlias = ta.Callable[['Cache'], None]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Cache(ta.MutableMapping[K, V]):
|
|
17
|
+
"""
|
|
18
|
+
https://google.github.io/guava/releases/16.0/api/docs/com/google/common/cache/CacheBuilder.html
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@abc.abstractmethod
|
|
22
|
+
def reap(self) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
class Stats(ta.NamedTuple):
|
|
26
|
+
seq: int
|
|
27
|
+
size: int
|
|
28
|
+
weight: float
|
|
29
|
+
hits: int
|
|
30
|
+
misses: int
|
|
31
|
+
max_size_ever: int
|
|
32
|
+
max_weight_ever: float
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def stats(self) -> Stats:
|
|
37
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import check
|
|
4
|
+
from .frozen import FrozenDict
|
|
5
|
+
from .frozen import FrozenList
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
T = ta.TypeVar('T')
|
|
9
|
+
T2 = ta.TypeVar('T2')
|
|
10
|
+
K = ta.TypeVar('K')
|
|
11
|
+
K2 = ta.TypeVar('K2')
|
|
12
|
+
V = ta.TypeVar('V')
|
|
13
|
+
V2 = ta.TypeVar('V2')
|
|
14
|
+
|
|
15
|
+
_map = map
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _unpack_fn(fn):
|
|
19
|
+
if isinstance(fn, tuple):
|
|
20
|
+
return check.of_isinstance(fn)
|
|
21
|
+
elif isinstance(fn, type) or callable(fn):
|
|
22
|
+
return fn
|
|
23
|
+
else:
|
|
24
|
+
raise TypeError(fn)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# region seq
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def seq(
|
|
31
|
+
it: ta.Iterable[T],
|
|
32
|
+
) -> ta.Sequence[T]:
|
|
33
|
+
if isinstance(it, str):
|
|
34
|
+
raise TypeError(it)
|
|
35
|
+
elif isinstance(it, FrozenList):
|
|
36
|
+
return it
|
|
37
|
+
else:
|
|
38
|
+
return FrozenList(it)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def opt_seq(
|
|
42
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
43
|
+
) -> ta.Optional[ta.Sequence[T]]:
|
|
44
|
+
if it is None:
|
|
45
|
+
return None
|
|
46
|
+
else:
|
|
47
|
+
return seq(it)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def seq_or_none(
|
|
51
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
52
|
+
) -> ta.Optional[ta.Sequence[T]]:
|
|
53
|
+
ret = opt_seq(it)
|
|
54
|
+
if ret:
|
|
55
|
+
return ret
|
|
56
|
+
else:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def seq_of(
|
|
61
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
62
|
+
) -> ta.Callable[[ta.Iterable[T]], ta.Sequence[T2]]:
|
|
63
|
+
def inner(it):
|
|
64
|
+
return seq(fn(e) for e in it) # type: ignore
|
|
65
|
+
|
|
66
|
+
fn = _unpack_fn(fn)
|
|
67
|
+
return inner
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def opt_seq_of(
|
|
71
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
72
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[ta.Sequence[T2]]]:
|
|
73
|
+
def inner(it):
|
|
74
|
+
if it is None:
|
|
75
|
+
return None
|
|
76
|
+
else:
|
|
77
|
+
return seq(fn(e) for e in it) # type: ignore
|
|
78
|
+
|
|
79
|
+
fn = _unpack_fn(fn)
|
|
80
|
+
return inner
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def seq_of_or_none(
|
|
84
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
85
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[ta.Sequence[T2]]]:
|
|
86
|
+
def inner(it):
|
|
87
|
+
if it is None:
|
|
88
|
+
return None
|
|
89
|
+
else:
|
|
90
|
+
ret = seq(fn(e) for e in it) # type: ignore
|
|
91
|
+
if ret:
|
|
92
|
+
return ret
|
|
93
|
+
else:
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
fn = _unpack_fn(fn)
|
|
97
|
+
return inner
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# endregion
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# region abs_set
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def abs_set(
|
|
107
|
+
it: ta.Iterable[T],
|
|
108
|
+
) -> ta.AbstractSet[T]:
|
|
109
|
+
if isinstance(it, str):
|
|
110
|
+
raise TypeError(it)
|
|
111
|
+
elif isinstance(it, frozenset):
|
|
112
|
+
return it
|
|
113
|
+
else:
|
|
114
|
+
return frozenset(it)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def opt_abs_set(
|
|
118
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
119
|
+
) -> ta.Optional[ta.AbstractSet[T]]:
|
|
120
|
+
if it is None:
|
|
121
|
+
return None
|
|
122
|
+
else:
|
|
123
|
+
return abs_set(it)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def abs_set_or_none(
|
|
127
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
128
|
+
) -> ta.Optional[ta.AbstractSet[T]]:
|
|
129
|
+
ret = opt_abs_set(it)
|
|
130
|
+
if ret:
|
|
131
|
+
return ret
|
|
132
|
+
else:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def abs_set_of(
|
|
137
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
138
|
+
) -> ta.Callable[[ta.Iterable[T]], ta.AbstractSet[T2]]:
|
|
139
|
+
def inner(it):
|
|
140
|
+
return abs_set(fn(e) for e in it) # type: ignore
|
|
141
|
+
|
|
142
|
+
fn = _unpack_fn(fn)
|
|
143
|
+
return inner
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def opt_abs_set_of(
|
|
147
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
148
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[ta.AbstractSet[T2]]]:
|
|
149
|
+
def inner(it):
|
|
150
|
+
if it is None:
|
|
151
|
+
return None
|
|
152
|
+
else:
|
|
153
|
+
return abs_set(fn(e) for e in it) # type: ignore
|
|
154
|
+
|
|
155
|
+
fn = _unpack_fn(fn)
|
|
156
|
+
return inner
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def abs_set_of_or_none(
|
|
160
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
161
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[ta.AbstractSet[T2]]]:
|
|
162
|
+
def inner(it):
|
|
163
|
+
if it is None:
|
|
164
|
+
return None
|
|
165
|
+
else:
|
|
166
|
+
ret = abs_set(fn(e) for e in it) # type: ignore
|
|
167
|
+
if ret:
|
|
168
|
+
return ret
|
|
169
|
+
else:
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
fn = _unpack_fn(fn)
|
|
173
|
+
return inner
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# endregion
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# region frozenset
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def frozenset_(
|
|
183
|
+
it: ta.Iterable[T],
|
|
184
|
+
) -> frozenset[T]:
|
|
185
|
+
if isinstance(it, str):
|
|
186
|
+
raise TypeError(it)
|
|
187
|
+
elif isinstance(it, frozenset):
|
|
188
|
+
return it
|
|
189
|
+
else:
|
|
190
|
+
return frozenset(it)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def opt_frozenset(
|
|
194
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
195
|
+
) -> ta.Optional[frozenset[T]]:
|
|
196
|
+
if it is None:
|
|
197
|
+
return None
|
|
198
|
+
else:
|
|
199
|
+
return frozenset_(it)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def frozenset_or_none(
|
|
203
|
+
it: ta.Optional[ta.Iterable[T]],
|
|
204
|
+
) -> ta.Optional[frozenset[T]]:
|
|
205
|
+
ret = opt_frozenset(it)
|
|
206
|
+
if ret:
|
|
207
|
+
return ret
|
|
208
|
+
else:
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def frozenset_of(
|
|
213
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
214
|
+
) -> ta.Callable[[ta.Iterable[T]], frozenset[T2]]:
|
|
215
|
+
def inner(it):
|
|
216
|
+
return frozenset_(fn(e) for e in it) # type: ignore
|
|
217
|
+
|
|
218
|
+
fn = _unpack_fn(fn)
|
|
219
|
+
return inner
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def opt_frozenset_of(
|
|
223
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
224
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[frozenset[T2]]]:
|
|
225
|
+
def inner(it):
|
|
226
|
+
if it is None:
|
|
227
|
+
return None
|
|
228
|
+
else:
|
|
229
|
+
return frozenset_(fn(e) for e in it) # type: ignore
|
|
230
|
+
|
|
231
|
+
fn = _unpack_fn(fn)
|
|
232
|
+
return inner
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def frozenset_of_or_none(
|
|
236
|
+
fn: ta.Union[ta.Callable[[T], T2], tuple],
|
|
237
|
+
) -> ta.Callable[[ta.Optional[ta.Iterable[T]]], ta.Optional[frozenset[T2]]]:
|
|
238
|
+
def inner(it):
|
|
239
|
+
if it is None:
|
|
240
|
+
return None
|
|
241
|
+
else:
|
|
242
|
+
ret = frozenset_(fn(e) for e in it) # type: ignore
|
|
243
|
+
if ret:
|
|
244
|
+
return ret
|
|
245
|
+
else:
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
fn = _unpack_fn(fn)
|
|
249
|
+
return inner
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# endregion
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# region map
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def map(
|
|
259
|
+
src: ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]],
|
|
260
|
+
) -> ta.Mapping[K, V]:
|
|
261
|
+
return FrozenDict(src)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def opt_map(
|
|
265
|
+
src: ta.Optional[ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]]],
|
|
266
|
+
) -> ta.Optional[ta.Mapping[K, V]]:
|
|
267
|
+
if src is None:
|
|
268
|
+
return None
|
|
269
|
+
else:
|
|
270
|
+
return map(src)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def map_or_none(
|
|
274
|
+
src: ta.Optional[ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]]],
|
|
275
|
+
) -> ta.Optional[ta.Mapping[K, V]]:
|
|
276
|
+
ret = opt_map(src)
|
|
277
|
+
if ret:
|
|
278
|
+
return ret
|
|
279
|
+
else:
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def map_of(
|
|
284
|
+
key_fn: ta.Union[ta.Callable[[K], K2], tuple],
|
|
285
|
+
value_fn: ta.Union[ta.Callable[[V], V2], tuple],
|
|
286
|
+
) -> ta.Callable[
|
|
287
|
+
[ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]]],
|
|
288
|
+
ta.Mapping[K2, V2],
|
|
289
|
+
]:
|
|
290
|
+
def inner(src):
|
|
291
|
+
return map((key_fn(k), value_fn(v)) for k, v in dict(src).items()) # type: ignore
|
|
292
|
+
|
|
293
|
+
key_fn = _unpack_fn(key_fn)
|
|
294
|
+
value_fn = _unpack_fn(value_fn)
|
|
295
|
+
return inner
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def opt_map_of(
|
|
299
|
+
key_fn: ta.Union[ta.Callable[[K], K2], tuple],
|
|
300
|
+
value_fn: ta.Union[ta.Callable[[V], V2], tuple],
|
|
301
|
+
) -> ta.Callable[
|
|
302
|
+
[ta.Optional[ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]]]],
|
|
303
|
+
ta.Optional[ta.Mapping[K2, V2]],
|
|
304
|
+
]:
|
|
305
|
+
def inner(src):
|
|
306
|
+
if src is None:
|
|
307
|
+
return None
|
|
308
|
+
else:
|
|
309
|
+
return map((key_fn(k), value_fn(v)) for k, v in dict(src).items()) # type: ignore
|
|
310
|
+
|
|
311
|
+
key_fn = _unpack_fn(key_fn)
|
|
312
|
+
value_fn = _unpack_fn(value_fn)
|
|
313
|
+
return inner
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def map_of_or_none(
|
|
317
|
+
key_fn: ta.Union[ta.Callable[[K], K2], tuple],
|
|
318
|
+
value_fn: ta.Union[ta.Callable[[V], V2], tuple],
|
|
319
|
+
) -> ta.Callable[
|
|
320
|
+
[ta.Optional[ta.Union[ta.Mapping[K, V], ta.Iterable[tuple[K, V]]]]],
|
|
321
|
+
ta.Optional[ta.Mapping[K2, V2]],
|
|
322
|
+
]:
|
|
323
|
+
def inner(src):
|
|
324
|
+
if src is None:
|
|
325
|
+
return None
|
|
326
|
+
else:
|
|
327
|
+
ret = map((key_fn(k), value_fn(v)) for k, v in dict(src).items()) # type: ignore
|
|
328
|
+
if ret:
|
|
329
|
+
return ret
|
|
330
|
+
else:
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
key_fn = _unpack_fn(key_fn)
|
|
334
|
+
value_fn = _unpack_fn(value_fn)
|
|
335
|
+
return inner
|
|
336
|
+
|
|
337
|
+
# endregion
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import collections.abc
|
|
3
|
+
import itertools
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from .mappings import yield_dict_init
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
T = ta.TypeVar('T')
|
|
10
|
+
K = ta.TypeVar('K')
|
|
11
|
+
V = ta.TypeVar('V')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Frozen(ta.Hashable, abc.ABC):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FrozenDict(ta.Mapping[K, V], Frozen):
|
|
19
|
+
|
|
20
|
+
def __new__(cls, *args, **kwargs) -> 'FrozenDict[K, V]':
|
|
21
|
+
if len(args) == 1 and Frozen in type(args[0]).__bases__:
|
|
22
|
+
return args[0]
|
|
23
|
+
return super().__new__(cls)
|
|
24
|
+
|
|
25
|
+
def __init__(self, *args, **kwargs):
|
|
26
|
+
super().__init__()
|
|
27
|
+
self._hash = None
|
|
28
|
+
if len(args) > 1:
|
|
29
|
+
raise TypeError(args)
|
|
30
|
+
self._dct: dict[K, V] = {}
|
|
31
|
+
self._dct.update(yield_dict_init(*args, **kwargs))
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def debug(self) -> ta.Mapping[K, V]:
|
|
35
|
+
return dict(self._dct)
|
|
36
|
+
|
|
37
|
+
def __repr__(self) -> str:
|
|
38
|
+
return '(%r)' % (self._dct,)
|
|
39
|
+
|
|
40
|
+
def __eq__(self, other) -> bool:
|
|
41
|
+
return type(self) == type(other) and self._dct == other._dct
|
|
42
|
+
|
|
43
|
+
def __getitem__(self, key: K) -> V:
|
|
44
|
+
return self._dct[key]
|
|
45
|
+
|
|
46
|
+
def __getstate__(self):
|
|
47
|
+
return tuple(self.items())
|
|
48
|
+
|
|
49
|
+
def __hash__(self) -> int:
|
|
50
|
+
if self._hash is None:
|
|
51
|
+
self._hash = hash(tuple((k, self[k]) for k in sorted(self))) # type: ignore
|
|
52
|
+
return self._hash
|
|
53
|
+
|
|
54
|
+
def __iter__(self) -> ta.Iterator[K]:
|
|
55
|
+
return iter(self._dct)
|
|
56
|
+
|
|
57
|
+
def __len__(self) -> int:
|
|
58
|
+
return len(self._dct)
|
|
59
|
+
|
|
60
|
+
def __ne__(self, other) -> bool:
|
|
61
|
+
return not (self == other)
|
|
62
|
+
|
|
63
|
+
def __setstate__(self, t):
|
|
64
|
+
self.__init__(t) # type: ignore
|
|
65
|
+
|
|
66
|
+
def drop(self, *keys):
|
|
67
|
+
ks = frozenset(keys)
|
|
68
|
+
return type(self)((k, self[k]) for k in self if k not in ks)
|
|
69
|
+
|
|
70
|
+
def set(self, *args, **kwargs):
|
|
71
|
+
new = type(self)(*args, **kwargs)
|
|
72
|
+
return type(self)(itertools.chain(self.items(), new.items()))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FrozenList(ta.Sequence[T], Frozen):
|
|
76
|
+
|
|
77
|
+
def __init__(self, it: ta.Optional[ta.Iterable[T]] = None) -> None:
|
|
78
|
+
super().__init__()
|
|
79
|
+
|
|
80
|
+
self._tup: tuple = tuple(it) if it is not None else ()
|
|
81
|
+
self._hash: ta.Optional[int] = None
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def debug(self) -> ta.Sequence[T]:
|
|
85
|
+
return list(self)
|
|
86
|
+
|
|
87
|
+
def __repr__(self) -> str:
|
|
88
|
+
return '([%s])' % (', '.join(map(repr, self._tup)),)
|
|
89
|
+
|
|
90
|
+
def __add__(self, o) -> 'FrozenList[T]':
|
|
91
|
+
if isinstance(o, FrozenList):
|
|
92
|
+
return FrozenList(self._tup + o._tup)
|
|
93
|
+
elif isinstance(o, collections.abc.Sequence):
|
|
94
|
+
return FrozenList(self._tup + tuple(o))
|
|
95
|
+
else:
|
|
96
|
+
return NotImplemented
|
|
97
|
+
|
|
98
|
+
def __contains__(self, x: object) -> bool:
|
|
99
|
+
return x in self._tup
|
|
100
|
+
|
|
101
|
+
def __eq__(self, o: object) -> bool:
|
|
102
|
+
if isinstance(o, FrozenList):
|
|
103
|
+
return self._tup == o._tup
|
|
104
|
+
elif isinstance(o, collections.abc.Sequence):
|
|
105
|
+
return len(self) == len(o) and all(l == r for l, r in zip(self, o))
|
|
106
|
+
else:
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
def __hash__(self) -> int:
|
|
110
|
+
if self._hash is None:
|
|
111
|
+
self._hash = hash(self._tup)
|
|
112
|
+
return self._hash
|
|
113
|
+
|
|
114
|
+
def __getitem__(self, idx: ta.Union[int, slice]) -> 'FrozenList[T]': # type: ignore
|
|
115
|
+
if isinstance(idx, int):
|
|
116
|
+
return self._tup[idx]
|
|
117
|
+
else:
|
|
118
|
+
return FrozenList(self._tup[idx])
|
|
119
|
+
|
|
120
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
121
|
+
return iter(self._tup)
|
|
122
|
+
|
|
123
|
+
def __len__(self) -> int:
|
|
124
|
+
return len(self._tup)
|
|
125
|
+
|
|
126
|
+
def __ne__(self, o: object) -> bool:
|
|
127
|
+
return not self.__eq__(o)
|
|
128
|
+
|
|
129
|
+
def __radd__(self, o) -> 'FrozenList[T]':
|
|
130
|
+
if isinstance(o, FrozenList):
|
|
131
|
+
return FrozenList(o._tup + self._tup)
|
|
132
|
+
elif isinstance(o, collections.abc.Sequence):
|
|
133
|
+
return FrozenList(tuple(o) + self._tup)
|
|
134
|
+
else:
|
|
135
|
+
return NotImplemented
|
|
136
|
+
|
|
137
|
+
def __reversed__(self) -> ta.Iterator[T]:
|
|
138
|
+
return reversed(self._tup)
|
|
139
|
+
|
|
140
|
+
def count(self, x: ta.Any) -> int:
|
|
141
|
+
return super().count(x)
|
|
142
|
+
|
|
143
|
+
def index(self, x: ta.Any, *args, **kwargs) -> int: # type: ignore
|
|
144
|
+
return self._tup.index(x, *args, **kwargs)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
frozendict = FrozenDict
|
|
148
|
+
frozenlist = FrozenList
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import operator as op
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import lang
|
|
5
|
+
from .mappings import yield_dict_init
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
T = ta.TypeVar('T')
|
|
9
|
+
K = ta.TypeVar('K')
|
|
10
|
+
V = ta.TypeVar('V')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class IdentityWrapper(ta.Generic[T]):
|
|
14
|
+
|
|
15
|
+
def __init__(self, value: T) -> None:
|
|
16
|
+
super().__init__()
|
|
17
|
+
self._value = value
|
|
18
|
+
|
|
19
|
+
def __repr__(self) -> str:
|
|
20
|
+
return lang.attr_repr(self, 'value')
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def value(self) -> T:
|
|
24
|
+
return self._value
|
|
25
|
+
|
|
26
|
+
def __eq__(self, other):
|
|
27
|
+
return isinstance(other, IdentityWrapper) and other._value is self._value
|
|
28
|
+
|
|
29
|
+
def __ne__(self, other):
|
|
30
|
+
return not (self == other)
|
|
31
|
+
|
|
32
|
+
def __hash__(self):
|
|
33
|
+
return id(self._value)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class IdentityKeyDict(ta.MutableMapping[K, V]):
|
|
37
|
+
|
|
38
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
39
|
+
super().__init__()
|
|
40
|
+
self._dict: dict[int, tuple[K, V]] = {}
|
|
41
|
+
for k, v in yield_dict_init(*args, **kwargs):
|
|
42
|
+
self[k] = v
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def debug(self) -> ta.Sequence[tuple[K, V]]:
|
|
46
|
+
return list(self.items())
|
|
47
|
+
|
|
48
|
+
def __repr__(self) -> str:
|
|
49
|
+
return lang.attr_repr(self, '_dict')
|
|
50
|
+
|
|
51
|
+
def __setitem__(self, k: K, v: V) -> None:
|
|
52
|
+
self._dict[id(k)] = (k, v)
|
|
53
|
+
|
|
54
|
+
def __delitem__(self, k: K) -> None:
|
|
55
|
+
del self._dict[id(k)]
|
|
56
|
+
|
|
57
|
+
def __getitem__(self, k: K) -> V:
|
|
58
|
+
return self._dict[id(k)][1]
|
|
59
|
+
|
|
60
|
+
def __len__(self) -> int:
|
|
61
|
+
return len(self._dict)
|
|
62
|
+
|
|
63
|
+
def __iter__(self) -> ta.Iterator[K]:
|
|
64
|
+
return iter(map(op.itemgetter(0), self._dict.values()))
|
|
65
|
+
|
|
66
|
+
def clear(self):
|
|
67
|
+
self._dict.clear()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class IdentitySet(ta.MutableSet[T]):
|
|
71
|
+
|
|
72
|
+
def __init__(self, init: ta.Optional[ta.Iterable[T]] = None) -> None:
|
|
73
|
+
super().__init__()
|
|
74
|
+
self._dict: dict[int, T] = {}
|
|
75
|
+
if init is not None:
|
|
76
|
+
for item in init:
|
|
77
|
+
self.add(item)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def debug(self) -> ta.Sequence[T]:
|
|
81
|
+
return list(self)
|
|
82
|
+
|
|
83
|
+
def __repr__(self) -> str:
|
|
84
|
+
return lang.attr_repr(self, '_dict')
|
|
85
|
+
|
|
86
|
+
def add(self, item: T) -> None:
|
|
87
|
+
self._dict[id(item)] = item
|
|
88
|
+
|
|
89
|
+
def discard(self, item: T) -> None:
|
|
90
|
+
try:
|
|
91
|
+
del self._dict[id(item)]
|
|
92
|
+
except KeyError:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
def update(self, items: ta.Iterable[T]) -> None:
|
|
96
|
+
for item in items:
|
|
97
|
+
self.add(item)
|
|
98
|
+
|
|
99
|
+
def __contains__(self, item: T) -> bool: # type: ignore
|
|
100
|
+
return id(item) in self._dict
|
|
101
|
+
|
|
102
|
+
def __len__(self) -> int:
|
|
103
|
+
return len(self._dict)
|
|
104
|
+
|
|
105
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
106
|
+
return iter(self._dict.values())
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .identity import IdentitySet
|
|
4
|
+
from .identity import IdentityKeyDict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
T = ta.TypeVar('T')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class IndexedSeq(ta.Sequence[T]):
|
|
11
|
+
|
|
12
|
+
def __init__(self, it: ta.Iterable[T], *, identity: bool = False) -> None:
|
|
13
|
+
super().__init__()
|
|
14
|
+
|
|
15
|
+
self._lst = list(it)
|
|
16
|
+
self._idxs = (IdentityKeyDict if identity else dict)(map(reversed, enumerate(self._lst)))
|
|
17
|
+
if len(self._idxs) != len(self._lst):
|
|
18
|
+
raise ValueError(f'{len(self._idxs)} != {len(self._lst)}')
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def debug(self) -> ta.Sequence[T]:
|
|
22
|
+
return self._lst
|
|
23
|
+
|
|
24
|
+
def __iter__(self) -> ta.Iterator[T]:
|
|
25
|
+
return iter(self._lst)
|
|
26
|
+
|
|
27
|
+
def __getitem__(self, idx: int) -> T: # type: ignore
|
|
28
|
+
return self._lst[idx]
|
|
29
|
+
|
|
30
|
+
def __len__(self) -> int:
|
|
31
|
+
return len(self._lst)
|
|
32
|
+
|
|
33
|
+
def __contains__(self, obj: T) -> bool: # type: ignore
|
|
34
|
+
return obj in self._idxs
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def idxs(self) -> ta.Mapping[T, int]:
|
|
38
|
+
return self._idxs
|
|
39
|
+
|
|
40
|
+
def idx(self, obj: T) -> int:
|
|
41
|
+
return self._idxs[obj]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class IndexedSetSeq(ta.Sequence[ta.AbstractSet[T]]):
|
|
45
|
+
|
|
46
|
+
def __init__(self, it: ta.Iterable[ta.Iterable[T]], *, identity: bool = False) -> None:
|
|
47
|
+
super().__init__()
|
|
48
|
+
|
|
49
|
+
self._lst = [(IdentitySet if identity else set)(e) for e in it]
|
|
50
|
+
self._idxs = (IdentityKeyDict if identity else dict)((e, i) for i, es in enumerate(self._lst) for e in es)
|
|
51
|
+
if len(self._idxs) != sum(map(len, self._lst)):
|
|
52
|
+
raise ValueError(f'{len(self._idxs)} != {sum(map(len, self._lst))}')
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def debug(self) -> ta.Sequence[ta.AbstractSet[T]]:
|
|
56
|
+
return self._lst
|
|
57
|
+
|
|
58
|
+
def __iter__(self) -> ta.Iterator[ta.AbstractSet[T]]:
|
|
59
|
+
return iter(self._lst)
|
|
60
|
+
|
|
61
|
+
def __getitem__(self, idx: int) -> ta.AbstractSet[T]: # type: ignore
|
|
62
|
+
return self._lst[idx]
|
|
63
|
+
|
|
64
|
+
def __len__(self) -> int:
|
|
65
|
+
return len(self._lst)
|
|
66
|
+
|
|
67
|
+
def __contains__(self, obj: T) -> bool: # type: ignore
|
|
68
|
+
return obj in self._idxs
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def idxs(self) -> ta.Mapping[T, int]:
|
|
72
|
+
return self._idxs
|
|
73
|
+
|
|
74
|
+
def idx(self, obj: T) -> int:
|
|
75
|
+
return self._idxs[obj]
|