omlish 0.0.0.dev453__py3-none-any.whl → 0.0.0.dev455__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 +2 -2
- omlish/collections/identity.py +1 -0
- omlish/dataclasses/__init__.py +2 -0
- omlish/funcs/guard.py +27 -16
- omlish/lang/__init__.py +1 -0
- omlish/lang/functions.py +2 -2
- omlish/lang/iterables.py +8 -0
- omlish/lite/attrops.py +2 -0
- omlish/lite/dataclasses.py +30 -0
- omlish/marshal/__init__.py +16 -11
- omlish/marshal/base/contexts.py +33 -20
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/types.py +38 -14
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +16 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +15 -56
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +20 -77
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/unions.py +17 -11
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +8 -8
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/os/forkhooks.py +4 -0
- omlish/specs/jsonrpc/_marshal.py +33 -24
- omlish/specs/openapi/_marshal.py +30 -21
- omlish/typedvalues/marshal.py +83 -57
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/RECORD +52 -52
- omlish/funcs/match.py +0 -229
- omlish/marshal/composite/unions.py +0 -213
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/collections/identity.py
CHANGED
omlish/dataclasses/__init__.py
CHANGED
omlish/funcs/guard.py
CHANGED
@@ -18,7 +18,7 @@ P = ta.ParamSpec('P')
|
|
18
18
|
|
19
19
|
|
20
20
|
class GuardFn(ta.Protocol[P, T_co]):
|
21
|
-
def __get__(self, instance, owner=None)
|
21
|
+
def __get__(self, instance, owner=None): ...
|
22
22
|
|
23
23
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T_co] | None: ...
|
24
24
|
|
@@ -53,12 +53,19 @@ class MultiGuardFn(ta.Generic[P, T]):
|
|
53
53
|
def __init__(
|
54
54
|
self,
|
55
55
|
*children: GuardFn[P, T],
|
56
|
+
default: GuardFn[P, T] | None = None,
|
56
57
|
strict: bool = False,
|
57
58
|
) -> None:
|
58
|
-
self._children, self._strict = children, strict
|
59
|
+
self._children, self._default, self._strict = children, default, strict
|
60
|
+
|
61
|
+
lang.attr_ops(lambda self: (
|
62
|
+
self._children,
|
63
|
+
self._default,
|
64
|
+
self._strict,
|
65
|
+
)).install(locals())
|
59
66
|
|
60
67
|
def __get__(self, instance, owner=None):
|
61
|
-
return MultiGuardFn(*map(operator.methodcaller('__get__', instance, owner), self._children), strict=self._strict) # noqa
|
68
|
+
return MultiGuardFn(*map(operator.methodcaller('__get__', instance, owner), self._children), default=self._default.__get__(instance, owner) if self._default is not None else None, strict=self._strict) # noqa
|
62
69
|
|
63
70
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ta.Callable[[], T] | None:
|
64
71
|
matches = []
|
@@ -68,7 +75,10 @@ class MultiGuardFn(ta.Generic[P, T]):
|
|
68
75
|
return m
|
69
76
|
matches.append(m)
|
70
77
|
if not matches:
|
71
|
-
|
78
|
+
if (dfl := self._default) is not None:
|
79
|
+
return dfl(*args, **kwargs)
|
80
|
+
else:
|
81
|
+
return None
|
72
82
|
elif len(matches) > 1:
|
73
83
|
raise AmbiguousGuardFnError
|
74
84
|
else:
|
@@ -88,13 +98,13 @@ class _BaseGuardFnMethod(lang.Abstract, ta.Generic[P, T]):
|
|
88
98
|
strict: bool = False,
|
89
99
|
requires_override: bool = False,
|
90
100
|
instance_cache: bool = False,
|
91
|
-
|
101
|
+
default: GuardFn[P, T] | None = None,
|
92
102
|
) -> None:
|
93
103
|
super().__init__()
|
94
104
|
|
95
105
|
self._strict = strict
|
96
106
|
self._instance_cache = instance_cache
|
97
|
-
self.
|
107
|
+
self._default = default
|
98
108
|
|
99
109
|
self._registry: col.AttrRegistry[ta.Callable, None] = col.AttrRegistry(
|
100
110
|
requires_override=requires_override,
|
@@ -122,6 +132,7 @@ class _BaseGuardFnMethod(lang.Abstract, ta.Generic[P, T]):
|
|
122
132
|
def _prepare(self, instance_cls: type, collected: ta.Mapping[str, tuple[ta.Callable, None]]) -> MultiGuardFn:
|
123
133
|
return MultiGuardFn(
|
124
134
|
*[getattr(instance_cls, a) for a in collected],
|
135
|
+
default=self._default,
|
125
136
|
strict=self._strict,
|
126
137
|
)
|
127
138
|
|
@@ -153,6 +164,7 @@ class _BaseGuardFnMethod(lang.Abstract, ta.Generic[P, T]):
|
|
153
164
|
#
|
154
165
|
|
155
166
|
|
167
|
+
@ta.final
|
156
168
|
class GuardFnMethod(_BaseGuardFnMethod[P, T]):
|
157
169
|
def _bind(self, instance, owner):
|
158
170
|
return self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
@@ -166,13 +178,14 @@ def method(
|
|
166
178
|
strict: bool = False,
|
167
179
|
requires_override: bool = False,
|
168
180
|
instance_cache: bool = False,
|
181
|
+
default: bool = False,
|
169
182
|
) -> ta.Callable[[ta.Callable[P, T]], GuardFnMethod[P, T]]: # noqa
|
170
183
|
def inner(fn):
|
171
184
|
return GuardFnMethod(
|
172
185
|
strict=strict,
|
173
186
|
requires_override=requires_override,
|
174
187
|
instance_cache=instance_cache,
|
175
|
-
|
188
|
+
default=fn if default else None,
|
176
189
|
)
|
177
190
|
|
178
191
|
return inner
|
@@ -181,15 +194,13 @@ def method(
|
|
181
194
|
#
|
182
195
|
|
183
196
|
|
184
|
-
|
197
|
+
@ta.final
|
198
|
+
class ImmediateGuardFnMethod(_BaseGuardFnMethod[P, T]):
|
185
199
|
def _bind(self, instance, owner):
|
186
200
|
gf = self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
187
|
-
x = self._prototype.__get__(instance, owner) # type: ignore
|
188
201
|
|
189
202
|
def inner(*args, **kwargs):
|
190
|
-
|
191
|
-
return m()
|
192
|
-
return x(*args, **kwargs)
|
203
|
+
return gf(*args, **kwargs)() # Note: cannot be None due to non-optional default
|
193
204
|
|
194
205
|
return inner
|
195
206
|
|
@@ -197,18 +208,18 @@ class DumbGuardFnMethod(_BaseGuardFnMethod[P, T]):
|
|
197
208
|
return self._call(*args, **kwargs)
|
198
209
|
|
199
210
|
|
200
|
-
def
|
211
|
+
def immediate_method(
|
201
212
|
*,
|
202
213
|
strict: bool = False,
|
203
214
|
requires_override: bool = False,
|
204
215
|
instance_cache: bool = False,
|
205
|
-
) -> ta.Callable[[ta.Callable[P, T]],
|
216
|
+
) -> ta.Callable[[ta.Callable[P, T]], ImmediateGuardFnMethod[P, T]]: # noqa
|
206
217
|
def inner(fn):
|
207
|
-
return
|
218
|
+
return ImmediateGuardFnMethod(
|
208
219
|
strict=strict,
|
209
220
|
requires_override=requires_override,
|
210
221
|
instance_cache=instance_cache,
|
211
|
-
|
222
|
+
default=(lambda *args, **kwargs: lambda: fn(*args, **kwargs)),
|
212
223
|
)
|
213
224
|
|
214
225
|
return inner
|
omlish/lang/__init__.py
CHANGED
omlish/lang/functions.py
CHANGED
@@ -59,11 +59,11 @@ def recurse(fn: ta.Callable[..., T], *args, **kwargs) -> T:
|
|
59
59
|
##
|
60
60
|
|
61
61
|
|
62
|
-
def raise_(o: BaseException) -> ta.NoReturn:
|
62
|
+
def raise_(o: BaseException | type[BaseException]) -> ta.NoReturn:
|
63
63
|
raise o
|
64
64
|
|
65
65
|
|
66
|
-
def raising(o: BaseException) -> ta.Callable[..., ta.NoReturn]:
|
66
|
+
def raising(o: BaseException | type[BaseException]) -> ta.Callable[..., ta.NoReturn]:
|
67
67
|
def inner(*args, **kwargs):
|
68
68
|
raise o
|
69
69
|
|
omlish/lang/iterables.py
CHANGED
@@ -26,6 +26,14 @@ def consume(it: ta.Iterable[ta.Any]) -> None:
|
|
26
26
|
collections.deque(it, maxlen=0)
|
27
27
|
|
28
28
|
|
29
|
+
def iterfrom(seq: ta.Sequence[T], start: int = 0, stop: int | None = None) -> ta.Iterator[T]:
|
30
|
+
if start < 0:
|
31
|
+
start += len(seq)
|
32
|
+
if stop is None:
|
33
|
+
stop = len(seq)
|
34
|
+
return map(seq.__getitem__, range(start, stop))
|
35
|
+
|
36
|
+
|
29
37
|
def peek(vs: ta.Iterable[T]) -> tuple[T, ta.Iterator[T]]:
|
30
38
|
it = iter(vs)
|
31
39
|
v = next(it)
|
omlish/lite/attrops.py
CHANGED
@@ -6,6 +6,8 @@ TODO:
|
|
6
6
|
- per-attr repr transform / filter
|
7
7
|
- __ne__ ? cases where it still matters
|
8
8
|
- ordering ?
|
9
|
+
- repr_filter: ta.Union[ta.Callable[[ta.Any], ta.Optional[str]], ta.Literal['not_none', 'truthy']]] ?
|
10
|
+
- unify repr/repr_fn/repr_filter
|
9
11
|
"""
|
10
12
|
import types # noqa
|
11
13
|
import typing as ta
|
omlish/lite/dataclasses.py
CHANGED
@@ -100,6 +100,36 @@ def dataclass_repr_omit_falsey(obj: ta.Any) -> str:
|
|
100
100
|
##
|
101
101
|
|
102
102
|
|
103
|
+
def dataclass_descriptor_method(*bind_attrs: str, bind_owner: bool = False) -> ta.Callable:
|
104
|
+
if not bind_attrs:
|
105
|
+
def __get__(self, instance, owner=None): # noqa
|
106
|
+
return self
|
107
|
+
|
108
|
+
elif bind_owner:
|
109
|
+
def __get__(self, instance, owner=None): # noqa
|
110
|
+
# Guaranteed to return a new instance even with no attrs
|
111
|
+
return dc.replace(self, **{
|
112
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
113
|
+
for a in bind_attrs
|
114
|
+
})
|
115
|
+
|
116
|
+
else:
|
117
|
+
def __get__(self, instance, owner=None): # noqa
|
118
|
+
if instance is None:
|
119
|
+
return self
|
120
|
+
|
121
|
+
# Guaranteed to return a new instance even with no attrs
|
122
|
+
return dc.replace(self, **{
|
123
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
124
|
+
for a in bind_attrs
|
125
|
+
})
|
126
|
+
|
127
|
+
return __get__
|
128
|
+
|
129
|
+
|
130
|
+
##
|
131
|
+
|
132
|
+
|
103
133
|
def dataclass_kw_only_init():
|
104
134
|
def inner(cls):
|
105
135
|
if not isinstance(cls, type) and dc.is_dataclass(cls):
|
omlish/marshal/__init__.py
CHANGED
@@ -54,6 +54,10 @@ with _lang.auto_proxy_init(globals()):
|
|
54
54
|
|
55
55
|
from .base.contexts import ( # noqa
|
56
56
|
BaseContext,
|
57
|
+
|
58
|
+
MarshalFactoryContext,
|
59
|
+
UnmarshalFactoryContext,
|
60
|
+
|
57
61
|
MarshalContext,
|
58
62
|
UnmarshalContext,
|
59
63
|
)
|
@@ -113,10 +117,15 @@ with _lang.auto_proxy_init(globals()):
|
|
113
117
|
OptionalUnmarshaler,
|
114
118
|
)
|
115
119
|
|
116
|
-
from .composite.unions import ( # noqa
|
117
|
-
|
118
|
-
|
120
|
+
from .composite.unions.literals import ( # noqa
|
121
|
+
LITERAL_UNION_TYPES,
|
122
|
+
LiteralUnionMarshaler,
|
123
|
+
LiteralUnionMarshalerFactory,
|
124
|
+
LiteralUnionUnmarshaler,
|
125
|
+
LiteralUnionUnmarshalerFactory,
|
126
|
+
)
|
119
127
|
|
128
|
+
from .composite.unions.primitives import ( # noqa
|
120
129
|
PRIMITIVE_UNION_TYPES,
|
121
130
|
PrimitiveUnionMarshaler,
|
122
131
|
PrimitiveUnionMarshalerFactory,
|
@@ -129,14 +138,9 @@ with _lang.auto_proxy_init(globals()):
|
|
129
138
|
WrappedUnmarshaler,
|
130
139
|
)
|
131
140
|
|
132
|
-
from .factories.
|
133
|
-
|
134
|
-
|
135
|
-
)
|
136
|
-
|
137
|
-
from .factories.match import ( # noqa
|
138
|
-
MarshalerFactoryMatchClass,
|
139
|
-
UnmarshalerFactoryMatchClass,
|
141
|
+
from .factories.method import ( # noqa
|
142
|
+
MarshalerFactoryMethodClass,
|
143
|
+
UnmarshalerFactoryMethodClass,
|
140
144
|
)
|
141
145
|
|
142
146
|
from .factories.moduleimport.configs import ( # noqa
|
@@ -246,6 +250,7 @@ with _lang.auto_proxy_init(globals()):
|
|
246
250
|
|
247
251
|
from .trivial.forbidden import ( # noqa
|
248
252
|
ForbiddenTypeMarshalerFactory,
|
253
|
+
ForbiddenTypeMarshalerFactoryUnmarshalerFactory,
|
249
254
|
ForbiddenTypeUnmarshalerFactory,
|
250
255
|
)
|
251
256
|
|
omlish/marshal/base/contexts.py
CHANGED
@@ -5,7 +5,6 @@ from ... import check
|
|
5
5
|
from ... import collections as col
|
6
6
|
from ... import lang
|
7
7
|
from ... import reflect as rfl
|
8
|
-
from ...funcs import match as mfs
|
9
8
|
from .configs import EMPTY_CONFIG_REGISTRY
|
10
9
|
from .configs import ConfigRegistry
|
11
10
|
from .errors import UnhandledTypeError
|
@@ -28,7 +27,7 @@ T = ta.TypeVar('T')
|
|
28
27
|
|
29
28
|
|
30
29
|
@dc.dataclass(frozen=True, kw_only=True)
|
31
|
-
class BaseContext(lang.Abstract):
|
30
|
+
class BaseContext(lang.Abstract, lang.Sealed):
|
32
31
|
config_registry: ConfigRegistry = EMPTY_CONFIG_REGISTRY
|
33
32
|
options: col.TypeMap[Option] = col.TypeMap()
|
34
33
|
|
@@ -41,33 +40,47 @@ class BaseContext(lang.Abstract):
|
|
41
40
|
return rfl.Reflector(override=override).type(o)
|
42
41
|
|
43
42
|
|
43
|
+
#
|
44
|
+
|
45
|
+
|
44
46
|
@dc.dataclass(frozen=True, kw_only=True)
|
45
|
-
class
|
46
|
-
|
47
|
+
class MarshalFactoryContext(BaseContext, lang.Final):
|
48
|
+
marshaler_factory: ta.Optional['MarshalerFactory'] = None
|
47
49
|
|
48
|
-
def
|
50
|
+
def make_marshaler(self, o: ta.Any) -> 'Marshaler':
|
49
51
|
rty = self._reflect(o)
|
50
|
-
fac = check.not_none(self.
|
51
|
-
|
52
|
-
return fac.make_marshaler(self, rty)
|
53
|
-
except mfs.MatchGuardError:
|
52
|
+
fac = check.not_none(self.marshaler_factory)
|
53
|
+
if (mfn := fac.make_marshaler(self, rty)) is None:
|
54
54
|
raise UnhandledTypeError(rty) # noqa
|
55
|
-
|
56
|
-
def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> 'Value':
|
57
|
-
return self.make(ty if ty is not None else type(obj)).marshal(self, obj)
|
55
|
+
return mfn()
|
58
56
|
|
59
57
|
|
60
58
|
@dc.dataclass(frozen=True, kw_only=True)
|
61
|
-
class
|
62
|
-
|
59
|
+
class UnmarshalFactoryContext(BaseContext, lang.Final):
|
60
|
+
unmarshaler_factory: ta.Optional['UnmarshalerFactory'] = None
|
63
61
|
|
64
|
-
def
|
62
|
+
def make_unmarshaler(self, o: ta.Any) -> 'Unmarshaler':
|
65
63
|
rty = self._reflect(o)
|
66
|
-
fac = check.not_none(self.
|
67
|
-
|
68
|
-
return fac.make_unmarshaler(self, rty)
|
69
|
-
except mfs.MatchGuardError:
|
64
|
+
fac = check.not_none(self.unmarshaler_factory)
|
65
|
+
if (mfn := fac.make_unmarshaler(self, rty)) is None:
|
70
66
|
raise UnhandledTypeError(rty) # noqa
|
67
|
+
return mfn()
|
68
|
+
|
69
|
+
|
70
|
+
#
|
71
|
+
|
72
|
+
|
73
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
74
|
+
class MarshalContext(BaseContext, lang.Final):
|
75
|
+
marshal_factory_context: MarshalFactoryContext
|
76
|
+
|
77
|
+
def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> 'Value':
|
78
|
+
return self.marshal_factory_context.make_marshaler(ty if ty is not None else type(obj)).marshal(self, obj)
|
79
|
+
|
80
|
+
|
81
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
82
|
+
class UnmarshalContext(BaseContext, lang.Final):
|
83
|
+
unmarshal_factory_context: UnmarshalFactoryContext
|
71
84
|
|
72
85
|
@ta.overload
|
73
86
|
def unmarshal(self, v: 'Value', ty: type[T]) -> T:
|
@@ -78,4 +91,4 @@ class UnmarshalContext(BaseContext, lang.Final):
|
|
78
91
|
...
|
79
92
|
|
80
93
|
def unmarshal(self, v, ty):
|
81
|
-
return self.
|
94
|
+
return self.unmarshal_factory_context.make_unmarshaler(ty).unmarshal(self, v)
|
omlish/marshal/base/funcs.py
CHANGED
@@ -3,9 +3,10 @@ import typing as ta
|
|
3
3
|
|
4
4
|
from ... import lang
|
5
5
|
from ... import reflect as rfl
|
6
|
-
from ...funcs import match as mfs
|
7
6
|
from .contexts import MarshalContext
|
7
|
+
from .contexts import MarshalFactoryContext
|
8
8
|
from .contexts import UnmarshalContext
|
9
|
+
from .contexts import UnmarshalFactoryContext
|
9
10
|
from .types import Marshaler
|
10
11
|
from .types import MarshalerFactory
|
11
12
|
from .types import MarshalerMaker
|
@@ -39,19 +40,15 @@ class FuncUnmarshaler(Unmarshaler, lang.Final):
|
|
39
40
|
|
40
41
|
@dc.dataclass(frozen=True)
|
41
42
|
class FuncMarshalerFactory(MarshalerFactory): # noqa
|
42
|
-
|
43
|
-
fn: ta.Callable[[MarshalContext, rfl.Type], Marshaler]
|
43
|
+
gf: MarshalerMaker
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
return mfs.simple(self.guard, self.fn)
|
45
|
+
def make_marshaler(self, ctx: MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
|
46
|
+
return self.gf(ctx, rty)
|
48
47
|
|
49
48
|
|
50
49
|
@dc.dataclass(frozen=True)
|
51
50
|
class FuncUnmarshalerFactory(UnmarshalerFactory): # noqa
|
52
|
-
|
53
|
-
fn: ta.Callable[[UnmarshalContext, rfl.Type], Unmarshaler]
|
51
|
+
gf: UnmarshalerMaker
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
return mfs.simple(self.guard, self.fn)
|
53
|
+
def make_unmarshaler(self, ctx: UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
|
54
|
+
return self.gf(ctx, rty)
|
omlish/marshal/base/options.py
CHANGED
omlish/marshal/base/types.py
CHANGED
@@ -3,10 +3,12 @@ import typing as ta
|
|
3
3
|
|
4
4
|
from ... import lang
|
5
5
|
from ... import reflect as rfl
|
6
|
-
from ...funcs import
|
6
|
+
from ...funcs import guard as gfs
|
7
7
|
from .configs import ConfigRegistry
|
8
8
|
from .contexts import MarshalContext
|
9
|
+
from .contexts import MarshalFactoryContext
|
9
10
|
from .contexts import UnmarshalContext
|
11
|
+
from .contexts import UnmarshalFactoryContext
|
10
12
|
from .values import Value
|
11
13
|
|
12
14
|
|
@@ -31,21 +33,19 @@ class Unmarshaler(lang.Abstract):
|
|
31
33
|
##
|
32
34
|
|
33
35
|
|
34
|
-
MarshalerMaker: ta.TypeAlias =
|
35
|
-
UnmarshalerMaker: ta.TypeAlias =
|
36
|
+
MarshalerMaker: ta.TypeAlias = gfs.GuardFn[[MarshalFactoryContext, rfl.Type], Marshaler]
|
37
|
+
UnmarshalerMaker: ta.TypeAlias = gfs.GuardFn[[UnmarshalFactoryContext, rfl.Type], Unmarshaler]
|
36
38
|
|
37
39
|
|
38
40
|
class MarshalerFactory(lang.Abstract):
|
39
|
-
@property
|
40
41
|
@abc.abstractmethod
|
41
|
-
def make_marshaler(self) ->
|
42
|
+
def make_marshaler(self, ctx: MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
|
42
43
|
raise NotImplementedError
|
43
44
|
|
44
45
|
|
45
46
|
class UnmarshalerFactory(lang.Abstract):
|
46
|
-
@property
|
47
47
|
@abc.abstractmethod
|
48
|
-
def make_unmarshaler(self) ->
|
48
|
+
def make_unmarshaler(self, ctx: UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
|
49
49
|
raise NotImplementedError
|
50
50
|
|
51
51
|
|
@@ -65,20 +65,32 @@ class Marshaling(lang.Abstract):
|
|
65
65
|
def unmarshaler_factory(self) -> UnmarshalerFactory:
|
66
66
|
raise NotImplementedError
|
67
67
|
|
68
|
-
|
68
|
+
##
|
69
|
+
|
70
|
+
def new_marshal_factory_context(self) -> MarshalFactoryContext:
|
71
|
+
return MarshalFactoryContext(
|
72
|
+
config_registry=self.config_registry(),
|
73
|
+
marshaler_factory=self.marshaler_factory(),
|
74
|
+
)
|
75
|
+
|
76
|
+
def new_unmarshal_factory_context(self) -> UnmarshalFactoryContext:
|
77
|
+
return UnmarshalFactoryContext(
|
78
|
+
config_registry=self.config_registry(),
|
79
|
+
unmarshaler_factory=self.unmarshaler_factory(),
|
80
|
+
)
|
69
81
|
|
70
|
-
|
82
|
+
##
|
83
|
+
|
84
|
+
def new_marshal_context(self) -> MarshalContext:
|
71
85
|
return MarshalContext(
|
72
86
|
config_registry=self.config_registry(),
|
73
|
-
|
74
|
-
**kwargs,
|
87
|
+
marshal_factory_context=self.new_marshal_factory_context(),
|
75
88
|
)
|
76
89
|
|
77
|
-
def new_unmarshal_context(self
|
90
|
+
def new_unmarshal_context(self) -> UnmarshalContext:
|
78
91
|
return UnmarshalContext(
|
79
92
|
config_registry=self.config_registry(),
|
80
|
-
|
81
|
-
**kwargs,
|
93
|
+
unmarshal_factory_context=self.new_unmarshal_factory_context(),
|
82
94
|
)
|
83
95
|
|
84
96
|
#
|
@@ -98,3 +110,15 @@ class Marshaling(lang.Abstract):
|
|
98
110
|
@ta.final
|
99
111
|
def unmarshal(self, v, ty, **kwargs):
|
100
112
|
return self.new_unmarshal_context(**kwargs).unmarshal(v, ty)
|
113
|
+
|
114
|
+
|
115
|
+
##
|
116
|
+
|
117
|
+
|
118
|
+
# MarshalerOrUnmarshaler: ta.TypeAlias = Marshaler | Unmarshaler
|
119
|
+
# MarshalerOrUnmarshalerT = ta.TypeVar('MarshalerOrUnmarshalerT', bound=MarshalerOrUnmarshaler)
|
120
|
+
#
|
121
|
+
# MarshalContextOrUnmarshalContext: ta.TypeAlias = MarshalContext | UnmarshalContext
|
122
|
+
# MarshalContextOrUnmarshalContextT = ta.TypeVar('MarshalContextOrUnmarshalContextT', bound=MarshalContextOrUnmarshalContext) # noqa
|
123
|
+
#
|
124
|
+
# MarshalerMakerOrUnmarshalerMaker: ta.TypeAlias = MarshalerMaker | UnmarshalerMaker
|
@@ -9,14 +9,15 @@ import typing as ta
|
|
9
9
|
|
10
10
|
from ... import check
|
11
11
|
from ... import reflect as rfl
|
12
|
-
from ...funcs import match as mfs
|
13
12
|
from ..base.contexts import MarshalContext
|
13
|
+
from ..base.contexts import MarshalFactoryContext
|
14
14
|
from ..base.contexts import UnmarshalContext
|
15
|
+
from ..base.contexts import UnmarshalFactoryContext
|
15
16
|
from ..base.types import Marshaler
|
16
17
|
from ..base.types import Unmarshaler
|
17
18
|
from ..base.values import Value
|
18
|
-
from ..factories.
|
19
|
-
from ..factories.
|
19
|
+
from ..factories.method import MarshalerFactoryMethodClass
|
20
|
+
from ..factories.method import UnmarshalerFactoryMethodClass
|
20
21
|
|
21
22
|
|
22
23
|
##
|
@@ -29,6 +30,9 @@ DEFAULT_ITERABLE_CONCRETE_TYPES: dict[type[collections.abc.Iterable], type[colle
|
|
29
30
|
}
|
30
31
|
|
31
32
|
|
33
|
+
#
|
34
|
+
|
35
|
+
|
32
36
|
@dc.dataclass(frozen=True)
|
33
37
|
class IterableMarshaler(Marshaler):
|
34
38
|
e: Marshaler
|
@@ -37,15 +41,21 @@ class IterableMarshaler(Marshaler):
|
|
37
41
|
return list(map(functools.partial(self.e.marshal, ctx), o))
|
38
42
|
|
39
43
|
|
40
|
-
class IterableMarshalerFactory(
|
41
|
-
@
|
42
|
-
def
|
43
|
-
|
44
|
-
|
44
|
+
class IterableMarshalerFactory(MarshalerFactoryMethodClass):
|
45
|
+
@MarshalerFactoryMethodClass.make_marshaler.register
|
46
|
+
def _make_generic(self, ctx: MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
|
47
|
+
if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable)):
|
48
|
+
return None
|
49
|
+
return lambda: IterableMarshaler(ctx.make_marshaler(check.single(rty.args)))
|
50
|
+
|
51
|
+
@MarshalerFactoryMethodClass.make_marshaler.register
|
52
|
+
def _make_concrete(self, ctx: MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
|
53
|
+
if not (isinstance(rty, type) and issubclass(rty, collections.abc.Iterable)):
|
54
|
+
return None
|
55
|
+
return lambda: IterableMarshaler(ctx.make_marshaler(ta.Any))
|
56
|
+
|
45
57
|
|
46
|
-
|
47
|
-
def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
|
48
|
-
return IterableMarshaler(ctx.make(ta.Any))
|
58
|
+
#
|
49
59
|
|
50
60
|
|
51
61
|
@dc.dataclass(frozen=True)
|
@@ -57,13 +67,16 @@ class IterableUnmarshaler(Unmarshaler):
|
|
57
67
|
return self.ctor(map(functools.partial(self.e.unmarshal, ctx), check.isinstance(v, collections.abc.Iterable)))
|
58
68
|
|
59
69
|
|
60
|
-
class IterableUnmarshalerFactory(
|
61
|
-
@
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
70
|
+
class IterableUnmarshalerFactory(UnmarshalerFactoryMethodClass):
|
71
|
+
@UnmarshalerFactoryMethodClass.make_unmarshaler.register
|
72
|
+
def _make_generic(self, ctx: UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
|
73
|
+
if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable)):
|
74
|
+
return None
|
75
|
+
cty = DEFAULT_ITERABLE_CONCRETE_TYPES.get(rty.cls, rty.cls) # noqa
|
76
|
+
return lambda: IterableUnmarshaler(cty, ctx.make_unmarshaler(check.single(rty.args))) # noqa
|
66
77
|
|
67
|
-
@
|
68
|
-
def
|
69
|
-
|
78
|
+
@UnmarshalerFactoryMethodClass.make_unmarshaler.register
|
79
|
+
def _make_concrete(self, ctx: UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
|
80
|
+
if not (isinstance(rty, type) and issubclass(rty, collections.abc.Iterable)):
|
81
|
+
return None
|
82
|
+
return lambda: IterableUnmarshaler(check.isinstance(rty, type), ctx.make_unmarshaler(ta.Any))
|