omlish 0.0.0.dev6__py3-none-any.whl → 0.0.0.dev8__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 +109 -5
- omlish/__init__.py +0 -8
- omlish/asyncs/__init__.py +0 -9
- omlish/asyncs/anyio.py +40 -0
- omlish/bootstrap.py +737 -0
- omlish/check.py +1 -1
- omlish/collections/__init__.py +4 -0
- omlish/collections/exceptions.py +2 -0
- omlish/collections/utils.py +38 -9
- omlish/configs/strings.py +2 -0
- omlish/dataclasses/__init__.py +7 -0
- omlish/dataclasses/impl/descriptors.py +95 -0
- omlish/dataclasses/impl/reflect.py +1 -1
- omlish/dataclasses/utils.py +23 -0
- omlish/{lang/datetimes.py → datetimes.py} +8 -4
- omlish/diag/procfs.py +1 -1
- omlish/diag/threads.py +131 -48
- omlish/docker.py +16 -1
- omlish/fnpairs.py +0 -4
- omlish/{serde → formats}/dotenv.py +3 -0
- omlish/{serde → formats}/yaml.py +2 -2
- omlish/graphs/trees.py +1 -1
- omlish/http/consts.py +6 -0
- omlish/http/sessions.py +2 -2
- omlish/inject/__init__.py +4 -0
- omlish/inject/binder.py +3 -3
- omlish/inject/elements.py +1 -1
- omlish/inject/impl/injector.py +57 -27
- omlish/inject/impl/origins.py +2 -0
- omlish/inject/origins.py +3 -0
- omlish/inject/utils.py +18 -0
- omlish/iterators.py +69 -2
- omlish/lang/__init__.py +16 -7
- omlish/lang/classes/restrict.py +10 -0
- omlish/lang/contextmanagers.py +1 -1
- omlish/lang/descriptors.py +3 -3
- omlish/lang/imports.py +67 -0
- omlish/lang/iterables.py +40 -0
- omlish/lang/maybes.py +3 -0
- omlish/lang/objects.py +38 -0
- omlish/lang/strings.py +25 -0
- omlish/lang/sys.py +9 -0
- omlish/lang/typing.py +37 -0
- omlish/lite/__init__.py +1 -0
- omlish/lite/cached.py +18 -0
- omlish/lite/check.py +29 -0
- omlish/lite/contextmanagers.py +18 -0
- omlish/lite/json.py +30 -0
- omlish/lite/logs.py +121 -0
- omlish/lite/marshal.py +318 -0
- omlish/lite/reflect.py +49 -0
- omlish/lite/runtime.py +18 -0
- omlish/lite/secrets.py +19 -0
- omlish/lite/strings.py +25 -0
- omlish/lite/subprocesses.py +112 -0
- omlish/logs/__init__.py +13 -9
- omlish/logs/configs.py +17 -22
- omlish/logs/formatters.py +3 -48
- omlish/marshal/__init__.py +28 -0
- omlish/marshal/any.py +5 -5
- omlish/marshal/base.py +27 -11
- omlish/marshal/base64.py +24 -9
- omlish/marshal/dataclasses.py +34 -28
- omlish/marshal/datetimes.py +74 -18
- omlish/marshal/enums.py +14 -8
- omlish/marshal/exceptions.py +11 -1
- omlish/marshal/factories.py +59 -74
- omlish/marshal/forbidden.py +35 -0
- omlish/marshal/global_.py +11 -4
- omlish/marshal/iterables.py +21 -24
- omlish/marshal/mappings.py +23 -26
- omlish/marshal/numbers.py +51 -0
- omlish/marshal/optionals.py +11 -12
- omlish/marshal/polymorphism.py +86 -21
- omlish/marshal/primitives.py +4 -5
- omlish/marshal/standard.py +13 -8
- omlish/marshal/uuids.py +4 -5
- omlish/matchfns.py +218 -0
- omlish/os.py +64 -0
- omlish/reflect/__init__.py +39 -0
- omlish/reflect/isinstance.py +38 -0
- omlish/reflect/ops.py +84 -0
- omlish/reflect/subst.py +110 -0
- omlish/reflect/types.py +275 -0
- omlish/secrets/__init__.py +18 -2
- omlish/secrets/crypto.py +132 -0
- omlish/secrets/marshal.py +36 -7
- omlish/secrets/openssl.py +207 -0
- omlish/secrets/secrets.py +260 -8
- omlish/secrets/subprocesses.py +42 -0
- omlish/sql/dbs.py +6 -5
- omlish/sql/exprs.py +12 -0
- omlish/sql/secrets.py +10 -0
- omlish/term.py +1 -1
- omlish/testing/pytest/plugins/switches.py +54 -19
- omlish/text/glyphsplit.py +5 -0
- omlish-0.0.0.dev8.dist-info/METADATA +50 -0
- {omlish-0.0.0.dev6.dist-info → omlish-0.0.0.dev8.dist-info}/RECORD +105 -78
- {omlish-0.0.0.dev6.dist-info → omlish-0.0.0.dev8.dist-info}/WHEEL +1 -1
- omlish/logs/filters.py +0 -11
- omlish/reflect.py +0 -470
- omlish-0.0.0.dev6.dist-info/METADATA +0 -34
- /omlish/{asyncs/futures.py → concurrent.py} +0 -0
- /omlish/{serde → formats}/__init__.py +0 -0
- /omlish/{serde → formats}/json.py +0 -0
- /omlish/{serde → formats}/props.py +0 -0
- {omlish-0.0.0.dev6.dist-info → omlish-0.0.0.dev8.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev6.dist-info → omlish-0.0.0.dev8.dist-info}/top_level.txt +0 -0
omlish/marshal/enums.py
CHANGED
|
@@ -22,10 +22,13 @@ class EnumMarshaler(Marshaler):
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class EnumMarshalerFactory(MarshalerFactory):
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
|
|
26
|
+
return isinstance(rty, type) and issubclass(rty, enum.Enum)
|
|
27
|
+
|
|
28
|
+
def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
29
|
+
ty = check.isinstance(rty, type)
|
|
30
|
+
check.state(issubclass(ty, enum.Enum))
|
|
31
|
+
return EnumMarshaler(ty)
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
@dc.dataclass(frozen=True)
|
|
@@ -37,7 +40,10 @@ class EnumUnmarshaler(Unmarshaler):
|
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
class EnumUnmarshalerFactory(UnmarshalerFactory):
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
|
|
44
|
+
return isinstance(rty, type) and issubclass(rty, enum.Enum)
|
|
45
|
+
|
|
46
|
+
def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
47
|
+
ty = check.isinstance(rty, type)
|
|
48
|
+
check.state(issubclass(ty, enum.Enum))
|
|
49
|
+
return EnumUnmarshaler(ty)
|
omlish/marshal/exceptions.py
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
from .. import reflect as rfl
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class MarshalError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UnhandledTypeError(MarshalError):
|
|
9
|
+
@property
|
|
10
|
+
def rty(self) -> rfl.Type:
|
|
11
|
+
return self.args[0]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ForbiddenTypeError(MarshalError):
|
|
5
15
|
@property
|
|
6
16
|
def rty(self) -> rfl.Type:
|
|
7
17
|
return self.args[0]
|
omlish/marshal/factories.py
CHANGED
|
@@ -1,86 +1,105 @@
|
|
|
1
|
-
import abc
|
|
2
1
|
import dataclasses as dc
|
|
3
|
-
import enum
|
|
4
2
|
import threading
|
|
5
3
|
import typing as ta
|
|
6
4
|
|
|
5
|
+
from .. import check
|
|
6
|
+
from .. import matchfns as mfs
|
|
7
7
|
from .. import reflect as rfl
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
R = ta.TypeVar('R')
|
|
11
11
|
C = ta.TypeVar('C')
|
|
12
|
-
A = ta.TypeVar('A')
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class Factory(abc.ABC, ta.Generic[R, C, A]):
|
|
19
|
-
@abc.abstractmethod
|
|
20
|
-
def __call__(self, ctx: C, arg: A) -> R | None:
|
|
21
|
-
raise NotImplementedError
|
|
22
12
|
|
|
23
13
|
|
|
24
14
|
##
|
|
25
15
|
|
|
26
16
|
|
|
27
17
|
@dc.dataclass(frozen=True)
|
|
28
|
-
class
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def __call__(self, ctx: C, arg: A) -> R | None:
|
|
32
|
-
return self.fn(ctx, arg)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
##
|
|
18
|
+
class TypeMapFactory(mfs.MatchFn[[C, rfl.Type], R]):
|
|
19
|
+
m: ta.Mapping[rfl.Type, R] = dc.field(default_factory=dict)
|
|
36
20
|
|
|
21
|
+
def __post_init__(self) -> None:
|
|
22
|
+
for k in self.m:
|
|
23
|
+
if not isinstance(k, rfl.TYPES):
|
|
24
|
+
raise TypeError(k)
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
def guard(self, ctx: C, rty: rfl.Type) -> bool:
|
|
27
|
+
check.isinstance(rty, rfl.TYPES)
|
|
28
|
+
return rty in self.m
|
|
41
29
|
|
|
42
|
-
def
|
|
43
|
-
|
|
30
|
+
def fn(self, ctx: C, rty: rfl.Type) -> R:
|
|
31
|
+
check.isinstance(rty, rfl.TYPES)
|
|
32
|
+
try:
|
|
33
|
+
return self.m[rty]
|
|
34
|
+
except KeyError:
|
|
35
|
+
raise mfs.MatchGuardError(ctx, rty) # noqa
|
|
44
36
|
|
|
45
37
|
|
|
46
38
|
##
|
|
47
39
|
|
|
48
40
|
|
|
49
|
-
class TypeCacheFactory(
|
|
50
|
-
def __init__(self, f:
|
|
41
|
+
class TypeCacheFactory(mfs.MatchFn[[C, rfl.Type], R]):
|
|
42
|
+
def __init__(self, f: mfs.MatchFn[[C, rfl.Type], R]) -> None:
|
|
51
43
|
super().__init__()
|
|
52
44
|
self._f = f
|
|
53
45
|
self._dct: dict[rfl.Type, R | None] = {}
|
|
54
46
|
self._mtx = threading.RLock()
|
|
55
47
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
return self._dct[rty]
|
|
59
|
-
except KeyError:
|
|
60
|
-
pass
|
|
48
|
+
def guard(self, ctx: C, rty: rfl.Type) -> bool:
|
|
49
|
+
check.isinstance(rty, rfl.TYPES)
|
|
61
50
|
with self._mtx:
|
|
62
51
|
try:
|
|
63
|
-
|
|
52
|
+
e = self._dct[rty]
|
|
64
53
|
except KeyError:
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
if self._f.guard(ctx, rty):
|
|
55
|
+
return True
|
|
56
|
+
else:
|
|
57
|
+
self._dct[rty] = None
|
|
58
|
+
return False
|
|
59
|
+
else:
|
|
60
|
+
return e is not None
|
|
61
|
+
|
|
62
|
+
def fn(self, ctx: C, rty: rfl.Type) -> R:
|
|
63
|
+
check.isinstance(rty, rfl.TYPES)
|
|
64
|
+
with self._mtx:
|
|
65
|
+
try:
|
|
66
|
+
e = self._dct[rty]
|
|
67
|
+
except KeyError:
|
|
68
|
+
try:
|
|
69
|
+
ret = self._f(ctx, rty)
|
|
70
|
+
except mfs.MatchGuardError:
|
|
71
|
+
self._dct[rty] = None
|
|
72
|
+
raise
|
|
73
|
+
else:
|
|
74
|
+
self._dct[rty] = ret
|
|
75
|
+
return ret
|
|
76
|
+
else:
|
|
77
|
+
if e is None:
|
|
78
|
+
raise mfs.MatchGuardError(ctx, rty)
|
|
79
|
+
else:
|
|
80
|
+
return e
|
|
67
81
|
|
|
68
82
|
|
|
69
83
|
##
|
|
70
84
|
|
|
71
85
|
|
|
72
|
-
class RecursiveTypeFactory(
|
|
86
|
+
class RecursiveTypeFactory(mfs.MatchFn[[C, rfl.Type], R]):
|
|
73
87
|
def __init__(
|
|
74
88
|
self,
|
|
75
|
-
f:
|
|
76
|
-
prx: ta.Callable[[], tuple[R
|
|
89
|
+
f: mfs.MatchFn[[C, rfl.Type], R],
|
|
90
|
+
prx: ta.Callable[[], tuple[R, ta.Callable[[R], None]]],
|
|
77
91
|
) -> None:
|
|
78
92
|
super().__init__()
|
|
79
93
|
self._f = f
|
|
80
94
|
self._prx = prx
|
|
81
|
-
self._dct: dict[rfl.Type, R
|
|
95
|
+
self._dct: dict[rfl.Type, R] = {}
|
|
96
|
+
|
|
97
|
+
def guard(self, ctx: C, rty: rfl.Type) -> bool:
|
|
98
|
+
check.isinstance(rty, rfl.TYPES)
|
|
99
|
+
return self._f.guard(ctx, rty)
|
|
82
100
|
|
|
83
|
-
def
|
|
101
|
+
def fn(self, ctx: C, rty: rfl.Type) -> R:
|
|
102
|
+
check.isinstance(rty, rfl.TYPES)
|
|
84
103
|
try:
|
|
85
104
|
return self._dct[rty]
|
|
86
105
|
except KeyError:
|
|
@@ -93,37 +112,3 @@ class RecursiveTypeFactory(Factory[R, C, rfl.Type]):
|
|
|
93
112
|
return r
|
|
94
113
|
finally:
|
|
95
114
|
del self._dct[rty]
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
##
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class CompositeFactory(Factory[R, C, A]):
|
|
102
|
-
class Strategy(enum.Enum):
|
|
103
|
-
FIRST = enum.auto()
|
|
104
|
-
ONE = enum.auto()
|
|
105
|
-
|
|
106
|
-
def __init__(self, *fs: Factory[R, C, A], strategy: Strategy = Strategy.FIRST) -> None:
|
|
107
|
-
super().__init__()
|
|
108
|
-
self._fs = fs
|
|
109
|
-
self._st = strategy
|
|
110
|
-
|
|
111
|
-
def __call__(self, ctx: C, arg: A) -> R | None:
|
|
112
|
-
w: list[R] = []
|
|
113
|
-
for c in self._fs:
|
|
114
|
-
if (r := c(ctx, arg)) is None:
|
|
115
|
-
continue
|
|
116
|
-
if self._st is CompositeFactory.Strategy.FIRST:
|
|
117
|
-
return r
|
|
118
|
-
w.append(r)
|
|
119
|
-
|
|
120
|
-
if not w:
|
|
121
|
-
return None
|
|
122
|
-
|
|
123
|
-
if self._st is CompositeFactory.Strategy.ONE:
|
|
124
|
-
if len(w) == 1:
|
|
125
|
-
return w[0]
|
|
126
|
-
|
|
127
|
-
raise TypeError(f'multiple implementations: {arg} {w}')
|
|
128
|
-
|
|
129
|
-
raise TypeError(f'unknown composite strategy: {self._st}')
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import matchfns as mfs
|
|
5
|
+
from .. import reflect as rfl
|
|
6
|
+
from .base import MarshalContext
|
|
7
|
+
from .base import Marshaler
|
|
8
|
+
from .base import UnmarshalContext
|
|
9
|
+
from .base import Unmarshaler
|
|
10
|
+
from .exceptions import ForbiddenTypeError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
C = ta.TypeVar('C')
|
|
14
|
+
R = ta.TypeVar('R')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
class ForbiddenTypeFactory(mfs.MatchFn[[C, rfl.Type], R]):
|
|
19
|
+
rtys: ta.AbstractSet[rfl.Type]
|
|
20
|
+
|
|
21
|
+
def guard(self, ctx: C, rty: rfl.Type) -> bool:
|
|
22
|
+
return rty in self.rtys
|
|
23
|
+
|
|
24
|
+
def fn(self, ctx: C, rty: rfl.Type) -> R:
|
|
25
|
+
raise ForbiddenTypeError(rty)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dc.dataclass(frozen=True)
|
|
29
|
+
class ForbiddenTypeMarshalerFactory(ForbiddenTypeFactory[MarshalContext, Marshaler]):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dc.dataclass(frozen=True)
|
|
34
|
+
class ForbiddenTypeUnmarshalerFactory(ForbiddenTypeFactory[UnmarshalContext, Unmarshaler]):
|
|
35
|
+
pass
|
omlish/marshal/global_.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
|
+
from .. import lang
|
|
3
4
|
from .base import MarshalContext
|
|
5
|
+
from .base import MarshalerFactory
|
|
4
6
|
from .base import UnmarshalContext
|
|
7
|
+
from .base import UnmarshalerFactory
|
|
5
8
|
from .registries import Registry
|
|
6
9
|
from .standard import new_standard_marshaler_factory
|
|
7
10
|
from .standard import new_standard_unmarshaler_factory
|
|
@@ -20,20 +23,24 @@ GLOBAL_REGISTRY = Registry()
|
|
|
20
23
|
##
|
|
21
24
|
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
@lang.cached_function(lock=True)
|
|
27
|
+
def global_marshaler_factory() -> MarshalerFactory:
|
|
28
|
+
return new_standard_marshaler_factory()
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
def marshal(obj: ta.Any, ty: type | None = None, **kwargs: ta.Any) -> Value:
|
|
27
|
-
mc = MarshalContext(GLOBAL_REGISTRY, factory=
|
|
32
|
+
mc = MarshalContext(GLOBAL_REGISTRY, factory=global_marshaler_factory(), **kwargs)
|
|
28
33
|
return mc.make(ty if ty is not None else type(obj)).marshal(mc, obj)
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
##
|
|
32
37
|
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
@lang.cached_function(lock=True)
|
|
40
|
+
def global_unmarshaler_factory() -> UnmarshalerFactory:
|
|
41
|
+
return new_standard_unmarshaler_factory()
|
|
35
42
|
|
|
36
43
|
|
|
37
44
|
def unmarshal(v: Value, ty: type[T], **kwargs: ta.Any) -> T:
|
|
38
|
-
uc = UnmarshalContext(GLOBAL_REGISTRY, factory=
|
|
45
|
+
uc = UnmarshalContext(GLOBAL_REGISTRY, factory=global_unmarshaler_factory(), **kwargs)
|
|
39
46
|
return uc.make(ty).unmarshal(uc, v)
|
omlish/marshal/iterables.py
CHANGED
|
@@ -4,13 +4,14 @@ import functools
|
|
|
4
4
|
import typing as ta
|
|
5
5
|
|
|
6
6
|
from .. import check
|
|
7
|
+
from .. import matchfns as mfs
|
|
7
8
|
from .. import reflect as rfl
|
|
8
9
|
from .base import MarshalContext
|
|
9
10
|
from .base import Marshaler
|
|
10
|
-
from .base import
|
|
11
|
+
from .base import MarshalerFactoryMatchClass
|
|
11
12
|
from .base import UnmarshalContext
|
|
12
13
|
from .base import Unmarshaler
|
|
13
|
-
from .base import
|
|
14
|
+
from .base import UnmarshalerFactoryMatchClass
|
|
14
15
|
from .values import Value
|
|
15
16
|
|
|
16
17
|
|
|
@@ -22,17 +23,15 @@ class IterableMarshaler(Marshaler):
|
|
|
22
23
|
return list(map(functools.partial(self.e.marshal, ctx), o))
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
class IterableMarshalerFactory(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return IterableMarshaler(e)
|
|
35
|
-
return None
|
|
26
|
+
class IterableMarshalerFactory(MarshalerFactoryMatchClass):
|
|
27
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
|
|
28
|
+
def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
29
|
+
gty = check.isinstance(rty, rfl.Generic)
|
|
30
|
+
return IterableMarshaler(ctx.make(check.single(gty.args)))
|
|
31
|
+
|
|
32
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
|
|
33
|
+
def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
34
|
+
return IterableMarshaler(ctx.make(ta.Any))
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
@dc.dataclass(frozen=True)
|
|
@@ -44,14 +43,12 @@ class IterableUnmarshaler(Unmarshaler):
|
|
|
44
43
|
return self.ctor(map(functools.partial(self.e.unmarshal, ctx), check.isinstance(v, collections.abc.Iterable)))
|
|
45
44
|
|
|
46
45
|
|
|
47
|
-
class IterableUnmarshalerFactory(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return IterableUnmarshaler(rty, e) # noqa
|
|
57
|
-
return None
|
|
46
|
+
class IterableUnmarshalerFactory(UnmarshalerFactoryMatchClass):
|
|
47
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
|
|
48
|
+
def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
49
|
+
gty = check.isinstance(rty, rfl.Generic)
|
|
50
|
+
return IterableUnmarshaler(gty.cls, ctx.make(check.single(gty.args)))
|
|
51
|
+
|
|
52
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
|
|
53
|
+
def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
54
|
+
return IterableUnmarshaler(check.isinstance(rty, type), ctx.make(ta.Any))
|
omlish/marshal/mappings.py
CHANGED
|
@@ -3,13 +3,14 @@ import dataclasses as dc
|
|
|
3
3
|
import typing as ta
|
|
4
4
|
|
|
5
5
|
from .. import check
|
|
6
|
+
from .. import matchfns as mfs
|
|
6
7
|
from .. import reflect as rfl
|
|
7
8
|
from .base import MarshalContext
|
|
8
9
|
from .base import Marshaler
|
|
9
|
-
from .base import
|
|
10
|
+
from .base import MarshalerFactoryMatchClass
|
|
10
11
|
from .base import UnmarshalContext
|
|
11
12
|
from .base import Unmarshaler
|
|
12
|
-
from .base import
|
|
13
|
+
from .base import UnmarshalerFactoryMatchClass
|
|
13
14
|
from .values import Value
|
|
14
15
|
|
|
15
16
|
|
|
@@ -25,18 +26,16 @@ class MappingMarshaler(Marshaler):
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
class MappingMarshalerFactory(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return MappingMarshaler(e, e)
|
|
39
|
-
return None
|
|
29
|
+
class MappingMarshalerFactory(MarshalerFactoryMatchClass):
|
|
30
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
|
|
31
|
+
def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
32
|
+
gty = check.isinstance(rty, rfl.Generic)
|
|
33
|
+
kt, vt = gty.args
|
|
34
|
+
return MappingMarshaler(ctx.make(kt), ctx.make(vt))
|
|
35
|
+
|
|
36
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
|
|
37
|
+
def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
38
|
+
return MappingMarshaler(a := ctx.make(ta.Any), a)
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
@dc.dataclass(frozen=True)
|
|
@@ -52,15 +51,13 @@ class MappingUnmarshaler(Unmarshaler):
|
|
|
52
51
|
return self.ctor(dct)
|
|
53
52
|
|
|
54
53
|
|
|
55
|
-
class MappingUnmarshalerFactory(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return MappingUnmarshaler(rty, e, e)
|
|
66
|
-
return None
|
|
54
|
+
class MappingUnmarshalerFactory(UnmarshalerFactoryMatchClass):
|
|
55
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
|
|
56
|
+
def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
57
|
+
gty = check.isinstance(rty, rfl.Generic)
|
|
58
|
+
kt, vt = gty.args
|
|
59
|
+
return MappingUnmarshaler(gty.cls, ctx.make(kt), ctx.make(vt))
|
|
60
|
+
|
|
61
|
+
@mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
|
|
62
|
+
def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
63
|
+
return MappingUnmarshaler(check.isinstance(rty, type), a := ctx.make(ta.Any), a)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import decimal
|
|
2
|
+
import fractions
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from .. import check
|
|
6
|
+
from .base import MarshalContext
|
|
7
|
+
from .base import Marshaler
|
|
8
|
+
from .base import TypeMapMarshalerFactory
|
|
9
|
+
from .base import TypeMapUnmarshalerFactory
|
|
10
|
+
from .base import UnmarshalContext
|
|
11
|
+
from .base import Unmarshaler
|
|
12
|
+
from .values import Value
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ComplexMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
16
|
+
def marshal(self, ctx: MarshalContext, o: complex) -> Value:
|
|
17
|
+
return [o.real, o.imag]
|
|
18
|
+
|
|
19
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
|
20
|
+
real, imag = check.isinstance(v, list)
|
|
21
|
+
return complex(real, imag) # type: ignore
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DecimalMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
25
|
+
def marshal(self, ctx: MarshalContext, o: decimal.Decimal) -> Value:
|
|
26
|
+
return str(o)
|
|
27
|
+
|
|
28
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
|
29
|
+
return decimal.Decimal(check.isinstance(v, str))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FractionMarshalerUnmarshaler(Marshaler, Unmarshaler):
|
|
33
|
+
def marshal(self, ctx: MarshalContext, o: fractions.Fraction) -> Value:
|
|
34
|
+
return [o.numerator, o.denominator]
|
|
35
|
+
|
|
36
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
|
37
|
+
num, denom = check.isinstance(v, list)
|
|
38
|
+
return fractions.Fraction(num, denom) # type: ignore
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
NUMBERS_MARSHALER_FACTORY = TypeMapMarshalerFactory({
|
|
42
|
+
complex: ComplexMarshalerUnmarshaler(),
|
|
43
|
+
decimal.Decimal: DecimalMarshalerUnmarshaler(),
|
|
44
|
+
fractions.Fraction: FractionMarshalerUnmarshaler(),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
NUMBERS_UNMARSHALER_FACTORY = TypeMapUnmarshalerFactory({
|
|
48
|
+
complex: ComplexMarshalerUnmarshaler(),
|
|
49
|
+
decimal.Decimal: DecimalMarshalerUnmarshaler(),
|
|
50
|
+
fractions.Fraction: FractionMarshalerUnmarshaler(),
|
|
51
|
+
})
|
omlish/marshal/optionals.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dataclasses as dc
|
|
2
2
|
import typing as ta
|
|
3
3
|
|
|
4
|
+
from .. import check
|
|
4
5
|
from .. import reflect as rfl
|
|
5
6
|
from .base import MarshalContext
|
|
6
7
|
from .base import Marshaler
|
|
@@ -22,12 +23,11 @@ class OptionalMarshaler(Marshaler):
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class OptionalMarshalerFactory(MarshalerFactory):
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return None
|
|
26
|
+
def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
|
|
27
|
+
return isinstance(rty, rfl.Union) and rty.is_optional
|
|
28
|
+
|
|
29
|
+
def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
|
30
|
+
return OptionalMarshaler(ctx.make(check.isinstance(rty, rfl.Union).without_none()))
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@dc.dataclass(frozen=True)
|
|
@@ -41,9 +41,8 @@ class OptionalUnmarshaler(Unmarshaler):
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class OptionalUnmarshalerFactory(UnmarshalerFactory):
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return None
|
|
44
|
+
def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
|
|
45
|
+
return isinstance(rty, rfl.Union) and rty.is_optional
|
|
46
|
+
|
|
47
|
+
def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
|
|
48
|
+
return OptionalUnmarshaler(ctx.make(check.isinstance(rty, rfl.Union).without_none()))
|