omlish 0.0.0.dev1__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +7 -0
- omlish/__init__.py +0 -0
- omlish/argparse.py +223 -0
- omlish/asyncs/__init__.py +17 -0
- omlish/asyncs/anyio.py +23 -0
- omlish/asyncs/asyncio.py +19 -0
- omlish/asyncs/asyncs.py +76 -0
- omlish/asyncs/futures.py +179 -0
- omlish/asyncs/trio.py +11 -0
- omlish/c3.py +173 -0
- omlish/cached.py +9 -0
- omlish/check.py +231 -0
- omlish/collections/__init__.py +63 -0
- omlish/collections/_abc.py +156 -0
- omlish/collections/_io_abc.py +78 -0
- omlish/collections/cache/__init__.py +11 -0
- omlish/collections/cache/descriptor.py +188 -0
- omlish/collections/cache/impl.py +485 -0
- omlish/collections/cache/types.py +37 -0
- omlish/collections/coerce.py +337 -0
- omlish/collections/frozen.py +148 -0
- omlish/collections/identity.py +106 -0
- omlish/collections/indexed.py +75 -0
- omlish/collections/mappings.py +127 -0
- omlish/collections/ordered.py +81 -0
- omlish/collections/persistent.py +36 -0
- omlish/collections/skiplist.py +193 -0
- omlish/collections/sorted.py +126 -0
- omlish/collections/treap.py +228 -0
- omlish/collections/treapmap.py +144 -0
- omlish/collections/unmodifiable.py +174 -0
- omlish/collections/utils.py +110 -0
- omlish/configs/__init__.py +0 -0
- omlish/configs/flattening.py +147 -0
- omlish/configs/props.py +64 -0
- omlish/dataclasses/__init__.py +83 -0
- omlish/dataclasses/impl/__init__.py +6 -0
- omlish/dataclasses/impl/api.py +260 -0
- omlish/dataclasses/impl/as_.py +76 -0
- omlish/dataclasses/impl/exceptions.py +2 -0
- omlish/dataclasses/impl/fields.py +148 -0
- omlish/dataclasses/impl/frozen.py +55 -0
- omlish/dataclasses/impl/hashing.py +85 -0
- omlish/dataclasses/impl/init.py +173 -0
- omlish/dataclasses/impl/internals.py +118 -0
- omlish/dataclasses/impl/main.py +150 -0
- omlish/dataclasses/impl/metaclass.py +126 -0
- omlish/dataclasses/impl/metadata.py +74 -0
- omlish/dataclasses/impl/order.py +47 -0
- omlish/dataclasses/impl/params.py +150 -0
- omlish/dataclasses/impl/processing.py +16 -0
- omlish/dataclasses/impl/reflect.py +173 -0
- omlish/dataclasses/impl/replace.py +40 -0
- omlish/dataclasses/impl/repr.py +34 -0
- omlish/dataclasses/impl/simple.py +92 -0
- omlish/dataclasses/impl/slots.py +80 -0
- omlish/dataclasses/impl/utils.py +167 -0
- omlish/defs.py +193 -0
- omlish/dispatch/__init__.py +3 -0
- omlish/dispatch/dispatch.py +137 -0
- omlish/dispatch/functions.py +52 -0
- omlish/dispatch/methods.py +162 -0
- omlish/docker.py +149 -0
- omlish/dynamic.py +220 -0
- omlish/graphs/__init__.py +0 -0
- omlish/graphs/dot/__init__.py +19 -0
- omlish/graphs/dot/items.py +162 -0
- omlish/graphs/dot/rendering.py +147 -0
- omlish/graphs/dot/utils.py +30 -0
- omlish/graphs/trees.py +249 -0
- omlish/http/__init__.py +0 -0
- omlish/http/consts.py +20 -0
- omlish/http/wsgi.py +34 -0
- omlish/inject/__init__.py +85 -0
- omlish/inject/binder.py +12 -0
- omlish/inject/bindings.py +49 -0
- omlish/inject/eagers.py +21 -0
- omlish/inject/elements.py +43 -0
- omlish/inject/exceptions.py +49 -0
- omlish/inject/impl/__init__.py +0 -0
- omlish/inject/impl/bindings.py +19 -0
- omlish/inject/impl/elements.py +154 -0
- omlish/inject/impl/injector.py +182 -0
- omlish/inject/impl/inspect.py +98 -0
- omlish/inject/impl/private.py +109 -0
- omlish/inject/impl/providers.py +132 -0
- omlish/inject/impl/scopes.py +198 -0
- omlish/inject/injector.py +40 -0
- omlish/inject/inspect.py +14 -0
- omlish/inject/keys.py +43 -0
- omlish/inject/managed.py +24 -0
- omlish/inject/overrides.py +18 -0
- omlish/inject/private.py +29 -0
- omlish/inject/providers.py +111 -0
- omlish/inject/proxy.py +48 -0
- omlish/inject/scopes.py +84 -0
- omlish/inject/types.py +21 -0
- omlish/iterators.py +184 -0
- omlish/json.py +194 -0
- omlish/lang/__init__.py +112 -0
- omlish/lang/cached.py +267 -0
- omlish/lang/classes/__init__.py +24 -0
- omlish/lang/classes/abstract.py +74 -0
- omlish/lang/classes/restrict.py +137 -0
- omlish/lang/classes/simple.py +120 -0
- omlish/lang/classes/test/__init__.py +0 -0
- omlish/lang/classes/test/test_abstract.py +89 -0
- omlish/lang/classes/test/test_restrict.py +71 -0
- omlish/lang/classes/test/test_simple.py +58 -0
- omlish/lang/classes/test/test_virtual.py +72 -0
- omlish/lang/classes/virtual.py +130 -0
- omlish/lang/clsdct.py +67 -0
- omlish/lang/cmp.py +63 -0
- omlish/lang/contextmanagers.py +249 -0
- omlish/lang/datetimes.py +67 -0
- omlish/lang/descriptors.py +52 -0
- omlish/lang/functions.py +126 -0
- omlish/lang/imports.py +153 -0
- omlish/lang/iterables.py +54 -0
- omlish/lang/maybes.py +136 -0
- omlish/lang/objects.py +103 -0
- omlish/lang/resolving.py +50 -0
- omlish/lang/strings.py +128 -0
- omlish/lang/typing.py +92 -0
- omlish/libc.py +532 -0
- omlish/logs/__init__.py +9 -0
- omlish/logs/_abc.py +247 -0
- omlish/logs/configs.py +62 -0
- omlish/logs/filters.py +9 -0
- omlish/logs/formatters.py +67 -0
- omlish/logs/utils.py +20 -0
- omlish/marshal/__init__.py +52 -0
- omlish/marshal/any.py +25 -0
- omlish/marshal/base.py +201 -0
- omlish/marshal/base64.py +25 -0
- omlish/marshal/dataclasses.py +115 -0
- omlish/marshal/datetimes.py +90 -0
- omlish/marshal/enums.py +43 -0
- omlish/marshal/exceptions.py +7 -0
- omlish/marshal/factories.py +129 -0
- omlish/marshal/global_.py +33 -0
- omlish/marshal/iterables.py +57 -0
- omlish/marshal/mappings.py +66 -0
- omlish/marshal/naming.py +17 -0
- omlish/marshal/objects.py +106 -0
- omlish/marshal/optionals.py +49 -0
- omlish/marshal/polymorphism.py +147 -0
- omlish/marshal/primitives.py +43 -0
- omlish/marshal/registries.py +57 -0
- omlish/marshal/standard.py +80 -0
- omlish/marshal/utils.py +23 -0
- omlish/marshal/uuids.py +29 -0
- omlish/marshal/values.py +30 -0
- omlish/math.py +184 -0
- omlish/os.py +32 -0
- omlish/reflect.py +359 -0
- omlish/replserver/__init__.py +5 -0
- omlish/replserver/__main__.py +4 -0
- omlish/replserver/console.py +247 -0
- omlish/replserver/server.py +146 -0
- omlish/runmodule.py +28 -0
- omlish/stats.py +342 -0
- omlish/term.py +222 -0
- omlish/testing/__init__.py +7 -0
- omlish/testing/pydevd.py +225 -0
- omlish/testing/pytest/__init__.py +8 -0
- omlish/testing/pytest/helpers.py +35 -0
- omlish/testing/pytest/inject/__init__.py +1 -0
- omlish/testing/pytest/inject/harness.py +159 -0
- omlish/testing/pytest/plugins/__init__.py +20 -0
- omlish/testing/pytest/plugins/_registry.py +6 -0
- omlish/testing/pytest/plugins/logging.py +13 -0
- omlish/testing/pytest/plugins/pycharm.py +54 -0
- omlish/testing/pytest/plugins/repeat.py +19 -0
- omlish/testing/pytest/plugins/skips.py +32 -0
- omlish/testing/pytest/plugins/spacing.py +19 -0
- omlish/testing/pytest/plugins/switches.py +70 -0
- omlish/testing/testing.py +102 -0
- omlish/text/__init__.py +0 -0
- omlish/text/delimit.py +171 -0
- omlish/text/indent.py +50 -0
- omlish/text/parts.py +265 -0
- omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
- omlish-0.0.0.dev1.dist-info/METADATA +17 -0
- omlish-0.0.0.dev1.dist-info/RECORD +187 -0
- omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
- omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
omlish/lang/resolving.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import string
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ResolvableClassNameError(NameError):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_cls_fqcn(cls: type, *, nocheck: bool = False) -> str:
|
|
11
|
+
if not isinstance(cls, type):
|
|
12
|
+
raise TypeError(cls)
|
|
13
|
+
mn = cls.__module__
|
|
14
|
+
if set(mn) - set(string.ascii_lowercase + string.digits + '_.'):
|
|
15
|
+
raise ResolvableClassNameError(cls)
|
|
16
|
+
qn = cls.__qualname__
|
|
17
|
+
if not all(qp[0].isupper() for qp in qn.split('.')) or (set(qn) - set(string.ascii_letters + string.digits + '.')):
|
|
18
|
+
raise ResolvableClassNameError(cls)
|
|
19
|
+
fqcn = '.'.join([cls.__module__, cls.__qualname__])
|
|
20
|
+
if not nocheck:
|
|
21
|
+
if get_fqcn_cls(fqcn, nocheck=True) is not cls:
|
|
22
|
+
raise ResolvableClassNameError(cls, fqcn)
|
|
23
|
+
return fqcn
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_fqcn_cls(fqcn: str, *, nocheck: bool = False) -> type:
|
|
27
|
+
if not isinstance(fqcn, str) or not fqcn:
|
|
28
|
+
raise TypeError(fqcn)
|
|
29
|
+
parts = fqcn.split('.')
|
|
30
|
+
pos = next(i for i, p in enumerate(parts) if p[0].isupper())
|
|
31
|
+
mps, qps = parts[:pos], parts[pos:]
|
|
32
|
+
mod = importlib.import_module('.'.join(mps))
|
|
33
|
+
o: ta.Any = mod
|
|
34
|
+
for qp in qps:
|
|
35
|
+
o = getattr(o, qp)
|
|
36
|
+
if not isinstance(o, type):
|
|
37
|
+
raise TypeError(o)
|
|
38
|
+
cls = o
|
|
39
|
+
if not isinstance(cls, type):
|
|
40
|
+
raise TypeError(cls)
|
|
41
|
+
if not nocheck:
|
|
42
|
+
if not get_cls_fqcn(cls, nocheck=True) == fqcn:
|
|
43
|
+
raise ResolvableClassNameError(cls, fqcn)
|
|
44
|
+
return o
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Resolvable:
|
|
48
|
+
def __init_subclass__(cls, **kwargs):
|
|
49
|
+
super().__init_subclass__(**kwargs)
|
|
50
|
+
get_cls_fqcn(cls, nocheck=True)
|
omlish/lang/strings.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
import unicodedata
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def prefix_lines(s: str, p: str) -> str:
|
|
9
|
+
return '\n'.join([p + l for l in s.split('\n')])
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def indent_lines(s: str, num: int) -> str:
|
|
13
|
+
return prefix_lines(s, ' ' * num)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def camel_case(name: str) -> str:
|
|
20
|
+
return ''.join(map(str.capitalize, name.split('_'))) # noqa
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def snake_case(name: str) -> str:
|
|
24
|
+
uppers: list[int | None] = [i for i, c in enumerate(name) if c.isupper()]
|
|
25
|
+
return '_'.join([name[l:r].lower() for l, r in zip([None] + uppers, uppers + [None])]).strip('_')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_dunder(name: str) -> bool:
|
|
29
|
+
return (
|
|
30
|
+
name[:2] == name[-2:] == '__' and
|
|
31
|
+
name[2:3] != '_' and
|
|
32
|
+
name[-3:-2] != '_' and
|
|
33
|
+
len(name) > 4
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def is_sunder(name: str) -> bool:
|
|
38
|
+
return (
|
|
39
|
+
name[0] == name[-1] == '_' and
|
|
40
|
+
name[1:2] != '_' and
|
|
41
|
+
name[-2:-1] != '_' and
|
|
42
|
+
len(name) > 2
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _CharSpec(ta.NamedTuple):
|
|
50
|
+
cats: ta.AbstractSet[str]
|
|
51
|
+
chars: ta.AbstractSet[str]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
_IDENT_START_CHAR_SPEC = _CharSpec(
|
|
55
|
+
{
|
|
56
|
+
'Ll',
|
|
57
|
+
'Lm',
|
|
58
|
+
'Lo',
|
|
59
|
+
'Lt',
|
|
60
|
+
'Lu',
|
|
61
|
+
'Nl',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
'_',
|
|
65
|
+
'\u2118',
|
|
66
|
+
'\u212E',
|
|
67
|
+
'\u309B',
|
|
68
|
+
'\u309C',
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
_IDENT_CONT_CHAR_SPEC = _CharSpec(
|
|
74
|
+
{
|
|
75
|
+
'Ll',
|
|
76
|
+
'Lm',
|
|
77
|
+
'Lo',
|
|
78
|
+
'Lt',
|
|
79
|
+
'Lu',
|
|
80
|
+
'Mc',
|
|
81
|
+
'Mn',
|
|
82
|
+
'Nd',
|
|
83
|
+
'Nl',
|
|
84
|
+
'Pc',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
'_',
|
|
88
|
+
'\u00B7',
|
|
89
|
+
'\u0387',
|
|
90
|
+
'\u1369',
|
|
91
|
+
'\u136A',
|
|
92
|
+
'\u136B',
|
|
93
|
+
'\u136C',
|
|
94
|
+
'\u136D',
|
|
95
|
+
'\u136E',
|
|
96
|
+
'\u136F',
|
|
97
|
+
'\u1370',
|
|
98
|
+
'\u1371',
|
|
99
|
+
'\u19DA',
|
|
100
|
+
'\u2118',
|
|
101
|
+
'\u212E',
|
|
102
|
+
'\u309B',
|
|
103
|
+
'\u309C',
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _is_char_in_spec(spec: _CharSpec, c: str) -> bool:
|
|
109
|
+
if len(c) != 1:
|
|
110
|
+
raise ValueError(c)
|
|
111
|
+
return (
|
|
112
|
+
unicodedata.category(c) in spec.cats or
|
|
113
|
+
c in spec.chars or
|
|
114
|
+
unicodedata.category(unicodedata.normalize('NFKC', c)) in spec.cats or
|
|
115
|
+
unicodedata.normalize('NFKC', c) in spec.chars
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def is_ident_start(c: str) -> bool:
|
|
120
|
+
return _is_char_in_spec(_IDENT_START_CHAR_SPEC, c)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def is_ident_cont(c: str) -> bool:
|
|
124
|
+
return _is_char_in_spec(_IDENT_CONT_CHAR_SPEC, c)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def is_ident(name: str) -> bool:
|
|
128
|
+
return is_ident_start(name[0]) and all(is_ident_cont(c) for c in name[1:])
|
omlish/lang/typing.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- typed_lambda is really kinda just 'annotate'
|
|
4
|
+
- TypedLambda / TypedPartial classes, picklable, reprs
|
|
5
|
+
- probably need to gen types per inst
|
|
6
|
+
"""
|
|
7
|
+
import functools
|
|
8
|
+
import inspect
|
|
9
|
+
import typing as ta
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Ty = ta.TypeVar('Ty', bound=type)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
BytesLike: ta.TypeAlias = ta.Union[bytes, bytearray]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def protocol_check(proto: type) -> ta.Callable[[Ty], Ty]:
|
|
22
|
+
def inner(cls):
|
|
23
|
+
if not issubclass(cls, proto):
|
|
24
|
+
raise TypeError(cls)
|
|
25
|
+
return cls
|
|
26
|
+
return inner
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_MISSING = object()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _update_wrapper_no_anns(wrapper, wrapped):
|
|
36
|
+
functools.update_wrapper(wrapper, wrapped, assigned=list(set(functools.WRAPPER_ASSIGNMENTS) - {'__annotations__'}))
|
|
37
|
+
return wrapper
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def typed_lambda(ret=_MISSING, **kw):
|
|
41
|
+
def inner(fn):
|
|
42
|
+
ns = {}
|
|
43
|
+
ns['__fn'] = fn
|
|
44
|
+
proto = ['def __lam(']
|
|
45
|
+
call = ['return __fn(']
|
|
46
|
+
pkw = {k: v for k, v in kw.items()}
|
|
47
|
+
for i, (n, t) in enumerate(pkw.items()):
|
|
48
|
+
if i:
|
|
49
|
+
call.append(', ')
|
|
50
|
+
else:
|
|
51
|
+
proto.append('*')
|
|
52
|
+
ns['__ann_' + n] = t
|
|
53
|
+
proto.append(f', {n}: __ann_{n}')
|
|
54
|
+
call.append(f'{n}={n}')
|
|
55
|
+
proto.append(')')
|
|
56
|
+
if ret is not _MISSING:
|
|
57
|
+
ns['__ann_return'] = ret
|
|
58
|
+
proto.append(f' -> __ann_return')
|
|
59
|
+
proto.append(':')
|
|
60
|
+
call.append(')')
|
|
61
|
+
src = f'{"".join(proto)} {"".join(call)}'
|
|
62
|
+
exec(src, ns)
|
|
63
|
+
lam = _update_wrapper_no_anns(ns['__lam'], fn)
|
|
64
|
+
lam.__signature__ = inspect.signature(lam, follow_wrapped=False)
|
|
65
|
+
return lam
|
|
66
|
+
for k in kw:
|
|
67
|
+
if k.startswith('__'):
|
|
68
|
+
raise NameError(k)
|
|
69
|
+
return inner
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def typed_partial(obj, **kw):
|
|
73
|
+
for k in kw:
|
|
74
|
+
if k.startswith('__'):
|
|
75
|
+
raise NameError(k)
|
|
76
|
+
sig = inspect.signature(obj)
|
|
77
|
+
inner = _update_wrapper_no_anns(lambda **lkw: obj(**lkw, **kw), obj)
|
|
78
|
+
ret = (
|
|
79
|
+
obj if isinstance(obj, type) else
|
|
80
|
+
sig.return_annotation if sig.return_annotation is not inspect.Signature.empty else
|
|
81
|
+
_MISSING
|
|
82
|
+
)
|
|
83
|
+
lam = typed_lambda(
|
|
84
|
+
ret,
|
|
85
|
+
**{
|
|
86
|
+
n: p.annotation
|
|
87
|
+
for n, p in sig.parameters.items()
|
|
88
|
+
if n not in kw
|
|
89
|
+
and p.annotation is not inspect.Signature.empty
|
|
90
|
+
}
|
|
91
|
+
)(inner)
|
|
92
|
+
return _update_wrapper_no_anns(lam, obj)
|