omlish 0.0.0.dev472__py3-none-any.whl → 0.0.0.dev473__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 +2 -2
- omlish/collections/__init__.py +4 -0
- omlish/collections/attrregistry.py +32 -4
- omlish/dispatch/__init__.py +18 -12
- omlish/formats/json/stream/__init__.py +13 -0
- omlish/http/clients/asyncs.py +11 -17
- omlish/http/clients/coro/sync.py +2 -1
- omlish/http/clients/executor.py +7 -1
- omlish/http/clients/httpx.py +37 -42
- omlish/http/clients/sync.py +11 -17
- omlish/http/clients/syncasync.py +7 -1
- omlish/http/clients/urllib.py +2 -1
- omlish/io/buffers.py +115 -0
- omlish/io/readers.py +29 -0
- omlish/lite/contextmanagers.py +4 -4
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/RECORD +21 -20
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev472.dist-info → omlish-0.0.0.dev473.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/collections/__init__.py
CHANGED
|
@@ -8,7 +8,9 @@ with _lang.auto_proxy_init(globals()):
|
|
|
8
8
|
|
|
9
9
|
from .attrregistry import ( # noqa
|
|
10
10
|
AttrRegistry,
|
|
11
|
+
|
|
11
12
|
AttrRegistryCache,
|
|
13
|
+
SimpleAttrRegistryCache,
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
from .bimap import ( # noqa
|
|
@@ -17,6 +19,8 @@ with _lang.auto_proxy_init(globals()):
|
|
|
17
19
|
make_bi_map,
|
|
18
20
|
)
|
|
19
21
|
|
|
22
|
+
from . import cache # noqa
|
|
23
|
+
|
|
20
24
|
from .coerce import ( # noqa
|
|
21
25
|
abs_set,
|
|
22
26
|
abs_set_of,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- lock?
|
|
4
|
+
"""
|
|
1
5
|
import dataclasses as dc
|
|
2
6
|
import typing as ta
|
|
3
7
|
import weakref
|
|
@@ -50,13 +54,32 @@ class AttrRegistry(ta.Generic[K, V]):
|
|
|
50
54
|
def add_invalidate_callback(self, callback: ta.Callable[[], None]) -> None:
|
|
51
55
|
self._invalidate_callbacks.append(callback)
|
|
52
56
|
|
|
57
|
+
@ta.overload
|
|
53
58
|
def register(self, obj: K, val: V) -> None:
|
|
54
|
-
|
|
59
|
+
...
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
@ta.overload
|
|
62
|
+
def register(self, val: V) -> ta.Callable[[T], T]:
|
|
63
|
+
...
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
def register(self, *args):
|
|
66
|
+
def inner(obj, val):
|
|
67
|
+
check.not_in(obj, self._objs)
|
|
68
|
+
|
|
69
|
+
self._objs[obj] = val
|
|
70
|
+
|
|
71
|
+
for iv in self._invalidate_callbacks:
|
|
72
|
+
iv()
|
|
73
|
+
|
|
74
|
+
return obj
|
|
75
|
+
|
|
76
|
+
if len(args) == 1:
|
|
77
|
+
return lambda obj: inner(obj, args[0])
|
|
78
|
+
elif len(args) == 2:
|
|
79
|
+
inner = inner(*args)
|
|
80
|
+
return None
|
|
81
|
+
else:
|
|
82
|
+
raise TypeError(args)
|
|
60
83
|
|
|
61
84
|
def _lookup(self, obj: ta.Any) -> lang.Maybe[V]:
|
|
62
85
|
if not self._identity:
|
|
@@ -180,3 +203,8 @@ class AttrRegistryCache(ta.Generic[K, V, T]):
|
|
|
180
203
|
out = self._prepare(instance_cls, collected)
|
|
181
204
|
self._cache[weakref.ref(instance_cls, self._cache_remove)] = out
|
|
182
205
|
return out
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class SimpleAttrRegistryCache(AttrRegistryCache[K, V, dict[str, tuple[K, V]]], ta.Generic[K, V]):
|
|
209
|
+
def __init__(self, registry: AttrRegistry[K, V]) -> None:
|
|
210
|
+
super().__init__(registry, lambda _, dct: dct)
|
omlish/dispatch/__init__.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
from .. import lang as _lang
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
with _lang.auto_proxy_init(globals()):
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
from .dispatch import ( # noqa
|
|
8
|
+
Dispatcher,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from .functions import ( # noqa
|
|
12
|
+
function,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from .methods import ( # noqa
|
|
16
|
+
install_method,
|
|
17
|
+
method,
|
|
18
|
+
)
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A generator powered, configurable, mostly fully streaming JSON parser.
|
|
3
|
+
|
|
4
|
+
Regarding the 'streamyness' of the subsystems:
|
|
5
|
+
- Lexing only buffers for string and number literals.
|
|
6
|
+
- Parsing maintains only a stack that scales by nesting depth.
|
|
7
|
+
- Building values will obviously hold everything under the topmost object it's building until it's finished.
|
|
8
|
+
|
|
9
|
+
It's reasonably optimized, but performance is not a primary or even secondary goal: its goal is flexibility. If speed
|
|
10
|
+
matters use a native library.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
1
14
|
from .building import ( # noqa
|
|
2
15
|
JsonValueBuilder,
|
|
3
16
|
)
|
omlish/http/clients/asyncs.py
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import abc
|
|
4
4
|
import contextlib
|
|
5
5
|
import dataclasses as dc
|
|
6
|
-
import io
|
|
7
6
|
import typing as ta
|
|
8
7
|
|
|
8
|
+
from ...io.readers import AsyncBufferedBytesReader
|
|
9
9
|
from ...lite.abstract import Abstract
|
|
10
10
|
from ...lite.dataclasses import dataclass_shallow_asdict
|
|
11
11
|
from .base import BaseHttpClient
|
|
@@ -27,25 +27,19 @@ AsyncHttpClientT = ta.TypeVar('AsyncHttpClientT', bound='AsyncHttpClient')
|
|
|
27
27
|
@ta.final
|
|
28
28
|
@dc.dataclass(frozen=True) # kw_only=True
|
|
29
29
|
class AsyncStreamHttpResponse(BaseHttpResponse):
|
|
30
|
-
|
|
31
|
-
def read1(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
30
|
+
_stream: ta.Optional[AsyncBufferedBytesReader] = None
|
|
32
31
|
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
raise TypeError
|
|
37
|
-
|
|
38
|
-
stream: Stream = _NullStream()
|
|
32
|
+
@property
|
|
33
|
+
def stream(self) -> 'AsyncBufferedBytesReader':
|
|
34
|
+
if (st := self._stream) is None:
|
|
35
|
+
raise TypeError('No data')
|
|
36
|
+
return st
|
|
39
37
|
|
|
40
38
|
@property
|
|
41
39
|
def has_data(self) -> bool:
|
|
42
|
-
return
|
|
40
|
+
return self._stream is not None
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
buf = io.BytesIO()
|
|
46
|
-
while (b := await self.stream.read1()):
|
|
47
|
-
buf.write(b)
|
|
48
|
-
return buf.getvalue()
|
|
42
|
+
#
|
|
49
43
|
|
|
50
44
|
_closer: ta.Optional[ta.Callable[[], ta.Awaitable[None]]] = None
|
|
51
45
|
|
|
@@ -96,8 +90,8 @@ async def async_read_http_client_response(resp: BaseHttpResponse) -> HttpRespons
|
|
|
96
90
|
|
|
97
91
|
elif isinstance(resp, AsyncStreamHttpResponse):
|
|
98
92
|
return HttpResponse(**{
|
|
99
|
-
**{k: v for k, v in dataclass_shallow_asdict(resp).items() if k not in ('
|
|
100
|
-
**({'data': await resp.
|
|
93
|
+
**{k: v for k, v in dataclass_shallow_asdict(resp).items() if k not in ('_stream', '_closer')},
|
|
94
|
+
**({'data': await resp.stream.readall()} if resp.has_data else {}),
|
|
101
95
|
})
|
|
102
96
|
|
|
103
97
|
else:
|
omlish/http/clients/coro/sync.py
CHANGED
|
@@ -5,6 +5,7 @@ import socket
|
|
|
5
5
|
import typing as ta
|
|
6
6
|
import urllib.parse
|
|
7
7
|
|
|
8
|
+
from ....io.buffers import ReadableListBuffer
|
|
8
9
|
from ....lite.check import check
|
|
9
10
|
from ...coro.client.connection import CoroHttpClientConnection
|
|
10
11
|
from ...coro.client.response import CoroHttpClientResponse
|
|
@@ -92,7 +93,7 @@ class CoroHttpClient(HttpClient):
|
|
|
92
93
|
headers=HttpHeaders(resp._state.headers.items()), # noqa
|
|
93
94
|
request=self._req,
|
|
94
95
|
underlying=self,
|
|
95
|
-
|
|
96
|
+
_stream=ReadableListBuffer().new_buffered_reader(self),
|
|
96
97
|
_closer=self.close,
|
|
97
98
|
)
|
|
98
99
|
|
omlish/http/clients/executor.py
CHANGED
|
@@ -33,6 +33,12 @@ class ExecutorAsyncHttpClient(AsyncHttpClient):
|
|
|
33
33
|
async def read1(self, /, n: int = -1) -> bytes:
|
|
34
34
|
return await self.owner._run_in_executor(self.resp.stream.read1, n) # noqa
|
|
35
35
|
|
|
36
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
37
|
+
return await self.owner._run_in_executor(self.resp.stream.read, n) # noqa
|
|
38
|
+
|
|
39
|
+
async def readall(self) -> bytes:
|
|
40
|
+
return await self.owner._run_in_executor(self.resp.stream.readall) # noqa
|
|
41
|
+
|
|
36
42
|
async def close(self) -> None:
|
|
37
43
|
return await self.owner._run_in_executor(self.resp.close) # noqa
|
|
38
44
|
|
|
@@ -44,7 +50,7 @@ class ExecutorAsyncHttpClient(AsyncHttpClient):
|
|
|
44
50
|
request=req,
|
|
45
51
|
underlying=resp,
|
|
46
52
|
**(dict( # type: ignore
|
|
47
|
-
|
|
53
|
+
_stream=(adapter := self._StreamAdapter(self, resp)),
|
|
48
54
|
_closer=adapter.close,
|
|
49
55
|
) if resp.has_data else {}),
|
|
50
56
|
)
|
omlish/http/clients/httpx.py
CHANGED
|
@@ -32,27 +32,12 @@ class HttpxHttpClient(HttpClient):
|
|
|
32
32
|
@dc.dataclass(frozen=True)
|
|
33
33
|
class _StreamAdapter:
|
|
34
34
|
it: ta.Iterator[bytes]
|
|
35
|
-
buf: ReadableListBuffer = dc.field(default_factory=ReadableListBuffer)
|
|
36
35
|
|
|
37
36
|
def read1(self, /, n: int = -1) -> bytes:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return next(self.it)
|
|
43
|
-
except StopIteration:
|
|
44
|
-
return b''
|
|
45
|
-
|
|
46
|
-
else:
|
|
47
|
-
while len(self.buf) < n:
|
|
48
|
-
try:
|
|
49
|
-
b = next(self.it)
|
|
50
|
-
except StopIteration:
|
|
51
|
-
b = b''
|
|
52
|
-
if not b:
|
|
53
|
-
return self.buf.read() or b''
|
|
54
|
-
self.buf.feed(b)
|
|
55
|
-
return self.buf.read(n) or b''
|
|
37
|
+
try:
|
|
38
|
+
return next(self.it)
|
|
39
|
+
except StopIteration:
|
|
40
|
+
return b''
|
|
56
41
|
|
|
57
42
|
def _stream_request(self, ctx: HttpClientContext, req: HttpRequest) -> StreamHttpResponse:
|
|
58
43
|
try:
|
|
@@ -76,7 +61,7 @@ class HttpxHttpClient(HttpClient):
|
|
|
76
61
|
headers=HttpHeaders(resp.headers.raw),
|
|
77
62
|
request=req,
|
|
78
63
|
underlying=resp,
|
|
79
|
-
|
|
64
|
+
_stream=ReadableListBuffer().new_buffered_reader(self._StreamAdapter(resp.iter_bytes())),
|
|
80
65
|
_closer=resp_close, # type: ignore
|
|
81
66
|
)
|
|
82
67
|
|
|
@@ -84,7 +69,7 @@ class HttpxHttpClient(HttpClient):
|
|
|
84
69
|
resp_close()
|
|
85
70
|
raise HttpClientError from e
|
|
86
71
|
|
|
87
|
-
except
|
|
72
|
+
except BaseException:
|
|
88
73
|
resp_close()
|
|
89
74
|
raise
|
|
90
75
|
|
|
@@ -96,27 +81,12 @@ class HttpxAsyncHttpClient(AsyncHttpClient):
|
|
|
96
81
|
@dc.dataclass(frozen=True)
|
|
97
82
|
class _StreamAdapter:
|
|
98
83
|
it: ta.AsyncIterator[bytes]
|
|
99
|
-
buf: ReadableListBuffer = dc.field(default_factory=ReadableListBuffer)
|
|
100
84
|
|
|
101
85
|
async def read1(self, /, n: int = -1) -> bytes:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return await anext(self.it)
|
|
107
|
-
except StopAsyncIteration:
|
|
108
|
-
return b''
|
|
109
|
-
|
|
110
|
-
else:
|
|
111
|
-
while len(self.buf) < n:
|
|
112
|
-
try:
|
|
113
|
-
b = await anext(self.it)
|
|
114
|
-
except StopAsyncIteration:
|
|
115
|
-
b = b''
|
|
116
|
-
if not b:
|
|
117
|
-
return self.buf.read() or b''
|
|
118
|
-
self.buf.feed(b)
|
|
119
|
-
return self.buf.read(n) or b''
|
|
86
|
+
try:
|
|
87
|
+
return await anext(self.it)
|
|
88
|
+
except StopAsyncIteration:
|
|
89
|
+
return b''
|
|
120
90
|
|
|
121
91
|
async def _stream_request(self, ctx: HttpClientContext, req: HttpRequest) -> AsyncStreamHttpResponse:
|
|
122
92
|
es = contextlib.AsyncExitStack()
|
|
@@ -132,12 +102,37 @@ class HttpxAsyncHttpClient(AsyncHttpClient):
|
|
|
132
102
|
timeout=req.timeout_s,
|
|
133
103
|
))
|
|
134
104
|
|
|
105
|
+
it = resp.aiter_bytes()
|
|
106
|
+
|
|
107
|
+
# FIXME:
|
|
108
|
+
# - https://github.com/encode/httpx/discussions/2963
|
|
109
|
+
# - Exception ignored in: <async_generator object HTTP11ConnectionByteStream.__aiter__ at 0x1325a7540>
|
|
110
|
+
# - RuntimeError: async generator ignored GeneratorExit
|
|
111
|
+
# - Traced to:
|
|
112
|
+
# - HTTP11ConnectionByteStream.aclose -> await self._connection._response_closed()
|
|
113
|
+
# - AsyncHTTP11Connection._response_closed -> async with self._state_lock
|
|
114
|
+
# - anyio._backends._asyncio.Lock.acquire -> await AsyncIOBackend.cancel_shielded_checkpoint() -> await sleep(0) # noqa
|
|
115
|
+
# - Might have something to do with pycharm/pydevd's nested asyncio, doesn't seem to happen under trio ever
|
|
116
|
+
# or asyncio outside debugger.
|
|
117
|
+
@es.push_async_callback
|
|
118
|
+
async def close_it() -> None:
|
|
119
|
+
try:
|
|
120
|
+
# print(f'close_it.begin: {it=}', file=sys.stderr)
|
|
121
|
+
await it.aclose() # type: ignore[attr-defined]
|
|
122
|
+
# print(f'close_it.end: {it=}', file=sys.stderr)
|
|
123
|
+
except BaseException as be: # noqa
|
|
124
|
+
# print(f'close_it.__exit__: {it=} {be=}', file=sys.stderr)
|
|
125
|
+
raise
|
|
126
|
+
finally:
|
|
127
|
+
# print(f'close_it.finally: {it=}', file=sys.stderr)
|
|
128
|
+
pass
|
|
129
|
+
|
|
135
130
|
return AsyncStreamHttpResponse(
|
|
136
131
|
status=resp.status_code,
|
|
137
132
|
headers=HttpHeaders(resp.headers.raw),
|
|
138
133
|
request=req,
|
|
139
134
|
underlying=resp,
|
|
140
|
-
|
|
135
|
+
_stream=ReadableListBuffer().new_async_buffered_reader(self._StreamAdapter(it)),
|
|
141
136
|
_closer=es.aclose,
|
|
142
137
|
)
|
|
143
138
|
|
|
@@ -145,6 +140,6 @@ class HttpxAsyncHttpClient(AsyncHttpClient):
|
|
|
145
140
|
await es.aclose()
|
|
146
141
|
raise HttpClientError from e
|
|
147
142
|
|
|
148
|
-
except
|
|
143
|
+
except BaseException:
|
|
149
144
|
await es.aclose()
|
|
150
145
|
raise
|
omlish/http/clients/sync.py
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import abc
|
|
4
4
|
import contextlib
|
|
5
5
|
import dataclasses as dc
|
|
6
|
-
import io
|
|
7
6
|
import typing as ta
|
|
8
7
|
|
|
8
|
+
from ...io.readers import BufferedBytesReader
|
|
9
9
|
from ...lite.abstract import Abstract
|
|
10
10
|
from ...lite.dataclasses import dataclass_shallow_asdict
|
|
11
11
|
from .base import BaseHttpClient
|
|
@@ -27,25 +27,19 @@ HttpClientT = ta.TypeVar('HttpClientT', bound='HttpClient')
|
|
|
27
27
|
@ta.final
|
|
28
28
|
@dc.dataclass(frozen=True) # kw_only=True
|
|
29
29
|
class StreamHttpResponse(BaseHttpResponse):
|
|
30
|
-
|
|
31
|
-
def read1(self, /, n: int = -1) -> bytes: ...
|
|
30
|
+
_stream: ta.Optional[BufferedBytesReader] = None
|
|
32
31
|
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
raise TypeError
|
|
37
|
-
|
|
38
|
-
stream: Stream = _NullStream()
|
|
32
|
+
@property
|
|
33
|
+
def stream(self) -> 'BufferedBytesReader':
|
|
34
|
+
if (st := self._stream) is None:
|
|
35
|
+
raise TypeError('No data')
|
|
36
|
+
return st
|
|
39
37
|
|
|
40
38
|
@property
|
|
41
39
|
def has_data(self) -> bool:
|
|
42
|
-
return
|
|
40
|
+
return self._stream is not None
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
buf = io.BytesIO()
|
|
46
|
-
while (b := self.stream.read1()):
|
|
47
|
-
buf.write(b)
|
|
48
|
-
return buf.getvalue()
|
|
42
|
+
#
|
|
49
43
|
|
|
50
44
|
_closer: ta.Optional[ta.Callable[[], None]] = None
|
|
51
45
|
|
|
@@ -94,8 +88,8 @@ def read_http_client_response(resp: BaseHttpResponse) -> HttpResponse:
|
|
|
94
88
|
|
|
95
89
|
elif isinstance(resp, StreamHttpResponse):
|
|
96
90
|
return HttpResponse(**{
|
|
97
|
-
**{k: v for k, v in dataclass_shallow_asdict(resp).items() if k not in ('
|
|
98
|
-
**({'data': resp.
|
|
91
|
+
**{k: v for k, v in dataclass_shallow_asdict(resp).items() if k not in ('_stream', '_closer')},
|
|
92
|
+
**({'data': resp.stream.readall()} if resp.has_data else {}),
|
|
99
93
|
})
|
|
100
94
|
|
|
101
95
|
else:
|
omlish/http/clients/syncasync.py
CHANGED
|
@@ -26,6 +26,12 @@ class SyncAsyncHttpClient(AsyncHttpClient):
|
|
|
26
26
|
async def read1(self, /, n: int = -1) -> bytes:
|
|
27
27
|
return self.ul.stream.read1(n)
|
|
28
28
|
|
|
29
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
30
|
+
return self.ul.stream.read(n)
|
|
31
|
+
|
|
32
|
+
async def readall(self) -> bytes:
|
|
33
|
+
return self.ul.stream.readall()
|
|
34
|
+
|
|
29
35
|
async def close(self) -> None:
|
|
30
36
|
self.ul.close()
|
|
31
37
|
|
|
@@ -37,7 +43,7 @@ class SyncAsyncHttpClient(AsyncHttpClient):
|
|
|
37
43
|
request=req,
|
|
38
44
|
underlying=resp,
|
|
39
45
|
**(dict( # type: ignore
|
|
40
|
-
|
|
46
|
+
_stream=(adapter := self._StreamAdapter(resp)),
|
|
41
47
|
_closer=adapter.close,
|
|
42
48
|
) if resp.has_data else {}),
|
|
43
49
|
)
|
omlish/http/clients/urllib.py
CHANGED
|
@@ -5,6 +5,7 @@ import typing as ta
|
|
|
5
5
|
import urllib.error
|
|
6
6
|
import urllib.request
|
|
7
7
|
|
|
8
|
+
from ...io.buffers import ReadableListBuffer
|
|
8
9
|
from ..headers import HttpHeaders
|
|
9
10
|
from .base import DEFAULT_ENCODING
|
|
10
11
|
from .base import HttpClientContext
|
|
@@ -72,7 +73,7 @@ class UrllibHttpClient(HttpClient):
|
|
|
72
73
|
headers=HttpHeaders(resp.headers.items()),
|
|
73
74
|
request=req,
|
|
74
75
|
underlying=resp,
|
|
75
|
-
|
|
76
|
+
_stream=ReadableListBuffer().new_buffered_reader(resp),
|
|
76
77
|
_closer=resp.close,
|
|
77
78
|
)
|
|
78
79
|
|
omlish/io/buffers.py
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
# ruff: noqa: UP006 UP007 UP043 UP045
|
|
2
2
|
# @omlish-lite
|
|
3
|
+
"""
|
|
4
|
+
TODO:
|
|
5
|
+
- overhaul and just coro-ify pyio?
|
|
6
|
+
"""
|
|
3
7
|
import io
|
|
4
8
|
import typing as ta
|
|
5
9
|
|
|
6
10
|
from ..lite.attrops import attr_repr
|
|
7
11
|
from ..lite.check import check
|
|
12
|
+
from .readers import AsyncBufferedBytesReader
|
|
13
|
+
from .readers import AsyncRawBytesReader
|
|
14
|
+
from .readers import BufferedBytesReader
|
|
15
|
+
from .readers import RawBytesReader
|
|
8
16
|
|
|
9
17
|
|
|
10
18
|
##
|
|
@@ -183,6 +191,9 @@ class ReadableListBuffer:
|
|
|
183
191
|
|
|
184
192
|
self._lst: list[bytes] = []
|
|
185
193
|
|
|
194
|
+
def __bool__(self) -> ta.NoReturn:
|
|
195
|
+
raise TypeError("Use 'buf is not None' or 'len(buf)'.")
|
|
196
|
+
|
|
186
197
|
def __len__(self) -> int:
|
|
187
198
|
return sum(map(len, self._lst))
|
|
188
199
|
|
|
@@ -249,6 +260,110 @@ class ReadableListBuffer:
|
|
|
249
260
|
r = self.read_until_(delim)
|
|
250
261
|
return r if isinstance(r, bytes) else None
|
|
251
262
|
|
|
263
|
+
#
|
|
264
|
+
|
|
265
|
+
DEFAULT_BUFFERED_READER_CHUNK_SIZE: ta.ClassVar[int] = -1
|
|
266
|
+
|
|
267
|
+
@ta.final
|
|
268
|
+
class _BufferedBytesReader(BufferedBytesReader):
|
|
269
|
+
def __init__(
|
|
270
|
+
self,
|
|
271
|
+
raw: RawBytesReader,
|
|
272
|
+
buf: 'ReadableListBuffer',
|
|
273
|
+
*,
|
|
274
|
+
chunk_size: ta.Optional[int] = None,
|
|
275
|
+
) -> None:
|
|
276
|
+
self._raw = raw
|
|
277
|
+
self._buf = buf
|
|
278
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
279
|
+
|
|
280
|
+
def read1(self, /, n: int = -1) -> bytes:
|
|
281
|
+
if n < 0:
|
|
282
|
+
n = self._chunk_size
|
|
283
|
+
if not n:
|
|
284
|
+
return b''
|
|
285
|
+
if 0 < n <= len(self._buf):
|
|
286
|
+
return self._buf.read(n) or b''
|
|
287
|
+
return self._raw.read1(n)
|
|
288
|
+
|
|
289
|
+
def read(self, /, n: int = -1) -> bytes:
|
|
290
|
+
if n < 0:
|
|
291
|
+
return self.readall()
|
|
292
|
+
while len(self._buf) < n:
|
|
293
|
+
if not (b := self._raw.read1(n)):
|
|
294
|
+
break
|
|
295
|
+
self._buf.feed(b)
|
|
296
|
+
return self._buf.read(n) or b''
|
|
297
|
+
|
|
298
|
+
def readall(self) -> bytes:
|
|
299
|
+
buf = io.BytesIO()
|
|
300
|
+
buf.write(self._buf.read() or b'')
|
|
301
|
+
while (b := self._raw.read1(self._chunk_size)):
|
|
302
|
+
buf.write(b)
|
|
303
|
+
return buf.getvalue()
|
|
304
|
+
|
|
305
|
+
def new_buffered_reader(
|
|
306
|
+
self,
|
|
307
|
+
raw: RawBytesReader,
|
|
308
|
+
*,
|
|
309
|
+
chunk_size: ta.Optional[int] = None,
|
|
310
|
+
) -> BufferedBytesReader:
|
|
311
|
+
return self._BufferedBytesReader(
|
|
312
|
+
raw,
|
|
313
|
+
self,
|
|
314
|
+
chunk_size=chunk_size,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
@ta.final
|
|
318
|
+
class _AsyncBufferedBytesReader(AsyncBufferedBytesReader):
|
|
319
|
+
def __init__(
|
|
320
|
+
self,
|
|
321
|
+
raw: AsyncRawBytesReader,
|
|
322
|
+
buf: 'ReadableListBuffer',
|
|
323
|
+
*,
|
|
324
|
+
chunk_size: ta.Optional[int] = None,
|
|
325
|
+
) -> None:
|
|
326
|
+
self._raw = raw
|
|
327
|
+
self._buf = buf
|
|
328
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
329
|
+
|
|
330
|
+
async def read1(self, /, n: int = -1) -> bytes:
|
|
331
|
+
if n < 0:
|
|
332
|
+
n = self._chunk_size
|
|
333
|
+
if not n:
|
|
334
|
+
return b''
|
|
335
|
+
if 0 < n <= len(self._buf):
|
|
336
|
+
return self._buf.read(n) or b''
|
|
337
|
+
return await self._raw.read1(n)
|
|
338
|
+
|
|
339
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
340
|
+
if n < 0:
|
|
341
|
+
return await self.readall()
|
|
342
|
+
while len(self._buf) < n:
|
|
343
|
+
if not (b := await self._raw.read1(n)):
|
|
344
|
+
break
|
|
345
|
+
self._buf.feed(b)
|
|
346
|
+
return self._buf.read(n) or b''
|
|
347
|
+
|
|
348
|
+
async def readall(self) -> bytes:
|
|
349
|
+
buf = io.BytesIO()
|
|
350
|
+
buf.write(self._buf.read() or b'')
|
|
351
|
+
while b := await self._raw.read1(self._chunk_size):
|
|
352
|
+
buf.write(b)
|
|
353
|
+
return buf.getvalue()
|
|
354
|
+
|
|
355
|
+
def new_async_buffered_reader(
|
|
356
|
+
self,
|
|
357
|
+
raw: AsyncRawBytesReader,
|
|
358
|
+
*,
|
|
359
|
+
chunk_size: ta.Optional[int] = None,
|
|
360
|
+
) -> AsyncBufferedBytesReader:
|
|
361
|
+
return self._AsyncBufferedBytesReader(
|
|
362
|
+
raw,
|
|
363
|
+
self,
|
|
364
|
+
chunk_size=chunk_size,
|
|
365
|
+
)
|
|
366
|
+
|
|
252
367
|
|
|
253
368
|
##
|
|
254
369
|
|
omlish/io/readers.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# ruff: noqa: UP045
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RawBytesReader(ta.Protocol):
|
|
10
|
+
def read1(self, /, n: int = -1) -> bytes: ...
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BufferedBytesReader(RawBytesReader, ta.Protocol):
|
|
14
|
+
def read(self, /, n: int = -1) -> bytes: ...
|
|
15
|
+
|
|
16
|
+
def readall(self) -> bytes: ...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AsyncRawBytesReader(ta.Protocol):
|
|
23
|
+
def read1(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AsyncBufferedBytesReader(AsyncRawBytesReader, ta.Protocol):
|
|
27
|
+
def read(self, /, n: int = -1) -> ta.Awaitable[bytes]: ...
|
|
28
|
+
|
|
29
|
+
def readall(self) -> ta.Awaitable[bytes]: ...
|
omlish/lite/contextmanagers.py
CHANGED
|
@@ -54,7 +54,7 @@ class ExitStacked:
|
|
|
54
54
|
es.__enter__()
|
|
55
55
|
try:
|
|
56
56
|
self._enter_contexts()
|
|
57
|
-
except
|
|
57
|
+
except BaseException: # noqa
|
|
58
58
|
es.__exit__(*sys.exc_info())
|
|
59
59
|
raise
|
|
60
60
|
return self
|
|
@@ -65,7 +65,7 @@ class ExitStacked:
|
|
|
65
65
|
return None
|
|
66
66
|
try:
|
|
67
67
|
self._exit_contexts()
|
|
68
|
-
except
|
|
68
|
+
except BaseException: # noqa
|
|
69
69
|
es.__exit__(*sys.exc_info())
|
|
70
70
|
raise
|
|
71
71
|
return es.__exit__(exc_type, exc_val, exc_tb)
|
|
@@ -113,7 +113,7 @@ class AsyncExitStacked:
|
|
|
113
113
|
await es.__aenter__()
|
|
114
114
|
try:
|
|
115
115
|
await self._async_enter_contexts()
|
|
116
|
-
except
|
|
116
|
+
except BaseException: # noqa
|
|
117
117
|
await es.__aexit__(*sys.exc_info())
|
|
118
118
|
raise
|
|
119
119
|
return self
|
|
@@ -124,7 +124,7 @@ class AsyncExitStacked:
|
|
|
124
124
|
return None
|
|
125
125
|
try:
|
|
126
126
|
await self._async_exit_contexts()
|
|
127
|
-
except
|
|
127
|
+
except BaseException: # noqa
|
|
128
128
|
await es.__aexit__(*sys.exc_info())
|
|
129
129
|
raise
|
|
130
130
|
return await es.__aexit__(exc_type, exc_val, exc_tb)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
omlish/.omlish-manifests.json,sha256=FLw7xkPiSXuImZgqSP8BwrEib2R1doSzUPLUkc-QUIA,8410
|
|
2
|
-
omlish/__about__.py,sha256=
|
|
2
|
+
omlish/__about__.py,sha256=BoG13E5l8VG76ZQEVeoy6T90tE-JO2_DCUi_285ZWU0,3611
|
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
|
4
4
|
omlish/c3.py,sha256=ZNIMl1kwg3qdei4DiUrJPQe5M81S1e76N-GuNSwLBAE,8683
|
|
5
5
|
omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
|
|
@@ -67,9 +67,9 @@ omlish/codecs/funcs.py,sha256=or0Jogczuzk7csDTRl-HURMEjl8LXXqxxXYK45xcM5w,855
|
|
|
67
67
|
omlish/codecs/registry.py,sha256=y7gjhBY1tTTHZmaK4X02zL5HD_25AAiZ8k27Op69Ag0,4006
|
|
68
68
|
omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
|
|
69
69
|
omlish/codecs/text.py,sha256=P9-xpdiQE3nbI5CzEentf07FBHPzD7_SwOtUQUJ01So,5710
|
|
70
|
-
omlish/collections/__init__.py,sha256=
|
|
70
|
+
omlish/collections/__init__.py,sha256=zlyn2_SR1QaRomuqziEmONqSdgcalHjjULA66GiKOyk,3001
|
|
71
71
|
omlish/collections/abc.py,sha256=p9zhL5oNV5WPyWmMn34fWfkuxPQAjOtL7WQA-Xsyhwk,2628
|
|
72
|
-
omlish/collections/attrregistry.py,sha256=
|
|
72
|
+
omlish/collections/attrregistry.py,sha256=IvepCE4EcU0zsjPRC-A9LxXjMqkK8i2LmlekVHHSsaY,6231
|
|
73
73
|
omlish/collections/bimap.py,sha256=3szDCscPJlFRtkpyVQNWneg4s50mr6Rd0jdTzVEIcnE,1661
|
|
74
74
|
omlish/collections/coerce.py,sha256=tAls15v_7p5bUN33R7Zbko87KW5toWHl9fRialCqyNY,7030
|
|
75
75
|
omlish/collections/frozen.py,sha256=drarjcMFpwKhBM01b1Gh6XDcaRaUgpyuxEiqppaKRkU,4220
|
|
@@ -217,7 +217,7 @@ omlish/diag/replserver/__init__.py,sha256=uLo6V2aQ29v9z3IMELlPDSlG3_2iOT4-_X8Vni
|
|
|
217
217
|
omlish/diag/replserver/__main__.py,sha256=LmU41lQ58bm1h4Mx7S8zhE_uEBSC6kPcp9mn5JRpulA,32
|
|
218
218
|
omlish/diag/replserver/console.py,sha256=MxDLslAaYfC-l0rfGO-SnYAJ__8RWBJQ5FxGi29czYU,7438
|
|
219
219
|
omlish/diag/replserver/server.py,sha256=zTeyaARK22KwaqCOzG8H8Rk009en7gBxOBaJcRB1jbM,5402
|
|
220
|
-
omlish/dispatch/__init__.py,sha256=
|
|
220
|
+
omlish/dispatch/__init__.py,sha256=OlebxKvMJs2nT36p3xCB4arA3Ln0pnQvfwBaUJ5SdiE,284
|
|
221
221
|
omlish/dispatch/dispatch.py,sha256=TzWihCt9Zr8wfIwVpKHVOOrYFVKpDXRevxYomtEfqYc,3176
|
|
222
222
|
omlish/dispatch/functions.py,sha256=cwNzGIg2ZIalEgn9I03cnJVbMTHjWloyDTaowlO3UPs,1524
|
|
223
223
|
omlish/dispatch/impls.py,sha256=3kyLw5yiYXWCN1DiqQbD1czMVrM8v1mpQ8NyD0tUrnk,1870
|
|
@@ -270,7 +270,7 @@ omlish/formats/json/backends/jiter.py,sha256=8qv_XWGpcupPtVm6Z_egHio_iY1Kk8eqkvX
|
|
|
270
270
|
omlish/formats/json/backends/orjson.py,sha256=X2jhKgUYYwaVuAppPQmfyncbOs2PJ7drqH5BioP-AYI,3831
|
|
271
271
|
omlish/formats/json/backends/std.py,sha256=Hhiug5CkC1TXLFrE9rnMR2on7xP-RliSvfYA9ill_U0,3159
|
|
272
272
|
omlish/formats/json/backends/ujson.py,sha256=U3iOlAURfiCdXbiNlXfIjDdtJDbDaLZsSuZriTUvbxs,2307
|
|
273
|
-
omlish/formats/json/stream/__init__.py,sha256=
|
|
273
|
+
omlish/formats/json/stream/__init__.py,sha256=YIRCs5ckY_y1v08OwGGtU4nXlo-ByO4IsibTlZZIsAM,1366
|
|
274
274
|
omlish/formats/json/stream/building.py,sha256=QAQaTyXuw9vkfhvzWIh_DSlypD1-HgzO855Dgz3_wFM,2517
|
|
275
275
|
omlish/formats/json/stream/errors.py,sha256=c8M8UAYmIZ-vWZLeKD2jMj4EDCJbr9QR8Jq_DyHjujQ,43
|
|
276
276
|
omlish/formats/json/stream/lexing.py,sha256=FeO7sjCQ6HHBj7VJIwkSxMPUneG1KqDyN-zuACdE_rw,17384
|
|
@@ -323,17 +323,17 @@ omlish/http/urls.py,sha256=dZBeQwf5ogKwsD_uCEei5EG_SbnHk-MzpX2FYLsfTgM,1774
|
|
|
323
323
|
omlish/http/versions.py,sha256=Lwk6FztKH7c5zuc7NFWxPVULuLeeQp5-NFJInY6r-Zo,420
|
|
324
324
|
omlish/http/wsgi.py,sha256=1JpfrY2JrQ0wrEVE0oLdQMWZw8Zcx0b4_9f3VmH4JKA,1070
|
|
325
325
|
omlish/http/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
326
|
-
omlish/http/clients/asyncs.py,sha256=
|
|
326
|
+
omlish/http/clients/asyncs.py,sha256=QrbavgXv4BuQFW0bRojy-dxa_jpxjPVLA7eyfo1zzns,4230
|
|
327
327
|
omlish/http/clients/base.py,sha256=bm3Oy2wuunSO3Rd2dxCmhHoZcQ8X9B5pkzaudbjZKvI,2810
|
|
328
328
|
omlish/http/clients/default.py,sha256=fnz-pvPKHc7Kgft4XRwOZ6ZUUtt5D6ljuvOGAA8mgQw,5639
|
|
329
|
-
omlish/http/clients/executor.py,sha256=
|
|
330
|
-
omlish/http/clients/httpx.py,sha256=
|
|
329
|
+
omlish/http/clients/executor.py,sha256=yvjLs8XfJuHx0mDOC1nqKsQbQXqo2cldH8oQIBhfjOY,1854
|
|
330
|
+
omlish/http/clients/httpx.py,sha256=Yp0u_DAPImqJ1_jlAN9RKWbkUP6Y_lfGJWJjaFWBdJQ,4793
|
|
331
331
|
omlish/http/clients/middleware.py,sha256=xnXlNN1MU4sUKtkhPzdpRQsRh9wpLf1r7OGKjqGzLWg,5058
|
|
332
|
-
omlish/http/clients/sync.py,sha256=
|
|
333
|
-
omlish/http/clients/syncasync.py,sha256=
|
|
334
|
-
omlish/http/clients/urllib.py,sha256=
|
|
332
|
+
omlish/http/clients/sync.py,sha256=jVbqbUlruuaNFKUYQr55kVF6bwcIZgeaLyLclXM_T5w,3891
|
|
333
|
+
omlish/http/clients/syncasync.py,sha256=2VfApHxoz3dBilOJhxyaP9LnWWNdqn5G4Tss6CRruXM,1401
|
|
334
|
+
omlish/http/clients/urllib.py,sha256=c8TQITZYRo5RrdxaNhsE2QoeDw4mZW0wLzoIsWYTYwU,2852
|
|
335
335
|
omlish/http/clients/coro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
336
|
-
omlish/http/clients/coro/sync.py,sha256=
|
|
336
|
+
omlish/http/clients/coro/sync.py,sha256=x5VoA31lPyxGMkuYAXgEziDfL_mhV_VP6iQ4HmpLjjE,5762
|
|
337
337
|
omlish/http/coro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
338
338
|
omlish/http/coro/io.py,sha256=d97Oa7KlgMP7BQWdhUbOv3sfA96uWyMtjJF7lJFwZC0,1090
|
|
339
339
|
omlish/http/coro/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -390,9 +390,10 @@ omlish/inject/impl/scopes.py,sha256=sqtjHe6g0pAEOHqIARXGiIE9mKmGmlqh1FDpskV4TIw,
|
|
|
390
390
|
omlish/inject/impl/sync.py,sha256=_aLaC-uVNHOePcfE1as61Ni7fuyHZpjEafIWBc7FvC0,1049
|
|
391
391
|
omlish/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
392
392
|
omlish/io/abc.py,sha256=M40QB2udYpCEqmlxCcHv6FlJYJY6ymmJQBlaklYv0U8,1256
|
|
393
|
-
omlish/io/buffers.py,sha256=
|
|
393
|
+
omlish/io/buffers.py,sha256=GueMHwOLGd6Q-UxLrGobYYNTm0fc5GBtltwzYgLxGIQ,10935
|
|
394
394
|
omlish/io/fileno.py,sha256=_W3qxkIKpnabn1_7kgmKdx0IsPF3R334xWnF_TtkEj4,185
|
|
395
395
|
omlish/io/pyio.py,sha256=xmHTV-sn7QZThWCVBo6lTM7dhgsQn7m2L0DqRwdF2-8,94509
|
|
396
|
+
omlish/io/readers.py,sha256=O_FcMW6wXSoKhyhM9dKFg9lVJ8mS-Q5I9xnFLfgJMKQ,583
|
|
396
397
|
omlish/io/compress/__init__.py,sha256=fJFPT4ONfqxmsA4jR6qbMt2woIyyEgnc_qOWK9o1kII,247
|
|
397
398
|
omlish/io/compress/abc.py,sha256=P9YoQX8XYoq2UfBsinKLUuwwqV1ODUIJzjTraRWGF1M,3090
|
|
398
399
|
omlish/io/compress/adapters.py,sha256=LJHhjwMHXstoLyX_q0QhGoBAcqyYGWfzhzQbGBXHzHY,6148
|
|
@@ -486,7 +487,7 @@ omlish/lite/attrops.py,sha256=02DNBjOl27NjznkwolgPwtWpA1q3UPUuwOjHsgG4oLo,11381
|
|
|
486
487
|
omlish/lite/cached.py,sha256=AF0PdB2k4h2dyNc5tzrmnNrb9zKnoMPQU3WA8KrhS_o,3108
|
|
487
488
|
omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
|
|
488
489
|
omlish/lite/configs.py,sha256=4-1uVxo-aNV7vMKa7PVNhM610eejG1WepB42-Dw2xQI,914
|
|
489
|
-
omlish/lite/contextmanagers.py,sha256=
|
|
490
|
+
omlish/lite/contextmanagers.py,sha256=McvPC6VsQlUHzwAppHgmo0RviABPGOAEdDsGPn7dShw,5879
|
|
490
491
|
omlish/lite/dataclasses.py,sha256=Kxr68nTinRAkdWFGeu8C2qLul8iw6bxpbqqp20yxZfg,5064
|
|
491
492
|
omlish/lite/imports.py,sha256=GyEDKL-WuHtdOKIL-cc8aFd0-bHwZFDEjAB52ItabX0,1341
|
|
492
493
|
omlish/lite/inject.py,sha256=BQgjBj2mzJgMimLam-loSpQzcb31-8NYPVRQgHVv3cQ,29159
|
|
@@ -842,9 +843,9 @@ omlish/typedvalues/marshal.py,sha256=2xqX6JllhtGpmeYkU7C-qzgU__0x-vd6CzYbAsocQlc
|
|
|
842
843
|
omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
|
|
843
844
|
omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
|
|
844
845
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
|
845
|
-
omlish-0.0.0.
|
|
846
|
-
omlish-0.0.0.
|
|
847
|
-
omlish-0.0.0.
|
|
848
|
-
omlish-0.0.0.
|
|
849
|
-
omlish-0.0.0.
|
|
850
|
-
omlish-0.0.0.
|
|
846
|
+
omlish-0.0.0.dev473.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
|
847
|
+
omlish-0.0.0.dev473.dist-info/METADATA,sha256=-EYEBlROnYaFvqD5fxDP0hmJ1GTBnmWbV0EzbBxPACc,18999
|
|
848
|
+
omlish-0.0.0.dev473.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
849
|
+
omlish-0.0.0.dev473.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
|
850
|
+
omlish-0.0.0.dev473.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
|
851
|
+
omlish-0.0.0.dev473.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|