omlish 0.0.0.dev75__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 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.dev75'
2
- __revision__ = 'dcdc82976a464689890fe99f9aaf5fc596ddd563'
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.29; python_version < "3.13"',
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__(self, field: str) -> None:
7
- super().__init__(field)
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(f'if not {cn}({value}): raise __dataclass_FieldValidationError__({f.name})')
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}__'
@@ -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
- '__dataclass_FieldValidationError__': FieldValidationError,
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: # type: ignore
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) # type: ignore
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
 
@@ -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) # type: ignore
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
@@ -40,3 +40,9 @@ from .json import ( # noqa
40
40
  json_dumps,
41
41
  json_loads,
42
42
  )
43
+
44
+ from .multipart import ( # noqa
45
+ MultipartData,
46
+ MultipartEncoder,
47
+ MultipartField,
48
+ )
omlish/http/clients.py CHANGED
@@ -203,10 +203,14 @@ class HttpxHttpClient(HttpClient):
203
203
  ##
204
204
 
205
205
 
206
- def client() -> HttpClient:
206
+ def _default_client() -> HttpClient:
207
207
  return UrllibHttpClient()
208
208
 
209
209
 
210
+ def client() -> HttpClient:
211
+ return _default_client()
212
+
213
+
210
214
  def request(
211
215
  url: str,
212
216
  method: str | None = None,
@@ -218,6 +222,8 @@ def request(
218
222
 
219
223
  check: bool = False,
220
224
 
225
+ client: HttpClient | None = None,
226
+
221
227
  **kwargs: ta.Any,
222
228
  ) -> HttpResponse:
223
229
  req = HttpRequest(
@@ -232,9 +238,16 @@ def request(
232
238
  **kwargs,
233
239
  )
234
240
 
235
- with client() as cli:
241
+ def do(cli: HttpClient) -> HttpResponse:
236
242
  return cli.request(
237
243
  req,
238
244
 
239
245
  check=check,
240
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
@@ -1,3 +1,7 @@
1
+ """
2
+ TODO:
3
+ - handle secrets (but they're strs..)
4
+ """
1
5
  import typing as ta
2
6
 
3
7
  from .. import cached
@@ -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/lang/__init__.py CHANGED
@@ -162,6 +162,7 @@ from .objects import ( # noqa
162
162
  build_mro_dict,
163
163
  can_weakref,
164
164
  deep_subclasses,
165
+ dir_dict,
165
166
  new_type,
166
167
  opt_repr,
167
168
  super_meta,
omlish/lang/objects.py CHANGED
@@ -129,6 +129,13 @@ def build_mro_dict(
129
129
  return dct
130
130
 
131
131
 
132
+ def dir_dict(o: ta.Any) -> dict[str, ta.Any]:
133
+ return {
134
+ a: getattr(o, a)
135
+ for a in dir(o)
136
+ }
137
+
138
+
132
139
  ##
133
140
 
134
141
 
@@ -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)) # type: ignore
58
+ self._listeners.append(check.isinstance(listener, LifecycleListener))
59
59
  return self
60
60
 
61
61
  def _advance(
@@ -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) # type: ignore
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) # type: ignore
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) # type: ignore
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 # type: ignore
170
+ ret[mn + check.non_empty_str(ek)] = ev
171
171
 
172
172
  else:
173
173
  ret[mn] = mv
@@ -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] # type: ignore
187
- return u.unmarshal(ctx, iv) # type: ignore
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) # type: ignore
198
- u = self.m[tag] # type: ignore
197
+ tag = ma.pop(self.tf)
198
+ u = self.m[tag]
199
199
  return u.unmarshal(ctx, ma)
200
200
 
201
201
 
