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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import reflect as rfl
|
|
5
|
+
from .base import MarshalContext
|
|
6
|
+
from .base import Marshaler
|
|
7
|
+
from .base import MarshalerFactory
|
|
8
|
+
from .base import UnmarshalContext
|
|
9
|
+
from .base import Unmarshaler
|
|
10
|
+
from .base import UnmarshalerFactory
|
|
11
|
+
from .values import Value
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dc.dataclass(frozen=True)
|
|
15
|
+
class OptionalMarshaler(Marshaler):
|
|
16
|
+
e: Marshaler
|
|
17
|
+
|
|
18
|
+
def marshal(self, ctx: MarshalContext, o: ta.Optional[ta.Any]) -> Value:
|
|
19
|
+
if o is None:
|
|
20
|
+
return None
|
|
21
|
+
return self.e.marshal(ctx, o)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OptionalMarshalerFactory(MarshalerFactory):
|
|
25
|
+
def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Optional[Marshaler]:
|
|
26
|
+
if isinstance(rty, rfl.Union) and rty.is_optional:
|
|
27
|
+
if (e := ctx.make(rty.without_none())) is None:
|
|
28
|
+
return None # type: ignore
|
|
29
|
+
return OptionalMarshaler(e)
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dc.dataclass(frozen=True)
|
|
34
|
+
class OptionalUnmarshaler(Unmarshaler):
|
|
35
|
+
e: Unmarshaler
|
|
36
|
+
|
|
37
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Optional[ta.Any]:
|
|
38
|
+
if v is None:
|
|
39
|
+
return None
|
|
40
|
+
return self.e.unmarshal(ctx, v)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class OptionalUnmarshalerFactory(UnmarshalerFactory):
|
|
44
|
+
def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Optional[Unmarshaler]:
|
|
45
|
+
if isinstance(rty, rfl.Union) and rty.is_optional:
|
|
46
|
+
if (e := ctx.make(rty.without_none())) is None:
|
|
47
|
+
return None # type: ignore
|
|
48
|
+
return OptionalUnmarshaler(e)
|
|
49
|
+
return None
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- auto-gen from __subclasses__ if abstract
|
|
4
|
+
- cfg: unless prefixed with _ or abstract
|
|
5
|
+
- auto-name
|
|
6
|
+
"""
|
|
7
|
+
import collections.abc
|
|
8
|
+
import dataclasses as dc
|
|
9
|
+
import typing as ta
|
|
10
|
+
|
|
11
|
+
from .. import check
|
|
12
|
+
from .. import lang
|
|
13
|
+
from .. import reflect as rfl
|
|
14
|
+
from .base import MarshalContext
|
|
15
|
+
from .base import Marshaler
|
|
16
|
+
from .base import MarshalerFactory
|
|
17
|
+
from .base import UnmarshalContext
|
|
18
|
+
from .base import Unmarshaler
|
|
19
|
+
from .base import UnmarshalerFactory
|
|
20
|
+
from .naming import Naming
|
|
21
|
+
from .naming import translate_name
|
|
22
|
+
from .values import Value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dc.dataclass(frozen=True)
|
|
29
|
+
class Impl:
|
|
30
|
+
ty: type
|
|
31
|
+
tag: str
|
|
32
|
+
alts: ta.AbstractSet[str] = frozenset()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Polymorphism:
|
|
36
|
+
def __init__(self, ty: type, impls: ta.Iterable[Impl]) -> None:
|
|
37
|
+
super().__init__()
|
|
38
|
+
self._ty = ty
|
|
39
|
+
self._impls = list(impls)
|
|
40
|
+
|
|
41
|
+
by_ty: dict[type, Impl] = {}
|
|
42
|
+
by_tag: dict[str, Impl] = {}
|
|
43
|
+
for i in self._impls:
|
|
44
|
+
if not issubclass(i.ty, ty) or i.ty in by_ty:
|
|
45
|
+
raise TypeError(i.ty, ty)
|
|
46
|
+
if i.tag in by_tag:
|
|
47
|
+
raise NameError(i.tag)
|
|
48
|
+
for a in i.alts:
|
|
49
|
+
if a in by_tag:
|
|
50
|
+
raise NameError(a)
|
|
51
|
+
by_ty[i.ty] = i
|
|
52
|
+
by_tag[i.tag] = i
|
|
53
|
+
for a in i.alts:
|
|
54
|
+
by_tag[a] = i
|
|
55
|
+
self._by_ty = by_ty
|
|
56
|
+
self._by_tag = by_tag
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def ty(self) -> type:
|
|
60
|
+
return self._ty
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def impls(self) -> ta.Sequence[Impl]:
|
|
64
|
+
return self._impls
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def by_ty(self) -> ta.Mapping[type, Impl]:
|
|
68
|
+
return self._by_ty
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def by_tag(self) -> ta.Mapping[str, Impl]:
|
|
72
|
+
return self._by_tag
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def polymorphism_from_subclasses(ty: type, *, naming: Naming | None = None) -> Polymorphism:
|
|
76
|
+
dct: dict[str, Impl] = {}
|
|
77
|
+
seen: set[type] = set()
|
|
78
|
+
todo: list[type] = [ty]
|
|
79
|
+
while todo:
|
|
80
|
+
cur = todo.pop()
|
|
81
|
+
seen.add(cur)
|
|
82
|
+
if not lang.is_abstract_class(cur):
|
|
83
|
+
nam = cur.__name__
|
|
84
|
+
if naming is not None:
|
|
85
|
+
nam = translate_name(nam, naming)
|
|
86
|
+
if nam in dct:
|
|
87
|
+
raise KeyError(f'Duplicate name: {nam}')
|
|
88
|
+
dct[nam] = Impl(
|
|
89
|
+
cur,
|
|
90
|
+
nam,
|
|
91
|
+
)
|
|
92
|
+
todo.extend(nxt for nxt in cur.__subclasses__() if nxt not in seen)
|
|
93
|
+
return Polymorphism(ty, dct.values())
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
##
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dc.dataclass(frozen=True)
|
|
100
|
+
class PolymorphismMarshaler(Marshaler):
|
|
101
|
+
m: ta.Mapping[type, tuple[str, Marshaler]]
|
|
102
|
+
|
|
103
|
+
def marshal(self, ctx: MarshalContext, o: ta.Optional[ta.Any]) -> Value:
|
|
104
|
+
tag, m = self.m[type(o)]
|
|
105
|
+
return {tag: m.marshal(ctx, o)}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dc.dataclass(frozen=True)
|
|
109
|
+
class PolymorphismMarshalerFactory(MarshalerFactory):
|
|
110
|
+
p: Polymorphism
|
|
111
|
+
|
|
112
|
+
def __call__(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Optional[Marshaler]:
|
|
113
|
+
if rty is self.p.ty:
|
|
114
|
+
return PolymorphismMarshaler({
|
|
115
|
+
i.ty: (i.tag, ctx.make(i.ty))
|
|
116
|
+
for i in self.p.impls
|
|
117
|
+
})
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
##
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dc.dataclass(frozen=True)
|
|
125
|
+
class PolymorphismUnmarshaler(Unmarshaler):
|
|
126
|
+
m: ta.Mapping[str, Unmarshaler]
|
|
127
|
+
|
|
128
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Optional[ta.Any]:
|
|
129
|
+
ma = check.isinstance(v, collections.abc.Mapping)
|
|
130
|
+
[(tag, iv)] = ma.items()
|
|
131
|
+
u = self.m[tag] # type: ignore
|
|
132
|
+
return u.unmarshal(ctx, iv) # type: ignore
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dc.dataclass(frozen=True)
|
|
136
|
+
class PolymorphismUnmarshalerFactory(UnmarshalerFactory):
|
|
137
|
+
p: Polymorphism
|
|
138
|
+
|
|
139
|
+
def __call__(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Optional[Unmarshaler]:
|
|
140
|
+
if rty is self.p.ty:
|
|
141
|
+
return PolymorphismUnmarshaler({
|
|
142
|
+
t: u
|
|
143
|
+
for i in self.p.impls
|
|
144
|
+
for u in [ctx.make(i.ty)]
|
|
145
|
+
for t in [i.tag, *i.alts]
|
|
146
|
+
})
|
|
147
|
+
return None
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .base import MarshalContext
|
|
4
|
+
from .base import Marshaler
|
|
5
|
+
from .base import MarshalerFactory
|
|
6
|
+
from .base import UnmarshalContext
|
|
7
|
+
from .base import Unmarshaler
|
|
8
|
+
from .base import UnmarshalerFactory
|
|
9
|
+
from .factories import TypeMapFactory
|
|
10
|
+
from .values import Value
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
PRIMITIVE_TYPES: tuple[type, ...] = (
|
|
14
|
+
bool,
|
|
15
|
+
int,
|
|
16
|
+
float,
|
|
17
|
+
str,
|
|
18
|
+
bytes,
|
|
19
|
+
type(None),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PrimitiveMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
24
|
+
def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
|
|
25
|
+
if isinstance(o, PRIMITIVE_TYPES):
|
|
26
|
+
return o # type: ignore
|
|
27
|
+
raise TypeError(o)
|
|
28
|
+
|
|
29
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
|
30
|
+
if isinstance(v, PRIMITIVE_TYPES):
|
|
31
|
+
return v
|
|
32
|
+
raise TypeError(v)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
PRIMITIVE_MARSHALER_UNMARSHALER = PrimitiveMarshalerUnmarshaler()
|
|
36
|
+
|
|
37
|
+
PRIMITIVE_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({ # noqa
|
|
38
|
+
t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
PRIMITIVE_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({ # noqa
|
|
42
|
+
t: PRIMITIVE_MARSHALER_UNMARSHALER for t in PRIMITIVE_TYPES
|
|
43
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import dataclasses as dc
|
|
3
|
+
import threading
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from .. import check
|
|
7
|
+
from .. import reflect as rfl
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RegistryItem(abc.ABC):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
RegistryItemT = ta.TypeVar('RegistryItemT', bound=RegistryItem)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
class _TypeRegistry:
|
|
19
|
+
rty: rfl.Type
|
|
20
|
+
items: list[RegistryItem] = dc.field(default_factory=list)
|
|
21
|
+
item_lists_by_ty: dict[type[RegistryItem], list[RegistryItem]] = dc.field(default_factory=dict)
|
|
22
|
+
|
|
23
|
+
def add(self, *items: RegistryItem) -> None:
|
|
24
|
+
for i in items:
|
|
25
|
+
self.items.append(i)
|
|
26
|
+
self.item_lists_by_ty.setdefault(type(i), []).append(i)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Registry:
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
super().__init__()
|
|
32
|
+
self._mtx = threading.Lock()
|
|
33
|
+
self._dct: dict[rfl.Type, _TypeRegistry] = {}
|
|
34
|
+
self._ps: ta.Sequence['Registry'] = []
|
|
35
|
+
|
|
36
|
+
def register(self, rty: rfl.Type, *items: RegistryItem) -> 'Registry':
|
|
37
|
+
check.isinstance(rty, rfl.TYPES)
|
|
38
|
+
with self._mtx:
|
|
39
|
+
if (sr := self._dct.get(rty)) is None:
|
|
40
|
+
sr = self._dct[rty] = _TypeRegistry(rty)
|
|
41
|
+
sr.add(*items)
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def get(self, rty: rfl.Type) -> ta.Sequence[RegistryItem]:
|
|
45
|
+
check.isinstance(rty, rfl.TYPES)
|
|
46
|
+
try:
|
|
47
|
+
return self._dct[rty].items
|
|
48
|
+
except KeyError:
|
|
49
|
+
return ()
|
|
50
|
+
|
|
51
|
+
def get_of(self, rty: rfl.Type, item_ty: type[RegistryItemT]) -> ta.Sequence[RegistryItemT]:
|
|
52
|
+
check.isinstance(rty, rfl.TYPES)
|
|
53
|
+
try:
|
|
54
|
+
sr = self._dct[rty]
|
|
55
|
+
except KeyError:
|
|
56
|
+
return ()
|
|
57
|
+
return sr.item_lists_by_ty.get(item_ty, ()) # type: ignore
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from .any import ANY_MARSHALER_FACTORY
|
|
2
|
+
from .any import ANY_UNMARSHALER_FACTORY
|
|
3
|
+
from .base import MarshalerFactory
|
|
4
|
+
from .base import RecursiveMarshalerFactory
|
|
5
|
+
from .base import RecursiveUnmarshalerFactory
|
|
6
|
+
from .base import UnmarshalerFactory
|
|
7
|
+
from .base64 import BASE64_MARSHALER_FACTORY
|
|
8
|
+
from .base64 import BASE64_UNMARSHALER_FACTORY
|
|
9
|
+
from .dataclasses import DataclassMarshalerFactory
|
|
10
|
+
from .dataclasses import DataclassUnmarshalerFactory
|
|
11
|
+
from .datetimes import DATETIME_MARSHALER_FACTORY
|
|
12
|
+
from .datetimes import DATETIME_UNMARSHALER_FACTORY
|
|
13
|
+
from .enums import EnumMarshalerFactory
|
|
14
|
+
from .enums import EnumUnmarshalerFactory
|
|
15
|
+
from .factories import CompositeFactory
|
|
16
|
+
from .factories import TypeCacheFactory
|
|
17
|
+
from .iterables import IterableMarshalerFactory
|
|
18
|
+
from .iterables import IterableUnmarshalerFactory
|
|
19
|
+
from .mappings import MappingMarshalerFactory
|
|
20
|
+
from .mappings import MappingUnmarshalerFactory
|
|
21
|
+
from .optionals import OptionalMarshalerFactory
|
|
22
|
+
from .optionals import OptionalUnmarshalerFactory
|
|
23
|
+
from .primitives import PRIMITIVE_MARSHALER_FACTORY
|
|
24
|
+
from .primitives import PRIMITIVE_UNMARSHALER_FACTORY
|
|
25
|
+
from .uuids import UUID_MARSHALER_FACTORY
|
|
26
|
+
from .uuids import UUID_UNMARSHALER_FACTORY
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
STANDARD_MARSHALER_FACTORIES: list[MarshalerFactory] = [
|
|
33
|
+
PRIMITIVE_MARSHALER_FACTORY,
|
|
34
|
+
OptionalMarshalerFactory(),
|
|
35
|
+
DataclassMarshalerFactory(),
|
|
36
|
+
EnumMarshalerFactory(),
|
|
37
|
+
UUID_MARSHALER_FACTORY,
|
|
38
|
+
BASE64_MARSHALER_FACTORY,
|
|
39
|
+
DATETIME_MARSHALER_FACTORY,
|
|
40
|
+
MappingMarshalerFactory(),
|
|
41
|
+
IterableMarshalerFactory(),
|
|
42
|
+
ANY_MARSHALER_FACTORY,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def new_standard_marshaler_factory() -> MarshalerFactory:
|
|
47
|
+
return TypeCacheFactory( # noqa
|
|
48
|
+
RecursiveMarshalerFactory(
|
|
49
|
+
CompositeFactory(
|
|
50
|
+
*STANDARD_MARSHALER_FACTORIES
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
STANDARD_UNMARSHALER_FACTORIES: list[UnmarshalerFactory] = [
|
|
60
|
+
PRIMITIVE_UNMARSHALER_FACTORY,
|
|
61
|
+
OptionalUnmarshalerFactory(),
|
|
62
|
+
DataclassUnmarshalerFactory(),
|
|
63
|
+
EnumUnmarshalerFactory(),
|
|
64
|
+
UUID_UNMARSHALER_FACTORY,
|
|
65
|
+
BASE64_UNMARSHALER_FACTORY,
|
|
66
|
+
DATETIME_UNMARSHALER_FACTORY,
|
|
67
|
+
MappingUnmarshalerFactory(),
|
|
68
|
+
IterableUnmarshalerFactory(),
|
|
69
|
+
ANY_UNMARSHALER_FACTORY,
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def new_standard_unmarshaler_factory() -> UnmarshalerFactory:
|
|
74
|
+
return TypeCacheFactory( # noqa
|
|
75
|
+
RecursiveUnmarshalerFactory(
|
|
76
|
+
CompositeFactory(
|
|
77
|
+
*STANDARD_UNMARSHALER_FACTORIES
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
)
|
omlish/marshal/utils.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
T = ta.TypeVar('T')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class _Proxy(ta.Generic[T]):
|
|
8
|
+
__obj: ta.Optional[T] = None
|
|
9
|
+
|
|
10
|
+
@property
|
|
11
|
+
def _obj(self) -> T:
|
|
12
|
+
if self.__obj is None:
|
|
13
|
+
raise TypeError('recursive proxy not set')
|
|
14
|
+
return self.__obj
|
|
15
|
+
|
|
16
|
+
def _set_obj(self, obj: T) -> None:
|
|
17
|
+
if self.__obj is not None:
|
|
18
|
+
raise TypeError('recursive proxy already set')
|
|
19
|
+
self.__obj = obj
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def _new(cls):
|
|
23
|
+
return (p := cls()), p._set_obj
|
omlish/marshal/uuids.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
from .. import check
|
|
5
|
+
from .base import MarshalContext
|
|
6
|
+
from .base import Marshaler
|
|
7
|
+
from .base import MarshalerFactory
|
|
8
|
+
from .base import UnmarshalContext
|
|
9
|
+
from .base import Unmarshaler
|
|
10
|
+
from .base import UnmarshalerFactory
|
|
11
|
+
from .factories import TypeMapFactory
|
|
12
|
+
from .values import Value
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PATTERN = re.compile(r'([0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12})|([0-9A-Fa-f]{32})')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UuidMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
19
|
+
def marshal(self, ctx: MarshalContext, o: uuid.UUID) -> Value:
|
|
20
|
+
return str(o)
|
|
21
|
+
|
|
22
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> uuid.UUID:
|
|
23
|
+
return uuid.UUID(check.isinstance(v, str).replace('-', ''))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
UUID_MARSHALER_UNMARSHALER = UuidMarshalerUnmarshaler()
|
|
27
|
+
|
|
28
|
+
UUID_MARSHALER_FACTORY: MarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
|
|
29
|
+
UUID_UNMARSHALER_FACTORY: UnmarshalerFactory = TypeMapFactory({uuid.UUID: UUID_MARSHALER_UNMARSHALER})
|
omlish/marshal/values.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Null
|
|
3
|
+
Bool
|
|
4
|
+
Int
|
|
5
|
+
Float
|
|
6
|
+
Number
|
|
7
|
+
String
|
|
8
|
+
Bytes
|
|
9
|
+
Array
|
|
10
|
+
Object
|
|
11
|
+
Any
|
|
12
|
+
"""
|
|
13
|
+
import typing as ta
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Value = ta.Union[
|
|
17
|
+
None,
|
|
18
|
+
|
|
19
|
+
bool,
|
|
20
|
+
int,
|
|
21
|
+
float,
|
|
22
|
+
# Number,
|
|
23
|
+
str,
|
|
24
|
+
bytes,
|
|
25
|
+
|
|
26
|
+
list, # list[Value],
|
|
27
|
+
dict, # dict[str, Value],
|
|
28
|
+
|
|
29
|
+
# ta.Any,
|
|
30
|
+
]
|
omlish/math.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import struct
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def isclose(a: float, b: float, *, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> float:
|
|
10
|
+
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_bit(bit: int, value: int) -> int:
|
|
14
|
+
return (value >> bit) & 1
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_bits(bits_from: int, num_bits: int, value: int) -> int:
|
|
18
|
+
return (value & ((1 << (bits_from + num_bits)) - 1)) >> bits_from
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_bit(bit: int, bit_value: int, value: int) -> int:
|
|
22
|
+
if bit_value:
|
|
23
|
+
return value | (1 << bit)
|
|
24
|
+
else:
|
|
25
|
+
return value & ~(1 << bit)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def set_bits(bits_from: int, num_bits: int, bits_value: int, value: int) -> int:
|
|
29
|
+
return value & ~(((1 << num_bits) - 1) << bits_from) | (bits_value << bits_from)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def float_to_bytes(f: float) -> bytes:
|
|
33
|
+
return struct.pack('>f', f)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def bytes_to_float(b: bytes) -> float:
|
|
37
|
+
return struct.unpack('>f', b)[0]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _gen_scalar_proxy_method(name):
|
|
44
|
+
def inner(self, *args, **kwargs):
|
|
45
|
+
return self.__class__(orig(self, *args, **kwargs))
|
|
46
|
+
|
|
47
|
+
orig = getattr(int, name)
|
|
48
|
+
return functools.wraps(orig)(inner)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _gen_tuple_proxy_method(name):
|
|
52
|
+
def inner(self, *args, **kwargs):
|
|
53
|
+
return tuple(map(self.__class__, orig(self, *args, **kwargs)))
|
|
54
|
+
|
|
55
|
+
orig = getattr(int, name)
|
|
56
|
+
return functools.wraps(orig)(inner)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class FixedWidthInt(int):
|
|
60
|
+
|
|
61
|
+
BITS: ta.ClassVar[int]
|
|
62
|
+
SIGNED: ta.ClassVar[bool]
|
|
63
|
+
|
|
64
|
+
MIN: ta.ClassVar[int]
|
|
65
|
+
MAX: ta.ClassVar[int]
|
|
66
|
+
|
|
67
|
+
MASK: ta.ClassVar[int]
|
|
68
|
+
|
|
69
|
+
def __init_subclass__(cls, **kwargs):
|
|
70
|
+
super().__init_subclass__()
|
|
71
|
+
|
|
72
|
+
if not isinstance(cls.BITS, int):
|
|
73
|
+
raise TypeError(cls.BITS)
|
|
74
|
+
|
|
75
|
+
if cls.SIGNED:
|
|
76
|
+
cls.MIN = -(1 << (cls.BITS - 1))
|
|
77
|
+
cls.MAX = (1 << (cls.BITS - 1)) - 1
|
|
78
|
+
else:
|
|
79
|
+
cls.MIN = 0
|
|
80
|
+
cls.MAX = (1 << cls.BITS) - 1
|
|
81
|
+
|
|
82
|
+
cls.MASK = (1 << cls.BITS) - 1
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def clamp(cls, value):
|
|
86
|
+
return ((value - cls.MIN) & cls.MASK) + cls.MIN
|
|
87
|
+
|
|
88
|
+
def __new__(cls, value, *args, **kwargs):
|
|
89
|
+
return super().__new__(cls, cls.clamp(value))
|
|
90
|
+
|
|
91
|
+
SCALAR_PROXY_METHODS = {
|
|
92
|
+
'__abs__',
|
|
93
|
+
'__add__',
|
|
94
|
+
'__and__',
|
|
95
|
+
'__floordiv__',
|
|
96
|
+
'__invert__',
|
|
97
|
+
'__lshift__',
|
|
98
|
+
'__mod__',
|
|
99
|
+
'__mul__',
|
|
100
|
+
'__neg__',
|
|
101
|
+
'__or__',
|
|
102
|
+
'__pos__',
|
|
103
|
+
'__pow__',
|
|
104
|
+
'__radd__',
|
|
105
|
+
'__rand__',
|
|
106
|
+
'__rfloordiv__',
|
|
107
|
+
'__rlshift__',
|
|
108
|
+
'__rmod__',
|
|
109
|
+
'__rmul__',
|
|
110
|
+
'__ror__',
|
|
111
|
+
'__rpow__',
|
|
112
|
+
'__rrshift__',
|
|
113
|
+
'__rshift__',
|
|
114
|
+
'__rsub__',
|
|
115
|
+
'__rtruediv__',
|
|
116
|
+
'__rxor__',
|
|
117
|
+
'__sub__',
|
|
118
|
+
'__truediv__',
|
|
119
|
+
'__xor__',
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
TUPLE_PROXY_METHODS = {
|
|
123
|
+
'__divmod__',
|
|
124
|
+
'__rdivmod__',
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for _proxy_name in SCALAR_PROXY_METHODS:
|
|
128
|
+
locals()[_proxy_name] = _gen_scalar_proxy_method(_proxy_name)
|
|
129
|
+
for _proxy_name in TUPLE_PROXY_METHODS:
|
|
130
|
+
locals()[_proxy_name] = _gen_tuple_proxy_method(_proxy_name)
|
|
131
|
+
del _proxy_name
|
|
132
|
+
|
|
133
|
+
def __repr__(self):
|
|
134
|
+
return f'{self.__class__.__name__}({int(self)})'
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Int8(FixedWidthInt):
|
|
138
|
+
BITS = 8
|
|
139
|
+
SIGNED = True
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class Int16(FixedWidthInt):
|
|
143
|
+
BITS = 16
|
|
144
|
+
SIGNED = True
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class Int32(FixedWidthInt):
|
|
148
|
+
BITS = 32
|
|
149
|
+
SIGNED = True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class Int64(FixedWidthInt):
|
|
153
|
+
BITS = 64
|
|
154
|
+
SIGNED = True
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class Int128(FixedWidthInt):
|
|
158
|
+
BITS = 128
|
|
159
|
+
SIGNED = True
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class Uint8(FixedWidthInt):
|
|
163
|
+
BITS = 8
|
|
164
|
+
SIGNED = False
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class Uint16(FixedWidthInt):
|
|
168
|
+
BITS = 16
|
|
169
|
+
SIGNED = False
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class Uint32(FixedWidthInt):
|
|
173
|
+
BITS = 32
|
|
174
|
+
SIGNED = False
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class Uint64(FixedWidthInt):
|
|
178
|
+
BITS = 64
|
|
179
|
+
SIGNED = False
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class Uint128(FixedWidthInt):
|
|
183
|
+
BITS = 128
|
|
184
|
+
SIGNED = False
|
omlish/os.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import shutil
|
|
3
|
+
import tempfile
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@contextlib.contextmanager
|
|
8
|
+
def tmp_dir(
|
|
9
|
+
root_dir: ta.Optional[str] = None,
|
|
10
|
+
cleanup: bool = True,
|
|
11
|
+
**kwargs: ta.Any
|
|
12
|
+
) -> ta.Iterator[str]:
|
|
13
|
+
path = tempfile.mkdtemp(dir=root_dir, **kwargs)
|
|
14
|
+
try:
|
|
15
|
+
yield path
|
|
16
|
+
finally:
|
|
17
|
+
if cleanup:
|
|
18
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@contextlib.contextmanager
|
|
22
|
+
def tmp_file(
|
|
23
|
+
root_dir: ta.Optional[str] = None,
|
|
24
|
+
cleanup: bool = True,
|
|
25
|
+
**kwargs: ta.Any
|
|
26
|
+
) -> ta.Iterator[tempfile._TemporaryFileWrapper]: # noqa
|
|
27
|
+
with tempfile.NamedTemporaryFile(dir=root_dir, delete=False, **kwargs) as f:
|
|
28
|
+
try:
|
|
29
|
+
yield f
|
|
30
|
+
finally:
|
|
31
|
+
if cleanup:
|
|
32
|
+
shutil.rmtree(f.name, ignore_errors=True)
|