omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__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.
- 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)
|