@@ -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.dev75
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.29 ; (python_version < "3.13") and extra == 'all'
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.29 ; (python_version < "3.13") and extra == 'sqldrivers'
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=TXvFdkAU0Zr2FKdo7fyvt9nr3UjCtrnAZ0diZXSAteE,1430
2
- omlish/__about__.py,sha256=KmKwb6iUcg1fxhudcMoQVNM13U_ufTfnRbe5K2n-Za0,3420
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
@@ -132,11 +132,11 @@ omlish/dataclasses/impl/api.py,sha256=p7W519_EnDAWlkOVS-4BpP4SxadWIiUzC3RldSoB28
132
132
  omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX0,2598
133
133
  omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
134
134
  omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZChABGi58Fdk,2476
135
- omlish/dataclasses/impl/exceptions.py,sha256=DeiM6rcjgncudn-XVuph9TDbVDEwBtyYb1bcbO3FFcA,193
136
- omlish/dataclasses/impl/fields.py,sha256=mr8tnSDceHGZ6VBbeegt-iCzQJbtCXoWOUwltjRULy4,6521
135
+ omlish/dataclasses/impl/exceptions.py,sha256=-vqxZmfXVflymVuiM553XTlJProse5HEMktTpfdPCIY,1275
136
+ omlish/dataclasses/impl/fields.py,sha256=DbdTUnwFNL7KxNZBmEAGg4muMyFWbiMR8BUtUAOLrrc,6863
137
137
  omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
138
138
  omlish/dataclasses/impl/hashing.py,sha256=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
139
- omlish/dataclasses/impl/init.py,sha256=IgxO9nwHaHF8jGrUAk-Y5xke9uV2OwzfEe-88McE1Wg,6161
139
+ omlish/dataclasses/impl/init.py,sha256=t8wFWS5jw1XaY8KwL5iLSoeON0iILA2sqa-lDair0Ck,6181
140
140
  omlish/dataclasses/impl/internals.py,sha256=UvZYjrLT1S8ntyxJ_vRPIkPOF00K8HatGAygErgoXTU,2990
141
141
  omlish/dataclasses/impl/main.py,sha256=Ti0PKbFKraKvfmoPuR-G7nLVNzRC8mvEuXhCuC-M2kc,2574
142
142
  omlish/dataclasses/impl/metaclass.py,sha256=Fb0ExFiyYdOpvck4ayXMr_vEVDvHLhe28Ns3F4aduM8,3222
@@ -182,7 +182,7 @@ omlish/docker/manifests.py,sha256=LR4FpOGNUT3bZQ-gTjB6r_-1C3YiG30QvevZjrsVUQM,70
182
182
  omlish/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
183
  omlish/formats/dotenv.py,sha256=UjZl3gac-0U24sDjCCGMcCqO1UCWG2Zs8PZ4JdAg2YE,17348
184
184
  omlish/formats/props.py,sha256=JwFJbKblqzqnzXf7YKFzQSDfcAXzkKsfoYvad6FPy98,18945
185
- omlish/formats/yaml.py,sha256=DSJXUq9yanfxdS6ufNTyBHMtIZO57LRnJj4w9fLY1aM,6852
185
+ omlish/formats/yaml.py,sha256=wTW8ECG9jyA7qIFUqKZUro4KAKpN4IvcW_qhlrKveXM,6836
186
186
  omlish/formats/json/__init__.py,sha256=moSR67Qkju2eYb_qVDtaivepe44mxAnYuC8OCSbtETg,298
187
187
  omlish/formats/json/__main__.py,sha256=1wxxKZVkj_u7HCcewwMIbGuZj_Wph95yrUbm474Op9M,188
188
188
  omlish/formats/json/cli.py,sha256=pHFvYji6h_kMUyTgHCuDFofeDVY_5Em0wBqqVOJzDmI,3504
@@ -193,24 +193,24 @@ omlish/formats/json/backends/orjson.py,sha256=GYZx0zgpxwkJbFh4EJLGa6VMoEK-Q6mf5t
193
193
  omlish/formats/json/backends/std.py,sha256=00NdUFT9GeWL1EWbgKhWLboDBIuDxr7EiizPZXbRWrc,1973
