omlish 0.0.0.dev62__py3-none-any.whl → 0.0.0.dev64__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev62'
2
- __revision__ = 'a5ef2d1548d1cdfb856b4a7ff99fe61080ab791e'
1
+ __version__ = '0.0.0.dev64'
2
+ __revision__ = '65b4d26bc20b482253b288f29eebe58b9ae531dd'
3
3
 
4
4
 
5
5
  #
@@ -92,7 +92,7 @@ class Project(ProjectBase):
92
92
  # 'psycopg ~= 3.2',
93
93
 
94
94
  'pymysql ~= 1.1',
95
- # 'mysql-connector-python ~= 9.0',
95
+ # 'mysql-connector-python ~= 9.1',
96
96
  # 'mysqlclient ~= 2.2',
97
97
 
98
98
  'aiomysql ~= 0.2',
omlish/argparse.py CHANGED
@@ -70,7 +70,7 @@ def arg(*args, **kwargs) -> Arg:
70
70
  #
71
71
 
72
72
 
73
- CommandFn = ta.Callable[[], None]
73
+ CommandFn = ta.Callable[[], int | None]
74
74
 
75
75
 
76
76
  @dc.dataclass(eq=False)
@@ -96,9 +96,9 @@ class Command:
96
96
  def __get__(self, instance, owner=None):
97
97
  if instance is None:
98
98
  return self
99
- return dc.replace(self, fn=self.fn.__get__(instance, owner))
99
+ return dc.replace(self, fn=self.fn.__get__(instance, owner)) # noqa
100
100
 
101
- def __call__(self, *args, **kwargs) -> None:
101
+ def __call__(self, *args, **kwargs) -> int | None:
102
102
  return self.fn(*args, **kwargs)
103
103
 
104
104
 
@@ -234,10 +234,10 @@ class Cli(metaclass=_CliMeta):
234
234
  def unknown_args(self) -> ta.Sequence[str]:
235
235
  return self._unknown_args
236
236
 
237
- def _run_cmd(self, cmd: Command) -> None:
238
- cmd.__get__(self, type(self))()
237
+ def _run_cmd(self, cmd: Command) -> int | None:
238
+ return cmd.__get__(self, type(self))()
239
239
 
240
- def __call__(self) -> None:
240
+ def __call__(self) -> int | None:
241
241
  cmd = getattr(self.args, '_cmd', None)
242
242
 
243
243
  if self._unknown_args and not (cmd is not None and cmd.accepts_unknown):
@@ -249,6 +249,9 @@ class Cli(metaclass=_CliMeta):
249
249
 
250
250
  if cmd is None:
251
251
  self.get_parser().print_help()
252
- return
252
+ return 0
253
253
 
254
- self._run_cmd(cmd)
254
+ return self._run_cmd(cmd)
255
+
256
+ def call_and_exit(self) -> ta.NoReturn:
257
+ sys.exit(rc if isinstance(rc := self(), int) else 0)
omlish/bootstrap/main.py CHANGED
@@ -83,7 +83,7 @@ def _add_arguments(parser: argparse.ArgumentParser) -> None:
83
83
  else:
84
84
  raise TypeError(fld)
85
85
 
86
- parser.add_argument(aname, action=_OrderedArgsAction, **kw)
86
+ parser.add_argument(aname.replace('_', '-'), action=_OrderedArgsAction, **kw)
87
87
 
88
88
 
89
89
  def _process_arguments(args: ta.Any) -> ta.Sequence[Bootstrap.Config]:
@@ -13,7 +13,7 @@ class IndexedSeq(ta.Sequence[T]):
13
13
  super().__init__()
14
14
 
15
15
  self._lst = list(it)
16
- self._idxs = (IdentityKeyDict if identity else dict)(map(reversed, enumerate(self._lst)))
16
+ self._idxs: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, e in enumerate(self._lst)) # noqa
17
17
  if len(self._idxs) != len(self._lst):
18
18
  raise ValueError(f'{len(self._idxs)} != {len(self._lst)}')
