omlish 0.0.0.dev141__py3-none-any.whl → 0.0.0.dev142__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/__about__.py +4 -2
- omlish/check.py +2 -0
- omlish/funcs/pairs.py +2 -2
- omlish/io/compress/__init__.py +9 -0
- omlish/io/compress/abc.py +4 -4
- omlish/io/compress/adapters.py +12 -11
- omlish/io/compress/base.py +24 -0
- omlish/io/compress/brotli.py +33 -0
- omlish/io/compress/bz2.py +26 -21
- omlish/io/compress/gzip.py +43 -10
- omlish/io/compress/lz4.py +77 -0
- omlish/io/compress/lzma.py +51 -16
- omlish/io/compress/snappy.py +20 -0
- omlish/io/compress/zlib.py +60 -0
- omlish/io/compress/zstd.py +30 -0
- omlish/io/generators/__init__.py +53 -0
- omlish/io/generators/consts.py +1 -0
- omlish/io/generators/direct.py +13 -0
- omlish/io/generators/readers.py +15 -9
- omlish/io/generators/stepped.py +85 -14
- omlish/io/pyio.py +5 -2
- omlish/lang/__init__.py +1 -0
- omlish/lang/iterables.py +20 -0
- omlish/lite/marshal.py +118 -94
- omlish/lite/subprocesses.py +13 -0
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/METADATA +3 -1
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/RECORD +31 -24
- omlish/io/compress/types.py +0 -29
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev142.dist-info}/top_level.txt +0 -0
omlish/io/generators/__init__.py
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
from .consts import ( # noqa
|
2
|
+
DEFAULT_BUFFER_SIZE,
|
3
|
+
)
|
4
|
+
|
5
|
+
from .direct import ( # noqa
|
6
|
+
DirectGenerator,
|
7
|
+
|
8
|
+
BytesDirectGenerator,
|
9
|
+
StrDirectGenerator,
|
10
|
+
)
|
11
|
+
|
12
|
+
from .readers import ( # noqa
|
13
|
+
ReaderGenerator,
|
14
|
+
BytesReaderGenerator,
|
15
|
+
StrReaderGenerator,
|
16
|
+
|
17
|
+
ExactReaderGenerator,
|
18
|
+
BytesExactReaderGenerator,
|
19
|
+
StrExactReaderGenerator,
|
20
|
+
|
21
|
+
GeneratorReader,
|
22
|
+
|
23
|
+
PrependableGeneratorReader,
|
24
|
+
PrependableBytesGeneratorReader,
|
25
|
+
PrependableStrGeneratorReader,
|
26
|
+
prependable_bytes_generator_reader,
|
27
|
+
prependable_str_generator_reader,
|
28
|
+
|
29
|
+
BufferedGeneratorReader,
|
30
|
+
BufferedBytesGeneratorReader,
|
31
|
+
BufferedStrGeneratorReader,
|
32
|
+
buffered_bytes_generator_reader,
|
33
|
+
buffered_str_generator_reader,
|
34
|
+
)
|
35
|
+
|
36
|
+
from .stepped import ( # noqa
|
37
|
+
SteppedGenerator,
|
38
|
+
BytesSteppedGenerator,
|
39
|
+
StrSteppedGenerator,
|
40
|
+
BytesToStrSteppedGenerator,
|
41
|
+
StrToBytesSteppedGenerator,
|
42
|
+
|
43
|
+
SteppedReaderGenerator,
|
44
|
+
BytesSteppedReaderGenerator,
|
45
|
+
StrSteppedReaderGenerator,
|
46
|
+
|
47
|
+
flatmap_stepped_generator,
|
48
|
+
|
49
|
+
joined_bytes_stepped_generator,
|
50
|
+
joined_str_stepped_generator,
|
51
|
+
|
52
|
+
read_into_bytes_stepped_generator,
|
53
|
+
)
|
@@ -0,0 +1 @@
|
|
1
|
+
DEFAULT_BUFFER_SIZE = 4 * 0x1000
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
|
4
|
+
O = ta.TypeVar('O')
|
5
|
+
I = ta.TypeVar('I')
|
6
|
+
R = ta.TypeVar('R')
|
7
|
+
|
8
|
+
|
9
|
+
# Direct generators yield outputs 1:1 with inputs.
|
10
|
+
DirectGenerator: ta.TypeAlias = ta.Generator[O, I, R]
|
11
|
+
|
12
|
+
BytesDirectGenerator: ta.TypeAlias = DirectGenerator[bytes, bytes, R]
|
13
|
+
StrDirectGenerator: ta.TypeAlias = DirectGenerator[str, str, R]
|
omlish/io/generators/readers.py
CHANGED
@@ -8,21 +8,29 @@ import abc
|
|
8
8
|
import typing as ta
|
9
9
|
|
10
10
|
from ... import check
|
11
|
+
from .consts import DEFAULT_BUFFER_SIZE
|
11
12
|
|
12
13
|
|
13
14
|
T = ta.TypeVar('T')
|
15
|
+
|
16
|
+
O = ta.TypeVar('O')
|
14
17
|
I = ta.TypeVar('I')
|
15
18
|
R = ta.TypeVar('R')
|
19
|
+
|
16
20
|
AnyT = ta.TypeVar('AnyT', bound=ta.Any)
|
17
21
|
|
18
22
|
|
23
|
+
# Reader generators yield ints of amounts of data needed, or None for needing any amount of data.
|
19
24
|
ReaderGenerator: ta.TypeAlias = ta.Generator[int | None, I, R]
|
20
|
-
ExactReaderGenerator: ta.TypeAlias = ta.Generator[int, I, R]
|
21
25
|
|
22
26
|
BytesReaderGenerator: ta.TypeAlias = ReaderGenerator[bytes, R]
|
23
|
-
BytesExactReaderGenerator: ta.TypeAlias = ExactReaderGenerator[bytes, R]
|
24
|
-
|
25
27
|
StrReaderGenerator: ta.TypeAlias = ReaderGenerator[str, R]
|
28
|
+
|
29
|
+
|
30
|
+
# Exact reader generators always specify read sizes.
|
31
|
+
ExactReaderGenerator: ta.TypeAlias = ta.Generator[int, I, R]
|
32
|
+
|
33
|
+
BytesExactReaderGenerator: ta.TypeAlias = ExactReaderGenerator[bytes, R]
|
26
34
|
StrExactReaderGenerator: ta.TypeAlias = ExactReaderGenerator[str, R]
|
27
35
|
|
28
36
|
|
@@ -44,10 +52,10 @@ class _StrJoiner:
|
|
44
52
|
|
45
53
|
class GeneratorReader(abc.ABC, ta.Generic[T]):
|
46
54
|
@abc.abstractmethod
|
47
|
-
def read(self, sz: int | None) ->
|
55
|
+
def read(self, sz: int | None) -> ReaderGenerator[T, T]:
|
48
56
|
raise NotImplementedError
|
49
57
|
|
50
|
-
def read_exact(self, sz: int) ->
|
58
|
+
def read_exact(self, sz: int) -> ReaderGenerator[T, T]:
|
51
59
|
d: ta.Any = yield from self.read(sz)
|
52
60
|
if len(d) != sz:
|
53
61
|
raise EOFError(f'GeneratorReader got {len(d)}, expected {sz}')
|
@@ -67,7 +75,7 @@ class PrependableGeneratorReader(GeneratorReader[AnyT]):
|
|
67
75
|
def _join(self, lst: list[AnyT]) -> AnyT:
|
68
76
|
raise NotImplementedError
|
69
77
|
|
70
|
-
def read(self, sz: int | None) ->
|
78
|
+
def read(self, sz: int | None) -> ReaderGenerator[AnyT, AnyT]:
|
71
79
|
if not self._queue:
|
72
80
|
d: AnyT = check.not_none((yield sz))
|
73
81
|
return d
|
@@ -126,8 +134,6 @@ prependable_str_generator_reader = PrependableStrGeneratorReader
|
|
126
134
|
|
127
135
|
|
128
136
|
class BufferedGeneratorReader(PrependableGeneratorReader[AnyT], abc.ABC):
|
129
|
-
DEFAULT_BUFFER_SIZE = 4 * 0x1000
|
130
|
-
|
131
137
|
def __init__(
|
132
138
|
self,
|
133
139
|
buffer_size: int = DEFAULT_BUFFER_SIZE,
|
@@ -138,7 +144,7 @@ class BufferedGeneratorReader(PrependableGeneratorReader[AnyT], abc.ABC):
|
|
138
144
|
|
139
145
|
self._buffer_size = buffer_size
|
140
146
|
|
141
|
-
def read(self, sz: int | None) ->
|
147
|
+
def read(self, sz: int | None) -> ReaderGenerator[AnyT, AnyT]:
|
142
148
|
g = super().read(sz)
|
143
149
|
i: ta.Any = None
|
144
150
|
while True:
|
omlish/io/generators/stepped.py
CHANGED
@@ -1,18 +1,40 @@
|
|
1
1
|
import typing as ta
|
2
2
|
|
3
|
+
from ... import check
|
3
4
|
from ... import lang
|
5
|
+
from .consts import DEFAULT_BUFFER_SIZE
|
6
|
+
from .direct import BytesDirectGenerator
|
7
|
+
from .direct import StrDirectGenerator
|
4
8
|
|
5
9
|
|
6
10
|
T = ta.TypeVar('T')
|
7
|
-
|
11
|
+
|
8
12
|
O = ta.TypeVar('O')
|
13
|
+
I = ta.TypeVar('I')
|
14
|
+
R = ta.TypeVar('R')
|
15
|
+
|
9
16
|
OF = ta.TypeVar('OF')
|
10
17
|
OT = ta.TypeVar('OT')
|
11
|
-
R = ta.TypeVar('R')
|
12
18
|
|
13
19
|
|
20
|
+
# Stepped generators accept a non-None input, then in response yield zero or more non-None outputs, until yielding None
|
21
|
+
# to signal they need more input again.
|
14
22
|
SteppedGenerator: ta.TypeAlias = ta.Generator[O | None, I | None, R]
|
15
23
|
|
24
|
+
# Conventionally, these are sent and themselves yield an empty value to signify termination.
|
25
|
+
BytesSteppedGenerator: ta.TypeAlias = SteppedGenerator[bytes, bytes, R]
|
26
|
+
StrSteppedGenerator: ta.TypeAlias = SteppedGenerator[str, str, R]
|
27
|
+
|
28
|
+
BytesToStrSteppedGenerator: ta.TypeAlias = SteppedGenerator[str, bytes, R]
|
29
|
+
StrToBytesSteppedGenerator: ta.TypeAlias = SteppedGenerator[bytes, str, R]
|
30
|
+
|
31
|
+
|
32
|
+
# Stepped reader generators emit either an int or None to request input, or emit some other kind of output.
|
33
|
+
SteppedReaderGenerator: ta.TypeAlias = ta.Generator[int | None | O, I | None, R]
|
34
|
+
|
35
|
+
BytesSteppedReaderGenerator: ta.TypeAlias = SteppedReaderGenerator[bytes, bytes, R]
|
36
|
+
StrSteppedReaderGenerator: ta.TypeAlias = SteppedReaderGenerator[str, str, R]
|
37
|
+
|
16
38
|
|
17
39
|
##
|
18
40
|
|
@@ -25,10 +47,8 @@ def flatmap_stepped_generator(
|
|
25
47
|
terminate: ta.Callable[[OF], bool] | None = None,
|
26
48
|
) -> ta.Generator[OT, I, lang.Maybe[R]]:
|
27
49
|
"""
|
28
|
-
Given a
|
29
|
-
|
30
|
-
1:1 generator which accepts input, builds a list of yielded generator output, calls the given function with that
|
31
|
-
list, and yields the result.
|
50
|
+
Given a stepped generator and a function taking a list, returns a direct (1:1) generator which accepts input, builds
|
51
|
+
a list of yielded generator output, calls the given function with that list, and yields the result.
|
32
52
|
|
33
53
|
An optional terminate function may be provided which will cause this function to return early if it returns true for
|
34
54
|
an encountered yielded value. The encountered value causing termination will be included in the list sent to the
|
@@ -89,16 +109,67 @@ def _is_empty(o: T) -> bool:
|
|
89
109
|
return len(o) < 1 # type: ignore
|
90
110
|
|
91
111
|
|
112
|
+
def joined_bytes_stepped_generator(g: BytesSteppedGenerator[R]) -> BytesDirectGenerator[R]:
|
113
|
+
return flatmap_stepped_generator(_join_bytes, g, terminate=_is_empty)
|
114
|
+
|
115
|
+
|
116
|
+
def joined_str_stepped_generator(g: StrSteppedGenerator[R]) -> StrDirectGenerator[R]:
|
117
|
+
return flatmap_stepped_generator(_join_str, g, terminate=_is_empty)
|
118
|
+
|
119
|
+
|
92
120
|
##
|
93
121
|
|
94
122
|
|
95
|
-
def
|
96
|
-
g:
|
97
|
-
|
98
|
-
|
123
|
+
def read_into_bytes_stepped_generator(
|
124
|
+
g: BytesSteppedGenerator,
|
125
|
+
f: ta.IO,
|
126
|
+
*,
|
127
|
+
read_size: int = DEFAULT_BUFFER_SIZE,
|
128
|
+
) -> ta.Iterator[bytes]:
|
129
|
+
yield from lang.genmap( # type: ignore[misc]
|
130
|
+
joined_bytes_stepped_generator(g),
|
131
|
+
lang.readiter(f, read_size),
|
132
|
+
)
|
99
133
|
|
100
134
|
|
101
|
-
def
|
102
|
-
g:
|
103
|
-
|
104
|
-
|
135
|
+
def read_into_str_stepped_generator(
|
136
|
+
g: StrSteppedGenerator,
|
137
|
+
f: ta.TextIO,
|
138
|
+
*,
|
139
|
+
read_size: int = DEFAULT_BUFFER_SIZE,
|
140
|
+
) -> ta.Iterator[str]:
|
141
|
+
yield from lang.genmap(
|
142
|
+
joined_str_stepped_generator(g),
|
143
|
+
lang.readiter(f, read_size),
|
144
|
+
)
|
145
|
+
|
146
|
+
|
147
|
+
##
|
148
|
+
|
149
|
+
|
150
|
+
@lang.autostart
|
151
|
+
def buffer_bytes_stepped_reader_generator(g: BytesSteppedReaderGenerator) -> BytesSteppedGenerator:
|
152
|
+
o = g.send(None)
|
153
|
+
buf: ta.Any = None
|
154
|
+
|
155
|
+
while True:
|
156
|
+
if not buf:
|
157
|
+
buf = check.isinstance((yield None), bytes)
|
158
|
+
|
159
|
+
if o is None or not buf:
|
160
|
+
i = buf
|
161
|
+
elif isinstance(o, int):
|
162
|
+
if len(buf) < o:
|
163
|
+
raise NotImplementedError
|
164
|
+
i = buf[:o]
|
165
|
+
buf = buf[o:]
|
166
|
+
else:
|
167
|
+
raise TypeError(o)
|
168
|
+
|
169
|
+
while True:
|
170
|
+
o = g.send(i)
|
171
|
+
i = None
|
172
|
+
if isinstance(o, bytes):
|
173
|
+
check.none((yield o))
|
174
|
+
else:
|
175
|
+
break
|
omlish/io/pyio.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
"""
|
5
5
|
Python implementation of the io module.
|
6
6
|
|
7
|
-
https://github.com/python/cpython/blob/
|
7
|
+
https://github.com/python/cpython/blob/8b3cccf3f9508572d85b0044519f2bd5715dacad/Lib/_pyio.py
|
8
8
|
"""
|
9
9
|
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
10
10
|
# --------------------------------------------
|
@@ -2580,8 +2580,11 @@ class TextIOWrapper(TextIOBase):
|
|
2580
2580
|
decoder = self._decoder or self._get_decoder()
|
2581
2581
|
|
2582
2582
|
if size < 0:
|
2583
|
+
chunk = self.buffer.read()
|
2584
|
+
if chunk is None:
|
2585
|
+
raise BlockingIOError("Read returned None.")
|
2583
2586
|
# Read everything.
|
2584
|
-
result = self._get_decoded_chars() + decoder.decode(
|
2587
|
+
result = self._get_decoded_chars() + decoder.decode(chunk, final=True)
|
2585
2588
|
if self._snapshot is not None:
|
2586
2589
|
self._set_decoded_chars('')
|
2587
2590
|
self._snapshot = None
|
omlish/lang/__init__.py
CHANGED
omlish/lang/iterables.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import dataclasses as dc
|
2
|
+
import functools
|
2
3
|
import itertools
|
3
4
|
import typing as ta
|
4
5
|
|
@@ -46,6 +47,25 @@ def interleave(vs: ta.Iterable[T], d: T) -> ta.Iterable[T]:
|
|
46
47
|
yield v
|
47
48
|
|
48
49
|
|
50
|
+
@ta.overload
|
51
|
+
def readiter(f: ta.TextIO, sz: int) -> ta.Iterator[str]:
|
52
|
+
...
|
53
|
+
|
54
|
+
|
55
|
+
@ta.overload
|
56
|
+
def readiter(f: ta.BinaryIO, sz: int) -> ta.Iterator[bytes]:
|
57
|
+
...
|
58
|
+
|
59
|
+
|
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)
|
67
|
+
|
68
|
+
|
49
69
|
@dc.dataclass(frozen=True)
|
50
70
|
class IterGen(ta.Generic[T]):
|
51
71
|
fn: ta.Callable[[], ta.Iterable[T]]
|
omlish/lite/marshal.py
CHANGED
@@ -251,117 +251,141 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
|
|
251
251
|
}
|
252
252
|
|
253
253
|
|
254
|
-
def _make_obj_marshaler(
|
255
|
-
ty: ta.Any,
|
256
|
-
rec: ta.Callable[[ta.Any], ObjMarshaler],
|
257
|
-
*,
|
258
|
-
nonstrict_dataclasses: bool = False,
|
259
|
-
) -> ObjMarshaler:
|
260
|
-
if isinstance(ty, type):
|
261
|
-
if abc.ABC in ty.__bases__:
|
262
|
-
return PolymorphicObjMarshaler.of([ # type: ignore
|
263
|
-
PolymorphicObjMarshaler.Impl(
|
264
|
-
ity,
|
265
|
-
ity.__qualname__,
|
266
|
-
rec(ity),
|
267
|
-
)
|
268
|
-
for ity in deep_subclasses(ty)
|
269
|
-
if abc.ABC not in ity.__bases__
|
270
|
-
])
|
271
|
-
|
272
|
-
if issubclass(ty, enum.Enum):
|
273
|
-
return EnumObjMarshaler(ty)
|
274
|
-
|
275
|
-
if dc.is_dataclass(ty):
|
276
|
-
return DataclassObjMarshaler(
|
277
|
-
ty,
|
278
|
-
{f.name: rec(f.type) for f in dc.fields(ty)},
|
279
|
-
nonstrict=nonstrict_dataclasses,
|
280
|
-
)
|
281
|
-
|
282
|
-
if is_generic_alias(ty):
|
283
|
-
try:
|
284
|
-
mt = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES[ta.get_origin(ty)]
|
285
|
-
except KeyError:
|
286
|
-
pass
|
287
|
-
else:
|
288
|
-
k, v = ta.get_args(ty)
|
289
|
-
return MappingObjMarshaler(mt, rec(k), rec(v))
|
290
|
-
|
291
|
-
try:
|
292
|
-
st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
|
293
|
-
except KeyError:
|
294
|
-
pass
|
295
|
-
else:
|
296
|
-
[e] = ta.get_args(ty)
|
297
|
-
return IterableObjMarshaler(st, rec(e))
|
298
|
-
|
299
|
-
if is_union_alias(ty):
|
300
|
-
return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
|
301
|
-
|
302
|
-
raise TypeError(ty)
|
303
|
-
|
304
|
-
|
305
254
|
##
|
306
255
|
|
307
256
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
257
|
+
class ObjMarshalerManager:
|
258
|
+
def __init__(
|
259
|
+
self,
|
260
|
+
*,
|
261
|
+
default_obj_marshalers: ta.Dict[ta.Any, ObjMarshaler] = _DEFAULT_OBJ_MARSHALERS, # noqa
|
262
|
+
generic_mapping_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_MAPPING_TYPES, # noqa
|
263
|
+
generic_iterable_types: ta.Dict[ta.Any, type] = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES, # noqa
|
264
|
+
) -> None:
|
265
|
+
super().__init__()
|
266
|
+
|
267
|
+
self._obj_marshalers = dict(default_obj_marshalers)
|
268
|
+
self._generic_mapping_types = generic_mapping_types
|
269
|
+
self._generic_iterable_types = generic_iterable_types
|
270
|
+
|
271
|
+
self._lock = threading.RLock()
|
272
|
+
self._marshalers: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
|
273
|
+
self._proxies: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
|
274
|
+
|
275
|
+
#
|
276
|
+
|
277
|
+
def make_obj_marshaler(
|
278
|
+
self,
|
279
|
+
ty: ta.Any,
|
280
|
+
rec: ta.Callable[[ta.Any], ObjMarshaler],
|
281
|
+
*,
|
282
|
+
nonstrict_dataclasses: bool = False,
|
283
|
+
) -> ObjMarshaler:
|
284
|
+
if isinstance(ty, type):
|
285
|
+
if abc.ABC in ty.__bases__:
|
286
|
+
return PolymorphicObjMarshaler.of([ # type: ignore
|
287
|
+
PolymorphicObjMarshaler.Impl(
|
288
|
+
ity,
|
289
|
+
ity.__qualname__,
|
290
|
+
rec(ity),
|
291
|
+
)
|
292
|
+
for ity in deep_subclasses(ty)
|
293
|
+
if abc.ABC not in ity.__bases__
|
294
|
+
])
|
295
|
+
|
296
|
+
if issubclass(ty, enum.Enum):
|
297
|
+
return EnumObjMarshaler(ty)
|
298
|
+
|
299
|
+
if dc.is_dataclass(ty):
|
300
|
+
return DataclassObjMarshaler(
|
301
|
+
ty,
|
302
|
+
{f.name: rec(f.type) for f in dc.fields(ty)},
|
303
|
+
nonstrict=nonstrict_dataclasses,
|
304
|
+
)
|
314
305
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
306
|
+
if is_generic_alias(ty):
|
307
|
+
try:
|
308
|
+
mt = self._generic_mapping_types[ta.get_origin(ty)]
|
309
|
+
except KeyError:
|
310
|
+
pass
|
311
|
+
else:
|
312
|
+
k, v = ta.get_args(ty)
|
313
|
+
return MappingObjMarshaler(mt, rec(k), rec(v))
|
320
314
|
|
315
|
+
try:
|
316
|
+
st = self._generic_iterable_types[ta.get_origin(ty)]
|
317
|
+
except KeyError:
|
318
|
+
pass
|
319
|
+
else:
|
320
|
+
[e] = ta.get_args(ty)
|
321
|
+
return IterableObjMarshaler(st, rec(e))
|
322
|
+
|
323
|
+
if is_union_alias(ty):
|
324
|
+
return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
|
325
|
+
|
326
|
+
raise TypeError(ty)
|
327
|
+
|
328
|
+
#
|
329
|
+
|
330
|
+
def register_opj_marshaler(self, ty: ta.Any, m: ObjMarshaler) -> None:
|
331
|
+
with self._lock:
|
332
|
+
if ty in self._obj_marshalers:
|
333
|
+
raise KeyError(ty)
|
334
|
+
self._obj_marshalers[ty] = m
|
335
|
+
|
336
|
+
def get_obj_marshaler(
|
337
|
+
self,
|
338
|
+
ty: ta.Any,
|
339
|
+
*,
|
340
|
+
no_cache: bool = False,
|
341
|
+
**kwargs: ta.Any,
|
342
|
+
) -> ObjMarshaler:
|
343
|
+
with self._lock:
|
344
|
+
if not no_cache:
|
345
|
+
try:
|
346
|
+
return self._obj_marshalers[ty]
|
347
|
+
except KeyError:
|
348
|
+
pass
|
321
349
|
|
322
|
-
def get_obj_marshaler(
|
323
|
-
ty: ta.Any,
|
324
|
-
*,
|
325
|
-
no_cache: bool = False,
|
326
|
-
**kwargs: ta.Any,
|
327
|
-
) -> ObjMarshaler:
|
328
|
-
with _OBJ_MARSHALERS_LOCK:
|
329
|
-
if not no_cache:
|
330
350
|
try:
|
331
|
-
return
|
351
|
+
return self._proxies[ty]
|
332
352
|
except KeyError:
|
333
353
|
pass
|
334
354
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
355
|
+
rec = functools.partial(
|
356
|
+
self.get_obj_marshaler,
|
357
|
+
no_cache=no_cache,
|
358
|
+
**kwargs,
|
359
|
+
)
|
339
360
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
361
|
+
p = ProxyObjMarshaler()
|
362
|
+
self._proxies[ty] = p
|
363
|
+
try:
|
364
|
+
m = self.make_obj_marshaler(ty, rec, **kwargs)
|
365
|
+
finally:
|
366
|
+
del self._proxies[ty]
|
367
|
+
p.m = m
|
368
|
+
|
369
|
+
if not no_cache:
|
370
|
+
self._obj_marshalers[ty] = m
|
371
|
+
return m
|
372
|
+
|
373
|
+
#
|
345
374
|
|
346
|
-
|
347
|
-
|
348
|
-
try:
|
349
|
-
m = _make_obj_marshaler(ty, rec, **kwargs)
|
350
|
-
finally:
|
351
|
-
del _OBJ_MARSHALER_PROXIES[ty]
|
352
|
-
p.m = m
|
375
|
+
def marshal_obj(self, o: ta.Any, ty: ta.Any = None) -> ta.Any:
|
376
|
+
return self.get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
|
353
377
|
|
354
|
-
|
355
|
-
|
356
|
-
return m
|
378
|
+
def unmarshal_obj(self, o: ta.Any, ty: ta.Union[ta.Type[T], ta.Any]) -> T:
|
379
|
+
return self.get_obj_marshaler(ty).unmarshal(o)
|
357
380
|
|
358
381
|
|
359
382
|
##
|
360
383
|
|
361
384
|
|
362
|
-
|
363
|
-
return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
|
385
|
+
OBJ_MARSHALER_MANAGER = ObjMarshalerManager()
|
364
386
|
|
387
|
+
register_opj_marshaler = OBJ_MARSHALER_MANAGER.register_opj_marshaler
|
388
|
+
get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
|
365
389
|
|
366
|
-
|
367
|
-
|
390
|
+
marshal_obj = OBJ_MARSHALER_MANAGER.marshal_obj
|
391
|
+
unmarshal_obj = OBJ_MARSHALER_MANAGER.unmarshal_obj
|
omlish/lite/subprocesses.py
CHANGED
@@ -10,6 +10,19 @@ from .logs import log
|
|
10
10
|
from .runtime import is_debugger_attached
|
11
11
|
|
12
12
|
|
13
|
+
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull']
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
|
18
|
+
|
19
|
+
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
20
|
+
'pipe': subprocess.PIPE,
|
21
|
+
'stdout': subprocess.STDOUT,
|
22
|
+
'devnull': subprocess.DEVNULL,
|
23
|
+
}
|
24
|
+
|
25
|
+
|
13
26
|
##
|
14
27
|
|
15
28
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev142
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -21,6 +21,7 @@ Requires-Dist: trio-asyncio~=0.15; extra == "all"
|
|
21
21
|
Requires-Dist: lz4~=4.3; extra == "all"
|
22
22
|
Requires-Dist: python-snappy~=0.7; extra == "all"
|
23
23
|
Requires-Dist: zstandard~=0.23; extra == "all"
|
24
|
+
Requires-Dist: brotli~=1.1; extra == "all"
|
24
25
|
Requires-Dist: asttokens~=3.0; extra == "all"
|
25
26
|
Requires-Dist: executing~=2.1; extra == "all"
|
26
27
|
Requires-Dist: psutil~=6.0; extra == "all"
|
@@ -60,6 +61,7 @@ Provides-Extra: compress
|
|
60
61
|
Requires-Dist: lz4~=4.3; extra == "compress"
|
61
62
|
Requires-Dist: python-snappy~=0.7; extra == "compress"
|
62
63
|
Requires-Dist: zstandard~=0.23; extra == "compress"
|
64
|
+
Requires-Dist: brotli~=1.1; extra == "compress"
|
63
65
|
Provides-Extra: diag
|
64
66
|
Requires-Dist: asttokens~=3.0; extra == "diag"
|
65
67
|
Requires-Dist: executing~=2.1; extra == "diag"
|