omlish 0.0.0.dev74__py3-none-any.whl → 0.0.0.dev76__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 +12 -0
- omlish/__about__.py +3 -3
- omlish/dataclasses/impl/exceptions.py +44 -2
- omlish/dataclasses/impl/fields.py +22 -1
- omlish/dataclasses/impl/init.py +2 -2
- omlish/formats/yaml.py +1 -1
- omlish/graphs/dags.py +1 -1
- omlish/graphs/domination.py +1 -1
- omlish/http/__init__.py +6 -0
- omlish/http/clients.py +16 -2
- omlish/http/headers.py +4 -0
- omlish/http/multipart.py +82 -0
- omlish/http/sse.py +96 -0
- omlish/io.py +142 -0
- omlish/lang/__init__.py +2 -0
- omlish/lang/iterables.py +7 -0
- omlish/lang/objects.py +7 -0
- omlish/lifecycles/controller.py +1 -1
- omlish/marshal/mappings.py +1 -1
- omlish/marshal/numbers.py +2 -2
- omlish/marshal/objects.py +1 -1
- omlish/marshal/polymorphism.py +4 -4
- omlish/secrets/pwgen.py +83 -0
- omlish/secrets/secrets.py +9 -0
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/METADATA +3 -3
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/RECORD +31 -28
- omlish/http/collections.py +0 -15
- /omlish/secrets/{passwords.py → pwhash.py} +0 -0
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev74.dist-info → omlish-0.0.0.dev76.dist-info}/top_level.txt +0 -0
omlish/.manifests.json
CHANGED
@@ -47,6 +47,18 @@
|
|
47
47
|
}
|
48
48
|
}
|
49
49
|
},
|
50
|
+
{
|
51
|
+
"module": ".secrets.pwgen",
|
52
|
+
"attr": "_CLI_MODULE",
|
53
|
+
"file": "omlish/secrets/pwgen.py",
|
54
|
+
"line": 75,
|
55
|
+
"value": {
|
56
|
+
"$omdev.cli.types.CliModule": {
|
57
|
+
"cmd_name": "pwgen",
|
58
|
+
"mod_name": "omlish.secrets.pwgen"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
},
|
50
62
|
{
|
51
63
|
"module": ".specs.jmespath.__main__",
|
52
64
|
"attr": "_CLI_MODULE",
|
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev76'
|
2
|
+
__revision__ = 'f7a91a7adb0b3e2018caef9de1ec592d87644c60'
|
3
3
|
|
4
4
|
|
5
5
|
#
|
@@ -97,7 +97,7 @@ class Project(ProjectBase):
|
|
97
97
|
|
98
98
|
'aiomysql ~= 0.2',
|
99
99
|
'aiosqlite ~= 0.20',
|
100
|
-
'asyncpg ~= 0.
|
100
|
+
'asyncpg ~= 0.30; python_version < "3.13"',
|
101
101
|
|
102
102
|
'apsw ~= 3.46',
|
103
103
|
|
@@ -1,8 +1,50 @@
|
|
1
|
+
import types
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
1
5
|
class ValidationError(Exception):
|
2
6
|
pass
|
3
7
|
|
4
8
|
|
9
|
+
def _hands_off_repr(obj: ta.Any) -> str:
|
10
|
+
return f'{obj.__class__.__qualname__}@{hex(id(obj))[2:]}'
|
11
|
+
|
12
|
+
|
13
|
+
def _fn_repr(fn: ta.Callable) -> str:
|
14
|
+
if (co := getattr(fn, '__code__', None)) is None or not isinstance(co, types.CodeType):
|
15
|
+
return repr(fn)
|
16
|
+
|
17
|
+
if not (co_filename := co.co_filename):
|
18
|
+
return repr(fn)
|
19
|
+
|
20
|
+
return f'{fn!r} ({co_filename}:{co.co_firstlineno})'
|
21
|
+
|
22
|
+
|
5
23
|
class FieldValidationError(ValidationError):
|
6
|
-
def __init__(
|
7
|
-
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
obj: ta.Any,
|
27
|
+
field: str,
|
28
|
+
fn: ta.Callable,
|
29
|
+
value: ta.Any,
|
30
|
+
) -> None:
|
31
|
+
super().__init__(
|
32
|
+
f'{self.__class__.__name__} '
|
33
|
+
f'for field {field!r} '
|
34
|
+
f'on object {_hands_off_repr(obj)} '
|
35
|
+
f'in validator {_fn_repr(fn)} '
|
36
|
+
f'with value {value!r}',
|
37
|
+
)
|
38
|
+
|
39
|
+
self.obj = obj
|
8
40
|
self.field = field
|
41
|
+
self.fn = fn
|
42
|
+
self.value = value
|
43
|
+
|
44
|
+
def __repr__(self) -> str:
|
45
|
+
return f'{self.__class__.__name__}({", ".join([
|
46
|
+
f"obj={_hands_off_repr(self.obj)}",
|
47
|
+
f"field={self.field!r}",
|
48
|
+
f"fn={_fn_repr(self.fn)}",
|
49
|
+
f"value={self.value!r}",
|
50
|
+
])})'
|
@@ -8,6 +8,7 @@ import typing as ta
|
|
8
8
|
|
9
9
|
from ... import check as check_
|
10
10
|
from ... import lang
|
11
|
+
from .exceptions import FieldValidationError
|
11
12
|
from .internals import FIELDS_ATTR
|
12
13
|
from .internals import FieldType
|
13
14
|
from .internals import is_classvar
|
@@ -29,6 +30,23 @@ MISSING = dc.MISSING
|
|
29
30
|
##
|
30
31
|
|
31
32
|
|
33
|
+
def raise_field_validation_error(
|
34
|
+
obj: ta.Any,
|
35
|
+
field: str,
|
36
|
+
fn: ta.Callable,
|
37
|
+
value: ta.Any,
|
38
|
+
):
|
39
|
+
raise FieldValidationError(
|
40
|
+
obj,
|
41
|
+
field,
|
42
|
+
fn,
|
43
|
+
value,
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
##
|
48
|
+
|
49
|
+
|
32
50
|
def field_type(f: dc.Field) -> FieldType:
|
33
51
|
if (ft := getattr(f, '_field_type')) is not None:
|
34
52
|
return FieldType(ft)
|
@@ -193,7 +211,10 @@ def field_init(
|
|
193
211
|
if fx.validate is not None:
|
194
212
|
cn = f'__dataclass_validate__{f.name}__'
|
195
213
|
locals[cn] = fx.validate
|
196
|
-
lines.append(
|
214
|
+
lines.append(
|
215
|
+
f'if not {cn}({value}): '
|
216
|
+
f'__dataclass_raise_field_validation_error__({self_name}, {f.name!r}, {cn}, {value})',
|
217
|
+
)
|
197
218
|
|
198
219
|
if fx.check_type:
|
199
220
|
cn = f'__dataclass_check_type__{f.name}__'
|
omlish/dataclasses/impl/init.py
CHANGED
@@ -3,11 +3,11 @@ import inspect
|
|
3
3
|
import typing as ta
|
4
4
|
|
5
5
|
from ... import lang
|
6
|
-
from .exceptions import FieldValidationError
|
7
6
|
from .exceptions import ValidationError
|
8
7
|
from .fields import field_init
|
9
8
|
from .fields import field_type
|
10
9
|
from .fields import has_default
|
10
|
+
from .fields import raise_field_validation_error
|
11
11
|
from .internals import HAS_DEFAULT_FACTORY
|
12
12
|
from .internals import POST_INIT_NAME
|
13
13
|
from .internals import FieldType
|
@@ -101,7 +101,7 @@ class InitBuilder:
|
|
101
101
|
'__dataclass_builtins_isinstance__': isinstance,
|
102
102
|
'__dataclass_builtins_TypeError__': TypeError,
|
103
103
|
'__dataclass_ValidationError__': ValidationError,
|
104
|
-
'
|
104
|
+
'__dataclass_raise_field_validation_error__': raise_field_validation_error,
|
105
105
|
})
|
106
106
|
|
107
107
|
body_lines: list[str] = []
|
omlish/formats/yaml.py
CHANGED
@@ -118,7 +118,7 @@ class NodeWrappingConstructorMixin:
|
|
118
118
|
yield omap
|
119
119
|
uomap = next(gen)
|
120
120
|
lang.exhaust(gen)
|
121
|
-
for key, value in uomap:
|
121
|
+
for key, value in uomap:
|
122
122
|
omap.append(NodeWrapped((key, value), node))
|
123
123
|
|
124
124
|
def construct_yaml_omap(self, node):
|
omlish/graphs/dags.py
CHANGED
@@ -80,7 +80,7 @@ class Subdag(ta.Generic[U]):
|
|
80
80
|
) -> None:
|
81
81
|
super().__init__()
|
82
82
|
|
83
|
-
self._dag: Dag[U] = check.isinstance(dag, Dag)
|
83
|
+
self._dag: Dag[U] = check.isinstance(dag, Dag)
|
84
84
|
self._targets = set(targets)
|
85
85
|
self._ignored = set(ignored or []) - self._targets
|
86
86
|
|
omlish/graphs/domination.py
CHANGED
@@ -195,7 +195,7 @@ class _ImmediateDominanceComputer(ta.Generic[V]):
|
|
195
195
|
def __init__(self, dfs: _Dfs[V]) -> None:
|
196
196
|
super().__init__()
|
197
197
|
|
198
|
-
self._dfs: _Dfs[V] = check.isinstance(dfs, _Dfs)
|
198
|
+
self._dfs: _Dfs[V] = check.isinstance(dfs, _Dfs)
|
199
199
|
|
200
200
|
self._ancestor: dict[V, V] = {}
|
201
201
|
self._semi = dict(self._dfs.semi)
|
omlish/http/__init__.py
CHANGED
omlish/http/clients.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
"""
|
2
2
|
TODO:
|
3
|
+
- httpx catch
|
3
4
|
- check=False
|
4
5
|
- return non-200 HttpResponses
|
5
6
|
- async
|
@@ -202,10 +203,14 @@ class HttpxHttpClient(HttpClient):
|
|
202
203
|
##
|
203
204
|
|
204
205
|
|
205
|
-
def
|
206
|
+
def _default_client() -> HttpClient:
|
206
207
|
return UrllibHttpClient()
|
207
208
|
|
208
209
|
|
210
|
+
def client() -> HttpClient:
|
211
|
+
return _default_client()
|
212
|
+
|
213
|
+
|
209
214
|
def request(
|
210
215
|
url: str,
|
211
216
|
method: str | None = None,
|
@@ -217,6 +222,8 @@ def request(
|
|
217
222
|
|
218
223
|
check: bool = False,
|
219
224
|
|
225
|
+
client: HttpClient | None = None,
|
226
|
+
|
220
227
|
**kwargs: ta.Any,
|
221
228
|
) -> HttpResponse:
|
222
229
|
req = HttpRequest(
|
@@ -231,9 +238,16 @@ def request(
|
|
231
238
|
**kwargs,
|
232
239
|
)
|
233
240
|
|
234
|
-
|
241
|
+
def do(cli: HttpClient) -> HttpResponse:
|
235
242
|
return cli.request(
|
236
243
|
req,
|
237
244
|
|
238
245
|
check=check,
|
239
246
|
)
|
247
|
+
|
248
|
+
if client is not None:
|
249
|
+
return do(client)
|
250
|
+
|
251
|
+
else:
|
252
|
+
with _default_client() as cli:
|
253
|
+
return do(cli)
|
omlish/http/headers.py
CHANGED
omlish/http/multipart.py
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
"""
|
2
|
+
https://datatracker.ietf.org/doc/html/rfc7578
|
3
|
+
"""
|
4
|
+
import dataclasses as dc
|
5
|
+
import io
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
from .. import cached
|
9
|
+
|
10
|
+
|
11
|
+
MultipartData: ta.TypeAlias = ta.Any # bytes | file
|
12
|
+
|
13
|
+
|
14
|
+
@dc.dataclass(frozen=True)
|
15
|
+
class MultipartField:
|
16
|
+
data: MultipartData
|
17
|
+
name: bytes | None = None
|
18
|
+
file_name: bytes | None = None
|
19
|
+
headers: ta.Sequence[tuple[bytes, bytes]] | None = None
|
20
|
+
|
21
|
+
|
22
|
+
class MultipartEncoder:
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
fields: ta.Sequence[MultipartField],
|
26
|
+
*,
|
27
|
+
boundary: bytes | None = None,
|
28
|
+
) -> None:
|
29
|
+
super().__init__()
|
30
|
+
self._fields = fields
|
31
|
+
self._boundary = boundary or b'----WebKitFormBoundary7MA4YWxkTrZu0gW'
|
32
|
+
|
33
|
+
class _Line(ta.NamedTuple):
|
34
|
+
data: MultipartData
|
35
|
+
sz: int
|
36
|
+
|
37
|
+
@cached.function
|
38
|
+
def _lines(self) -> ta.Sequence[_Line]:
|
39
|
+
l: list[MultipartEncoder._Line] = []
|
40
|
+
|
41
|
+
def add(d: MultipartData) -> None:
|
42
|
+
if isinstance(d, bytes):
|
43
|
+
sz = len(d)
|
44
|
+
else:
|
45
|
+
raise TypeError(d)
|
46
|
+
l.append(MultipartEncoder._Line(d, sz))
|
47
|
+
|
48
|
+
for f in self._fields:
|
49
|
+
add(b'--%s' % (self._boundary,))
|
50
|
+
ps = [b'form-data']
|
51
|
+
if f.name is not None:
|
52
|
+
ps.append(b'name="%s"' % (f.name,))
|
53
|
+
if f.file_name is not None:
|
54
|
+
ps.append(b'filename="%s"' % (f.file_name,))
|
55
|
+
add(b'Content-Disposition: ' + b'; '.join(ps))
|
56
|
+
for hk, hv in f.headers or ():
|
57
|
+
add(b'%s: %s' % (hk, hv))
|
58
|
+
add(b'')
|
59
|
+
add(f.data)
|
60
|
+
|
61
|
+
add(b'--%s--' % (self._boundary,))
|
62
|
+
|
63
|
+
return l
|
64
|
+
|
65
|
+
@cached.function
|
66
|
+
def content_type(self) -> bytes:
|
67
|
+
return b'multipart/form-data; boundary=%s' % (self._boundary,)
|
68
|
+
|
69
|
+
@cached.function
|
70
|
+
def content_length(self) -> int:
|
71
|
+
return sum(l.sz + 2 for l in self._lines())
|
72
|
+
|
73
|
+
@cached.function
|
74
|
+
def content(self) -> bytes:
|
75
|
+
buf = io.BytesIO()
|
76
|
+
for l in self._lines():
|
77
|
+
if isinstance(l.data, bytes):
|
78
|
+
buf.write(l.data)
|
79
|
+
else:
|
80
|
+
raise TypeError(l.data)
|
81
|
+
buf.write(b'\r\n')
|
82
|
+
return buf.getvalue()
|
omlish/http/sse.py
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- end-of-line = ( cr lf / cr / lf )
|
4
|
+
"""
|
5
|
+
import string
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
from .. import dataclasses as dc
|
9
|
+
from .. import lang
|
10
|
+
|
11
|
+
|
12
|
+
class SseDecoderOutput(lang.Abstract):
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
@dc.dataclass(frozen=True)
|
17
|
+
class SseComment(SseDecoderOutput, lang.Final):
|
18
|
+
data: bytes
|
19
|
+
|
20
|
+
|
21
|
+
SseEventId: ta.TypeAlias = bytes
|
22
|
+
|
23
|
+
|
24
|
+
@dc.dataclass(frozen=True)
|
25
|
+
class SseEvent(SseDecoderOutput, lang.Final):
|
26
|
+
type: bytes
|
27
|
+
data: bytes
|
28
|
+
last_id: SseEventId = dc.xfield(b'', repr_fn=dc.truthy_repr)
|
29
|
+
|
30
|
+
|
31
|
+
_DIGIT_BYTES = string.digits.encode('ascii')
|
32
|
+
|
33
|
+
|
34
|
+
class SseDecoder:
|
35
|
+
"""https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation"""
|
36
|
+
|
37
|
+
def __init__(self) -> None:
|
38
|
+
super().__init__()
|
39
|
+
|
40
|
+
self._reset()
|
41
|
+
self._last_event_id = b''
|
42
|
+
self._reconnection_time: int | None = None
|
43
|
+
|
44
|
+
_event_type: bytes
|
45
|
+
_data: list[bytes]
|
46
|
+
|
47
|
+
def _reset(self) -> None:
|
48
|
+
self._event_type = b'message'
|
49
|
+
self._data = []
|
50
|
+
|
51
|
+
def _process_field(self, name: bytes, value: bytes) -> None:
|
52
|
+
if name == b'event':
|
53
|
+
self._event_type = value
|
54
|
+
|
55
|
+
elif name == b'data':
|
56
|
+
self._data.append(value)
|
57
|
+
|
58
|
+
elif name == b'id':
|
59
|
+
if 0 not in value:
|
60
|
+
self._last_event_id = value
|
61
|
+
|
62
|
+
elif name == b'retry':
|
63
|
+
if all(c in _DIGIT_BYTES for c in value):
|
64
|
+
self._reconnection_time = int(value)
|
65
|
+
|
66
|
+
def _dispatch_event(self) -> SseEvent:
|
67
|
+
data = b''.join(lang.interleave(self._data, b'\n'))
|
68
|
+
|
69
|
+
e = SseEvent(
|
70
|
+
type=self._event_type,
|
71
|
+
data=data,
|
72
|
+
last_id=self._last_event_id,
|
73
|
+
)
|
74
|
+
|
75
|
+
self._reset()
|
76
|
+
|
77
|
+
return e
|
78
|
+
|
79
|
+
def process_line(self, line: bytes) -> ta.Iterable[SseDecoderOutput]:
|
80
|
+
if b'\r' in line or b'\n' in line:
|
81
|
+
raise ValueError(line)
|
82
|
+
|
83
|
+
if not line:
|
84
|
+
yield self._dispatch_event()
|
85
|
+
|
86
|
+
elif line[0] == b':'[0]:
|
87
|
+
yield SseComment(line)
|
88
|
+
|
89
|
+
elif (c := line.find(b':')) >= 0:
|
90
|
+
d = c + 1
|
91
|
+
if len(line) > d and line[d] == b' '[0]:
|
92
|
+
d += 1
|
93
|
+
self._process_field(line[:c], line[d:])
|
94
|
+
|
95
|
+
else:
|
96
|
+
self._process_field(line, b'')
|
omlish/io.py
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import io
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from . import check
|
6
|
+
|
7
|
+
|
8
|
+
@dc.dataclass(frozen=True)
|
9
|
+
class DelimitingBufferError(Exception):
|
10
|
+
buffer: 'DelimitingBuffer'
|
11
|
+
|
12
|
+
|
13
|
+
class ClosedDelimitingBufferError(DelimitingBufferError):
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
class FullDelimitingBufferError(DelimitingBufferError):
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class IncompleteDelimitingBufferError(DelimitingBufferError):
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
class DelimitingBuffer:
|
26
|
+
"""
|
27
|
+
https://github.com/python-trio/trio/issues/796 :|
|
28
|
+
"""
|
29
|
+
|
30
|
+
DEFAULT_DELIMITERS: bytes = b'\n'
|
31
|
+
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
|
35
|
+
*,
|
36
|
+
keep_ends: bool = False,
|
37
|
+
max_size: int | None = None,
|
38
|
+
on_full: ta.Literal['raise', 'yield'] = 'raise',
|
39
|
+
on_incomplete: ta.Literal['raise', 'yield'] = 'yield',
|
40
|
+
) -> None:
|
41
|
+
super().__init__()
|
42
|
+
|
43
|
+
self._delimiters = frozenset(check.isinstance(d, int) for d in delimiters)
|
44
|
+
self._keep_ends = keep_ends
|
45
|
+
self._max_size = max_size
|
46
|
+
self._on_full = on_full
|
47
|
+
self._on_incomplete = on_incomplete
|
48
|
+
|
49
|
+
self._buf: io.BytesIO | None = io.BytesIO()
|
50
|
+
|
51
|
+
@property
|
52
|
+
def is_closed(self) -> bool:
|
53
|
+
return self._buf is None
|
54
|
+
|
55
|
+
def tell(self) -> int:
|
56
|
+
if (buf := self._buf) is None:
|
57
|
+
raise ClosedDelimitingBufferError(self)
|
58
|
+
return buf.tell()
|
59
|
+
|
60
|
+
def peek(self) -> bytes:
|
61
|
+
if (buf := self._buf) is None:
|
62
|
+
raise ClosedDelimitingBufferError(self)
|
63
|
+
return buf.getvalue()
|
64
|
+
|
65
|
+
def _find_delim(self, data: bytes | bytearray, i: int) -> int | None:
|
66
|
+
r = None # type: int | None
|
67
|
+
for d in self._delimiters:
|
68
|
+
if (p := data.find(d, i)) >= 0:
|
69
|
+
if r is None or p < r:
|
70
|
+
r = p
|
71
|
+
return r
|
72
|
+
|
73
|
+
def _append_and_reset(self, chunk: bytes) -> bytes:
|
74
|
+
buf = check.not_none(self._buf)
|
75
|
+
if not buf.tell():
|
76
|
+
return chunk
|
77
|
+
|
78
|
+
buf.write(chunk)
|
79
|
+
ret = buf.getvalue()
|
80
|
+
buf.seek(0)
|
81
|
+
return ret
|
82
|
+
|
83
|
+
def feed(self, data: bytes | bytearray) -> ta.Generator[bytes, None, None]:
|
84
|
+
if (buf := self._buf) is None:
|
85
|
+
raise ClosedDelimitingBufferError(self)
|
86
|
+
|
87
|
+
if not data:
|
88
|
+
self._buf = None
|
89
|
+
|
90
|
+
if buf.tell():
|
91
|
+
if self._on_incomplete == 'raise':
|
92
|
+
raise IncompleteDelimitingBufferError(self)
|
93
|
+
|
94
|
+
elif self._on_incomplete == 'yield':
|
95
|
+
yield buf.getvalue()
|
96
|
+
|
97
|
+
else:
|
98
|
+
raise ValueError(f'Unknown on_incomplete value: {self._on_incomplete!r}')
|
99
|
+
|
100
|
+
return
|
101
|
+
|
102
|
+
l = len(data)
|
103
|
+
i = 0
|
104
|
+
while i < l:
|
105
|
+
if (p := self._find_delim(data, i)) is None:
|
106
|
+
break
|
107
|
+
|
108
|
+
n = p + 1
|
109
|
+
if self._keep_ends:
|
110
|
+
p = n
|
111
|
+
|
112
|
+
yield self._append_and_reset(data[i:p])
|
113
|
+
|
114
|
+
i = n
|
115
|
+
|
116
|
+
if i >= l:
|
117
|
+
return
|
118
|
+
|
119
|
+
if self._max_size is None:
|
120
|
+
buf.write(data[i:])
|
121
|
+
return
|
122
|
+
|
123
|
+
while i < l:
|
124
|
+
remaining_data_len = l - i
|
125
|
+
remaining_buf_capacity = self._max_size - buf.tell()
|
126
|
+
|
127
|
+
if remaining_data_len < remaining_buf_capacity:
|
128
|
+
buf.write(data[i:])
|
129
|
+
return
|
130
|
+
|
131
|
+
if self._on_full == 'raise':
|
132
|
+
raise FullDelimitingBufferError(self)
|
133
|
+
|
134
|
+
elif self._on_full == 'yield':
|
135
|
+
p = i + remaining_buf_capacity
|
136
|
+
|
137
|
+
yield self._append_and_reset(data[i:p])
|
138
|
+
|
139
|
+
i = p
|
140
|
+
|
141
|
+
else:
|
142
|
+
raise ValueError(f'Unknown on_full value: {self._on_full!r}')
|
omlish/lang/__init__.py
CHANGED
@@ -140,6 +140,7 @@ from .iterables import ( # noqa
|
|
140
140
|
flatmap,
|
141
141
|
flatten,
|
142
142
|
ilen,
|
143
|
+
interleave,
|
143
144
|
itergen,
|
144
145
|
peek,
|
145
146
|
prodrange,
|
@@ -161,6 +162,7 @@ from .objects import ( # noqa
|
|
161
162
|
build_mro_dict,
|
162
163
|
can_weakref,
|
163
164
|
deep_subclasses,
|
165
|
+
dir_dict,
|
164
166
|
new_type,
|
165
167
|
opt_repr,
|
166
168
|
super_meta,
|
omlish/lang/iterables.py
CHANGED
@@ -37,6 +37,13 @@ def peek(vs: ta.Iterable[T]) -> tuple[T, ta.Iterator[T]]:
|
|
37
37
|
return v, itertools.chain(iter((v,)), it)
|
38
38
|
|
39
39
|
|
40
|
+
def interleave(vs: ta.Iterable[T], d: T) -> ta.Iterable[T]:
|
41
|
+
for i, v in enumerate(vs):
|
42
|
+
if i:
|
43
|
+
yield d
|
44
|
+
yield v
|
45
|
+
|
46
|
+
|
40
47
|
Rangeable: ta.TypeAlias = ta.Union[ # noqa
|
41
48
|
int,
|
42
49
|
tuple[int],
|
omlish/lang/objects.py
CHANGED
omlish/lifecycles/controller.py
CHANGED
@@ -55,7 +55,7 @@ class LifecycleController(Lifecycle, ta.Generic[LifecycleT]):
|
|
55
55
|
return self._state
|
56
56
|
|
57
57
|
def add_listener(self, listener: LifecycleListener[LifecycleT]) -> 'LifecycleController':
|
58
|
-
self._listeners.append(check.isinstance(listener, LifecycleListener))
|
58
|
+
self._listeners.append(check.isinstance(listener, LifecycleListener))
|
59
59
|
return self
|
60
60
|
|
61
61
|
def _advance(
|
omlish/marshal/mappings.py
CHANGED
@@ -53,7 +53,7 @@ class MappingUnmarshaler(Unmarshaler):
|
|
53
53
|
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Mapping:
|
54
54
|
dct: dict = {}
|
55
55
|
for mk, mv in check.isinstance(v, collections.abc.Mapping).items():
|
56
|
-
dct[self.ke.unmarshal(ctx, mk)] = self.ve.unmarshal(ctx, mv)
|
56
|
+
dct[self.ke.unmarshal(ctx, mk)] = self.ve.unmarshal(ctx, mv)
|
57
57
|
return self.ctor(dct)
|
58
58
|
|
59
59
|
|
omlish/marshal/numbers.py
CHANGED
@@ -18,7 +18,7 @@ class ComplexMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
18
18
|
|
19
19
|
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
20
20
|
real, imag = check.isinstance(v, list)
|
21
|
-
return complex(real, imag)
|
21
|
+
return complex(real, imag)
|
22
22
|
|
23
23
|
|
24
24
|
class DecimalMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
@@ -35,7 +35,7 @@ class FractionMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
35
35
|
|
36
36
|
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
37
37
|
num, denom = check.isinstance(v, list)
|
38
|
-
return fractions.Fraction(num, denom)
|
38
|
+
return fractions.Fraction(num, denom)
|
39
39
|
|
40
40
|
|
41
41
|
NUMBERS_MARSHALER_FACTORY = TypeMapMarshalerFactory({
|
omlish/marshal/objects.py
CHANGED
@@ -167,7 +167,7 @@ class ObjectMarshaler(Marshaler):
|
|
167
167
|
|
168
168
|
if fi.options.embed:
|
169
169
|
for ek, ev in check.isinstance(mv, collections.abc.Mapping).items():
|
170
|
-
ret[mn + check.non_empty_str(ek)] = ev
|
170
|
+
ret[mn + check.non_empty_str(ek)] = ev
|
171
171
|
|
172
172
|
else:
|
173
173
|
ret[mn] = mv
|
omlish/marshal/polymorphism.py
CHANGED
@@ -183,8 +183,8 @@ class WrapperPolymorphismUnmarshaler(Unmarshaler):
|
|
183
183
|
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
|
184
184
|
ma = check.isinstance(v, collections.abc.Mapping)
|
185
185
|
[(tag, iv)] = ma.items()
|
186
|
-
u = self.m[tag]
|
187
|
-
return u.unmarshal(ctx, iv)
|
186
|
+
u = self.m[tag]
|
187
|
+
return u.unmarshal(ctx, iv)
|
188
188
|
|
189
189
|
|
190
190
|
@dc.dataclass(frozen=True)
|
@@ -194,8 +194,8 @@ class FieldPolymorphismUnmarshaler(Unmarshaler):
|
|
194
194
|
|
195
195
|
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
|
196
196
|
ma = dict(check.isinstance(v, collections.abc.Mapping))
|
197
|
-
tag = ma.pop(self.tf)
|
198
|
-
u = self.m[tag]
|
197
|
+
tag = ma.pop(self.tf)
|
198
|
+
u = self.m[tag]
|
199
199
|
return u.unmarshal(ctx, ma)
|
200
200
|
|
201
201
|
|
omlish/secrets/pwgen.py
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- len
|
4
|
+
- required character classes
|
5
|
+
- lowercase
|
6
|
+
- uppercase
|
7
|
+
- digits
|
8
|
+
- symbols
|
9
|
+
- move to omlish/secrets
|
10
|
+
- argparse, CliCmd
|
11
|
+
"""
|
12
|
+
import argparse
|
13
|
+
import random
|
14
|
+
import secrets
|
15
|
+
import string
|
16
|
+
import typing as ta
|
17
|
+
|
18
|
+
|
19
|
+
CHAR_CLASSES: ta.Mapping[str, str] = {
|
20
|
+
'lower': string.ascii_lowercase,
|
21
|
+
'upper': string.ascii_uppercase,
|
22
|
+
'digit': string.digits,
|
23
|
+
'special': string.punctuation,
|
24
|
+
}
|
25
|
+
|
26
|
+
|
27
|
+
ALL_CHAR_CLASSES = tuple(CHAR_CLASSES.values())
|
28
|
+
DEFAULT_LENGTH = 16
|
29
|
+
|
30
|
+
|
31
|
+
def generate_password(
|
32
|
+
char_classes: ta.Sequence[str] = ALL_CHAR_CLASSES,
|
33
|
+
length: int = DEFAULT_LENGTH,
|
34
|
+
*,
|
35
|
+
rand: random.Random | None = None,
|
36
|
+
) -> str:
|
37
|
+
if rand is None:
|
38
|
+
rand = secrets.SystemRandom()
|
39
|
+
l: list[str] = []
|
40
|
+
for cc in char_classes:
|
41
|
+
l.append(rand.choice(cc))
|
42
|
+
cs = ''.join(char_classes)
|
43
|
+
if not cs:
|
44
|
+
raise ValueError(cs)
|
45
|
+
while len(l) < length:
|
46
|
+
l.append(rand.choice(cs))
|
47
|
+
rand.shuffle(l)
|
48
|
+
return ''.join(l)
|
49
|
+
|
50
|
+
|
51
|
+
def _main() -> None:
|
52
|
+
parser = argparse.ArgumentParser()
|
53
|
+
parser.add_argument('length', type=int, nargs='?', default=DEFAULT_LENGTH)
|
54
|
+
for cc in CHAR_CLASSES:
|
55
|
+
parser.add_argument(f'-{cc[0]}', f'--{cc}', action='store_true')
|
56
|
+
args = parser.parse_args()
|
57
|
+
|
58
|
+
cs = {
|
59
|
+
cc
|
60
|
+
for cc in CHAR_CLASSES
|
61
|
+
if getattr(args, cc) is not None
|
62
|
+
}
|
63
|
+
if cs:
|
64
|
+
ccs = tuple(CHAR_CLASSES[cc] for cc in cs)
|
65
|
+
else:
|
66
|
+
ccs = ALL_CHAR_CLASSES
|
67
|
+
|
68
|
+
pw = generate_password(
|
69
|
+
ccs,
|
70
|
+
args.length,
|
71
|
+
)
|
72
|
+
print(pw)
|
73
|
+
|
74
|
+
|
75
|
+
# @omlish-manifest
|
76
|
+
_CLI_MODULE = {'$omdev.cli.types.CliModule': {
|
77
|
+
'cmd_name': 'pwgen',
|
78
|
+
'mod_name': __name__,
|
79
|
+
}}
|
80
|
+
|
81
|
+
|
82
|
+
if __name__ == '__main__':
|
83
|
+
_main()
|
omlish/secrets/secrets.py
CHANGED
@@ -36,6 +36,15 @@ class Secret(lang.NotPicklable, lang.Sensitive, lang.Final):
|
|
36
36
|
self._key = key
|
37
37
|
setattr(self, self._VALUE_ATTR, lambda: value)
|
38
38
|
|
39
|
+
@classmethod
|
40
|
+
def of(cls, src: ta.Union['Secret', str], *, key: str | None = None) -> 'Secret':
|
41
|
+
if isinstance(src, Secret):
|
42
|
+
return src
|
43
|
+
elif isinstance(src, str):
|
44
|
+
return cls(key=key, value=src)
|
45
|
+
else:
|
46
|
+
raise TypeError(src)
|
47
|
+
|
39
48
|
def __repr__(self) -> str:
|
40
49
|
return f'Secret<{self._key or ""}>'
|
41
50
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev76
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -41,7 +41,7 @@ Requires-Dist: apsw ~=3.46 ; extra == 'all'
|
|
41
41
|
Requires-Dist: duckdb ~=1.1 ; extra == 'all'
|
42
42
|
Requires-Dist: pytest ~=8.0 ; extra == 'all'
|
43
43
|
Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'all'
|
44
|
-
Requires-Dist: asyncpg ~=0.
|
44
|
+
Requires-Dist: asyncpg ~=0.30 ; (python_version < "3.13") and extra == 'all'
|
45
45
|
Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'all'
|
46
46
|
Provides-Extra: async
|
47
47
|
Requires-Dist: anyio ~=4.6 ; extra == 'async'
|
@@ -87,7 +87,7 @@ Requires-Dist: aiomysql ~=0.2 ; extra == 'sqldrivers'
|
|
87
87
|
Requires-Dist: aiosqlite ~=0.20 ; extra == 'sqldrivers'
|
88
88
|
Requires-Dist: apsw ~=3.46 ; extra == 'sqldrivers'
|
89
89
|
Requires-Dist: duckdb ~=1.1 ; extra == 'sqldrivers'
|
90
|
-
Requires-Dist: asyncpg ~=0.
|
90
|
+
Requires-Dist: asyncpg ~=0.30 ; (python_version < "3.13") and extra == 'sqldrivers'
|
91
91
|
Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'sqldrivers'
|
92
92
|
Provides-Extra: testing
|
93
93
|
Requires-Dist: pytest ~=8.0 ; extra == 'testing'
|
@@ -1,5 +1,5 @@
|
|
1
|
-
omlish/.manifests.json,sha256=
|
2
|
-
omlish/__about__.py,sha256=
|
1
|
+
omlish/.manifests.json,sha256=ucaSu1XcJPryi-AqINUejkVDeJAFk7Bp5ar5_tJTgME,1692
|
2
|
+
omlish/__about__.py,sha256=ndeBykRuOFL5NcUF-CXeCBZk1bdqwu15XuWzvQiIeHU,3420
|
3
3
|
omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
omlish/argparse.py,sha256=Dc73G8lyoQBLvXhMYUbzQUh4SJu_OTvKUXjSUxq_ang,7499
|
5
5
|
omlish/c3.py,sha256=4vogWgwPb8TbNS2KkZxpoWbwjj7MuHG2lQG-hdtkvjI,8062
|
@@ -11,6 +11,7 @@ omlish/dynamic.py,sha256=35C_cCX_Vq2HrHzGk5T-zbrMvmUdiIiwDzDNixczoDo,6541
|
|
11
11
|
omlish/fnpairs.py,sha256=Sl8CMFNyDS-1JYAjSWqnT5FmUm9Lj6o7FxSRo7g4jww,10875
|
12
12
|
omlish/fnpipes.py,sha256=AJkgz9nvRRm7oqw7ZgYyz21klu276LWi54oYCLg-vOg,2196
|
13
13
|
omlish/genmachine.py,sha256=LCMiqvK32dAWtrlB6lKw9tXdQFiXC8rRdk4TMQYIroU,1603
|
14
|
+
omlish/io.py,sha256=4_0naIRniQ_xGhCW44xkk3sKqgddCbtIjbs72SGqK9g,3679
|
14
15
|
omlish/iterators.py,sha256=GGLC7RIT86uXMjhIIIqnff_Iu5SI_b9rXYywYGFyzmo,7292
|
15
16
|
omlish/libc.py,sha256=8r7Ejyhttk9ruCfBkxNTrlzir5WPbDE2vmY7VPlceMA,15362
|
16
17
|
omlish/matchfns.py,sha256=I1IlQGfEyk_AcFSy6ulVS3utC-uwyZM2YfUXYHc9Bw0,6152
|
@@ -131,11 +132,11 @@ omlish/dataclasses/impl/api.py,sha256=p7W519_EnDAWlkOVS-4BpP4SxadWIiUzC3RldSoB28
|
|
131
132
|
omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX0,2598
|
132
133
|
omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
|
133
134
|
omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZChABGi58Fdk,2476
|
134
|
-
omlish/dataclasses/impl/exceptions.py,sha256
|
135
|
-
omlish/dataclasses/impl/fields.py,sha256=
|
135
|
+
omlish/dataclasses/impl/exceptions.py,sha256=-vqxZmfXVflymVuiM553XTlJProse5HEMktTpfdPCIY,1275
|
136
|
+
omlish/dataclasses/impl/fields.py,sha256=DbdTUnwFNL7KxNZBmEAGg4muMyFWbiMR8BUtUAOLrrc,6863
|
136
137
|
omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
|
137
138
|
omlish/dataclasses/impl/hashing.py,sha256=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
|
138
|
-
omlish/dataclasses/impl/init.py,sha256=
|
139
|
+
omlish/dataclasses/impl/init.py,sha256=t8wFWS5jw1XaY8KwL5iLSoeON0iILA2sqa-lDair0Ck,6181
|
139
140
|
omlish/dataclasses/impl/internals.py,sha256=UvZYjrLT1S8ntyxJ_vRPIkPOF00K8HatGAygErgoXTU,2990
|
140
141
|
omlish/dataclasses/impl/main.py,sha256=Ti0PKbFKraKvfmoPuR-G7nLVNzRC8mvEuXhCuC-M2kc,2574
|
141
142
|
omlish/dataclasses/impl/metaclass.py,sha256=Fb0ExFiyYdOpvck4ayXMr_vEVDvHLhe28Ns3F4aduM8,3222
|
@@ -181,7 +182,7 @@ omlish/docker/manifests.py,sha256=LR4FpOGNUT3bZQ-gTjB6r_-1C3YiG30QvevZjrsVUQM,70
|
|
181
182
|
omlish/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
182
183
|
omlish/formats/dotenv.py,sha256=UjZl3gac-0U24sDjCCGMcCqO1UCWG2Zs8PZ4JdAg2YE,17348
|
183
184
|
omlish/formats/props.py,sha256=JwFJbKblqzqnzXf7YKFzQSDfcAXzkKsfoYvad6FPy98,18945
|
184
|
-
omlish/formats/yaml.py,sha256=
|
185
|
+
omlish/formats/yaml.py,sha256=wTW8ECG9jyA7qIFUqKZUro4KAKpN4IvcW_qhlrKveXM,6836
|
185
186
|
omlish/formats/json/__init__.py,sha256=moSR67Qkju2eYb_qVDtaivepe44mxAnYuC8OCSbtETg,298
|
186
187
|
omlish/formats/json/__main__.py,sha256=1wxxKZVkj_u7HCcewwMIbGuZj_Wph95yrUbm474Op9M,188
|
187
188
|
omlish/formats/json/cli.py,sha256=pHFvYji6h_kMUyTgHCuDFofeDVY_5Em0wBqqVOJzDmI,3504
|
@@ -192,25 +193,26 @@ omlish/formats/json/backends/orjson.py,sha256=GYZx0zgpxwkJbFh4EJLGa6VMoEK-Q6mf5t
|
|
192
193
|
omlish/formats/json/backends/std.py,sha256=00NdUFT9GeWL1EWbgKhWLboDBIuDxr7EiizPZXbRWrc,1973
|
193
194
|
omlish/formats/json/backends/ujson.py,sha256=m5-hlEQCMLhat3Hg_8QTyfMH-rSsQGJYdWRWoTWkfhM,1029
|
194
195
|
omlish/graphs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
195
|
-
omlish/graphs/dags.py,sha256=
|
196
|
-
omlish/graphs/domination.py,sha256=
|
196
|
+
omlish/graphs/dags.py,sha256=zp55lYgUdRCxmADwiGDHeehMJczZFA_tzdWqy77icOk,3047
|
197
|
+
omlish/graphs/domination.py,sha256=oCGoWzWTxLwow0LDyGjjEf2AjFiOiDz4WaBtczwSbsQ,7576
|
197
198
|
omlish/graphs/trees.py,sha256=t9kzLy33ynYV0TowVkyDvkkRBQV5x--1vtNBSB4Auus,8156
|
198
199
|
omlish/graphs/dot/__init__.py,sha256=Y1MZRQBZkcYyG1Tn7K2FhL8aYbm4v4tk6f5g9AqEkUw,359
|
199
200
|
omlish/graphs/dot/items.py,sha256=OWPf0-hjBgS1uyy2QgAEn4IgFHJcEg7sHVWeTx1ghZc,4083
|
200
201
|
omlish/graphs/dot/make.py,sha256=RN30gHfJPiXx5Q51kbDdhVJYf59Fr84Lz9J-mXRt9sI,360
|
201
202
|
omlish/graphs/dot/rendering.py,sha256=2UgXvMRN4Z9cfIqLlC7Iu_8bWbwUDEL4opHHkFfSqTw,3630
|
202
203
|
omlish/graphs/dot/utils.py,sha256=_FMwn77WfiiAfLsRTOKWm4IYbNv5kQN22YJ5psw6CWg,801
|
203
|
-
omlish/http/__init__.py,sha256
|
204
|
+
omlish/http/__init__.py,sha256=OqCovZi_jv1Mnk975idaXA8FCGy4laoQIvNZ3hdKpRQ,722
|
204
205
|
omlish/http/asgi.py,sha256=wXhBZ21bEl32Kv9yBrRwUR_7pHEgVtHP8ZZwbasQ6-4,3307
|
205
|
-
omlish/http/clients.py,sha256=
|
206
|
-
omlish/http/collections.py,sha256=s8w5s4Gewgxxhe2Ai0R45PgJYYifrLgTbU3VXVflHj4,260
|
206
|
+
omlish/http/clients.py,sha256=WRtCNIt9Y790xpem69HiXJY9W-vPlpGPKZwpHusa2EE,6280
|
207
207
|
omlish/http/consts.py,sha256=FTolezLknKU6WJjk_x2T3a5LEMlnZSqv7gzTq55lxcU,2147
|
208
208
|
omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
|
209
209
|
omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
|
210
210
|
omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
|
211
|
-
omlish/http/headers.py,sha256=
|
211
|
+
omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
|
212
212
|
omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
|
213
|
+
omlish/http/multipart.py,sha256=vUU1OlYghsODs_OAJiz9nrWTBGXk1WIuk4FtSDykDqk,2205
|
213
214
|
omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
|
215
|
+
omlish/http/sse.py,sha256=T2_EXTcDfEhCF4E9B68YtEYLFb803MPnh8eCNjdPlRo,2223
|
214
216
|
omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
|
215
217
|
omlish/inject/__init__.py,sha256=JQ7x8l9MjU-kJ5ap7cPVq7SY7zbbCIrjyJAF0UeE5-s,1886
|
216
218
|
omlish/inject/binder.py,sha256=H8AQ4ecmBOtDL8fMgrU1yUJl1gBADLNcdysRbvO8Wso,4167
|
@@ -242,7 +244,7 @@ omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCF
|
|
242
244
|
omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNxwg,2375
|
243
245
|
omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
|
244
246
|
omlish/inject/impl/scopes.py,sha256=ASfULXgP_ETlsAqFJfrZmyEaZt64Zr8tNn5ScA-EoXk,5900
|
245
|
-
omlish/lang/__init__.py,sha256
|
247
|
+
omlish/lang/__init__.py,sha256=pCZoKj7wnFeyl_f7AKBg3Ajl1vrInkqP7miRcjIy6tI,3666
|
246
248
|
omlish/lang/cached.py,sha256=92TvRZQ6sWlm7dNn4hgl7aWKbX0J1XUEo3DRjBpgVQk,7834
|
247
249
|
omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
|
248
250
|
omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
|
@@ -252,9 +254,9 @@ omlish/lang/descriptors.py,sha256=RRBbkMgTzg82fFFE4D0muqobpM-ZZaOta6yB1lpX3s8,66
|
|
252
254
|
omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
|
253
255
|
omlish/lang/functions.py,sha256=kkPfcdocg-OmyN7skIqrFxNvqAv89Zc_kXKYAN8vw8g,3895
|
254
256
|
omlish/lang/imports.py,sha256=Oy7iInOTqgZv6nyRbnvGrPv4cKKIAzPbhfDXCajDUcc,6626
|
255
|
-
omlish/lang/iterables.py,sha256=
|
257
|
+
omlish/lang/iterables.py,sha256=xRwktm6i2RHSb_ELfAXdjITIfE69qDyMEzgeZqvQXiU,2386
|
256
258
|
omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
|
257
|
-
omlish/lang/objects.py,sha256=
|
259
|
+
omlish/lang/objects.py,sha256=LOC3JvX1g5hPxJ7Sv2TK9kNkAo9c8J-Jw2NmClR_rkA,4576
|
258
260
|
omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
|
259
261
|
omlish/lang/resources.py,sha256=-NmVTrSMKFZ6smVfOMz46ekZYVGgYh8cPooxQlFpG6s,2135
|
260
262
|
omlish/lang/strings.py,sha256=BsciSYnckD4vGtC6kmtnugR9IN6CIHdcjO4nZu-pSAw,3898
|
@@ -270,7 +272,7 @@ omlish/lifecycles/__init__.py,sha256=1FjYceXs-4fc-S-C9zFYmc2axHs4znnQHcJVHdY7a6E
|
|
270
272
|
omlish/lifecycles/abstract.py,sha256=70CQyZy-c9a2o0ZJxPeUT7eYjWZTBrp2HpUBnrHdAOM,1109
|
271
273
|
omlish/lifecycles/base.py,sha256=ceXrNSzuv7iiTlX96UI1fvsQ70OgOmZl-UisDPyA3NA,1394
|
272
274
|
omlish/lifecycles/contextmanagers.py,sha256=W0trOo6atbPSCoswmtUVOayAYnJ722qHBgda1oYxUEc,2073
|
273
|
-
omlish/lifecycles/controller.py,sha256=
|
275
|
+
omlish/lifecycles/controller.py,sha256=ToYNJKH1Mxr7HyyF1cJrrec8NV_m84jrcvTMX0V5emM,3464
|
274
276
|
omlish/lifecycles/manager.py,sha256=Au66KaO-fI-SEJALaPUJsCHYW2GE20xextk1wKn2BEU,5445
|
275
277
|
omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1292
|
276
278
|
omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
|
@@ -306,14 +308,14 @@ omlish/marshal/forbidden.py,sha256=BNshzm4lN5O8sUZ1YvxrSYq3WPklq9NMQCRZ7RC3DLM,8
|
|
306
308
|
omlish/marshal/global_.py,sha256=K76wB1-pdg4VWgiqR7wyxRNYr-voJApexYW2nV-R4DM,1127
|
307
309
|
omlish/marshal/helpers.py,sha256=-SOgYJmrURILHpPK6Wu3cCvhj8RJrqfJxuKhh9UMs7o,1102
|
308
310
|
omlish/marshal/iterables.py,sha256=6I_ZdJemLSQtJ4J5NrB9wi-eyxiJZS61HzHXp1yeiX8,2592
|
309
|
-
omlish/marshal/mappings.py,sha256=
|
311
|
+
omlish/marshal/mappings.py,sha256=s2cFSLyo0PM1eoQ2-SONtFSOldk5ARsBj55-icvWZ5o,2787
|
310
312
|
omlish/marshal/maybes.py,sha256=mgK3QsWHkXgRqo076KxYKH6elRxzJ_QDTodv93mgHR0,2198
|
311
313
|
omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
|
312
314
|
omlish/marshal/nop.py,sha256=2mWve_dicFAiUQ2Y5asKkUW-XGmEE9Qi2ClIasFad0c,461
|
313
|
-
omlish/marshal/numbers.py,sha256=
|
314
|
-
omlish/marshal/objects.py,sha256=
|
315
|
+
omlish/marshal/numbers.py,sha256=kFRIX9l1yofiYzafV6SnYfEg0PiCsAqeRHOeT6BSxlM,1672
|
316
|
+
omlish/marshal/objects.py,sha256=74tUmMymimSqgd4a6kyMh_owJe6J7YQXwCXEF-JWt1c,8419
|
315
317
|
omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
|
316
|
-
omlish/marshal/polymorphism.py,sha256=
|
318
|
+
omlish/marshal/polymorphism.py,sha256=gCQ4_uzuqOcWstihK3twiMc-10G1ZHWLuLZxbajbecY,5644
|
317
319
|
omlish/marshal/primitives.py,sha256=f_6m24Cb-FDGsZpYSas11nLt3xCCEUXugw3Hv4-aNhg,1291
|
318
320
|
omlish/marshal/registries.py,sha256=FvC6qXHCizNB2QmU_N3orxW7iqfGYkiUXYYdTRWS6HA,2353
|
319
321
|
omlish/marshal/standard.py,sha256=uQZIGiCwihmhB1tmhpKnZWZly0DDkdGjCnN0d41WHho,2985
|
@@ -334,8 +336,9 @@ omlish/secrets/__init__.py,sha256=SGB1KrlNrxlNpazEHYy95NTzteLi8ndoEgMhU7luBl8,42
|
|
334
336
|
omlish/secrets/crypto.py,sha256=6CsLy0UEqCrBK8Xx_3-iFF6SKtu2GlEqUQ8-MliY3tk,3709
|
335
337
|
omlish/secrets/marshal.py,sha256=U9uSRTWzZmumfNZeh_dROwVdGrARsp155TylRbjilP8,2048
|
336
338
|
omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,6219
|
337
|
-
omlish/secrets/
|
338
|
-
omlish/secrets/
|
339
|
+
omlish/secrets/pwgen.py,sha256=v-5ztnOTHTAWXLGR-3H6HkMj2nPIZBMbo5xWR3q0rDY,1707
|
340
|
+
omlish/secrets/pwhash.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
|
341
|
+
omlish/secrets/secrets.py,sha256=cnDGBoPknVxsCN04_gqcJT_7Ebk3iO3VPkRZ2oMjkMw,7868
|
339
342
|
omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
|
340
343
|
omlish/specs/__init__.py,sha256=Xl4fT1o1MlcEIAjMt5EifgMuO4UBSa9Suj5NE9eMX1A,87
|
341
344
|
omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
|
@@ -436,9 +439,9 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
|
|
436
439
|
omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
|
437
440
|
omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
|
438
441
|
omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
|
439
|
-
omlish-0.0.0.
|
440
|
-
omlish-0.0.0.
|
441
|
-
omlish-0.0.0.
|
442
|
-
omlish-0.0.0.
|
443
|
-
omlish-0.0.0.
|
444
|
-
omlish-0.0.0.
|
442
|
+
omlish-0.0.0.dev76.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
443
|
+
omlish-0.0.0.dev76.dist-info/METADATA,sha256=w0ccpB3fCgf6T797VrwXYnw7tUxFswGFbwRA4qKLWTc,4167
|
444
|
+
omlish-0.0.0.dev76.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
445
|
+
omlish-0.0.0.dev76.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
446
|
+
omlish-0.0.0.dev76.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
447
|
+
omlish-0.0.0.dev76.dist-info/RECORD,,
|
omlish/http/collections.py
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
import typing as ta
|
2
|
-
|
3
|
-
|
4
|
-
V = ta.TypeVar('V')
|
5
|
-
|
6
|
-
|
7
|
-
class HttpMap(ta.Mapping[str, V]):
|
8
|
-
def __getitem__(self, k):
|
9
|
-
raise NotImplementedError
|
10
|
-
|
11
|
-
def __len__(self):
|
12
|
-
raise NotImplementedError
|
13
|
-
|
14
|
-
def __iter__(self):
|
15
|
-
raise NotImplementedError
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|