19
19
 
@@ -47,7 +47,7 @@ class IndexedSetSeq(ta.Sequence[ta.AbstractSet[T]]):
47
47
  super().__init__()
48
48
 
49
49
  self._lst = [(IdentitySet if identity else set)(e) for e in it]
50
- self._idxs = (IdentityKeyDict if identity else dict)((e, i) for i, es in enumerate(self._lst) for e in es)
50
+ self._idxs: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, es in enumerate(self._lst) for e in es) # noqa
51
51
  if len(self._idxs) != sum(map(len, self._lst)):
52
52
  raise ValueError(f'{len(self._idxs)} != {sum(map(len, self._lst))}')
53
53
 
omlish/docker/__init__.py CHANGED
@@ -24,4 +24,6 @@ from .helpers import ( # noqa
24
24
  from .hub import ( # noqa
25
25
  HubRepoInfo,
26
26
  get_hub_repo_info,
27
+ select_latest_tag,
28
+ split_tag_suffix,
27
29
  )
omlish/docker/hub.py CHANGED
@@ -1,15 +1,79 @@
1
1
  import typing as ta
2
+ import urllib.error
2
3
  import urllib.request
3
4
 
5
+ from .. import check
4
6
  from .. import dataclasses as dc
5
7
  from ..formats import json
6
8
 
7
9
 
10
+ ##
11
+
12
+
13
+ def _tag_sort_key(s: str) -> tuple:
14
+ l = []
15
+ for p in s.split('.'):
16
+ v: ta.Any
17
+ try:
18
+ v = int(p)
19
+ except ValueError:
20
+ v = s
21
+ l.append((not isinstance(v, int), v))
22
+ return tuple(l)
23
+
24
+
25
+ DEFAULT_TAG_SUFFIX_DELIM = '-+'
26
+
27
+
28
+ def split_tag_suffix(
29
+ tag: str,
30
+ suffix_delim: ta.Iterable[str] = DEFAULT_TAG_SUFFIX_DELIM,
31
+ ) -> tuple[str, str | None]:
32
+ for d in suffix_delim:
33
+ if d in tag:
34
+ p, _, s = tag.partition(d)
35
+ return p, s
36
+ return tag, None
37
+
38
+
39
+ def select_latest_tag(
40
+ tags: ta.Iterable[str],
41
+ *,
42
+ base: str | None = None,
43
+ suffix: str | None = None,
44
+ suffix_delim: ta.Iterable[str] = '-+',
45
+ ) -> str:
46
+ check.not_isinstance(tags, str)
47
+
48
+ tags_by_sfx: dict[str | None, set[tuple[tuple, str]]] = {}
49
+ for t in tags:
50
+ p, s = split_tag_suffix(t, suffix_delim)
51
+ tags_by_sfx.setdefault(s, set()).add((_tag_sort_key(p), t))
52
+
53
+ if base is not None:
54
+ bp, bs = split_tag_suffix(base, suffix_delim)
55
+ if suffix is None:
56
+ suffix = bs
57
+ base_key = _tag_sort_key(bp)
58
+ else:
59
+ base_key = None
60
+
61
+ sl = sorted(tags_by_sfx[suffix])
62
+
63
+ if base_key is not None:
64
+ sl = [(k, t) for k, t in sl if k[0] == base_key[0]]
65
+
66
+ return sl[-1][1]
67
+
68
+
69
+ ##
70
+
71
+
8
72
  @dc.dataclass(frozen=True)
9
73
  class HubRepoInfo:
10
74
  repo: str
11
- tags: ta.Mapping[str, ta.Any]
12
- latest_manifests: ta.Mapping[str, ta.Any]
75
+ tags: ta.Sequence[str]
76
+ manifests: ta.Mapping[str, ta.Mapping[str, ta.Any]]
13
77
 
14
78
 
15
79
  def get_hub_repo_info(
@@ -17,7 +81,9 @@ def get_hub_repo_info(
17
81
  *,
18
82
  auth_url: str = 'https://auth.docker.io/',
19
83
  api_url: str = 'https://registry-1.docker.io/v2/',
20
- ) -> HubRepoInfo:
84
+ tags: ta.Iterable[str] | None = None,
85
+ handled_codes: ta.Container[int] | None = (401, 404),
86
+ ) -> HubRepoInfo | None:
21
87
  """
22
88
  https://stackoverflow.com/a/39376254
23
89
 
@@ -36,10 +102,19 @@ def get_hub_repo_info(
36
102
  -s "https://registry-1.docker.io/v2/${repo}/manifests/latest" \
37
103
  | jq .
38
104
  """
105
+ if tags is not None:
106
+ check.not_isinstance(tags, str)
107
+ else:
108
+ tags = []
39
109
 
40
110
  auth_url = auth_url.rstrip('/')
41
111
  api_url = api_url.rstrip('/')
42
112
 
113
+ if '/' not in repo:
114
+ repo = '_/' + repo
115
+ if repo.startswith('_/'):
116
+ repo = 'library' + repo[1:]
117
+
43
118
  #
44
119
 
45
120
  def req_json(url: str, **kwargs: ta.Any) -> ta.Any:
@@ -55,21 +130,32 @@ def get_hub_repo_info(
55
130
 
56
131
  #
57
132
 
58
- tags_dct = req_json(
59
- f'{api_url}/{repo}/tags/list',
60
- headers=req_hdrs,
61
- )
62
-
63
- latest_mani_dct = req_json(
64
- f'{api_url}/{repo}/manifests/latest',
65
- headers={
66
- **req_hdrs,
67
- 'Accept': 'application/vnd.docker.distribution.manifest.v2+json',
68
- },
69
- )
133
+ try:
134
+ tags_resp = req_json(
135
+ f'{api_url}/{repo}/tags/list',
136
+ headers=req_hdrs,
137
+ )
138
+ except urllib.error.HTTPError as ue:
139
+ if ue.code in (handled_codes or ()):
140
+ return None
141
+ else:
142
+ raise
143
+
144
+ tags_dct = tags_resp.get('tags', {})
145
+
146
+ manis = {}
147
+ for tag in tags:
148
+ mani = req_json(
149
+ f'{api_url}/{repo}/manifests/latest',
150
+ headers={
151
+ **req_hdrs,
152
+ 'Accept': 'application/vnd.docker.distribution.manifest.v2+json',
153
+ },
154
+ )
155
+ manis[tag] = mani
70
156
 
71
157
  return HubRepoInfo(
72
158
  repo,
73
159
  tags_dct,
74
- latest_mani_dct,
160
+ manis,
75
161
  )
omlish/formats/yaml.py CHANGED
@@ -225,6 +225,14 @@ def load_all(stream, Loader): # noqa
225
225
  yield loader.get_data()
226
226
 
227
227
 
228
+ def safe_load(stream): # noqa
229
+ return load(stream, yaml.SafeLoader)
230
+
231
+
232
+ def safe_load_all(stream): # noqa # noqa
233
+ return load_all(stream, yaml.SafeLoader)
234
+
235
+
228
236
  def full_load(stream): # noqa
229
237
  return load(stream, yaml.FullLoader)
230
238
 
@@ -14,6 +14,17 @@ V = ta.TypeVar('V')
14
14
  ##
15
15
 
16
16
 
17
+ class SimpleMetaDict(dict):
18
+ def update(self, m: ta.Mapping[K, V], **kwargs: V) -> None: # type: ignore
19
+ for k, v in m.items():
20
+ self[k] = v
21
+ for k, v in kwargs.items(): # type: ignore
22
+ self[k] = v
23
+
24
+
25
+ ##
26
+
27
+
17
28
  class _NamespaceMeta(abc.ABCMeta):
18
29
  def __new__(mcls, name, bases, namespace):
19
30
  if bases:
@@ -23,9 +34,14 @@ class _NamespaceMeta(abc.ABCMeta):
23
34
  return super().__new__(mcls, name, bases, namespace)
24
35
 
25
36
  def __iter__(cls) -> ta.Iterator[tuple[str, ta.Any]]:
26
- for a in dir(cls):
27
- if not a.startswith('_'):
28
- yield (a, getattr(cls, a))
37
+ seen: set[str] = set()
38
+ for bcls in reversed(cls.__mro__):
39
+ for a in bcls.__dict__:
40
+ if a in seen:
41
+ continue
42
+ seen.add(a)
43
+ if not a.startswith('_'):
44
+ yield (a, getattr(cls, a))
29
45
 
30
46
  def __getitem__(cls, n: str) -> ta.Any:
31
47
  return getattr(cls, n)
@@ -75,17 +91,6 @@ class Marker(NotInstantiable, metaclass=_MarkerMeta):
75
91
  ##
76
92
 
77
93
 
78
- class SimpleMetaDict(dict):
79
- def update(self, m: ta.Mapping[K, V], **kwargs: V) -> None: # type: ignore
80
- for k, v in m.items():
81
- self[k] = v
82
- for k, v in kwargs.items(): # type: ignore
83
- self[k] = v
84
-
85
-
86
- ##
87
-
88
-
89
94
  _SINGLETON_INSTANCE_ATTR = '__singleton_instance__'
90
95
  _SINGLETON_LOCK = threading.RLock()
91
96
 
@@ -97,15 +97,15 @@ def update_wrapper(
97
97
  assigned: ta.Iterable[str] = functools.WRAPPER_ASSIGNMENTS,
98
98
  updated: ta.Iterable[str] = functools.WRAPPER_UPDATES,
99
99
  *,
100
- filter: ta.Iterable[str] | None = None, # noqa
100
+ exclude: ta.Iterable[str] | None = None,
101
101
  getattr: ta.Callable = getattr, # noqa
102
102
  setattr: ta.Callable = setattr, # noqa
103
103
  ) -> T:
104
- if filter:
105
- if isinstance(filter, str):
106
- filter = [filter] # noqa
107
- assigned = tuple(a for a in assigned if a not in filter)
108
- updated = tuple(a for a in updated if a not in filter)
104
+ if exclude:
105
+ if isinstance(exclude, str):
106
+ exclude = [exclude] # noqa
107
+ assigned = tuple(a for a in assigned if a not in exclude)
108
+ updated = tuple(a for a in updated if a not in exclude)
109
109
 
110
110
  for attr in assigned:
111
111
  try:
@@ -135,7 +135,7 @@ class _decorator_descriptor: # noqa
135
135
  if not _DECORATOR_HANDLES_UNBOUND_METHODS:
136
136
  def __init__(self, wrapper, fn):
137
137
  self._wrapper, self._fn = wrapper, fn
138
- update_wrapper(self, fn, filter='__dict__')
138
+ update_wrapper(self, fn, exclude='__dict__')
139
139
 
140
140
  def __get__(self, instance, owner=None):
141
141
  return functools.update_wrapper(functools.partial(self._wrapper, fn := self._fn.__get__(instance, owner)), fn) # noqa
@@ -144,7 +144,7 @@ class _decorator_descriptor: # noqa
144
144
  def __init__(self, wrapper, fn):
145
145
  self._wrapper, self._fn = wrapper, fn
146
146
  self._md = _has_method_descriptor(fn)
147
- update_wrapper(self, fn, filter='__dict__')
147
+ update_wrapper(self, fn, exclude='__dict__')
148
148
 
149
149
  def __get__(self, instance, owner=None):
150
150
  fn = self._fn.__get__(instance, owner)
@@ -174,7 +174,7 @@ class _decorator_descriptor: # noqa
174
174
  class _decorator: # noqa
175
175
  def __init__(self, wrapper):
176
176
  self._wrapper = wrapper
177
- update_wrapper(self, wrapper, filter='__dict__')
177
+ update_wrapper(self, wrapper, exclude='__dict__')
178
178
 
179
179
  def __repr__(self):
180
180
  return f'{self.__class__.__name__}<{self._wrapper}>'
omlish/lang/strings.py CHANGED
@@ -14,7 +14,7 @@ def prefix_delimited(s: StrOrBytesT, p: StrOrBytesT, d: StrOrBytesT) -> StrOrByt
14
14
 
15
15
 
16
16
  def prefix_lines(s: StrOrBytesT, p: StrOrBytesT) -> StrOrBytesT:
17
- return prefix_delimited(s, p, '\n' if isinstance(s, str) else b'\n')
17
+ return prefix_delimited(s, p, '\n' if isinstance(s, str) else b'\n') # type: ignore
18
18
 
19
19
 
20
20
  def indent_lines(s: StrOrBytesT, num: StrOrBytesT) -> StrOrBytesT:
omlish/lite/marshal.py CHANGED
@@ -246,29 +246,30 @@ def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
246
246
 
247
247
 
248
248
  def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
249
- if isinstance(ty, type) and abc.ABC in ty.__bases__:
250
- impls = [ # type: ignore
251
- PolymorphicObjMarshaler.Impl(
252
- ity,
253
- ity.__qualname__,
254
- get_obj_marshaler(ity),
249
+ if isinstance(ty, type):
250
+ if abc.ABC in ty.__bases__:
251
+ impls = [ # type: ignore
252
+ PolymorphicObjMarshaler.Impl(
253
+ ity,
254
+ ity.__qualname__,
255
+ get_obj_marshaler(ity),
256
+ )
257
+ for ity in deep_subclasses(ty)
258
+ if abc.ABC not in ity.__bases__
259
+ ]
260
+ return PolymorphicObjMarshaler(
261
+ {i.ty: i for i in impls},
262
+ {i.tag: i for i in impls},
263
+ )
264
+
265
+ if issubclass(ty, enum.Enum):
266
+ return EnumObjMarshaler(ty)
267
+
268
+ if dc.is_dataclass(ty):
269
+ return DataclassObjMarshaler(
270
+ ty,
271
+ {f.name: get_obj_marshaler(f.type) for f in dc.fields(ty)},
255
272
  )
256
- for ity in deep_subclasses(ty)
257
- if abc.ABC not in ity.__bases__
258
- ]
259
- return PolymorphicObjMarshaler(
260
- {i.ty: i for i in impls},
261
- {i.tag: i for i in impls},
262
- )
263
-
264
- if isinstance(ty, type) and issubclass(ty, enum.Enum):
265
- return EnumObjMarshaler(ty)
266
-
267
- if dc.is_dataclass(ty):
268
- return DataclassObjMarshaler(
269
- ty,
270
- {f.name: get_obj_marshaler(f.type) for f in dc.fields(ty)},
271
- )
272
273
 
273
274
  if is_generic_alias(ty):
274
275
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev62
3
+ Version: 0.0.0.dev64
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,7 +1,7 @@
1
1
  omlish/.manifests.json,sha256=jvyoQ7x8UJ9lpRgkh7eElwJ8qnzyG5aUGameT9Yk8GM,1419
2
- omlish/__about__.py,sha256=u-gRUFmrAMM8C-1-u6UfjGvA_1qc3iVQiZLYnMGHQxg,3420
2
+ omlish/__about__.py,sha256=GXVeIGR5dUduDtgf1PYJSdJKJyBBSxbzWMxY1GQOHN8,3420
3
3
  omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- omlish/argparse.py,sha256=Vr70_85EVLJLgEkRtwOr264tMRtqtlN7ncFfXRUk5aM,6914
4
+ omlish/argparse.py,sha256=XLrLFCLNY1RfbiXIAELkzHK-vUPum_9dyylEdJi9Pog,7068
5
5
  omlish/c3.py,sha256=4vogWgwPb8TbNS2KkZxpoWbwjj7MuHG2lQG-hdtkvjI,8062
6
6
  omlish/cached.py,sha256=UAizxlH4eMWHPzQtmItmyE6FEpFEUFzIkxaO2BHWZ5s,196
7
7
  omlish/check.py,sha256=fgWiBoHvqZlE8tjaxK7OMW4J8z3_rEGRENTka3EohbI,10378
@@ -91,7 +91,7 @@ omlish/bootstrap/__main__.py,sha256=4jCwsaogp0FrJjJZ85hzF4-WqluPeheHbfeoKynKvNs,
91
91
  omlish/bootstrap/base.py,sha256=d8hqn4hp1XMMi5PgcJBQXPKmW47epu8CxBlqDZiRZb4,1073
92
92
  omlish/bootstrap/diag.py,sha256=LADLhusbJ1tKxVD8-gmia1HShX1VeszRO1OApIQhSpI,5507
93
93
  omlish/bootstrap/harness.py,sha256=VW8YP-yENGyXIuJ8GL_xintArF13nafwpz-iAghPt34,1967
94
- omlish/bootstrap/main.py,sha256=ripSWAlYz3LVyv6S_Js9MWYO3QNKgBSaFQv3gqGjuRM,5885
94
+ omlish/bootstrap/main.py,sha256=yZhOHDDlj4xB5a89dRdT8z58FsqqnpoBg1-tvY2CJe4,5903
95
95
  omlish/bootstrap/marshal.py,sha256=ZxdAeMNd2qXRZ1HUK89HmEhz8tqlS9OduW34QBscKw0,516
96
96
  omlish/bootstrap/sys.py,sha256=i6veZeE83wO0HTl9b6ykj_pEN05fqu0enoAv4sw5Ayc,8742
97
97
  omlish/collections/__init__.py,sha256=tGUzvS_ZjiqALsLRy7JX3h4KZRQX2CmtdAfTRD7UwMk,1677
@@ -101,7 +101,7 @@ omlish/collections/coerce.py,sha256=o11AMrUiyoadd8WkdqeKPIpXf2xd0LyylzNCyJivCLU,
101
101
  omlish/collections/exceptions.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
102
102
  omlish/collections/frozen.py,sha256=DGxemj_pVID85tSBm-Wns_x4ov0wOEIT6X5bVgJtmkA,4152
103
103
  omlish/collections/identity.py,sha256=jhEpC8tnfh3Sg-MJff1Fp9eMydt150wits_UeVdctUk,2723
104
- omlish/collections/indexed.py,sha256=YHs_q0GALisXPKKMgeDQxZ6hMzYndqDL3m3ag8cnzH0,2143
104
+ omlish/collections/indexed.py,sha256=tFQsIWH4k9QqsF5VB7DsIVNsRThiQNx-ooRF36X_PnU,2203
105
105
  omlish/collections/mappings.py,sha256=eEifLZez-BWunTuj6974bGxBFfNRODZpu6Oa7_2ME94,3190
106
106
  omlish/collections/ordered.py,sha256=RzEC3fHvrDeJQSWThVDNYQKke263Vje1II5YwtDwT1Q,2335
107
107
  omlish/collections/persistent.py,sha256=KG471s0bhhReQrjlmX0xaN9HeAIcrtT264ddZCxsExo,875
@@ -168,16 +168,16 @@ omlish/dispatch/_dispatch3.py,sha256=Vnu5DfoPWFJLodudBqoZBXGTi2wYk-Az56MXJgdQvwc
168
168
  omlish/dispatch/dispatch.py,sha256=8XQiLVoAq4u2oO0DnDSXQB9Q5qDk569l4CIFBqwDSyc,3847
169
169
  omlish/dispatch/functions.py,sha256=S8ElsLi6DKxTdtFGigWaF0vAquwy2sK-3f4iRLaYq70,1522
170
170
  omlish/dispatch/methods.py,sha256=XHjwwC9Gn4iDWxbyLAcbdSwRgVaq-8Bnn5cAwf5oZdA,5403
171
- omlish/docker/__init__.py,sha256=LGL5ByHrd7EaQnIDO6eLQvovDamngUiTfnpThV_4-MA,437
171
+ omlish/docker/__init__.py,sha256=dmda-4zBo0UM_CMws_1MOwtyObdF79LB0HF5IT3sDVk,482
172
172
  omlish/docker/cli.py,sha256=gtb9kitVfGnd4cr587NsVVk8D5Ok5y5SAsqD_SwGrSA,2565
173
173
  omlish/docker/compose.py,sha256=4drmnGQzbkOFJ9B6XSg9rnXkJeZz1ETmdcMe1PE790U,1237
174
174
  omlish/docker/helpers.py,sha256=j2eZIqIUpy34ZmoGyIzsYuKx9HeewwYBfrGNC99EFYk,928
175
- omlish/docker/hub.py,sha256=YcDYOi6t1FA2Sp0RVrmZ9cBXbzFWQ8wTps3wOskA-K0,1955
175
+ omlish/docker/hub.py,sha256=7LIuJGdA-N1Y1dmo50ynKM1KUTcnQM_5XbtPbdT_QLU,3940
176
176
  omlish/docker/manifests.py,sha256=LR4FpOGNUT3bZQ-gTjB6r_-1C3YiG30QvevZjrsVUQM,7068
177
177
  omlish/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
178
  omlish/formats/dotenv.py,sha256=UjZl3gac-0U24sDjCCGMcCqO1UCWG2Zs8PZ4JdAg2YE,17348
179
179
  omlish/formats/props.py,sha256=JwFJbKblqzqnzXf7YKFzQSDfcAXzkKsfoYvad6FPy98,18945
180
- omlish/formats/yaml.py,sha256=R3NTkjomsIfjsUNmSf_bOaCUIID3JTyHJHsliQDSYQo,6688
180
+ omlish/formats/yaml.py,sha256=DSJXUq9yanfxdS6ufNTyBHMtIZO57LRnJj4w9fLY1aM,6852
181
181
  omlish/formats/json/__init__.py,sha256=moSR67Qkju2eYb_qVDtaivepe44mxAnYuC8OCSbtETg,298
182
182
  omlish/formats/json/__main__.py,sha256=1wxxKZVkj_u7HCcewwMIbGuZj_Wph95yrUbm474Op9M,188
183
183
  omlish/formats/json/cli.py,sha256=4zftNijlIOnGUHYn5J1s4yRDRM1K4udBzS3Kh8R2vNc,3374
@@ -242,7 +242,7 @@ omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
242
242
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
243
243
  omlish/lang/contextmanagers.py,sha256=NEwaTLQMfhKawD5x_0HgI2RpeLXbMa5r9NqWqfDnUXI,10408
244
244
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
245
- omlish/lang/descriptors.py,sha256=tszC_fMICqCz1cUXejJ4beWzt6DlIBulknJFRkSTZp4,6615
245
+ omlish/lang/descriptors.py,sha256=RRBbkMgTzg82fFFE4D0muqobpM-ZZaOta6yB1lpX3s8,6617
246
246
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
247
247
  omlish/lang/functions.py,sha256=kkPfcdocg-OmyN7skIqrFxNvqAv89Zc_kXKYAN8vw8g,3895
248
248
  omlish/lang/imports.py,sha256=04ugFC8NI5sbL7NH4V0r0q_nFsP_AMkHLz697CVkMtQ,6274
@@ -251,14 +251,14 @@ omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
251
251
  omlish/lang/objects.py,sha256=PJXGm-WgC7vpWzaXGwofk48V2XZNaQLje60K1ariwvQ,4454
252
252
  omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
253
253
  omlish/lang/resources.py,sha256=-NmVTrSMKFZ6smVfOMz46ekZYVGgYh8cPooxQlFpG6s,2135
254
- omlish/lang/strings.py,sha256=LWgUy9WghUyV0zmZ1c3HZjEfekLlNPy7Jl6J1Z5vzp0,3882
254
+ omlish/lang/strings.py,sha256=BsciSYnckD4vGtC6kmtnugR9IN6CIHdcjO4nZu-pSAw,3898
255
255
  omlish/lang/sys.py,sha256=UoZz_PJYVKLQAKqYxxn-LHz1okK_38I__maZgnXMcxU,406
256
256
  omlish/lang/timeouts.py,sha256=vECdWYhc_IZgcal1Ng1Y42wf2FV3KAx-i8As-MgGHIQ,1186
257
257
  omlish/lang/typing.py,sha256=lJ2NGe4Pmb61I0Tx4A_rOqXNFTws1XHOzafg2knRUio,4155
258
258
  omlish/lang/classes/__init__.py,sha256=h9QXrvAKD17_pIog0uF-7BCqZbSpJZYxL7kzVzvljp0,583
259
259
  omlish/lang/classes/abstract.py,sha256=IRnjuLLNwpxvEJsp8fwoQdCIpw0MDAd0TiQfoDMgsn4,2306
260
260
  omlish/lang/classes/restrict.py,sha256=pSK7ZT_kpwqS6lWRrxwuEe-tt07F0-uZVazgGh-HDco,3921
261
- omlish/lang/classes/simple.py,sha256=roGxmtl5BAXl6_WAt89Hfd1Xmu-Cvnwo-YCZgs1Wq-s,3116
261
+ omlish/lang/classes/simple.py,sha256=XQ8b86WvQA0qtSYqlbMOJS7tHgE8sv9onda33uQmbkM,3294
262
262
  omlish/lang/classes/virtual.py,sha256=W-QJuKsDehOcrydwg6eMN0bFPTYbk3Tz84TSH3blb44,3367
263
263
  omlish/lifecycles/__init__.py,sha256=1FjYceXs-4fc-S-C9zFYmc2axHs4znnQHcJVHdY7a6E,578
264
264
  omlish/lifecycles/abstract.py,sha256=70CQyZy-c9a2o0ZJxPeUT7eYjWZTBrp2HpUBnrHdAOM,1109
@@ -274,7 +274,7 @@ omlish/lite/check.py,sha256=B0VnyBSWI5qipidkwnU-BP43S9E-UOgp4WUM17pVpHc,750
274
274
  omlish/lite/contextmanagers.py,sha256=HnQJiyrOmSvTL22XRJrFl5CLpCyHD9fsntEUAr9G-60,427
275
275
  omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
276
276
  omlish/lite/logs.py,sha256=vkFkSX0Izb2P-NNMqqNLSec0BzeLOtHoQWgdXwQuDPU,6007
277
- omlish/lite/marshal.py,sha256=u6jYUN_AndvI6__HJBvSw5ElHWC0CfHqgiDS28Vpqjg,8593
277
+ omlish/lite/marshal.py,sha256=kZtfIiFfmxEi8ZKne3fT0R8g8kLmJ-Q5nq4kOvwhiqk,8656
278
278
  omlish/lite/reflect.py,sha256=9QYJwdINraq1JNMEgvoqeSlVvRRgOXpxAkpgX8EgRXc,1307
279
279
  omlish/lite/runtime.py,sha256=VUhmNQvwf8QzkWSKj4Q0ReieJA_PzHaJNRBivfTseow,452
280
280
  omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
@@ -408,9 +408,9 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
408
408
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
409
409
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
410
410
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
411
- omlish-0.0.0.dev62.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
412
- omlish-0.0.0.dev62.dist-info/METADATA,sha256=mt0fT8Bk_wKy64eUKY_AYPNxHg-yruiGNd2EYcnYUPw,4167
413
- omlish-0.0.0.dev62.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
414
- omlish-0.0.0.dev62.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
415
- omlish-0.0.0.dev62.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
416
- omlish-0.0.0.dev62.dist-info/RECORD,,
411
+ omlish-0.0.0.dev64.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
412
+ omlish-0.0.0.dev64.dist-info/METADATA,sha256=fd-7ozSHicCgpU4SOmqEUW7WJAsroSMO531X7vxMDVo,4167
413
+ omlish-0.0.0.dev64.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
414
+ omlish-0.0.0.dev64.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
415
+ omlish-0.0.0.dev64.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
416
+ omlish-0.0.0.dev64.dist-info/RECORD,,