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.
Files changed (56) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/collections/identity.py +1 -0
  3. omlish/dataclasses/__init__.py +2 -0
  4. omlish/funcs/guard.py +27 -16
  5. omlish/lang/__init__.py +1 -0
  6. omlish/lang/functions.py +2 -2
  7. omlish/lang/iterables.py +8 -0
  8. omlish/lite/attrops.py +2 -0
  9. omlish/lite/dataclasses.py +30 -0
  10. omlish/marshal/__init__.py +16 -11
  11. omlish/marshal/base/contexts.py +33 -20
  12. omlish/marshal/base/funcs.py +8 -11
  13. omlish/marshal/base/options.py +8 -0
  14. omlish/marshal/base/types.py +38 -14
  15. omlish/marshal/composite/iterables.py +33 -20
  16. omlish/marshal/composite/literals.py +16 -18
  17. omlish/marshal/composite/mappings.py +36 -23
  18. omlish/marshal/composite/maybes.py +29 -19
  19. omlish/marshal/composite/newtypes.py +16 -16
  20. omlish/marshal/composite/optionals.py +14 -14
  21. omlish/marshal/composite/special.py +15 -15
  22. omlish/marshal/composite/unions/__init__.py +0 -0
  23. omlish/marshal/composite/unions/literals.py +93 -0
  24. omlish/marshal/composite/unions/primitives.py +103 -0
  25. omlish/marshal/factories/invalidate.py +18 -68
  26. omlish/marshal/factories/method.py +26 -0
  27. omlish/marshal/factories/moduleimport/factories.py +15 -56
  28. omlish/marshal/factories/multi.py +13 -25
  29. omlish/marshal/factories/recursive.py +42 -56
  30. omlish/marshal/factories/typecache.py +20 -77
  31. omlish/marshal/factories/typemap.py +42 -43
  32. omlish/marshal/objects/dataclasses.py +129 -106
  33. omlish/marshal/objects/marshal.py +18 -14
  34. omlish/marshal/objects/namedtuples.py +48 -42
  35. omlish/marshal/objects/unmarshal.py +19 -15
  36. omlish/marshal/polymorphism/marshal.py +9 -11
  37. omlish/marshal/polymorphism/unions.py +17 -11
  38. omlish/marshal/polymorphism/unmarshal.py +9 -10
  39. omlish/marshal/singular/enums.py +14 -18
  40. omlish/marshal/standard.py +8 -8
  41. omlish/marshal/trivial/any.py +1 -1
  42. omlish/marshal/trivial/forbidden.py +21 -26
  43. omlish/os/forkhooks.py +4 -0
  44. omlish/specs/jsonrpc/_marshal.py +33 -24
  45. omlish/specs/openapi/_marshal.py +30 -21
  46. omlish/typedvalues/marshal.py +83 -57
  47. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/METADATA +1 -1
  48. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/RECORD +52 -52
  49. omlish/funcs/match.py +0 -229
  50. omlish/marshal/composite/unions.py +0 -213
  51. omlish/marshal/factories/match.py +0 -34
  52. omlish/marshal/factories/simple.py +0 -28
  53. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/WHEEL +0 -0
  54. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/entry_points.txt +0 -0
  55. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/licenses/LICENSE +0 -0
  56. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev455.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev453'
2
- __revision__ = '66cf981e193780bd726e2a5ea06dd1ac590f7298'
1
+ __version__ = '0.0.0.dev455'
2
+ __revision__ = '83eb94a310c0880350d3f2b4440d1673f4d9402d'
3
3
 
4
4
 
5
5
  #
@@ -105,6 +105,7 @@ class IdentityWeakKeyDictionary(ta.MutableMapping[K, V]):
105
105
 
106
106
  TODO:
107
107
  - audit for freethreaded
