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.

Files changed (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. 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]