omlish 0.0.0.dev453__py3-none-any.whl → 0.0.0.dev454__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 (52) 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/iterables.py +8 -0
  7. omlish/lite/attrops.py +2 -0
  8. omlish/lite/dataclasses.py +30 -0
  9. omlish/marshal/__init__.py +12 -11
  10. omlish/marshal/base/contexts.py +4 -7
  11. omlish/marshal/base/funcs.py +16 -11
  12. omlish/marshal/base/types.py +17 -7
  13. omlish/marshal/composite/iterables.py +31 -20
  14. omlish/marshal/composite/literals.py +14 -18
  15. omlish/marshal/composite/mappings.py +34 -23
  16. omlish/marshal/composite/maybes.py +27 -19
  17. omlish/marshal/composite/newtypes.py +14 -14
  18. omlish/marshal/composite/optionals.py +12 -14
  19. omlish/marshal/composite/special.py +13 -13
  20. omlish/marshal/composite/unions/__init__.py +0 -0
  21. omlish/marshal/composite/unions/literals.py +91 -0
  22. omlish/marshal/composite/unions/primitives.py +101 -0
  23. omlish/marshal/factories/invalidate.py +16 -66
  24. omlish/marshal/factories/method.py +28 -0
  25. omlish/marshal/factories/moduleimport/factories.py +13 -54
  26. omlish/marshal/factories/multi.py +11 -23
  27. omlish/marshal/factories/recursive.py +40 -56
  28. omlish/marshal/factories/typecache.py +23 -75
  29. omlish/marshal/factories/typemap.py +40 -41
  30. omlish/marshal/objects/dataclasses.py +106 -97
  31. omlish/marshal/objects/marshal.py +15 -12
  32. omlish/marshal/objects/namedtuples.py +46 -40
  33. omlish/marshal/objects/unmarshal.py +16 -13
  34. omlish/marshal/polymorphism/marshal.py +6 -9
  35. omlish/marshal/polymorphism/unions.py +15 -9
  36. omlish/marshal/polymorphism/unmarshal.py +6 -8
  37. omlish/marshal/singular/enums.py +12 -18
  38. omlish/marshal/standard.py +8 -8
  39. omlish/marshal/trivial/forbidden.py +19 -24
  40. omlish/os/forkhooks.py +4 -0
  41. omlish/specs/jsonrpc/_marshal.py +33 -24
  42. omlish/specs/openapi/_marshal.py +20 -17
  43. omlish/typedvalues/marshal.py +81 -55
  44. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.dist-info}/METADATA +1 -1
  45. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.dist-info}/RECORD +49 -48
  46. omlish/marshal/composite/unions.py +0 -213
  47. omlish/marshal/factories/match.py +0 -34
  48. omlish/marshal/factories/simple.py +0 -28
  49. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.dist-info}/WHEEL +0 -0
  50. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.dist-info}/entry_points.txt +0 -0
  51. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.dist-info}/licenses/LICENSE +0 -0
  52. {omlish-0.0.0.dev453.dist-info → omlish-0.0.0.dev454.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.dev454'
2
+ __revision__ = '59a1efb9c2d924f74345aa315eef7c197a2d3a91'
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/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):
@@ -113,10 +113,15 @@ with _lang.auto_proxy_init(globals()):
113
113
  OptionalUnmarshaler,
114
114
  )
115
115
 
