omlish 0.0.0.dev141__py3-none-any.whl → 0.0.0.dev142__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|