108
+ - leans on stdlib impls so shouldn't matter?
108
109
  """
109
110
 
110
111
  def __init__(self, *args: ta.Any, **kwargs: ta.Any) -> None:
@@ -159,6 +159,8 @@ with _lang.auto_proxy_init(globals()) as _api_cap:
159
159
  is_immediate_dataclass,
160
160
 
161
161
  dataclass_maybe_post_init as maybe_post_init,
162
+
163
+ dataclass_descriptor_method as descriptor_method,
162
164
  )
163
165
 
164
166
 
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) -> ta.Self: ...
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
- return None
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
- prototype: ta.Callable[P, T] | None = None,
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._prototype = prototype
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
- prototype=fn,
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
- class DumbGuardFnMethod(_BaseGuardFnMethod[P, T]):
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
- if (m := gf(*args, **kwargs)) is not None:
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 dumb_method(
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]], DumbGuardFnMethod[P, T]]: # noqa
216
+ ) -> ta.Callable[[ta.Callable[P, T]], ImmediateGuardFnMethod[P, T]]: # noqa
206
217
  def inner(fn):
207
- return DumbGuardFnMethod(
218
+ return ImmediateGuardFnMethod(
208
219
  strict=strict,
209
220
  requires_override=requires_override,
210
221
  instance_cache=instance_cache,
211
- prototype=fn,
222
+ default=(lambda *args, **kwargs: lambda: fn(*args, **kwargs)),
212
223
  )
213
224
 
214
225
  return inner
omlish/lang/__init__.py CHANGED
@@ -334,6 +334,7 @@ with _auto_proxy_init(globals(), update_exports=True):
334
334
  ilen,
335
335
  take,
336
336
  consume,
337
+ iterfrom,
337
338
  peek,
338
339
  chunk,
339
340
  interleave,
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
@@ -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):
@@ -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
- MatchUnionMarshaler,
118
- MatchUnionUnmarshaler,
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.simple import ( # noqa
133
- SimpleMarshalerFactory,
134
- SimpleUnmarshalerFactory,
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
 
@@ -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 MarshalContext(BaseContext, lang.Final):
46
- factory: ta.Optional['MarshalerFactory'] = None
47
+ class MarshalFactoryContext(BaseContext, lang.Final):
48
+ marshaler_factory: ta.Optional['MarshalerFactory'] = None
47
49
 
48
- def make(self, o: ta.Any) -> 'Marshaler':
50
+ def make_marshaler(self, o: ta.Any) -> 'Marshaler':
49
51
  rty = self._reflect(o)
50
- fac = check.not_none(self.factory)
51
- try:
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 UnmarshalContext(BaseContext, lang.Final):
62
- factory: ta.Optional['UnmarshalerFactory'] = None
59
+ class UnmarshalFactoryContext(BaseContext, lang.Final):
60
+ unmarshaler_factory: ta.Optional['UnmarshalerFactory'] = None
63
61
 
64
- def make(self, o: ta.Any) -> 'Unmarshaler':
62
+ def make_unmarshaler(self, o: ta.Any) -> 'Unmarshaler':
65
63
  rty = self._reflect(o)
66
- fac = check.not_none(self.factory)
67
- try:
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.make(ty).unmarshal(self, v)
94
+ return self.unmarshal_factory_context.make_unmarshaler(ty).unmarshal(self, v)
@@ -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
- guard: ta.Callable[[MarshalContext, rfl.Type], bool]
43
- fn: ta.Callable[[MarshalContext, rfl.Type], Marshaler]
43
+ gf: MarshalerMaker
44
44
 
45
- @lang.cached_property
46
- def make_marshaler(self) -> MarshalerMaker:
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
- guard: ta.Callable[[UnmarshalContext, rfl.Type], bool]
53
- fn: ta.Callable[[UnmarshalContext, rfl.Type], Unmarshaler]
51
+ gf: UnmarshalerMaker
54
52
 
55
- @lang.cached_property
56
- def make_unmarshaler(self) -> UnmarshalerMaker:
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)
@@ -1,2 +1,10 @@
1
+ """
2
+ TODO:
3
+ - MarshalOption, UnmarshalOption, check if a context got something unexpected
4
+ - Options only apply to Factories?
5
+ - MarshalFactoryOption, MarshalOption, UnmarshalFactoryOption, MarshalOption ?
6
+ """
7
+
8
+
1
9
  class Option:
2
10
  pass
@@ -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 match as mfs
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 = mfs.MatchFn[[MarshalContext, rfl.Type], Marshaler]
35
- UnmarshalerMaker: ta.TypeAlias = mfs.MatchFn[[UnmarshalContext, rfl.Type], Unmarshaler]
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) -> MarshalerMaker:
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) -> UnmarshalerMaker:
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
- def new_marshal_context(self, **kwargs: ta.Any) -> MarshalContext:
82
+ ##
83
+
84
+ def new_marshal_context(self) -> MarshalContext:
71
85
  return MarshalContext(
72
86
  config_registry=self.config_registry(),
73
- factory=self.marshaler_factory(),
74
- **kwargs,
87
+ marshal_factory_context=self.new_marshal_factory_context(),
75
88
  )
76
89
 
77
- def new_unmarshal_context(self, **kwargs: ta.Any) -> UnmarshalContext:
90
+ def new_unmarshal_context(self) -> UnmarshalContext:
78
91
  return UnmarshalContext(
79
92
  config_registry=self.config_registry(),
80
- factory=self.unmarshaler_factory(),
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.match import MarshalerFactoryMatchClass
19
- from ..factories.match import UnmarshalerFactoryMatchClass
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(MarshalerFactoryMatchClass):
41
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
42
- def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
43
- gty = check.isinstance(rty, rfl.Generic)
44
- return IterableMarshaler(ctx.make(check.single(gty.args)))
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
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
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(UnmarshalerFactoryMatchClass):
61
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable))
62
- def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
63
- gty = check.isinstance(rty, rfl.Generic)
64
- cty = DEFAULT_ITERABLE_CONCRETE_TYPES.get(gty.cls, gty.cls) # noqa
65
- return IterableUnmarshaler(cty, ctx.make(check.single(gty.args)))
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
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Iterable))
68
- def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
69
- return IterableUnmarshaler(check.isinstance(rty, type), ctx.make(ta.Any))
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))