116
- from .composite.unions import ( # noqa
117
- MatchUnionMarshaler,
118
- MatchUnionUnmarshaler,
116
+ from .composite.unions.literals import ( # noqa
117
+ LITERAL_UNION_TYPES,
118
+ LiteralUnionMarshaler,
119
+ LiteralUnionMarshalerFactory,
120
+ LiteralUnionUnmarshaler,
121
+ LiteralUnionUnmarshalerFactory,
122
+ )
119
123
 
124
+ from .composite.unions.primitives import ( # noqa
120
125
  PRIMITIVE_UNION_TYPES,
121
126
  PrimitiveUnionMarshaler,
122
127
  PrimitiveUnionMarshalerFactory,
@@ -129,14 +134,9 @@ with _lang.auto_proxy_init(globals()):
129
134
  WrappedUnmarshaler,
130
135
  )
131
136
 
132
- from .factories.simple import ( # noqa
133
- SimpleMarshalerFactory,
134
- SimpleUnmarshalerFactory,
135
- )
136
-
137
- from .factories.match import ( # noqa
138
- MarshalerFactoryMatchClass,
139
- UnmarshalerFactoryMatchClass,
137
+ from .factories.method import ( # noqa
138
+ MarshalerFactoryMethodClass,
139
+ UnmarshalerFactoryMethodClass,
140
140
  )
141
141
 
142
142
  from .factories.moduleimport.configs import ( # noqa
@@ -246,6 +246,7 @@ with _lang.auto_proxy_init(globals()):
246
246
 
247
247
  from .trivial.forbidden import ( # noqa
248
248
  ForbiddenTypeMarshalerFactory,
249
+ ForbiddenTypeMarshalerFactoryUnmarshalerFactory,
249
250
  ForbiddenTypeUnmarshalerFactory,
250
251
  )
251
252
 
@@ -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
@@ -48,10 +47,9 @@ class MarshalContext(BaseContext, lang.Final):
48
47
  def make(self, o: ta.Any) -> 'Marshaler':
49
48
  rty = self._reflect(o)
50
49
  fac = check.not_none(self.factory)
51
- try:
52
- return fac.make_marshaler(self, rty)
53
- except mfs.MatchGuardError:
50
+ if (mfn := fac.make_marshaler(self, rty)) is None:
54
51
  raise UnhandledTypeError(rty) # noqa
52
+ return mfn()
55
53
 
56
54
  def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> 'Value':
57
55
  return self.make(ty if ty is not None else type(obj)).marshal(self, obj)
@@ -64,10 +62,9 @@ class UnmarshalContext(BaseContext, lang.Final):
64
62
  def make(self, o: ta.Any) -> 'Unmarshaler':
65
63
  rty = self._reflect(o)
66
64
  fac = check.not_none(self.factory)
67
- try:
68
- return fac.make_unmarshaler(self, rty)
69
- except mfs.MatchGuardError:
65
+ if (mfn := fac.make_unmarshaler(self, rty)) is None:
70
66
  raise UnhandledTypeError(rty) # noqa
67
+ return mfn()
71
68
 
72
69
  @ta.overload
73
70
  def unmarshal(self, v: 'Value', ty: type[T]) -> T:
@@ -3,7 +3,7 @@ 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 .contexts import MarshalContext
8
8
  from .contexts import UnmarshalContext
9
9
  from .types import Marshaler
@@ -39,19 +39,24 @@ class FuncUnmarshaler(Unmarshaler, lang.Final):
39
39
 
40
40
  @dc.dataclass(frozen=True)
41
41
  class FuncMarshalerFactory(MarshalerFactory): # noqa
42
- guard: ta.Callable[[MarshalContext, rfl.Type], bool]
43
- fn: ta.Callable[[MarshalContext, rfl.Type], Marshaler]
42
+ gf: MarshalerMaker
44
43
 
45
- @lang.cached_property
46
- def make_marshaler(self) -> MarshalerMaker:
47
- return mfs.simple(self.guard, self.fn)
44
+ def make_marshaler(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
45
+ return self.gf(ctx, rty)
48
46
 
49
47
 
50
48
  @dc.dataclass(frozen=True)
51
49
  class FuncUnmarshalerFactory(UnmarshalerFactory): # noqa
52
- guard: ta.Callable[[UnmarshalContext, rfl.Type], bool]
53
- fn: ta.Callable[[UnmarshalContext, rfl.Type], Unmarshaler]
50
+ gf: UnmarshalerMaker
54
51
 
55
- @lang.cached_property
56
- def make_unmarshaler(self) -> UnmarshalerMaker:
57
- return mfs.simple(self.guard, self.fn)
52
+ def make_unmarshaler(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
53
+ return self.gf(ctx, rty)
54
+
55
+
56
+ ##
57
+
58
+
59
+ class GuardMethodMarshalerFactory(MarshalerFactory):
60
+ @gfs.method(instance_cache=True)
61
+ def make_marshaler(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
62
+ raise NotImplementedError
@@ -3,7 +3,7 @@ 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
9
  from .contexts import UnmarshalContext
@@ -31,21 +31,19 @@ class Unmarshaler(lang.Abstract):
31
31
  ##
32
32
 
33
33
 
34
- MarshalerMaker: ta.TypeAlias = mfs.MatchFn[[MarshalContext, rfl.Type], Marshaler]
35
- UnmarshalerMaker: ta.TypeAlias = mfs.MatchFn[[UnmarshalContext, rfl.Type], Unmarshaler]
34
+ MarshalerMaker: ta.TypeAlias = gfs.GuardFn[[MarshalContext, rfl.Type], Marshaler]
35
+ UnmarshalerMaker: ta.TypeAlias = gfs.GuardFn[[UnmarshalContext, rfl.Type], Unmarshaler]
36
36
 
37
37
 
38
38
  class MarshalerFactory(lang.Abstract):
39
- @property
40
39
  @abc.abstractmethod
41
- def make_marshaler(self) -> MarshalerMaker:
40
+ def make_marshaler(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
42
41
  raise NotImplementedError
43
42
 
44
43
 
45
44
  class UnmarshalerFactory(lang.Abstract):
46
- @property
47
45
  @abc.abstractmethod
48
- def make_unmarshaler(self) -> UnmarshalerMaker:
46
+ def make_unmarshaler(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
49
47
  raise NotImplementedError
50
48
 
51
49
 
@@ -98,3 +96,15 @@ class Marshaling(lang.Abstract):
98
96
  @ta.final
99
97
  def unmarshal(self, v, ty, **kwargs):
100
98
  return self.new_unmarshal_context(**kwargs).unmarshal(v, ty)
99
+
100
+
101
+ ##
102
+
103
+
104
+ # MarshalerOrUnmarshaler: ta.TypeAlias = Marshaler | Unmarshaler
105
+ # MarshalerOrUnmarshalerT = ta.TypeVar('MarshalerOrUnmarshalerT', bound=MarshalerOrUnmarshaler)
106
+ #
107
+ # MarshalContextOrUnmarshalContext: ta.TypeAlias = MarshalContext | UnmarshalContext
108
+ # MarshalContextOrUnmarshalContextT = ta.TypeVar('MarshalContextOrUnmarshalContextT', bound=MarshalContextOrUnmarshalContext) # noqa
109
+ #
110
+ # MarshalerMakerOrUnmarshalerMaker: ta.TypeAlias = MarshalerMaker | UnmarshalerMaker
@@ -9,14 +9,13 @@ 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
14
13
  from ..base.contexts import UnmarshalContext
15
14
  from ..base.types import Marshaler
16
15
  from ..base.types import Unmarshaler
17
16
  from ..base.values import Value
18
- from ..factories.match import MarshalerFactoryMatchClass
19
- from ..factories.match import UnmarshalerFactoryMatchClass
17
+ from ..factories.method import MarshalerFactoryMethodClass
18
+ from ..factories.method import UnmarshalerFactoryMethodClass
20
19
 
21
20
 
22
21
  ##
@@ -29,6 +28,9 @@ DEFAULT_ITERABLE_CONCRETE_TYPES: dict[type[collections.abc.Iterable], type[colle
29
28
  }
30
29
 
31
30
 
31
+ #
32
+
33
+
32
34
  @dc.dataclass(frozen=True)
33
35
  class IterableMarshaler(Marshaler):
34
36
  e: Marshaler
@@ -37,15 +39,21 @@ class IterableMarshaler(Marshaler):
37
39
  return list(map(functools.partial(self.e.marshal, ctx), o))
38
40
 
39
41
 
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)))
42
+ class IterableMarshalerFactory(MarshalerFactoryMethodClass):
43
+ @MarshalerFactoryMethodClass.make_marshaler.register
44
+ def _make_generic(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
45
+ if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable)):
46
+ return None
47
+ return lambda: IterableMarshaler(ctx.make(check.single(rty.args)))
48
+
49
+ @MarshalerFactoryMethodClass.make_marshaler.register
50
+ def _make_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
51
+ if not (isinstance(rty, type) and issubclass(rty, collections.abc.Iterable)):
52
+ return None
53
+ return lambda: IterableMarshaler(ctx.make(ta.Any))
54
+
45
55
 
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))
56
+ #
49
57
 
50
58
 
51
59
  @dc.dataclass(frozen=True)
@@ -57,13 +65,16 @@ class IterableUnmarshaler(Unmarshaler):
57
65
  return self.ctor(map(functools.partial(self.e.unmarshal, ctx), check.isinstance(v, collections.abc.Iterable)))
58
66
 
59
67
 
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)))
68
+ class IterableUnmarshalerFactory(UnmarshalerFactoryMethodClass):
69
+ @UnmarshalerFactoryMethodClass.make_unmarshaler.register
70
+ def _make_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
71
+ if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Iterable)):
72
+ return None
73
+ cty = DEFAULT_ITERABLE_CONCRETE_TYPES.get(rty.cls, rty.cls) # noqa
74
+ return lambda: IterableUnmarshaler(cty, ctx.make(check.single(rty.args))) # noqa
66
75
 
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))
76
+ @UnmarshalerFactoryMethodClass.make_unmarshaler.register
77
+ def _make_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
78
+ if not (isinstance(rty, type) and issubclass(rty, collections.abc.Iterable)):
79
+ return None
80
+ return lambda: IterableUnmarshaler(check.isinstance(rty, type), ctx.make(ta.Any))
@@ -10,10 +10,10 @@ from ... import reflect as rfl
10
10
  from ..base.contexts import MarshalContext
