omlish 0.0.0.dev461__py3-none-any.whl → 0.0.0.dev463__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 CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev461'
2
- __revision__ = '7ebd7a07f84e80a8d1855b8a182da756dbb7d6ec'
1
+ __version__ = '0.0.0.dev463'
2
+ __revision__ = '3ce0d0667b2ff4d64b7757f449fef0c480e8790f'
3
3
 
4
4
 
5
5
  #
omlish/argparse/all.py CHANGED
@@ -1,17 +1,25 @@
1
1
  # ruff: noqa: I001
2
2
  import argparse
3
3
 
4
- from .cli import ( # noqa
5
- ArgparseArg as Arg,
6
- argparse_arg as arg,
7
- argparse_arg_ as arg_,
4
+ from .. import lang as _lang
8
5
 
9
- ArgparseCmdFn as CmdFn,
10
- ArgparseCmd as Cmd,
11
- argparse_cmd as cmd,
12
6
 
13
- ArgparseCli as Cli,
14
- )
7
+ with _lang.auto_proxy_init(globals()):
8
+ from .cli import ( # noqa
9
+ ArgparseArg as Arg,
10
+ argparse_arg as arg,
11
+ argparse_arg_ as arg_,
12
+
13
+ ArgparseCmdFn as CmdFn,
14
+ ArgparseCmd as Cmd,
15
+ argparse_cmd as cmd,
16
+
17
+ ArgparseCli as Cli,
18
+ )
19
+
20
+ from .utils import ( # noqa
21
+ NoExitArgumentParser,
22
+ )
15
23
 
16
24
 
17
25
  ##
@@ -0,0 +1,21 @@
1
+ import argparse
2
+ import typing as ta
3
+
4
+
5
+ ##
6
+
7
+
8
+ class NoExitArgumentParser(argparse.ArgumentParser):
9
+ def __init__(
10
+ self,
11
+ *args: ta.Any,
12
+ exit_on_error: bool = False,
13
+ **kwargs: ta.Any,
14
+ ) -> None:
15
+ if exit_on_error:
16
+ raise TypeError('exit_on_error=True not supported')
17
+
18
+ super().__init__(*args, exit_on_error=False, **kwargs) # type: ignore[misc]
19
+
20
+ def exit(self, status=0, message=None):
21
+ raise TypeError('NoExitArgumentParser.exit() not supported')
omlish/inject/__init__.py CHANGED
@@ -19,11 +19,28 @@ from .. import lang as _lang # noqa
19
19
  with _lang.auto_proxy_init(globals()):
20
20
  ##
21
21
 
22
+ from .helpers.constfn import ( # noqa
23
+ ConstFn,
24
+ )
25
+
26
+ from .helpers.id import ( # noqa
27
+ Id,
28
+ )
29
+
30
+ from .helpers.multis import ( # noqa
31
+ bind_map_entry_const,
32
+ bind_set_entry_const,
33
+
34
+ ItemsBinderHelper as items_binder_helper, # noqa
35
+ )
36
+
37
+ from .helpers.wrappers import ( # noqa
38
+ WrapperBinderHelper as wrapper_binder_helper, # noqa
39
+ )
40
+
22
41
  from .binder import ( # noqa
23
42
  bind,
24
43
  bind_as_fn,
25
- bind_map_entry_const,
26
- bind_set_entry_const,
27
44
  )
28
45
 