194
194
  omlish/formats/json/backends/ujson.py,sha256=m5-hlEQCMLhat3Hg_8QTyfMH-rSsQGJYdWRWoTWkfhM,1029
195
195
  omlish/graphs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
196
- omlish/graphs/dags.py,sha256=JpTGxt5rsK7hy5EUy9rNUlIeDStT9ri86m8xEKiHQLE,3063
197
- omlish/graphs/domination.py,sha256=45iTyn7mZWPJ1ANrqD96aPXqzEeyFpybMvvcVxo9XvQ,7592
196
+ omlish/graphs/dags.py,sha256=zp55lYgUdRCxmADwiGDHeehMJczZFA_tzdWqy77icOk,3047
197
+ omlish/graphs/domination.py,sha256=oCGoWzWTxLwow0LDyGjjEf2AjFiOiDz4WaBtczwSbsQ,7576
198
198
  omlish/graphs/trees.py,sha256=t9kzLy33ynYV0TowVkyDvkkRBQV5x--1vtNBSB4Auus,8156
199
199
  omlish/graphs/dot/__init__.py,sha256=Y1MZRQBZkcYyG1Tn7K2FhL8aYbm4v4tk6f5g9AqEkUw,359
200
200
  omlish/graphs/dot/items.py,sha256=OWPf0-hjBgS1uyy2QgAEn4IgFHJcEg7sHVWeTx1ghZc,4083
201
201
  omlish/graphs/dot/make.py,sha256=RN30gHfJPiXx5Q51kbDdhVJYf59Fr84Lz9J-mXRt9sI,360
202
202
  omlish/graphs/dot/rendering.py,sha256=2UgXvMRN4Z9cfIqLlC7Iu_8bWbwUDEL4opHHkFfSqTw,3630
203
203
  omlish/graphs/dot/utils.py,sha256=_FMwn77WfiiAfLsRTOKWm4IYbNv5kQN22YJ5psw6CWg,801
204
- omlish/http/__init__.py,sha256=-ENDALr8ehHvivRD6cxIbEC94t0RHhrakf6CQRDTc8o,625
204
+ omlish/http/__init__.py,sha256=OqCovZi_jv1Mnk975idaXA8FCGy4laoQIvNZ3hdKpRQ,722
205
205
  omlish/http/asgi.py,sha256=wXhBZ21bEl32Kv9yBrRwUR_7pHEgVtHP8ZZwbasQ6-4,3307
206
- omlish/http/clients.py,sha256=phwWe4a6aVU2_E-Z_zSzrmAb5iX9zoCDIMa2l6Trzck,6019
207
- omlish/http/collections.py,sha256=s8w5s4Gewgxxhe2Ai0R45PgJYYifrLgTbU3VXVflHj4,260
206
+ omlish/http/clients.py,sha256=WRtCNIt9Y790xpem69HiXJY9W-vPlpGPKZwpHusa2EE,6280
208
207
  omlish/http/consts.py,sha256=FTolezLknKU6WJjk_x2T3a5LEMlnZSqv7gzTq55lxcU,2147
209
208
  omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
210
209
  omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
211
210
  omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
212
- omlish/http/headers.py,sha256=S66wiXezBHybrnjAM15E9x4GJvPRvFQHeKaXdJ799fw,5028
211
+ omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
213
212
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
213
+ omlish/http/multipart.py,sha256=vUU1OlYghsODs_OAJiz9nrWTBGXk1WIuk4FtSDykDqk,2205
214
214
  omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
215
215
  omlish/http/sse.py,sha256=T2_EXTcDfEhCF4E9B68YtEYLFb803MPnh8eCNjdPlRo,2223
216
216
  omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
@@ -244,7 +244,7 @@ omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCF
244
244
  omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNxwg,2375
