omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/.manifests.json +265 -7
- omlish/__about__.py +5 -3
- omlish/antlr/_runtime/__init__.py +0 -22
- omlish/antlr/_runtime/_all.py +24 -0
- omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
- omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
- omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
- omlish/antlr/_runtime/xpath/XPath.py +7 -1
- omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
- omlish/antlr/delimit.py +106 -0
- omlish/antlr/dot.py +31 -0
- omlish/antlr/errors.py +11 -0
- omlish/antlr/input.py +96 -0
- omlish/antlr/parsing.py +19 -0
- omlish/antlr/runtime.py +102 -0
- omlish/antlr/utils.py +38 -0
- omlish/argparse/all.py +45 -0
- omlish/{argparse.py → argparse/cli.py} +112 -107
- omlish/asyncs/__init__.py +0 -35
- omlish/asyncs/all.py +35 -0
- omlish/asyncs/asyncio/all.py +7 -0
- omlish/asyncs/asyncio/channels.py +40 -0
- omlish/asyncs/asyncio/streams.py +45 -0
- omlish/asyncs/asyncio/subprocesses.py +238 -0
- omlish/asyncs/asyncio/timeouts.py +16 -0
- omlish/asyncs/bluelet/LICENSE +6 -0
- omlish/asyncs/bluelet/all.py +67 -0
- omlish/asyncs/bluelet/api.py +23 -0
- omlish/asyncs/bluelet/core.py +178 -0
- omlish/asyncs/bluelet/events.py +78 -0
- omlish/asyncs/bluelet/files.py +80 -0
- omlish/asyncs/bluelet/runner.py +416 -0
- omlish/asyncs/bluelet/sockets.py +214 -0
- omlish/bootstrap/sys.py +3 -3
- omlish/cached.py +2 -2
- omlish/check.py +49 -460
- omlish/codecs/__init__.py +72 -0
- omlish/codecs/base.py +106 -0
- omlish/codecs/bytes.py +119 -0
- omlish/codecs/chain.py +23 -0
- omlish/codecs/funcs.py +39 -0
- omlish/codecs/registry.py +139 -0
- omlish/codecs/standard.py +4 -0
- omlish/codecs/text.py +217 -0
- omlish/collections/cache/impl.py +50 -57
- omlish/collections/coerce.py +1 -0
- omlish/collections/mappings.py +1 -1
- omlish/configs/flattening.py +1 -1
- omlish/defs.py +1 -1
- omlish/diag/_pycharm/runhack.py +8 -2
- omlish/diag/procfs.py +8 -8
- omlish/docker/__init__.py +0 -36
- omlish/docker/all.py +31 -0
- omlish/docker/consts.py +4 -0
- omlish/{lite/docker.py → docker/detect.py} +18 -0
- omlish/docker/{helpers.py → timebomb.py} +0 -21
- omlish/formats/cbor.py +31 -0
- omlish/formats/cloudpickle.py +31 -0
- omlish/formats/codecs.py +93 -0
- omlish/formats/json/codecs.py +29 -0
- omlish/formats/json/delimted.py +4 -0
- omlish/formats/json/stream/errors.py +2 -0
- omlish/formats/json/stream/lex.py +12 -6
- omlish/formats/json/stream/parse.py +38 -22
- omlish/formats/json5.py +31 -0
- omlish/formats/pickle.py +31 -0
- omlish/formats/repr.py +25 -0
- omlish/formats/toml.py +17 -0
- omlish/formats/yaml.py +25 -0
- omlish/funcs/__init__.py +0 -0
- omlish/{genmachine.py → funcs/genmachine.py} +5 -4
- omlish/{matchfns.py → funcs/match.py} +1 -1
- omlish/funcs/pairs.py +215 -0
- omlish/http/__init__.py +0 -48
- omlish/http/all.py +48 -0
- omlish/http/coro/__init__.py +0 -0
- omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
- omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
- omlish/{lite/http → http}/handlers.py +3 -2
- omlish/{lite/http → http}/parsing.py +1 -0
- omlish/http/sessions.py +1 -1
- omlish/{lite/http → http}/versions.py +1 -0
- omlish/inject/managed.py +2 -2
- omlish/io/__init__.py +0 -3
- omlish/{lite/io.py → io/buffers.py} +8 -9
- omlish/io/compress/__init__.py +9 -0
- omlish/io/compress/abc.py +104 -0
- omlish/io/compress/adapters.py +148 -0
- omlish/io/compress/base.py +24 -0
- omlish/io/compress/brotli.py +47 -0
- omlish/io/compress/bz2.py +61 -0
- omlish/io/compress/codecs.py +78 -0
- omlish/io/compress/gzip.py +350 -0
- omlish/io/compress/lz4.py +91 -0
- omlish/io/compress/lzma.py +81 -0
- omlish/io/compress/snappy.py +34 -0
- omlish/io/compress/zlib.py +74 -0
- omlish/io/compress/zstd.py +44 -0
- omlish/io/fdio/__init__.py +1 -0
- omlish/{lite → io}/fdio/handlers.py +5 -5
- omlish/{lite → io}/fdio/kqueue.py +8 -8
- omlish/{lite → io}/fdio/manager.py +7 -7
- omlish/{lite → io}/fdio/pollers.py +13 -13
- omlish/io/generators/__init__.py +56 -0
- omlish/io/generators/consts.py +1 -0
- omlish/io/generators/direct.py +13 -0
- omlish/io/generators/readers.py +189 -0
- omlish/io/generators/stepped.py +191 -0
- omlish/io/pyio.py +5 -2
- omlish/iterators/__init__.py +24 -0
- omlish/iterators/iterators.py +132 -0
- omlish/iterators/recipes.py +18 -0
- omlish/iterators/tools.py +96 -0
- omlish/iterators/unique.py +67 -0
- omlish/lang/__init__.py +13 -1
- omlish/lang/functions.py +11 -2
- omlish/lang/generators.py +243 -0
- omlish/lang/iterables.py +46 -49
- omlish/lang/maybes.py +4 -4
- omlish/lite/cached.py +39 -6
- omlish/lite/check.py +438 -75
- omlish/lite/contextmanagers.py +17 -4
- omlish/lite/dataclasses.py +42 -0
- omlish/lite/inject.py +28 -45
- omlish/lite/logs.py +0 -270
- omlish/lite/marshal.py +309 -144
- omlish/lite/pycharm.py +47 -0
- omlish/lite/reflect.py +33 -0
- omlish/lite/resources.py +8 -0
- omlish/lite/runtime.py +4 -4
- omlish/lite/shlex.py +12 -0
- omlish/lite/socketserver.py +2 -2
- omlish/lite/strings.py +31 -0
- omlish/logs/__init__.py +0 -32
- omlish/logs/{_abc.py → abc.py} +0 -1
- omlish/logs/all.py +37 -0
- omlish/logs/{formatters.py → color.py} +1 -2
- omlish/logs/configs.py +7 -38
- omlish/logs/filters.py +10 -0
- omlish/logs/handlers.py +4 -1
- omlish/logs/json.py +56 -0
- omlish/logs/proxy.py +99 -0
- omlish/logs/standard.py +128 -0
- omlish/logs/utils.py +2 -2
- omlish/manifests/__init__.py +2 -0
- omlish/manifests/load.py +209 -0
- omlish/manifests/types.py +17 -0
- omlish/marshal/base.py +1 -1
- omlish/marshal/factories.py +1 -1
- omlish/marshal/forbidden.py +1 -1
- omlish/marshal/iterables.py +1 -1
- omlish/marshal/literals.py +50 -0
- omlish/marshal/mappings.py +1 -1
- omlish/marshal/maybes.py +1 -1
- omlish/marshal/standard.py +5 -1
- omlish/marshal/unions.py +1 -1
- omlish/os/__init__.py +0 -0
- omlish/os/atomics.py +205 -0
- omlish/os/deathsig.py +23 -0
- omlish/{os.py → os/files.py} +0 -9
- omlish/{lite → os}/journald.py +2 -1
- omlish/os/linux.py +484 -0
- omlish/os/paths.py +36 -0
- omlish/{lite → os}/pidfile.py +1 -0
- omlish/os/sizes.py +9 -0
- omlish/reflect/__init__.py +3 -0
- omlish/reflect/subst.py +2 -1
- omlish/reflect/types.py +126 -44
- omlish/secrets/pwhash.py +1 -1
- omlish/secrets/subprocesses.py +3 -1
- omlish/specs/jsonrpc/marshal.py +1 -1
- omlish/specs/openapi/marshal.py +1 -1
- omlish/sql/alchemy/asyncs.py +1 -1
- omlish/sql/queries/__init__.py +9 -1
- omlish/sql/queries/building.py +3 -0
- omlish/sql/queries/exprs.py +10 -27
- omlish/sql/queries/idents.py +48 -10
- omlish/sql/queries/names.py +80 -13
- omlish/sql/queries/params.py +64 -0
- omlish/sql/queries/rendering.py +1 -1
- omlish/subprocesses.py +340 -0
- omlish/term.py +29 -14
- omlish/testing/pytest/marks.py +2 -2
- omlish/testing/pytest/plugins/asyncs.py +6 -1
- omlish/testing/pytest/plugins/logging.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
- omlish/fnpairs.py +0 -496
- omlish/formats/json/cli/__main__.py +0 -11
- omlish/formats/json/cli/cli.py +0 -298
- omlish/formats/json/cli/formats.py +0 -71
- omlish/formats/json/cli/io.py +0 -74
- omlish/formats/json/cli/parsing.py +0 -82
- omlish/formats/json/cli/processing.py +0 -48
- omlish/formats/json/cli/rendering.py +0 -92
- omlish/iterators.py +0 -300
- omlish/lite/subprocesses.py +0 -130
- /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
- /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
- /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
- /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
- /omlish/collections/{_abc.py → abc.py} +0 -0
- /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
- /omlish/io/{_abc.py → abc.py} +0 -0
- /omlish/sql/{_abc.py → abc.py} +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,243 @@
|
|
1
|
+
import abc
|
2
|
+
import functools
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from .maybes import Maybe
|
6
|
+
from .maybes import empty
|
7
|
+
from .maybes import just
|
8
|
+
|
9
|
+
|
10
|
+
T = ta.TypeVar('T')
|
11
|
+
I = ta.TypeVar('I')
|
12
|
+
O = ta.TypeVar('O')
|
13
|
+
R = ta.TypeVar('R')
|
14
|
+
I_contra = ta.TypeVar('I_contra', contravariant=True)
|
15
|
+
O_co = ta.TypeVar('O_co', covariant=True)
|
16
|
+
R_co = ta.TypeVar('R_co', covariant=True)
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
|
21
|
+
|
22
|
+
def nextgen(g: T) -> T:
|
23
|
+
next(g) # type: ignore
|
24
|
+
return g
|
25
|
+
|
26
|
+
|
27
|
+
def autostart(fn):
|
28
|
+
@functools.wraps(fn)
|
29
|
+
def inner(*args, **kwargs):
|
30
|
+
g = fn(*args, **kwargs)
|
31
|
+
if (o := next(g)) is not None:
|
32
|
+
raise TypeError(o)
|
33
|
+
return g
|
34
|
+
return inner
|
35
|
+
|
36
|
+
|
37
|
+
##
|
38
|
+
|
39
|
+
|
40
|
+
@ta.runtime_checkable
|
41
|
+
class GeneratorLike(ta.Protocol[O_co, I_contra, R_co]):
|
42
|
+
def send(self, i: I_contra) -> O_co: # Raises[StopIteration[R_co]]
|
43
|
+
...
|
44
|
+
|
45
|
+
def close(self) -> None:
|
46
|
+
...
|
47
|
+
|
48
|
+
|
49
|
+
class GeneratorLike_(abc.ABC, ta.Generic[O, I, R]): # noqa
|
50
|
+
@abc.abstractmethod
|
51
|
+
def send(self, i: I) -> O: # Raises[StopIteration[R]]
|
52
|
+
raise NotImplementedError
|
53
|
+
|
54
|
+
def close(self) -> None:
|
55
|
+
pass
|
56
|
+
|
57
|
+
|
58
|
+
@ta.overload
|
59
|
+
def adapt_generator_like(gl: GeneratorLike_[O, I, R]) -> ta.Generator[O, I, R]:
|
60
|
+
...
|
61
|
+
|
62
|
+
|
63
|
+
@ta.overload
|
64
|
+
def adapt_generator_like(gl: GeneratorLike[O, I, R]) -> ta.Generator[O, I, R]:
|
65
|
+
...
|
66
|
+
|
67
|
+
|
68
|
+
def adapt_generator_like(gl):
|
69
|
+
try:
|
70
|
+
i = yield
|
71
|
+
while True:
|
72
|
+
i = yield gl.send(i)
|
73
|
+
except StopIteration as e:
|
74
|
+
return e.value
|
75
|
+
finally:
|
76
|
+
gl.close()
|
77
|
+
|
78
|
+
|
79
|
+
##
|
80
|
+
|
81
|
+
|
82
|
+
class Generator(ta.Generator[O, I, R]):
|
83
|
+
def __init__(self, g: ta.Generator[O, I, R]) -> None:
|
84
|
+
super().__init__()
|
85
|
+
self._g = g
|
86
|
+
|
87
|
+
@property
|
88
|
+
def g(self) -> ta.Generator[O, I, R]:
|
89
|
+
return self._g
|
90
|
+
|
91
|
+
value: R
|
92
|
+
|
93
|
+
def __iter__(self):
|
94
|
+
return self
|
95
|
+
|
96
|
+
def __next__(self):
|
97
|
+
try:
|
98
|
+
return next(self._g)
|
99
|
+
except StopIteration as e:
|
100
|
+
self.value = e.value
|
101
|
+
raise
|
102
|
+
|
103
|
+
def send(self, v):
|
104
|
+
try:
|
105
|
+
return self._g.send(v)
|
106
|
+
except StopIteration as e:
|
107
|
+
self.value = e.value
|
108
|
+
raise
|
109
|
+
|
110
|
+
def throw(self, *args):
|
111
|
+
try:
|
112
|
+
return self._g.throw(*args)
|
113
|
+
except StopIteration as e:
|
114
|
+
self.value = e.value
|
115
|
+
raise
|
116
|
+
|
117
|
+
def close(self):
|
118
|
+
self._g.close()
|
119
|
+
|
120
|
+
|
121
|
+
##
|
122
|
+
|
123
|
+
|
124
|
+
class CoroutineGenerator(ta.Generic[O, I, R]):
|
125
|
+
def __init__(self, g: ta.Generator[O, I, R]) -> None:
|
126
|
+
super().__init__()
|
127
|
+
self._g = g
|
128
|
+
|
129
|
+
@property
|
130
|
+
def g(self) -> ta.Generator[O, I, R]:
|
131
|
+
return self._g
|
132
|
+
|
133
|
+
#
|
134
|
+
|
135
|
+
def close(self) -> None:
|
136
|
+
self._g.close()
|
137
|
+
|
138
|
+
def __enter__(self) -> ta.Self:
|
139
|
+
return self
|
140
|
+
|
141
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
142
|
+
self._g.close()
|
143
|
+
|
144
|
+
#
|
145
|
+
|
146
|
+
class Output(ta.NamedTuple, ta.Generic[T]):
|
147
|
+
v: T
|
148
|
+
|
149
|
+
@property
|
150
|
+
def is_return(self) -> bool:
|
151
|
+
raise NotImplementedError
|
152
|
+
|
153
|
+
class Yield(Output[T]):
|
154
|
+
@property
|
155
|
+
def is_return(self) -> bool:
|
156
|
+
return False
|
157
|
+
|
158
|
+
class Return(Output[T]):
|
159
|
+
@property
|
160
|
+
def is_return(self) -> bool:
|
161
|
+
return True
|
162
|
+
|
163
|
+
class Nothing:
|
164
|
+
def __new__(cls):
|
165
|
+
raise TypeError
|
166
|
+
|
167
|
+
#
|
168
|
+
|
169
|
+
def send(self, /, v: I | type[Nothing] = Nothing) -> Yield[O] | Return[R]:
|
170
|
+
try:
|
171
|
+
if v is self.Nothing:
|
172
|
+
o = next(self._g)
|
173
|
+
else:
|
174
|
+
o = self._g.send(v) # type: ignore[arg-type]
|
175
|
+
except StopIteration as e:
|
176
|
+
return self.Return(e.value)
|
177
|
+
else:
|
178
|
+
return self.Yield(o)
|
179
|
+
|
180
|
+
def send_opt(self, v: I | None) -> Yield[O] | Return[R]:
|
181
|
+
return self.send(v if v is not None else self.Nothing)
|
182
|
+
|
183
|
+
def send_maybe(self, v: Maybe[I]) -> Yield[O] | Return[R]:
|
184
|
+
return self.send(v.or_else(self.Nothing))
|
185
|
+
|
186
|
+
def throw(self, v: BaseException) -> Yield[O] | Return[R]:
|
187
|
+
try:
|
188
|
+
o = self._g.throw(v)
|
189
|
+
except StopIteration as e:
|
190
|
+
return self.Return(e.value)
|
191
|
+
else:
|
192
|
+
return self.Yield(o)
|
193
|
+
|
194
|
+
|
195
|
+
corogen = CoroutineGenerator
|
196
|
+
|
197
|
+
|
198
|
+
##
|
199
|
+
|
200
|
+
|
201
|
+
class GeneratorMappedIterator(ta.Generic[O, I, R]):
|
202
|
+
"""
|
203
|
+
Like a `map` iterator but takes a generator instead of a function. Provided generator *must* yield outputs 1:1 with
|
204
|
+
inputs.
|
205
|
+
|
206
|
+
Generator return value will be captured on `value` property - if present generator stopped, it absent iterator
|
207
|
+
stopped.
|
208
|
+
"""
|
209
|
+
|
210
|
+
def __init__(self, g: ta.Generator[O, I, R], it: ta.Iterator[I]) -> None:
|
211
|
+
super().__init__()
|
212
|
+
|
213
|
+
self._g = g
|
214
|
+
self._it = it
|
215
|
+
self._value: Maybe[R] = empty()
|
216
|
+
|
217
|
+
@property
|
218
|
+
def g(self) -> ta.Generator[O, I, R]:
|
219
|
+
return self._g
|
220
|
+
|
221
|
+
@property
|
222
|
+
def it(self) -> ta.Iterator[I]:
|
223
|
+
return self._it
|
224
|
+
|
225
|
+
@property
|
226
|
+
def value(self) -> Maybe[R]:
|
227
|
+
return self._value
|
228
|
+
|
229
|
+
def __iter__(self) -> ta.Iterator[O]:
|
230
|
+
return self
|
231
|
+
|
232
|
+
def __next__(self) -> O:
|
233
|
+
i = next(self._it)
|
234
|
+
try:
|
235
|
+
o = self._g.send(i)
|
236
|
+
except StopIteration as e:
|
237
|
+
self._value = just(e.value)
|
238
|
+
raise StopIteration from e
|
239
|
+
return o
|
240
|
+
|
241
|
+
|
242
|
+
def genmap(g: ta.Generator[O, I, R], it: ta.Iterable[I]) -> GeneratorMappedIterator[O, I, R]:
|
243
|
+
return GeneratorMappedIterator(g, iter(it))
|
omlish/lang/iterables.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
import dataclasses as dc
|
2
|
+
import functools
|
2
3
|
import itertools
|
3
4
|
import typing as ta
|
4
5
|
|
5
6
|
|
6
7
|
T = ta.TypeVar('T')
|
7
|
-
S = ta.TypeVar('S')
|
8
8
|
R = ta.TypeVar('R')
|
9
9
|
|
10
10
|
|
@@ -15,6 +15,9 @@ BUILTIN_SCALAR_ITERABLE_TYPES: tuple[type, ...] = (
|
|
15
15
|
)
|
16
16
|
|
17
17
|
|
18
|
+
##
|
19
|
+
|
20
|
+
|
18
21
|
def ilen(it: ta.Iterable) -> int:
|
19
22
|
c = 0
|
20
23
|
for _ in it:
|
@@ -44,40 +47,36 @@ def interleave(vs: ta.Iterable[T], d: T) -> ta.Iterable[T]:
|
|
44
47
|
yield v
|
45
48
|
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
tuple[int, int],
|
51
|
-
tuple[int, int, int],
|
52
|
-
ta.Iterable[int],
|
53
|
-
]
|
50
|
+
@ta.overload
|
51
|
+
def readiter(f: ta.TextIO, sz: int) -> ta.Iterator[str]:
|
52
|
+
...
|
54
53
|
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
elif isinstance(i, tuple):
|
60
|
-
return range(*i)
|
61
|
-
elif isinstance(i, ta.Iterable):
|
62
|
-
return i
|
63
|
-
else:
|
64
|
-
raise TypeError(i)
|
55
|
+
@ta.overload
|
56
|
+
def readiter(f: ta.BinaryIO, sz: int) -> ta.Iterator[bytes]:
|
57
|
+
...
|
65
58
|
|
66
59
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
@ta.overload
|
61
|
+
def readiter(f: ta.IO, sz: int) -> ta.Iterator[ta.AnyStr]:
|
62
|
+
...
|
63
|
+
|
64
|
+
|
65
|
+
def readiter(f, sz):
|
66
|
+
return iter(functools.partial(f.read, sz), None)
|
71
67
|
|
72
68
|
|
73
69
|
@dc.dataclass(frozen=True)
|
74
|
-
class
|
70
|
+
class IterGen(ta.Generic[T]):
|
75
71
|
fn: ta.Callable[[], ta.Iterable[T]]
|
76
72
|
|
77
73
|
def __iter__(self):
|
78
74
|
return iter(self.fn())
|
79
75
|
|
80
76
|
|
77
|
+
itergen = IterGen
|
78
|
+
|
79
|
+
|
81
80
|
def renumerate(it: ta.Iterable[T]) -> ta.Iterable[tuple[T, int]]:
|
82
81
|
return ((e, i) for i, e in enumerate(it))
|
83
82
|
|
@@ -89,32 +88,30 @@ def flatmap(fn: ta.Callable[[T], ta.Iterable[R]], it: ta.Iterable[T]) -> ta.Iter
|
|
89
88
|
return flatten(map(fn, it))
|
90
89
|
|
91
90
|
|
92
|
-
|
93
|
-
def __init__(self, gen: ta.Generator[T, S, R]) -> None:
|
94
|
-
super().__init__()
|
95
|
-
self.gen = gen
|
91
|
+
##
|
96
92
|
|
97
|
-
value: R
|
98
93
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
94
|
+
Rangeable: ta.TypeAlias = ta.Union[ # noqa
|
95
|
+
int,
|
96
|
+
tuple[int],
|
97
|
+
tuple[int, int],
|
98
|
+
tuple[int, int, int],
|
99
|
+
ta.Iterable[int],
|
100
|
+
]
|
101
|
+
|
102
|
+
|
103
|
+
def asrange(i: Rangeable) -> ta.Iterable[int]:
|
104
|
+
if isinstance(i, int):
|
105
|
+
return range(i)
|
106
|
+
elif isinstance(i, tuple):
|
107
|
+
return range(*i)
|
108
|
+
elif isinstance(i, ta.Iterable):
|
109
|
+
return i
|
110
|
+
else:
|
111
|
+
raise TypeError(i)
|
112
|
+
|
113
|
+
|
114
|
+
def prodrange(*dims: Rangeable) -> ta.Iterable[ta.Sequence[int]]:
|
115
|
+
if not dims:
|
116
|
+
return []
|
117
|
+
return itertools.product(*map(asrange, dims))
|
omlish/lang/maybes.py
CHANGED
@@ -50,11 +50,11 @@ class Maybe(abc.ABC, ta.Generic[T]):
|
|
50
50
|
raise NotImplementedError
|
51
51
|
|
52
52
|
@abc.abstractmethod
|
53
|
-
def or_else(self, other: T) -> T:
|
53
|
+
def or_else(self, other: T | U) -> T | U:
|
54
54
|
raise NotImplementedError
|
55
55
|
|
56
56
|
@abc.abstractmethod
|
57
|
-
def or_else_get(self, supplier: ta.Callable[[],
|
57
|
+
def or_else_get(self, supplier: ta.Callable[[], U]) -> T | U:
|
58
58
|
raise NotImplementedError
|
59
59
|
|
60
60
|
@abc.abstractmethod
|
@@ -109,10 +109,10 @@ class _Maybe(Maybe[T], tuple):
|
|
109
109
|
return value
|
110
110
|
return _empty # noqa
|
111
111
|
|
112
|
-
def or_else(self, other: T) -> T:
|
112
|
+
def or_else(self, other: T | U) -> T | U:
|
113
113
|
return self.must() if self else other
|
114
114
|
|
115
|
-
def or_else_get(self, supplier: ta.Callable[[], T]) -> T:
|
115
|
+
def or_else_get(self, supplier: ta.Callable[[], T | U]) -> T | U:
|
116
116
|
return self.must() if self else supplier()
|
117
117
|
|
118
118
|
def or_else_raise(self, exception_supplier: ta.Callable[[], Exception]) -> T:
|
omlish/lite/cached.py
CHANGED
@@ -4,8 +4,13 @@ import typing as ta
|
|
4
4
|
|
5
5
|
T = ta.TypeVar('T')
|
6
6
|
|
7
|
+
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
7
8
|
|
8
|
-
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
class _AbstractCachedNullary:
|
9
14
|
def __init__(self, fn):
|
10
15
|
super().__init__()
|
11
16
|
self._fn = fn
|
@@ -13,14 +18,42 @@ class _cached_nullary: # noqa
|
|
13
18
|
functools.update_wrapper(self, fn)
|
14
19
|
|
15
20
|
def __call__(self, *args, **kwargs): # noqa
|
16
|
-
|
17
|
-
self._value = self._fn()
|
18
|
-
return self._value
|
21
|
+
raise TypeError
|
19
22
|
|
20
23
|
def __get__(self, instance, owner): # noqa
|
21
24
|
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
22
25
|
return bound
|
23
26
|
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
##
|
29
|
+
|
30
|
+
|
31
|
+
class _CachedNullary(_AbstractCachedNullary):
|
32
|
+
def __call__(self, *args, **kwargs): # noqa
|
33
|
+
if self._value is self._missing:
|
34
|
+
self._value = self._fn()
|
35
|
+
return self._value
|
36
|
+
|
37
|
+
|
38
|
+
def cached_nullary(fn: CallableT) -> CallableT:
|
39
|
+
return _CachedNullary(fn) # type: ignore
|
40
|
+
|
41
|
+
|
42
|
+
def static_init(fn: CallableT) -> CallableT:
|
43
|
+
fn = cached_nullary(fn)
|
44
|
+
fn()
|
45
|
+
return fn
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
|
50
|
+
|
51
|
+
class _AsyncCachedNullary(_AbstractCachedNullary):
|
52
|
+
async def __call__(self, *args, **kwargs):
|
53
|
+
if self._value is self._missing:
|
54
|
+
self._value = await self._fn()
|
55
|
+
return self._value
|
56
|
+
|
57
|
+
|
58
|
+
def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
59
|
+
return _AsyncCachedNullary(fn)
|