29
46
  from .bindings import ( # noqa
@@ -36,9 +53,10 @@ with _lang.auto_proxy_init(globals()):
36
53
 
37
54
  from .elements import ( # noqa
38
55
  Element,
39
- Elemental,
40
56
  Elements,
57
+ Elemental,
41
58
  as_elements,
59
+ iter_elements,
42
60
  )
43
61
 
44
62
  from .errors import ( # noqa
@@ -153,16 +171,8 @@ with _lang.auto_proxy_init(globals()):
153
171
  create_injector,
154
172
  )
155
173
 
156
- from .tags import ( # noqa
157
- Id,
158
- )
159
-
160
174
  from .types import ( # noqa
161
175
  Scope,
162
176
  Tag,
163
177
  Unscoped,
164
178
  )
165
-
166
- from .utils import ( # noqa
167
- ConstFn,
168
- )
omlish/inject/binder.py CHANGED
@@ -11,13 +11,8 @@ from .bindings import Binding
11
11
  from .eagers import Eager
12
12
  from .elements import Element
13
13
  from .elements import Elements
14
- from .elements import as_elements
15
14
  from .keys import Key
16
15
  from .keys import as_key
17
- from .multis import MapBinding
18
- from .multis import SetBinding
19
- from .multis import is_map_multi_key
20
- from .multis import is_set_multi_key
21
16
  from .privates import Expose
22
17
  from .providers import AsyncFnProvider
23
18
  from .providers import ConstProvider
@@ -27,7 +22,6 @@ from .providers import LinkProvider
27
22
  from .providers import Provider
28
23
  from .scopes import SCOPE_ALIASES
29
24
  from .scopes import Singleton
30
- from .tags import Id
31
25
  from .types import Scope
32
26
  from .types import Unscoped
33
27
 
@@ -84,6 +78,7 @@ def bind(
84
78
  *,
85
79
  tag: ta.Any = None,
86
80
 
81
+ to_provider: Provider | None = None,
87
82
  to_async_fn: ta.Any = None,
88
83
  to_fn: ta.Any = None,
89
84
  to_ctor: ta.Any = None,
@@ -104,6 +99,7 @@ def bind(
104
99
  ##
105
100
 
106
101
  has_to = (
102
+ to_provider is not None or
107
103
  to_async_fn is not None or
108
104
  to_fn is not None or
109
105
  to_ctor is not None or
@@ -140,6 +136,8 @@ def bind(
140
136
  ##
141
137
 
142
138
  providers: list[Provider] = []
139
+ if to_provider is not None:
140
+ providers.append(to_provider)
143
141
  if to_async_fn is not None:
144
142
  providers.append(AsyncFnProvider(to_async_fn))
145
143
  if to_fn is not None:
@@ -191,45 +189,3 @@ def bind(
191
189
  return elements[0]
192
190
  else:
193
191
  return Elements(frozenset(elements))
194
-
195
-
196
- ##
197
-
198
-
199
- def bind_set_entry_const(
200
- multi_key: ta.Any,
201
- obj: ta.Any,
202
- *,
203
- tag: ta.Any | None = None,
204
- ) -> Elements:
205
- multi_key = as_key(multi_key)
206
- check.arg(is_set_multi_key(multi_key))
207
-
208
- if tag is None:
209
- tag = Id(id(obj), tag=multi_key.tag)
210
- obj_key: Key = Key(type(obj), tag=tag)
211
-
212
- return as_elements(
213
- bind(obj_key, to_const=obj),
214
- SetBinding(multi_key, obj_key),
215
- )
216
-
217
-
218
- def bind_map_entry_const(
219
- multi_key: ta.Any,
220
- map_key: ta.Any,
221
- obj: ta.Any,
222
- *,
223
- tag: ta.Any | None = None,
224
- ) -> Elements:
225
- multi_key = as_key(multi_key)
226
- check.arg(is_map_multi_key(multi_key))
227
-
228
- if tag is None:
229
- tag = Id(id(obj), tag=multi_key.tag)
230
- obj_key: Key = Key(type(obj), tag=tag)
231
-
232
- return as_elements(
233
- bind(obj_key, to_const=obj),
234
- MapBinding(multi_key, map_key, obj_key),
235
- )
omlish/inject/elements.py CHANGED
@@ -64,3 +64,13 @@ def as_elements(*args: Elemental) -> Elements:
64
64
  es if es else None,
65
65
  cs if cs else None,
66
66
  )
67
+
68
+
69
+ def iter_elements(*args: Elemental) -> ta.Iterator[Element]:
70
+ for a in args:
71
+ if isinstance(a, Element):
72
+ yield a
73
+ elif isinstance(a, (Elements, ElementGenerator)):
74
+ yield from a
75
+ else:
76
+ raise TypeError(a)
File without changes
@@ -1,8 +1,8 @@
1
1
  import typing as ta
2
2
 
3
- from .. import dataclasses as dc
4
- from .. import lang
5
- from .impl.origins import HasOriginsImpl
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from ..impl.origins import HasOriginsImpl
6
6
 
7
7
 
8
8
  T = ta.TypeVar('T')
@@ -1,7 +1,7 @@
1
1
  import typing as ta
2
2
 
3
- from .. import dataclasses as dc
4
- from .types import Tag
3
+ from ... import dataclasses as dc
4
+ from ..types import Tag
5
5
 
6
6
 
7
7
  ##
@@ -0,0 +1,140 @@
1
+ import typing as ta
2
+
3
+ from ... import cached
4
+ from ... import check
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ... import reflect as rfl
8
+ from ..binder import bind
9
+ from ..elements import Elements
10
+ from ..elements import as_elements
11
+ from ..inspect import KwargsTarget
12
+ from ..keys import Key
13
+ from ..keys import as_key
14
+ from ..multis import MapBinding
15
+ from ..multis import SetBinder
16
+ from ..multis import SetBinding
17
+ from ..multis import is_map_multi_key
18
+ from ..multis import is_set_multi_key
19
+ from ..providers import FnProvider
20
+ from .id import Id
21
+
22
+
23
+ ItemT = ta.TypeVar('ItemT')
24
+
25
+
26
+ ##
27
+
28
+
29
+ def bind_set_entry_const(
30
+ multi_key: ta.Any,
31
+ obj: ta.Any,
32
+ *,
33
+ tag: ta.Any | None = None,
34
+ ) -> Elements:
35
+ multi_key = as_key(multi_key)
36
+ check.arg(is_set_multi_key(multi_key))
37
+
38
+ if tag is None:
39
+ tag = Id(id(obj), tag=multi_key.tag)
40
+ obj_key: Key = Key(type(obj), tag=tag)
41
+
42
+ return as_elements(
43
+ bind(obj_key, to_const=obj),
44
+ SetBinding(multi_key, obj_key),
45
+ )
46
+
47
+
48
+ def bind_map_entry_const(
49
+ multi_key: ta.Any,
50
+ map_key: ta.Any,
51
+ obj: ta.Any,
52
+ *,
53
+ tag: ta.Any | None = None,
54
+ ) -> Elements:
55
+ multi_key = as_key(multi_key)
56
+ check.arg(is_map_multi_key(multi_key))
57
+
58
+ if tag is None:
59
+ tag = Id(id(obj), tag=multi_key.tag)
60
+ obj_key: Key = Key(type(obj), tag=tag)
61
+
62
+ return as_elements(
63
+ bind(obj_key, to_const=obj),
64
+ MapBinding(multi_key, map_key, obj_key),
65
+ )
66
+
67
+
68
+ ##
69
+
70
+
71
+ @ta.final
72
+ class ItemsBinderHelper(ta.Generic[ItemT]):
73
+ def __init__(self, items_cls: ta.Any) -> None:
74
+ self._items_cls = items_cls
75
+
76
+ @cached.property
77
+ def _item_rty(self) -> rfl.Type:
78
+ rty = check.isinstance(rfl.type_(rfl.get_orig_class(self)), rfl.Generic)
79
+ check.is_(rty.cls, self.__class__)
80
+ return check.single(rty.args)
81
+
82
+ @dc.dataclass(frozen=True, eq=False)
83
+ class _ItemsBox:
84
+ vs: ta.Sequence
85
+
86
+ @cached.property
87
+ def _items_box(self) -> type[_ItemsBox]:
88
+ if isinstance(item_rty := self._item_rty, type):
89
+ sfx = item_rty.__qualname__
90
+ else:
91
+ sfx = str(item_rty).replace("'", '')
92
+
93
+ return lang.new_type( # noqa
94
+ f'{ItemsBinderHelper._ItemsBox.__qualname__}${sfx}@{id(self):x}',
95
+ (ItemsBinderHelper._ItemsBox,),
96
+ {},
97
+ )
98
+
99
+ @cached.property
100
+ def _set_key(self) -> Key:
101
+ return as_key(ta.AbstractSet[self._item_rty]) # type: ignore
102
+
103
+ def bind_item_consts(self, *items: ItemT) -> Elements:
104
+ return as_elements(
105
+ bind_set_entry_const(self._set_key, self._items_box(items)),
106
+ )
107
+
108
+ @dc.dataclass(frozen=True, eq=False)
109
+ @dc.extra_class_params(repr_id=True)
110
+ class _ItemTag:
111
+ pass
112
+
113
+ def bind_item(self, **kwargs: ta.Any) -> Elements:
114
+ tag = ItemsBinderHelper._ItemTag()
115
+ item_key: Key = Key(ta.Any, tag=tag)
116
+ items_box_key: Key = Key(self._items_box, tag=tag)
117
+ return as_elements(
118
+ bind(item_key, **kwargs),
119
+ bind(
120
+ items_box_key,
121
+ to_provider=FnProvider(KwargsTarget.of(
122
+ lambda v: self._items_box([v]),
123
+ v=item_key,
124
+ )),
125
+ ),
126
+ SetBinding(self._set_key, items_box_key),
127
+ )
128
+
129
+ def bind_items_provider(self, **kwargs: ta.Any) -> Elements:
130
+ return as_elements(
131
+ SetBinder[self._item_rty](), # type: ignore
132
+ bind(
133
+ self._items_cls,
134
+ to_provider=FnProvider(KwargsTarget.of(
135
+ lambda s: self._items_cls([v for i in s for v in i.vs]),
136
+ s=self._set_key,
137
+ )),
138
+ **kwargs,
139
+ ),
140
+ )
@@ -0,0 +1,51 @@
1
+ import typing as ta
2
+
3
+ from ... import cached
4
+ from ... import dataclasses as dc
5
+ from ..binder import bind
6
+ from ..elements import Elemental
7
+ from ..keys import Key
8
+ from ..keys import as_key
9
+ from ..privates import private
10
+
11
+
12
+ ##
13
+
14
+
15
+ @ta.final
16
+ class WrapperBinderHelper:
17
+ def __init__(self, key: ta.Any) -> None:
18
+ self._key = as_key(key)
19
+ self._root = WrapperBinderHelper._Root()
20
+ self._top = WrapperBinderHelper._Level(self._root, 0)
21
+
22
+ @dc.dataclass(frozen=True, eq=False)
23
+ @dc.extra_class_params(repr_id=True)
24
+ class _Root:
25
+ pass
26
+
27
+ @dc.dataclass(frozen=True)
28
+ class _Level:
29
+ root: 'WrapperBinderHelper._Root'
30
+ level: int
31
+
32
+ def next(self) -> 'WrapperBinderHelper._Level':
33
+ return WrapperBinderHelper._Level(self.root, self.level + 1)
34
+
35
+ @cached.property
36
+ def key(self) -> Key:
37
+ return Key(ta.Any, tag=self)
38
+
39
+ @property
40
+ def top(self) -> Key:
41
+ return self._top.key
42
+
43
+ def push_bind(self, **kwargs: ta.Any) -> Elemental:
44
+ prv = self._top
45
+ nxt = prv.next()
46
+ out = private(
47
+ *([bind(self._key, to_key=prv.key)] if prv.level else []),
48
+ bind(nxt.key, **kwargs, expose=True),
49
+ )
50
+ self._top = nxt
51
+ return out
@@ -63,6 +63,23 @@ ElementT = ta.TypeVar('ElementT', bound=Element)
63
63
  ##
64
64
 
65
65
 
66
+ _SIMPLE_KEYED_ELEMENT_TYPES: tuple[type[Element], ...] = (
67
+ Binding,
68
+ Eager,
69
+ Expose,
70
+ )
71
+
72
+ _SIMPLE_NON_KEYED_ELEMENT_TYPES: tuple[type[Element], ...] = (
73
+ ProvisionListenerBinding,
74
+ )
75
+
76
+ _NON_BINDING_ELEMENT_TYPES: tuple[type[Element], ...] = (
77
+ Eager,
78
+ Expose,
79
+ ProvisionListenerBinding,
80
+ )
81
+
82
+
66
83
  class ElementCollection(lang.Final):
67
84
  def __init__(self, es: Elements) -> None:
68
85
  super().__init__()
@@ -96,28 +113,28 @@ class ElementCollection(lang.Final):
96
113
  out.setdefault(k, []).extend(e)
97
114
 
98
115
  for e in es:
99
- if isinstance(e, ScopeBinding):
116
+ if isinstance(e, _SIMPLE_KEYED_ELEMENT_TYPES):
117
+ add(e.key, e) # type: ignore[attr-defined] # noqa
118
+
119
+ elif isinstance(e, _SIMPLE_NON_KEYED_ELEMENT_TYPES):
120
+ add(None, e)
121
+
122
+ elif isinstance(e, (SetBinding, MapBinding)):
123
+ add(e.multi_key, e)
124
+
125
+ elif isinstance(e, ScopeBinding):
100
126
  add(None, e)
101
127
  sci = make_scope_impl(e.scope)
102
128
  if (sae := sci.auto_elements()) is not None:
103
129
  self._build_raw_element_multimap(sae, out)
104
130
 
105
- elif isinstance(e, (Binding, Eager, Expose)):
106
- add(e.key, e)
107
-
108
131
  elif isinstance(e, Private):
109
132
  pi = self._get_private_info(e)
110
133
  self._build_raw_element_multimap(pi.owner_elements(), out)
111
134
 
112
- elif isinstance(e, (SetBinding, MapBinding)):
113
- add(e.multi_key, e)
114
-
115
- elif isinstance(e, ProvisionListenerBinding):
116
- add(None, e)
117
-
118
135
  elif isinstance(e, Overrides):
119
- ovr = self._build_raw_element_multimap(e.ovr)
120
136
  src = self._build_raw_element_multimap(e.src)
137
+ ovr = self._build_raw_element_multimap(e.ovr)
121
138
  for k, b in src.items(): # FIXME: merge None keys?
122
139
  try:
123
140
  bs = ovr[k]
@@ -166,9 +183,8 @@ class ElementCollection(lang.Final):
166
183
 
167
184
  es_by_ty = col.multi_map_by(type, es)
168
185
 
169
- es_by_ty.pop(Eager, None)
170
- es_by_ty.pop(Expose, None)
171
- es_by_ty.pop(ProvisionListenerBinding, None)
186
+ for nb_ty in _NON_BINDING_ELEMENT_TYPES:
187
+ es_by_ty.pop(nb_ty, None)
172
188
 
173
189
  if (bs := es_by_ty.pop(Binding, None)):
174
190
  b = self._get_single_binding(k, bs) # type: ignore
@@ -176,7 +192,6 @@ class ElementCollection(lang.Final):
176
192
  p: ProviderImpl
177
193
  if isinstance(b.provider, (SetProvider, MapProvider)):
178
194
  p = make_multi_provider_impl(b.provider, es_by_ty)
179
-
180
195
  else:
181
196
  p = make_provider_impl(b.provider)
182
197
 
@@ -12,6 +12,8 @@ TODO:
12
12
  - injection listeners
13
13
  - unions - raise on ambiguous - usecase: sql.AsyncEngineLike
14
14
  - multiple live request scopes on single injector - use private injectors?
15
+ - more listeners - UnboundKeyListener
16
+ - lazy parent listener chain cache thing
15
17
  """
16
18
  import contextlib
17
19
  import functools
@@ -55,6 +57,7 @@ DEFAULT_SCOPES: list[Scope] = [
55
57
  ]
56
58
 
57
59
 
60
+ @ta.final
58
61
  class AsyncInjectorImpl(AsyncInjector, lang.Final):
59
62
  def __init__(
60
63
  self,
@@ -83,7 +86,7 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
83
86
  )
84
87
  )
85
88
 
86
- self._cs: weakref.WeakSet[AsyncInjectorImpl] | None = None
89
+ self._cs: weakref.WeakSet[AsyncInjectorImpl] | None = None # noqa
87
90
  self._root: AsyncInjectorImpl = p._root if p is not None else self # noqa
88
91
 
89
92
  self.__cur_req: AsyncInjectorImpl._Request | None = None
@@ -76,6 +76,9 @@ def build_kwargs_target(
76
76
  skip_kwargs: ta.Iterable[str] | None = None,
77
77
  raw_optional: bool = False,
78
78
  ) -> KwargsTarget:
79
+ if isinstance(obj, KwargsTarget):
80
+ return obj
81
+
79
82
  sig = signature(obj)
80
83
  tags = _TAGS.get(obj)
81
84
 
omlish/inject/inspect.py CHANGED
@@ -2,6 +2,7 @@ import typing as ta
2
2
 
3
3
  from .. import lang
4
4
  from .keys import Key
5
+ from .keys import as_key
5
6
 
6
7
 
7
8
  if ta.TYPE_CHECKING:
@@ -21,11 +22,45 @@ class Kwarg(ta.NamedTuple):
21
22
  key: Key
22
23
  has_default: bool
23
24
 
25
+ @classmethod
26
+ def of(
27
+ cls,
28
+ name: str,
29
+ key: Key,
30
+ *,
31
+ has_default: bool = False,
32
+ ) -> 'Kwarg':
33
+ return cls(
34
+ name,
35
+ key,
36
+ has_default,
37
+ )
38
+
24
39
 
25
40
  class KwargsTarget(ta.NamedTuple):
26
41
  obj: ta.Any
27
42
  kwargs: ta.Sequence[Kwarg]
28
43
 
44
+ @classmethod
45
+ def of(
46
+ cls,
47
+ obj: ta.Any,
48
+ *kws: Kwarg,
49
+ **kwargs: tuple[Key, bool] | Key | ta.Any,
50
+ ) -> 'KwargsTarget':
51
+ kw_kwargs: list[Kwarg] = []
52
+ for n, v in kwargs.items():
53
+ if isinstance(v, tuple):
54
+ kw_k, kw_hd = v
55
+ kw_kwargs.append(Kwarg.of(n, kw_k, has_default=kw_hd))
56
+ else:
57
+ kw_kwargs.append(Kwarg.of(n, as_key(v)))
58
+
59
+ return cls(
60
+ obj,
61
+ [*kws, *kw_kwargs],
62
+ )
63
+
29
64
 
30
65
  def tag(obj: T, **kwargs: ta.Any) -> T:
31
66
  return _inspect.tag(obj, **kwargs)
@@ -14,9 +14,9 @@ from .elements import as_elements
14
14
  @dc.dataclass(frozen=True)
15
15
  @dc.extra_class_params(cache_hash=True)
16
16
  class Overrides(Element, lang.Final):
17
- ovr: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
18
17
  src: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
18
+ ovr: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
19
19
 
20
20
 
21
- def override(ovr: ta.Any, *a: ta.Any) -> Element:
22
- return Overrides(as_elements(ovr), as_elements(*a))
21
+ def override(src: ta.Any, *ovr: ta.Any) -> Element:
22
+ return Overrides(as_elements(src), as_elements(*ovr))
@@ -3,6 +3,7 @@ import typing as ta
3
3
  from .. import check
4
4
  from .. import dataclasses as dc
5
5
  from .. import lang
6
+ from .inspect import KwargsTarget
6
7
  from .keys import Key
7
8
 
8
9
 
@@ -20,13 +21,13 @@ class Provider(lang.Abstract):
20
21
  @dc.dataclass(frozen=True)
21
22
  @dc.extra_class_params(cache_hash=True)
22
23
  class AsyncFnProvider(Provider):
23
- fn: ta.Any = dc.xfield(validate=callable)
24
+ fn: ta.Any = dc.xfield(validate=lambda v: callable(v) or isinstance(v, KwargsTarget))
24
25
 
25
26
 
26
27
  @dc.dataclass(frozen=True)
27
28
  @dc.extra_class_params(cache_hash=True)
28
29
  class FnProvider(Provider):
29
- fn: ta.Any = dc.xfield(validate=callable)
30
+ fn: ta.Any = dc.xfield(validate=lambda v: callable(v) or isinstance(v, KwargsTarget))
30
31
 
31
32
 
32
33
  @dc.dataclass(frozen=True)
omlish/lang/__init__.py CHANGED
@@ -63,6 +63,9 @@ with _auto_proxy_init(globals(), update_exports=True):
63
63
  snake_case,
64
64
  up_snake_case,
65
65
 
66
+ camel_to_snake,
67
+ snake_to_camel,
68
+
66
69
  get_string_casing,
67
70
  split_string_casing,
68
71
  )
omlish/lang/casing.py CHANGED
@@ -50,6 +50,13 @@ class StringCasing(Abstract):
50
50
 
51
51
  raise NotImplementedError
52
52
 
53
+ #
54
+
55
+ def to(self, other: 'StringCasing') -> ta.Callable[[str], str]:
56
+ def inner(s: str) -> str:
57
+ return other.join(*self.split(s))
58
+ return inner
59
+
53
60
 
54
61
  #
55
62
 
@@ -167,6 +174,10 @@ snake_case = SNAKE_CASE.join
167
174
  up_snake_case = UP_SNAKE_CASE.join
168
175
 
169
176
 
177
+ camel_to_snake = CAMEL_CASE.to(SNAKE_CASE)
178
+ snake_to_camel = SNAKE_CASE.to(CAMEL_CASE)
179
+
180
+
170
181
  ##
171
182
 
172
183
 
omlish/lang/recursion.py CHANGED
@@ -13,7 +13,6 @@ P = ta.ParamSpec('P')
13
13
 
14
14
 
15
15
  _LOCK = threading.RLock()
16
-
17
16
  _LOCAL: threading.local
18
17
 
19
18
 
omlish/lite/typing.py CHANGED
@@ -12,6 +12,12 @@ A2 = ta.TypeVar('A2')
12
12
 
13
13
  ##
14
14
  # A workaround for typing deficiencies (like `Argument 2 to NewType(...) must be subclassable`).
15
+ #
16
+ # Note that this problem doesn't happen at runtime - it happens in mypy:
17
+ #
18
+ # mypy <(echo "import typing as ta; MyCallback = ta.NewType('MyCallback', ta.Callable[[], None])")
19
+ # /dev/fd/11:1:22: error: Argument 2 to NewType(...) must be subclassable (got "Callable[[], None]") [valid-newtype]
20
+ #
15
21
 
16
22
 
17
23
  @dc.dataclass(frozen=True)
omlish/reflect/types.py CHANGED
@@ -9,6 +9,7 @@ give it some guiding North Star to make all of its decisions for it, and to add
9
9
  meet, join, solve, ...), but it's quite a bit of work and not a priority at the moment.
10
10
 
11
11
  TODO:
12
+ - !!! refactor like a GuardFn - no check_only, return a closure to continue computation !!!
12
13
  - !! cache this shit !!
13
14
  - especially generic_mro shit
14
15
  """
omlish/term/alt.py ADDED
@@ -0,0 +1,60 @@
1
+ import io
2
+
3
+
4
+ ##
5
+
6
+
7
+ _ESC = '\x1b'
8
+
9
+
10
+ def _csi(seq: str) -> str:
11
+ return f'{_ESC}[{seq}'
12
+
13
+
14
+ _ENTER_ALT = _csi('?1049h')
15
+ _LEAVE_ALT = _csi('?1049l')
16
+ _HIDE_CURSOR = _csi('?25l')
17
+ _SHOW_CURSOR = _csi('?25h')
18
+ _CLEAR_LINE = _csi('2K')
19
+
20
+ _SYNC_OUTPUT_ON = _csi('?2026h')
21
+ _SYNC_OUTPUT_OFF = _csi('?2026l')
22
+
23
+
24
+ def _move(row: int, col: int) -> str:
25
+ return _csi(f'{row};{col}H') # CUP
26
+
27
+
28
+ _MOVE_BOTTOM_LEFT = _move(999, 1) # clamped
29
+
30
+
31
+ ##
32
+
33
+
34
+ def render_write_from_alt(
35
+ s: str,
36
+ *,
37
+ no_sync_output: bool = False,
38
+ move_and_clear: bool = False,
39
+ ) -> str:
40
+ out = io.StringIO()
41
+
42
+ if not no_sync_output:
43
+ out.write(_SYNC_OUTPUT_ON)
44
+
45
+ out.write(_HIDE_CURSOR)
46
+ out.write(_LEAVE_ALT)
47
+
48
+ if move_and_clear:
49
+ out.write(_MOVE_BOTTOM_LEFT)
50
+ out.write(_CLEAR_LINE)
51
+
52
+ out.write(s)
53
+
54
+ out.write(_ENTER_ALT)
55
+ out.write(_SHOW_CURSOR)
56
+
57
+ if not no_sync_output:
58
+ out.write(_SYNC_OUTPUT_OFF)
59
+
60
+ return out.getvalue()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev461
3
+ Version: 0.0.0.dev463
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.omlish-manifests.json,sha256=FLw7xkPiSXuImZgqSP8BwrEib2R1doSzUPLUkc-QUIA,8410
2
- omlish/__about__.py,sha256=LlWiGEazhGs4KJP-X_qmIvAXOXB4LxUSsqQz07ymSCM,3613
2
+ omlish/__about__.py,sha256=QvTjEBGfJoR0pcnoda5VAKaV7YmWvLdvLl-4CWcxpnc,3613
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
@@ -16,8 +16,9 @@ omlish/algorithm/distribute.py,sha256=juv6JaCynQG6RaxX0fnNNEVJcvZ8hUS2Mv3ND2t9Y3
16
16
  omlish/algorithm/toposort.py,sha256=5wog_7XTYtg5vq4tcKtn9DcXRsEMaVobzQ6ndMK4HhQ,899
17
17
  omlish/algorithm/unify.py,sha256=jADtgVQkcGKRV4WokG0ePYe9X6BT_8RAS-WSfbBbjUk,838
18
18
  omlish/argparse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- omlish/argparse/all.py,sha256=NeeMM5MIebY7XDAHaCxUzeesEoUYwsf5i9PrBUcO1cI,1057
19
+ omlish/argparse/all.py,sha256=ZQ2jb1eptdDcngyS6ECdTiUdUfoKIev3Z_ej9zQvgIs,1233
20
20
  omlish/argparse/cli.py,sha256=60cfq_WFLwL3YsIQxGAQ7XDi-LzNjH33RavcKdRnhUU,8737
21
+ omlish/argparse/utils.py,sha256=tZAoypACgkTjgOoz7wGWki2TxtRSoGyi0VA6VBElj9k,535
21
22
  omlish/asyncs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
23
  omlish/asyncs/all.py,sha256=zE9zBNepDSczQ-QhnzwFz59IZIex3HuUqfKIgwbJLgY,329
23
24
  omlish/asyncs/buffers.py,sha256=_Ds4Aa1bUWQwQTGmcYsKLjcJ_d5HgbSkPTFrG9y-eMQ,1424
@@ -339,14 +340,14 @@ omlish/http/coro/server/fdio.py,sha256=wd4ShtoX0Ag2xf9PiiQcZR1XLmqHukb_anp0TipNG
339
340
  omlish/http/coro/server/server.py,sha256=pB-QV70koRtFwmKmyjnriZDJtErhE6dNqTVvF7s4BVg,18433
340
341
  omlish/http/coro/server/simple.py,sha256=j1RZ3niKrgGM2qFnjdYWn_eniZzay5j49Ca4L3u8vO4,3296
341
342
  omlish/http/coro/server/sockets.py,sha256=kFZYbcTGYftvm7zpOhkZGtyX2qYdem-Gk018GVBOzeg,2285
342
- omlish/inject/__init__.py,sha256=8ik0yhn0LCdDr2UMACBeatENs76yprB8pDXUNllXRWg,2954
343
- omlish/inject/binder.py,sha256=7-Lhf39FuwtpAA57ljJ_h8fIUNCpcd10E6CJiR4Cdxc,5303
343
+ omlish/inject/__init__.py,sha256=boxaEFFzlclhJZDtPRzg-1wEjKZP9fYjNaZR6JHlfuI,3214
344
+ omlish/inject/binder.py,sha256=ET0BC-tCYVhlQK5-7KKwgRGcFFkzscPgY107TnFu7oQ,4361
344
345
  omlish/inject/bindings.py,sha256=PlvOnUREjvc6F8nOJdzl1k9SAf80icRB4qWFqDop87M,536
345
346
  omlish/inject/eagers.py,sha256=JBY7PcjXt-Rg9scQ1ol9xpcoTLXkXC_Ie9uwTWdzUkA,340
346
- omlish/inject/elements.py,sha256=y4luEO_-eOlVnLcUDiNGSyMXee4pusl46ZGr0JFhbcY,1405
347
+ omlish/inject/elements.py,sha256=I6_Jdqk265T7KegrChVTRnYrhXFE80tCr7nMxqV9xkE,1670
347
348
  omlish/inject/errors.py,sha256=_wkN2tF55gQzmMOMKJC_9jYHBZzaBiCDcyqI9Sf2UZs,626
348
349
  omlish/inject/injector.py,sha256=Lw8RLPdJYCHx2zYckttcZnAXBg_UYHe6KAeBilpz-SY,1177
349
- omlish/inject/inspect.py,sha256=Uq4KMloGWF_YS2mgZbrx-JXhZQnYHHKJSr68i9yoBVc,597
350
+ omlish/inject/inspect.py,sha256=d1IOpgPV1UCUm0uqLRa8PW-jGdfrhzaV1qLitANfCDY,1420
350
351
  omlish/inject/keys.py,sha256=7jnI2cw7cvLlzZAfe5SC50O3oPOpOB6iGZGTigyfQvs,682
351
352
  omlish/inject/listeners.py,sha256=bav7-uzfpajFAmH_snM0PW2oCfMavmhbE6R4-gjOmJ8,620
352
353
  omlish/inject/lite.py,sha256=AFOCj_SznDCPjkiVSKdFXL2hH1q2o4kaDnzkxRWDpsI,2615
@@ -354,19 +355,22 @@ omlish/inject/managed.py,sha256=jaZiiLqHHhL5aHtryou7M15QgHvZ8rSIHveG7ka9sAw,3087
354
355
  omlish/inject/maysync.py,sha256=I_gV1efDgqi-A-wJVHAmeswzIxAI0WW_U416E7LnSBs,491
355
356
  omlish/inject/multis.py,sha256=Dn63jE8P5ahSKc1IDBdzzx6ByBCgVOth5t4frG9m4UA,3336
356
357
  omlish/inject/origins.py,sha256=-qXa18rIIkNwBdTrvASRDjgPYnoY6n6OPC222jJDrXg,551
357
- omlish/inject/overrides.py,sha256=ybEcq9cDf6kvqu5mqnwi6Evj0MFjKNeE3r0oUlGw5E4,546
358
+ omlish/inject/overrides.py,sha256=3fMHSfX4Xym2NBHP5_vTZTq2Q47SfGhoC5WnTdYOLx0,550
358
359
  omlish/inject/privates.py,sha256=CyE-hvQ-F_uyCzcwfdiYVtfm9IF1WZvMDOYilFyZmWk,658
359
- omlish/inject/providers.py,sha256=Usvi0YgjS5jrAqQFhzeU2artxRSTM4zIoz72lac1PEA,931
360
+ omlish/inject/providers.py,sha256=OroBtCBvd0YqfdkLsQLGKmL3cbPngUWFfHqQYo4rYGo,1053
360
361
  omlish/inject/scopes.py,sha256=9atVF24QEn073kvoCw_4yLrkdIEzSAqqI0cSXAg4G1A,2722
361
362
  omlish/inject/sync.py,sha256=ovVoMY7X9hxe1xverBEec4la3j_041HKjNSlarGsfuA,1051
362
- omlish/inject/tags.py,sha256=gRDLa-WdZc9DC7KwwmoIPAi8g_qdGpRWuMT7HCd7CL0,433
363
363
  omlish/inject/types.py,sha256=Z-ZEdgtCpHBNrbxxKaMVvfeD7hYXdL4rC7A9_VGxZ6g,256
364
- omlish/inject/utils.py,sha256=Gc2qq45KgkyqDt03WSvOEZBCiuqQ6ESwplx5ZRBcY5M,413
364
+ omlish/inject/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
365
+ omlish/inject/helpers/constfn.py,sha256=Q7yfaGtxEb3L9izvwWSHh8udvR111qOtUYItw6OiyXo,416
366
+ omlish/inject/helpers/id.py,sha256=F1RYU03q4evteO6O3NDjwHZtPgd7MUK-qwsQAH1X-P0,435
367
+ omlish/inject/helpers/multis.py,sha256=NCLsD9XmjVv70OmJeYshIoMmCCV5mkUeb441U2YohXY,3765
368
+ omlish/inject/helpers/wrappers.py,sha256=RVHeoFjIBAhTEU6BWNic5PSTtYFLuMZUDKln6BeLTGs,1273
365
369
  omlish/inject/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
366
370
  omlish/inject/impl/bindings.py,sha256=xSvUcoDz8NH-aNHPwBPEZsFg73K2WcF_A63npVbGt_k,420
367
- omlish/inject/impl/elements.py,sha256=BZweNf8lbG_tO5X_A8-yM2ukIwtHHVMR6nsxai95EOA,5948
368
- omlish/inject/impl/injector.py,sha256=0e8Il9ObzWMDBJDLQk9RRBkK83mk-nIRlKU_LtmQfLI,8266
369
- omlish/inject/impl/inspect.py,sha256=HLhz5DfP9dwvbIYnwqsfR9ADjCoWs9q4Gh7J4BpImf4,3135
371
+ omlish/inject/impl/elements.py,sha256=qR06KaAjZMaQgdMBE6_tdrT7cWP1Ft0CFq71bnyp224,6265
372
+ omlish/inject/impl/injector.py,sha256=tcPyq_747L12G3CT_rA9KU4l_gWlesX0uCDv3GJOZGY,8366
373
+ omlish/inject/impl/inspect.py,sha256=UcCaQEhQfRINrY9Phz9UYKCuAg7HnZTqBJ2i-6j_O1A,3193
370
374
  omlish/inject/impl/maysync.py,sha256=7GWjrvJStOx85BCvk8IJAmmkoGkChFAAi2h7j2pe6Qs,1207
371
375
  omlish/inject/impl/multis.py,sha256=fa31UdkBYdAulfYdrkU1klDZicuQRyaBDbG28kaw8SI,2092
372
376
  omlish/inject/impl/origins.py,sha256=dgGdkoMN6I4DZrWjlpZYijeFsrF6Up1WPq_QSAgTtuQ,1676
@@ -410,10 +414,10 @@ omlish/iterators/recipes.py,sha256=wOwOZg-zWG9Zc3wcAxJFSe2rtavVBYwZOfG09qYEx_4,4
410
414
  omlish/iterators/tools.py,sha256=M16LXrJhMdsz5ea2qH0vws30ZvhQuQSCVFSLpRf_gTg,2096
411
415
  omlish/iterators/transforms.py,sha256=YHVdD9nBkS1k4kogi4Ba0UOTU_pKkuX9jGw1Tqj3UMw,3598
412
416
  omlish/iterators/unique.py,sha256=BSE-eanva8byFCJi09Nt2zzTsVr8LnTqY1PIInGYRs0,1396
413
- omlish/lang/__init__.py,sha256=cu35SEtPGFFKOrttPsD__wjnefZrue-upqpw01ml50c,10802
417
+ omlish/lang/__init__.py,sha256=qrxPnDUpWIuxUD37cBAOb910CvJ1yX0xWXEQSh5-crY,10851
414
418
  omlish/lang/asyncs.py,sha256=iIHJp7nvgJVj7zS0Ji7NsVSzz54vkzrj0Snc83dxe9g,1965
415
419
  omlish/lang/attrstorage.py,sha256=UUnoENCMQF3twBfxBcIKa5mpXsAxWnNYDayhU8xgmpU,5224
416
- omlish/lang/casing.py,sha256=3_c7cxQOc4z_YezaU2B4NCTAsPh_kDL4wUTK5kZU6kg,4675
420
+ omlish/lang/casing.py,sha256=dmk6gPwfr7Tqp3g2d8d_zZ8ir8TWvXHCEZYl-ECkJS0,4940
417
421
  omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
418
422
  omlish/lang/collections.py,sha256=kVMp1JJ6ycvKzuiOmf2ZF5Eg2mm3vJGPjkUcV_IACMk,2528
419
423
  omlish/lang/comparison.py,sha256=MOwEG0Yny-jBPHO9kQto9FSRyeNpQW24UABsghkrHxY,1356
@@ -432,7 +436,7 @@ omlish/lang/objects.py,sha256=JMOZU5I6sK4rJm04898dOJkvef-lDIh5O3k6tlLbBJw,4616
432
436
  omlish/lang/outcomes.py,sha256=rCyjWjElNheJ-sQhauxfERT98IZ0mrUoaSI9nMpJZTg,8751
433
437
  omlish/lang/overrides.py,sha256=IBzK6ljfLX6TLgIyKTSjhqTLcuKRkQNVtEOnBLS4nuA,2095
434
438
  omlish/lang/params.py,sha256=sfbNoGrKCsAtubFufj_uh_WKshIgA8fqJ4PmLH1PH00,6639
435
- omlish/lang/recursion.py,sha256=1VfSqzKO-8Is3t9LKw0W4jwPfE0aBS70EUlbUxAx4eE,1900
439
+ omlish/lang/recursion.py,sha256=tfCCe4poGcyV56Wj7j9NBjm7akp828mBZegJpm-i9SU,1899
436
440
  omlish/lang/resolving.py,sha256=nMosn-rcYjI8t6b35oICDyPw6t6-HvWj5jMdkfn1jfA,1612
437
441
  omlish/lang/resources.py,sha256=awfh33Uxkd9Ho-5Z3d9CPWQE3gjktV0XWM6XbdG0ejA,2845
438
442
  omlish/lang/sequences.py,sha256=OJ5hdgjvgzOgsb0Bg8vGrwPyef4gkRPp-Bz21sc9_iE,3185
@@ -492,7 +496,7 @@ omlish/lite/strings.py,sha256=rapGrc2BrIDstAEJov3pG_30PimOIR7IFVYioyTi-MM,1831
492
496
  omlish/lite/timeouts.py,sha256=OLU9iju2pkk3niM20aPnmA6AqabFmW8zeLDu6WsuaxA,5008
493
497
  omlish/lite/timing.py,sha256=KTlEa5PyT6BXf8AwGVWUNtoVgRx9zwSUrBQnkpygK78,262
494
498
  omlish/lite/types.py,sha256=QM9whf55r7TmmQBRApIWSlyVKsl1p_jcut_YheyZMFY,146
495
- omlish/lite/typing.py,sha256=m2CyJTz2OVOCPRvp-0UuEx7oleZgXqs3rYXijE0bTsA,1280
499
+ omlish/lite/typing.py,sha256=RZBto50cqbeZrLbFtSPMmxc0gR-dnRsH02Yx4t4xosQ,1580
496
500
  omlish/lite/wrappers.py,sha256=d00Ls2kFHuogKd5wEBaU65VNCN10YXIZtiwu1mbMpmA,530
497
501
  omlish/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
498
502
  omlish/logs/_amalg.py,sha256=XTfwEPyxNLHgDq3rEDa5WnotoyFIxvvcAKeqOFZxBY8,204
@@ -627,7 +631,7 @@ omlish/reflect/__init__.py,sha256=omD3VLFQtYTwPxrTH6gLATQIax9sTGGKc-7ps96-q0g,12
627
631
  omlish/reflect/inspect.py,sha256=dUrVz8VfAdLVFtFpW416DxzVC17D80cvFb_g2Odzgq8,1823
628
632
  omlish/reflect/ops.py,sha256=4mGvFMw5D6XGbhDhdCqZ1dZsiqezUTenDv63FIDohpY,3029
629
633
  omlish/reflect/subst.py,sha256=_lfNS2m2UiJgqARQtmGLTGo7CrSm9OMvVzt6GWOEX6M,4590
630
- omlish/reflect/types.py,sha256=4Plo_1cHIk8-68lu8_c_SUEohy19exTNDsgvuVbOJ5A,16066
634
+ omlish/reflect/types.py,sha256=iKLnOhOfbssFp7J4TNFif6as4SyNVFRYlCv7zLQH4iU,16159
631
635
  omlish/secrets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
632
636
  omlish/secrets/all.py,sha256=qBxUFIqxCExADL71taNH_W6FYT9QvOrdcaMeUUPO3aw,298
633
637
  omlish/secrets/crypto.py,sha256=q0Hca5oMwvh39r0hrupN_ewxhlllbdDgAgVoloYFmDg,3714
@@ -756,6 +760,7 @@ omlish/subprocesses/sync.py,sha256=A4ApwLVJZc8ztT5kYh8O_2i8fq5-7pKH9S3VVxqOCKA,3
756
760
  omlish/subprocesses/utils.py,sha256=v5uEzxmbmRvXwOl_0DtBa5Il6yITKYRgmVSGHcLsT4o,402
757
761
  omlish/subprocesses/wrap.py,sha256=AhGV8rsnaVUMQCFYKkrjj35fs3O-VJLZC1hZ14dz3C8,769
758
762
  omlish/term/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
763
+ omlish/term/alt.py,sha256=To7EfFnqssnMfbrkWzjT_iTGP73P1vbhrHXnCp8_uco,966
759
764
  omlish/term/codes.py,sha256=6_g4wwXP4z9koC9oEW3jSEuw27mQRf43ngD5RA-Qu2s,6390
760
765
  omlish/term/coloring.py,sha256=5lV7E2fyFDixAfm4tM5MFV9vreW5RM94AgUHB9hKaVE,2598
761
766
  omlish/term/confirm.py,sha256=0Qoo-MFBWw26khMMHv92tFXFHNB9GOubfdPLi48KkkY,1054
@@ -826,9 +831,9 @@ omlish/typedvalues/marshal.py,sha256=2xqX6JllhtGpmeYkU7C-qzgU__0x-vd6CzYbAsocQlc
826
831
  omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
827
832
  omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
828
833
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
829
- omlish-0.0.0.dev461.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
830
- omlish-0.0.0.dev461.dist-info/METADATA,sha256=77pvoCEFopTc7xv_Ej86VMdyzb88vIfaZA22GkYO16c,19003
831
- omlish-0.0.0.dev461.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
832
- omlish-0.0.0.dev461.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
833
- omlish-0.0.0.dev461.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
834
- omlish-0.0.0.dev461.dist-info/RECORD,,
834
+ omlish-0.0.0.dev463.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
835
+ omlish-0.0.0.dev463.dist-info/METADATA,sha256=v1wM59WlvF3Gl-GpHVYnNAGtRVKtswYzvt98awdix7w,19003
836
+ omlish-0.0.0.dev463.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
837
+ omlish-0.0.0.dev463.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
838
+ omlish-0.0.0.dev463.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
839
+ omlish-0.0.0.dev463.dist-info/RECORD,,