11
11
  from ..base.contexts import UnmarshalContext
12
12
  from ..base.types import Marshaler
13
+ from ..base.types import MarshalerFactory
13
14
  from ..base.types import Unmarshaler
15
+ from ..base.types import UnmarshalerFactory
14
16
  from ..base.values import Value
15
- from ..factories.simple import SimpleMarshalerFactory
16
- from ..factories.simple import SimpleUnmarshalerFactory
17
17
 
18
18
 
19
19
  ##
@@ -28,14 +28,12 @@ class LiteralMarshaler(Marshaler):
28
28
  return self.e.marshal(ctx, check.in_(o, self.vs))
29
29
 
30
30
 
31
- class LiteralMarshalerFactory(SimpleMarshalerFactory):
32
- def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
33
- return isinstance(rty, rfl.Literal) and len(set(map(type, rty.args))) == 1
34
-
35
- def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
36
- lty = check.isinstance(rty, rfl.Literal)
37
- ety = check.single(set(map(type, lty.args)))
38
- return LiteralMarshaler(ctx.make(ety), frozenset(lty.args))
31
+ class LiteralMarshalerFactory(MarshalerFactory):
32
+ def make_marshaler(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
33
+ if not (isinstance(rty, rfl.Literal) and len(set(map(type, rty.args))) == 1):
34
+ return None
35
+ ety = check.single(set(map(type, rty.args)))
36
+ return lambda: LiteralMarshaler(ctx.make(ety), frozenset(rty.args))
39
37
 
40
38
 
41
39
  @dc.dataclass(frozen=True)
@@ -47,11 +45,9 @@ class LiteralUnmarshaler(Unmarshaler):
47
45
  return check.in_(self.e.unmarshal(ctx, v), self.vs)
48
46
 
49
47
 
50
- class LiteralUnmarshalerFactory(SimpleUnmarshalerFactory):
51
- def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
52
- return isinstance(rty, rfl.Literal) and len(set(map(type, rty.args))) == 1
53
-
54
- def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
55
- lty = check.isinstance(rty, rfl.Literal)
56
- ety = check.single(set(map(type, lty.args)))
57
- return LiteralUnmarshaler(ctx.make(ety), frozenset(lty.args))
48
+ class LiteralUnmarshalerFactory(UnmarshalerFactory):
49
+ def make_unmarshaler(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
50
+ if not (isinstance(rty, rfl.Literal) and len(set(map(type, rty.args))) == 1):
51
+ return None
52
+ ety = check.single(set(map(type, rty.args)))
53
+ return lambda: LiteralUnmarshaler(ctx.make(ety), frozenset(rty.args))
@@ -4,14 +4,13 @@ import typing as ta
4
4
 
5
5
  from ... import check
6
6
  from ... import reflect as rfl
7
- from ...funcs import match as mfs
8
7
  from ..base.contexts import MarshalContext
9
8
  from ..base.contexts import UnmarshalContext
10
9
  from ..base.types import Marshaler
11
10
  from ..base.types import Unmarshaler
12
11
  from ..base.values import Value
13
- from ..factories.match import MarshalerFactoryMatchClass
14
- from ..factories.match import UnmarshalerFactoryMatchClass
12
+ from ..factories.method import MarshalerFactoryMethodClass
13
+ from ..factories.method import UnmarshalerFactoryMethodClass
15
14
 
16
15
 
17
16
  ##
@@ -23,6 +22,9 @@ DEFAULT_MAPPING_CONCRETE_TYPES: dict[type[collections.abc.Mapping], type[collect
23
22
  }
24
23
 
25
24
 
25
+ #
26
+
27
+
26
28
  @dc.dataclass(frozen=True)
27
29
  class MappingMarshaler(Marshaler):
28
30
  ke: Marshaler
@@ -35,16 +37,22 @@ class MappingMarshaler(Marshaler):
35
37
  }
36
38
 
37
39
 
38
- class MappingMarshalerFactory(MarshalerFactoryMatchClass):
39
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
40
- def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
41
- gty = check.isinstance(rty, rfl.Generic)
42
- kt, vt = gty.args
43
- return MappingMarshaler(ctx.make(kt), ctx.make(vt))
40
+ class MappingMarshalerFactory(MarshalerFactoryMethodClass):
41
+ @MarshalerFactoryMethodClass.make_marshaler.register
42
+ def _build_generic(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
43
+ if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping)):
44
+ return None
45
+ kt, vt = rty.args
46
+ return lambda: MappingMarshaler(ctx.make(kt), ctx.make(vt))
47
+
48
+ @MarshalerFactoryMethodClass.make_marshaler.register
49
+ def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> ta.Callable[[], Marshaler] | None:
50
+ if not (isinstance(rty, type) and issubclass(rty, collections.abc.Mapping)):
51
+ return None
52
+ return lambda: MappingMarshaler(a := ctx.make(ta.Any), a)
44
53
 
45
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
46
- def _build_concrete(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
47
- return MappingMarshaler(a := ctx.make(ta.Any), a)
54
+
55
+ #
48
56
 
49
57
 
50
58
  @dc.dataclass(frozen=True)
@@ -60,14 +68,17 @@ class MappingUnmarshaler(Unmarshaler):
60
68
  return self.ctor(dct)
61
69
 
62
70
 
63
- class MappingUnmarshalerFactory(UnmarshalerFactoryMatchClass):
64
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping))
65
- def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
66
- gty = check.isinstance(rty, rfl.Generic)
67
- cty = DEFAULT_MAPPING_CONCRETE_TYPES.get(gty.cls, gty.cls) # noqa
68
- kt, vt = gty.args
69
- return MappingUnmarshaler(cty, ctx.make(kt), ctx.make(vt))
70
-
71
- @mfs.simple(lambda _, ctx, rty: isinstance(rty, type) and issubclass(rty, collections.abc.Mapping))
72
- def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
73
- return MappingUnmarshaler(check.isinstance(rty, type), a := ctx.make(ta.Any), a)
71
+ class MappingUnmarshalerFactory(UnmarshalerFactoryMethodClass):
72
+ @UnmarshalerFactoryMethodClass.make_unmarshaler.register
73
+ def _build_generic(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
74
+ if not (isinstance(rty, rfl.Generic) and issubclass(rty.cls, collections.abc.Mapping)):
75
+ return None
76
+ cty = DEFAULT_MAPPING_CONCRETE_TYPES.get(rty.cls, rty.cls) # noqa
77
+ kt, vt = rty.args
78
+ return lambda: MappingUnmarshaler(cty, ctx.make(kt), ctx.make(vt))
79
+
80
+ @UnmarshalerFactoryMethodClass.make_unmarshaler.register
81
+ def _build_concrete(self, ctx: UnmarshalContext, rty: rfl.Type) -> ta.Callable[[], Unmarshaler] | None:
82
+ if not (isinstance(rty, type) and issubclass(rty, collections.abc.Mapping)):
83
+ return None
84
+ return lambda: MappingUnmarshaler(check.isinstance(rty, type), a := ctx.make(ta.Any), a)