245
245
  omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
246
246
  omlish/inject/impl/scopes.py,sha256=ASfULXgP_ETlsAqFJfrZmyEaZt64Zr8tNn5ScA-EoXk,5900
247
- omlish/lang/__init__.py,sha256=p63qmjZwg2CjLhMaZncnZKsuLZ6B_QVfpPGZKVH8FTw,3652
247
+ omlish/lang/__init__.py,sha256=pCZoKj7wnFeyl_f7AKBg3Ajl1vrInkqP7miRcjIy6tI,3666
248
248
  omlish/lang/cached.py,sha256=92TvRZQ6sWlm7dNn4hgl7aWKbX0J1XUEo3DRjBpgVQk,7834
249
249
  omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
250
250
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
@@ -256,7 +256,7 @@ omlish/lang/functions.py,sha256=kkPfcdocg-OmyN7skIqrFxNvqAv89Zc_kXKYAN8vw8g,3895
256
256
  omlish/lang/imports.py,sha256=Oy7iInOTqgZv6nyRbnvGrPv4cKKIAzPbhfDXCajDUcc,6626
257
257
  omlish/lang/iterables.py,sha256=xRwktm6i2RHSb_ELfAXdjITIfE69qDyMEzgeZqvQXiU,2386
258
258
  omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
259
- omlish/lang/objects.py,sha256=t7Pvj9ILoxfdAMy5HC7bb9LfUokW5WfpLaoH2YYyTjQ,4460
259
+ omlish/lang/objects.py,sha256=LOC3JvX1g5hPxJ7Sv2TK9kNkAo9c8J-Jw2NmClR_rkA,4576
260
260
  omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
261
261
  omlish/lang/resources.py,sha256=-NmVTrSMKFZ6smVfOMz46ekZYVGgYh8cPooxQlFpG6s,2135
262
262
  omlish/lang/strings.py,sha256=BsciSYnckD4vGtC6kmtnugR9IN6CIHdcjO4nZu-pSAw,3898
@@ -272,7 +272,7 @@ omlish/lifecycles/__init__.py,sha256=1FjYceXs-4fc-S-C9zFYmc2axHs4znnQHcJVHdY7a6E
272
272
  omlish/lifecycles/abstract.py,sha256=70CQyZy-c9a2o0ZJxPeUT7eYjWZTBrp2HpUBnrHdAOM,1109
273
273
  omlish/lifecycles/base.py,sha256=ceXrNSzuv7iiTlX96UI1fvsQ70OgOmZl-UisDPyA3NA,1394
274
274
  omlish/lifecycles/contextmanagers.py,sha256=W0trOo6atbPSCoswmtUVOayAYnJ722qHBgda1oYxUEc,2073
275
- omlish/lifecycles/controller.py,sha256=L9U2KQohrOfxJnsu-LYNVBvLyUJnRCZyo1ehH1DjG14,3480
275
+ omlish/lifecycles/controller.py,sha256=ToYNJKH1Mxr7HyyF1cJrrec8NV_m84jrcvTMX0V5emM,3464
276
276
  omlish/lifecycles/manager.py,sha256=Au66KaO-fI-SEJALaPUJsCHYW2GE20xextk1wKn2BEU,5445
277
277
  omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1292
278
278
  omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
@@ -308,14 +308,14 @@ omlish/marshal/forbidden.py,sha256=BNshzm4lN5O8sUZ1YvxrSYq3WPklq9NMQCRZ7RC3DLM,8
308
308
  omlish/marshal/global_.py,sha256=K76wB1-pdg4VWgiqR7wyxRNYr-voJApexYW2nV-R4DM,1127
309
309
  omlish/marshal/helpers.py,sha256=-SOgYJmrURILHpPK6Wu3cCvhj8RJrqfJxuKhh9UMs7o,1102
310
310
  omlish/marshal/iterables.py,sha256=6I_ZdJemLSQtJ4J5NrB9wi-eyxiJZS61HzHXp1yeiX8,2592
311
- omlish/marshal/mappings.py,sha256=zhLtyot7tzQtBNj7C4RBxjMELxA5r2q2Mth8Br7xkFs,2803
311
+ omlish/marshal/mappings.py,sha256=s2cFSLyo0PM1eoQ2-SONtFSOldk5ARsBj55-icvWZ5o,2787
312
312
  omlish/marshal/maybes.py,sha256=mgK3QsWHkXgRqo076KxYKH6elRxzJ_QDTodv93mgHR0,2198
313
313
  omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
314
314
  omlish/marshal/nop.py,sha256=2mWve_dicFAiUQ2Y5asKkUW-XGmEE9Qi2ClIasFad0c,461
315
- omlish/marshal/numbers.py,sha256=oY_yMNJEnJhjfLh89gpPXvKqeUyhQcaTcQB6ecyHiG8,1704
316
- omlish/marshal/objects.py,sha256=8-w4Vc222gGGmTiTnUIIZBe1XXdAy0yo9aa1ZUAi1b4,8435
315
+ omlish/marshal/numbers.py,sha256=kFRIX9l1yofiYzafV6SnYfEg0PiCsAqeRHOeT6BSxlM,1672
316
+ omlish/marshal/objects.py,sha256=74tUmMymimSqgd4a6kyMh_owJe6J7YQXwCXEF-JWt1c,8419
317
317
  omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
318
- omlish/marshal/polymorphism.py,sha256=doA8aLUhna6aco5b2Ok3jsem1V4NsF3rM5RTfJt0a7U,5708
318
+ omlish/marshal/polymorphism.py,sha256=gCQ4_uzuqOcWstihK3twiMc-10G1ZHWLuLZxbajbecY,5644
319
319
  omlish/marshal/primitives.py,sha256=f_6m24Cb-FDGsZpYSas11nLt3xCCEUXugw3Hv4-aNhg,1291
320
320
  omlish/marshal/registries.py,sha256=FvC6qXHCizNB2QmU_N3orxW7iqfGYkiUXYYdTRWS6HA,2353
321
321
  omlish/marshal/standard.py,sha256=uQZIGiCwihmhB1tmhpKnZWZly0DDkdGjCnN0d41WHho,2985
@@ -336,8 +336,9 @@ omlish/secrets/__init__.py,sha256=SGB1KrlNrxlNpazEHYy95NTzteLi8ndoEgMhU7luBl8,42
336
336
  omlish/secrets/crypto.py,sha256=6CsLy0UEqCrBK8Xx_3-iFF6SKtu2GlEqUQ8-MliY3tk,3709
337
337
  omlish/secrets/marshal.py,sha256=U9uSRTWzZmumfNZeh_dROwVdGrARsp155TylRbjilP8,2048
338
338
  omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,6219
339
- omlish/secrets/passwords.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
340
- omlish/secrets/secrets.py,sha256=XkzCrGNRLXUBXbw6_2pFGV2fuphbcgehtpp8zsjHaWM,7580
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
341
342
  omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
342
343
  omlish/specs/__init__.py,sha256=Xl4fT1o1MlcEIAjMt5EifgMuO4UBSa9Suj5NE9eMX1A,87
343
344
  omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
@@ -438,9 +439,9 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
438
439
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
439
440
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
440
441
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
441
- omlish-0.0.0.dev75.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
442
- omlish-0.0.0.dev75.dist-info/METADATA,sha256=GuYbZyayGe8TDZ3NyirRfVwE06aEFatiflv_jOd9zQI,4167
443
- omlish-0.0.0.dev75.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
444
- omlish-0.0.0.dev75.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
445
- omlish-0.0.0.dev75.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
446
- omlish-0.0.0.dev75.dist-info/RECORD,,
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,,
@@ -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