omlish 0.0.0.dev226__py3-none-any.whl → 0.0.0.dev228__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 (50) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/diag/lslocks.py +4 -4
  3. omlish/diag/lsof.py +3 -4
  4. omlish/diag/ps.py +9 -0
  5. omlish/lite/timeouts.py +1 -1
  6. omlish/marshal/__init__.py +39 -24
  7. omlish/marshal/composite/__init__.py +0 -0
  8. omlish/marshal/{iterables.py → composite/iterables.py} +10 -10
  9. omlish/marshal/{literals.py → composite/literals.py} +9 -9
  10. omlish/marshal/{mappings.py → composite/mappings.py} +10 -10
  11. omlish/marshal/{maybes.py → composite/maybes.py} +11 -11
  12. omlish/marshal/{newtypes.py → composite/newtypes.py} +8 -8
  13. omlish/marshal/{optionals.py → composite/optionals.py} +9 -9
  14. omlish/marshal/objects/__init__.py +7 -0
  15. omlish/marshal/{dataclasses.py → objects/dataclasses.py} +24 -24
  16. omlish/marshal/{helpers.py → objects/helpers.py} +6 -3
  17. omlish/marshal/objects/marshal.py +108 -0
  18. omlish/marshal/objects/metadata.py +124 -0
  19. omlish/marshal/{namedtuples.py → objects/namedtuples.py} +16 -16
  20. omlish/marshal/objects/unmarshal.py +141 -0
  21. omlish/marshal/polymorphism/__init__.py +7 -0
  22. omlish/marshal/polymorphism/marshal.py +66 -0
  23. omlish/marshal/polymorphism/metadata.py +140 -0
  24. omlish/marshal/{unions.py → polymorphism/unions.py} +18 -18
  25. omlish/marshal/polymorphism/unmarshal.py +73 -0
  26. omlish/marshal/singular/__init__.py +0 -0
  27. omlish/marshal/{any.py → singular/any.py} +8 -8
  28. omlish/marshal/{base64.py → singular/base64.py} +9 -9
  29. omlish/marshal/{datetimes.py → singular/datetimes.py} +9 -9
  30. omlish/marshal/{enums.py → singular/enums.py} +9 -9
  31. omlish/marshal/{numbers.py → singular/numbers.py} +8 -8
  32. omlish/marshal/{primitives.py → singular/primitives.py} +8 -8
  33. omlish/marshal/{uuids.py → singular/uuids.py} +8 -8
  34. omlish/marshal/standard.py +32 -32
  35. omlish/os/death.py +70 -4
  36. omlish/os/fcntl.py +11 -12
  37. omlish/os/files.py +18 -3
  38. omlish/os/forkhooks.py +215 -0
  39. omlish/os/pidfiles/manager.py +4 -1
  40. omlish/os/pidfiles/pidfile.py +31 -11
  41. omlish/os/pidfiles/pinning.py +250 -0
  42. omlish/sockets/bind.py +4 -4
  43. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/METADATA +3 -3
  44. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/RECORD +48 -38
  45. omlish/marshal/objects.py +0 -317
  46. omlish/marshal/polymorphism.py +0 -267
  47. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/LICENSE +0 -0
  48. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/WHEEL +0 -0
  49. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/entry_points.txt +0 -0
  50. {omlish-0.0.0.dev226.dist-info → omlish-0.0.0.dev228.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,124 @@
1
+ import typing as ta
2
+
3
+ from ... import cached
4
+ from ... import collections as col
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ..base import Marshaler
8
+ from ..base import MarshalerFactory
9
+ from ..base import Unmarshaler
10
+ from ..base import UnmarshalerFactory
11
+ from ..naming import Naming
12
+
13
+
14
+ ##
15
+
16
+
17
+ @dc.dataclass(frozen=True, kw_only=True)
18
+ class FieldOptions:
19
+ omit_if: ta.Callable[[ta.Any], bool] | None = None
20
+
21
+ default: lang.Maybe[ta.Any] = dc.xfield(default=lang.empty(), check_type=lang.Maybe)
22
+
23
+ embed: bool = False
24
+
25
+ no_marshal: bool = False
26
+ no_unmarshal: bool = False
27
+
28
+
29
+ DEFAULT_FIELD_OPTIONS = FieldOptions()
30
+ FIELD_OPTIONS_KWARGS: frozenset[str] = frozenset(dc.fields_dict(FieldOptions).keys())
31
+
32
+
33
+ @dc.dataclass(frozen=True, kw_only=True)
34
+ class FieldMetadata:
35
+ name: str | None = None
36
+ alts: ta.Iterable[str] | None = None
37
+
38
+ options: FieldOptions = DEFAULT_FIELD_OPTIONS
39
+
40
+ marshaler: Marshaler | None = dc.xfield(None, check_type=(Marshaler, None))
41
+ marshaler_factory: MarshalerFactory | None = None
42
+
43
+ unmarshaler: Unmarshaler | None = dc.xfield(None, check_type=(Unmarshaler, None))
44
+ unmarshaler_factory: UnmarshalerFactory | None = None
45
+
46
+ def update(self, **kwargs: ta.Any) -> 'FieldMetadata':
47
+ okw = {k: v for k, v in kwargs.items() if k in FIELD_OPTIONS_KWARGS}
48
+ mkw = {k: v for k, v in kwargs.items() if k not in FIELD_OPTIONS_KWARGS}
49
+ return dc.replace(
50
+ self,
51
+ **(dict(options=dc.replace(self.options, **okw)) if okw else {}),
52
+ **mkw,
53
+ )
54
+
55
+
56
+ @dc.dataclass(frozen=True, kw_only=True)
57
+ class ObjectMetadata:
58
+ field_naming: Naming | None = None
59
+
60
+ unknown_field: str | None = None
61
+ source_field: str | None = None
62
+
63
+ @cached.property
64
+ def specials(self) -> 'ObjectSpecials':
65
+ return ObjectSpecials(
66
+ unknown=self.unknown_field,
67
+ source=self.source_field,
68
+ )
69
+
70
+ field_defaults: FieldMetadata = FieldMetadata()
71
+
72
+ ignore_unknown: bool = False
73
+
74
+
75
+ @dc.dataclass(frozen=True, kw_only=True)
76
+ class ObjectSpecials:
77
+ unknown: str | None = None
78
+ source: str | None = None
79
+
80
+ @cached.property
81
+ def set(self) -> frozenset[str]:
82
+ return frozenset(v for v in dc.asdict(self).values() if v is not None)
83
+
84
+
85
+ ##
86
+
87
+
88
+ @dc.dataclass(frozen=True, kw_only=True)
89
+ class FieldInfo:
90
+ name: str
91
+ type: ta.Any
92
+
93
+ marshal_name: str | None
94
+ unmarshal_names: ta.Sequence[str]
95
+
96
+ metadata: FieldMetadata = FieldMetadata()
97
+
98
+ options: FieldOptions = FieldOptions()
99
+
100
+
101
+ @dc.dataclass(frozen=True)
102
+ class FieldInfos:
103
+ lst: ta.Sequence[FieldInfo]
104
+
105
+ def __iter__(self) -> ta.Iterator[FieldInfo]:
106
+ return iter(self.lst)
107
+
108
+ def __len__(self) -> int:
109
+ return len(self.lst)
110
+
111
+ @cached.property
112
+ @dc.init
113
+ def by_name(self) -> ta.Mapping[str, FieldInfo]:
114
+ return col.make_map(((fi.name, fi) for fi in self), strict=True)
115
+
116
+ @cached.property
117
+ @dc.init
118
+ def by_marshal_name(self) -> ta.Mapping[str, FieldInfo]:
119
+ return col.make_map(((fi.marshal_name, fi) for fi in self if fi.marshal_name is not None), strict=True)
120
+
121
+ @cached.property
122
+ @dc.init
123
+ def by_unmarshal_name(self) -> ta.Mapping[str, FieldInfo]:
124
+ return col.make_map(((n, fi) for fi in self for n in fi.unmarshal_names), strict=True)
@@ -1,22 +1,22 @@
1
1
  import inspect
2
2
  import typing as ta
3
3
 
4
- from .. import check
5
- from .. import collections as col
6
- from .. import lang
7
- from .. import reflect as rfl
8
- from .base import MarshalContext
9
- from .base import Marshaler
10
- from .base import MarshalerFactory
11
- from .base import Option
12
- from .base import UnmarshalContext
13
- from .base import Unmarshaler
14
- from .base import UnmarshalerFactory
15
- from .objects import FieldInfo
16
- from .objects import FieldInfos
17
- from .objects import FieldMetadata
18
- from .objects import ObjectMarshaler
19
- from .objects import ObjectUnmarshaler
4
+ from ... import check
5
+ from ... import collections as col
6
+ from ... import lang
7
+ from ... import reflect as rfl
8
+ from ..base import MarshalContext
9
+ from ..base import Marshaler
10
+ from ..base import MarshalerFactory
11
+ from ..base import Option
12
+ from ..base import UnmarshalContext
13
+ from ..base import Unmarshaler
14
+ from ..base import UnmarshalerFactory
15
+ from .marshal import ObjectMarshaler
16
+ from .metadata import FieldInfo
17
+ from .metadata import FieldInfos
18
+ from .metadata import FieldMetadata
19
+ from .unmarshal import ObjectUnmarshaler
20
20
 
21
21
 
22
22
  ##
@@ -0,0 +1,141 @@
1
+ import collections.abc
2
+ import typing as ta
3
+
4
+ from ... import check
5
+ from ... import dataclasses as dc
6
+ from ... import reflect as rfl
7
+ from ..base import UnmarshalContext
8
+ from ..base import Unmarshaler
9
+ from ..base import UnmarshalerFactory
10
+ from ..values import Value
11
+ from .metadata import FieldInfo
12
+ from .metadata import FieldInfos
13
+ from .metadata import ObjectSpecials
14
+
15
+
16
+ ##
17
+
18
+
19
+ @dc.dataclass(frozen=True)
20
+ class ObjectUnmarshaler(Unmarshaler):
21
+ factory: ta.Callable
22
+ fields_by_unmarshal_name: ta.Mapping[str, tuple[FieldInfo, Unmarshaler]]
23
+
24
+ _: dc.KW_ONLY
25
+
26
+ specials: ObjectSpecials = ObjectSpecials()
27
+
28
+ defaults: ta.Mapping[str, ta.Any] | None = None
29
+
30
+ embeds: ta.Mapping[str, type] | None = None
31
+ embeds_by_unmarshal_name: ta.Mapping[str, tuple[str, str]] | None = None
32
+
33
+ ignore_unknown: bool = False
34
+
35
+ @classmethod
36
+ def make(
37
+ cls,
38
+ ctx: UnmarshalContext,
39
+ factory: ta.Callable,
40
+ fis: FieldInfos,
41
+ **kwargs: ta.Any,
42
+ ) -> Unmarshaler:
43
+ fields_by_unmarshal_name = {
44
+ n: (fi, ctx.make(fi.type))
45
+ for fi in fis
46
+ for n in fi.unmarshal_names
47
+ }
48
+
49
+ defaults = {
50
+ fi.name: fi.options.default.must()
51
+ for fi in fis
52
+ if fi.options.default.present
53
+ }
54
+
55
+ return cls(
56
+ factory,
57
+ fields_by_unmarshal_name,
58
+ defaults=defaults,
59
+ **kwargs,
60
+ )
61
+
62
+ #
63
+
64
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
65
+ ma = check.isinstance(v, collections.abc.Mapping)
66
+
67
+ u: ta.Any
68
+ kw: dict[str, ta.Any] = {}
69
+ ukf: dict[str, ta.Any] | None = None
70
+
71
+ ekws: dict[str, dict[str, ta.Any]] = {en: {} for en in self.embeds or ()}
72
+
73
+ if self.specials.source is not None:
74
+ kw[self.specials.source] = v
75
+
76
+ if self.specials.unknown is not None:
77
+ kw[self.specials.unknown] = ukf = {}
78
+
79
+ for k, mv in ma.items():
80
+ ks = check.isinstance(k, str)
81
+
82
+ try:
83
+ fi, u = self.fields_by_unmarshal_name[ks]
84
+
85
+ except KeyError:
86
+ if ukf is not None:
87
+ ukf[ks] = mv # FIXME: unmarshal?
88
+ continue
89
+
90
+ if self.ignore_unknown:
91
+ continue
92
+
93
+ raise
94
+
95
+ if self.embeds_by_unmarshal_name and (en := self.embeds_by_unmarshal_name.get(ks)):
96
+ tkw, tk = ekws[en[0]], en[1]
97
+ else:
98
+ tkw, tk = kw, fi.name
99
+
100
+ if tk in tkw:
101
+ raise KeyError(f'Duplicate keys for field {tk!r}: {ks!r}')
102
+
103
+ tkw[tk] = u.unmarshal(ctx, mv)
104
+
105
+ for em, ecls in self.embeds.items() if self.embeds else ():
106
+ ekw = ekws[em]
107
+ ev = ecls(**ekw)
108
+ kw[em] = ev
109
+
110
+ if self.defaults:
111
+ for dk, dv in self.defaults.items():
112
+ kw.setdefault(dk, dv)
113
+
114
+ return self.factory(**kw)
115
+
116
+
117
+ ##
118
+
119
+
120
+ @dc.dataclass(frozen=True)
121
+ class SimpleObjectUnmarshalerFactory(UnmarshalerFactory):
122
+ dct: ta.Mapping[type, ta.Sequence[FieldInfo]]
123
+
124
+ _: dc.KW_ONLY
125
+
126
+ specials: ObjectSpecials = ObjectSpecials()
127
+
128
+ def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
129
+ return isinstance(rty, type) and rty in self.dct
130
+
131
+ def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
132
+ ty = check.isinstance(rty, type)
133
+
134
+ fis = FieldInfos(self.dct[ty])
135
+
136
+ return ObjectUnmarshaler.make(
137
+ ctx,
138
+ ty,
139
+ fis,
140
+ specials=self.specials,
141
+ )
@@ -0,0 +1,7 @@
1
+ """
2
+ TODO:
3
+ - auto-gen from __subclasses__ if abstract
4
+ - cfg: unless prefixed with _ or abstract
5
+ - iff Sealed
6
+ - auto-name
7
+ """
@@ -0,0 +1,66 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import check
5
+ from ... import reflect as rfl
6
+ from ..base import MarshalContext
7
+ from ..base import Marshaler
8
+ from ..base import MarshalerFactory
9
+ from ..values import Value
10
+ from .metadata import FieldTypeTagging
11
+ from .metadata import Impls
12
+ from .metadata import Polymorphism
13
+ from .metadata import TypeTagging
14
+ from .metadata import WrapperTypeTagging
15
+
16
+
17
+ ##
18
+
19
+
20
+ @dc.dataclass(frozen=True)
21
+ class WrapperPolymorphismMarshaler(Marshaler):
22
+ m: ta.Mapping[type, tuple[str, Marshaler]]
23
+
24
+ def marshal(self, ctx: MarshalContext, o: ta.Any | None) -> Value:
25
+ tag, m = self.m[type(o)]
26
+ return {tag: m.marshal(ctx, o)}
27
+
28
+
29
+ @dc.dataclass(frozen=True)
30
+ class FieldPolymorphismMarshaler(Marshaler):
31
+ m: ta.Mapping[type, tuple[str, Marshaler]]
32
+ tf: str
33
+
34
+ def marshal(self, ctx: MarshalContext, o: ta.Any | None) -> Value:
35
+ tag, m = self.m[type(o)]
36
+ return {self.tf: tag, **m.marshal(ctx, o)} # type: ignore
37
+
38
+
39
+ def make_polymorphism_marshaler(
40
+ impls: Impls,
41
+ tt: TypeTagging,
42
+ ctx: MarshalContext,
43
+ ) -> Marshaler:
44
+ m = {
45
+ i.ty: (i.tag, ctx.make(i.ty))
46
+ for i in impls
47
+ }
48
+ if isinstance(tt, WrapperTypeTagging):
49
+ return WrapperPolymorphismMarshaler(m)
50
+ elif isinstance(tt, FieldTypeTagging):
51
+ return FieldPolymorphismMarshaler(m, tt.field)
52
+ else:
53
+ raise TypeError(tt)
54
+
55
+
56
+ @dc.dataclass(frozen=True)
57
+ class PolymorphismMarshalerFactory(MarshalerFactory):
58
+ p: Polymorphism
59
+ tt: TypeTagging = WrapperTypeTagging()
60
+
61
+ def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
62
+ return rty is self.p.ty
63
+
64
+ def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
65
+ check.is_(rty, self.p.ty)
66
+ return make_polymorphism_marshaler(self.p.impls, self.tt, ctx)
@@ -0,0 +1,140 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import lang
5
+ from ..naming import Naming
6
+ from ..naming import translate_name
7
+ from ..registries import RegistryItem
8
+
9
+
10
+ ##
11
+
12
+
13
+ class TypeTagging(RegistryItem, lang.Abstract, lang.Sealed):
14
+ pass
15
+
16
+
17
+ class WrapperTypeTagging(TypeTagging, lang.Final):
18
+ pass
19
+
20
+
21
+ @dc.dataclass(frozen=True)
22
+ class FieldTypeTagging(TypeTagging, lang.Final):
23
+ field: str
24
+
25
+
26
+ ##
27
+
28
+
29
+ @dc.dataclass(frozen=True)
30
+ class Impl:
31
+ ty: type
32
+ tag: str
33
+ alts: ta.AbstractSet[str] = frozenset()
34
+
35
+
36
+ class Impls(ta.Sequence[Impl]):
37
+ def __init__(
38
+ self,
39
+ lst: ta.Iterable[Impl],
40
+ ) -> None:
41
+ super().__init__()
42
+ self._lst = list(lst)
43
+
44
+ by_ty: dict[type, Impl] = {}
45
+ by_tag: dict[str, Impl] = {}
46
+ for i in self._lst:
47
+ if i.ty in by_ty:
48
+ raise TypeError(i.ty)
49
+ if i.tag in by_tag:
50
+ raise NameError(i.tag)
51
+ for a in i.alts:
52
+ if a in by_tag:
53
+ raise NameError(a)
54
+ by_ty[i.ty] = i
55
+ by_tag[i.tag] = i
56
+ for a in i.alts:
57
+ by_tag[a] = i
58
+ self._by_ty = by_ty
59
+ self._by_tag = by_tag
60
+
61
+ def __iter__(self) -> ta.Iterator[Impl]:
62
+ return iter(self._lst)
63
+
64
+ def __len__(self) -> int:
65
+ return len(self._lst)
66
+
67
+ @ta.overload
68
+ def __getitem__(self, index: int) -> Impl: ...
69
+
70
+ @ta.overload
71
+ def __getitem__(self, index: slice) -> ta.Sequence[Impl]: ...
72
+
73
+ def __getitem__(self, index):
74
+ return self._lst[index]
75
+
76
+ @property
77
+ def by_ty(self) -> ta.Mapping[type, Impl]:
78
+ return self._by_ty
79
+
80
+ @property
81
+ def by_tag(self) -> ta.Mapping[str, Impl]:
82
+ return self._by_tag
83
+
84
+
85
+ class Polymorphism:
86
+ def __init__(
87
+ self,
88
+ ty: type,
89
+ impls: ta.Iterable[Impl],
90
+ ) -> None:
91
+ super().__init__()
92
+ self._ty = ty
93
+ self._impls = Impls(impls)
94
+
95
+ for i in self._impls:
96
+ if not issubclass(i.ty, ty):
97
+ raise TypeError(i.ty, ty)
98
+
99
+ @property
100
+ def ty(self) -> type:
101
+ return self._ty
102
+
103
+ @property
104
+ def impls(self) -> Impls:
105
+ return self._impls
106
+
107
+
108
+ def polymorphism_from_subclasses(
109
+ ty: type,
110
+ *,
111
+ naming: Naming | None = None,
112
+ strip_suffix: bool = False,
113
+ ) -> Polymorphism:
114
+ dct: dict[str, Impl] = {}
115
+
116
+ seen: set[type] = set()
117
+ todo: list[type] = [ty]
118
+ while todo:
119
+ cur = todo.pop()
120
+ seen.add(cur)
121
+
122
+ todo.extend(nxt for nxt in cur.__subclasses__() if nxt not in seen)
123
+
124
+ if lang.is_abstract_class(cur):
125
+ continue
126
+
127
+ name = cur.__name__
128
+ if strip_suffix:
129
+ name = lang.strip_suffix(name, ty.__name__)
130
+ if naming is not None:
131
+ name = translate_name(name, naming)
132
+ if name in dct:
133
+ raise KeyError(f'Duplicate name: {name}')
134
+
135
+ dct[name] = Impl(
136
+ cur,
137
+ name,
138
+ )
139
+
140
+ return Polymorphism(ty, dct.values())
@@ -1,23 +1,23 @@
1
1
  import typing as ta
2
2
 
3
- from .. import cached
4
- from .. import check
5
- from .. import dataclasses as dc
6
- from .. import lang
7
- from .. import reflect as rfl
8
- from ..funcs import match as mfs
9
- from .base import MarshalContext
10
- from .base import Marshaler
11
- from .base import MarshalerFactory
12
- from .base import UnmarshalContext
13
- from .base import Unmarshaler
14
- from .base import UnmarshalerFactory
15
- from .polymorphism import Impls
16
- from .polymorphism import TypeTagging
17
- from .polymorphism import WrapperTypeTagging
18
- from .polymorphism import make_polymorphism_marshaler
19
- from .polymorphism import make_polymorphism_unmarshaler
20
- from .values import Value
3
+ from ... import cached
4
+ from ... import check
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ... import reflect as rfl
8
+ from ...funcs import match as mfs
9
+ from ..base import MarshalContext
10
+ from ..base import Marshaler
11
+ from ..base import MarshalerFactory
12
+ from ..base import UnmarshalContext
13
+ from ..base import Unmarshaler
14
+ from ..base import UnmarshalerFactory
15
+ from ..values import Value
16
+ from .marshal import make_polymorphism_marshaler
17
+ from .metadata import Impls
18
+ from .metadata import TypeTagging
19
+ from .metadata import WrapperTypeTagging
20
+ from .unmarshal import make_polymorphism_unmarshaler
21
21
 
22
22
 
23
23
  ##
@@ -0,0 +1,73 @@
1
+ import collections.abc
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+ from ... import check
6
+ from ... import reflect as rfl
7
+ from ..base import UnmarshalContext
8
+ from ..base import Unmarshaler
9
+ from ..base import UnmarshalerFactory
10
+ from ..values import Value
11
+ from .metadata import FieldTypeTagging
12
+ from .metadata import Impls
13
+ from .metadata import Polymorphism
14
+ from .metadata import TypeTagging
15
+ from .metadata import WrapperTypeTagging
16
+
17
+
18
+ ##
19
+
20
+
21
+ @dc.dataclass(frozen=True)
22
+ class WrapperPolymorphismUnmarshaler(Unmarshaler):
23
+ m: ta.Mapping[str, Unmarshaler]
24
+
25
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
26
+ ma = check.isinstance(v, collections.abc.Mapping)
27
+ [(tag, iv)] = ma.items()
28
+ u = self.m[tag]
29
+ return u.unmarshal(ctx, iv)
30
+
31
+
32
+ @dc.dataclass(frozen=True)
33
+ class FieldPolymorphismUnmarshaler(Unmarshaler):
34
+ m: ta.Mapping[str, Unmarshaler]
35
+ tf: str
36
+
37
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any | None:
38
+ ma = dict(check.isinstance(v, collections.abc.Mapping))
39
+ tag = ma.pop(self.tf)
40
+ u = self.m[tag]
41
+ return u.unmarshal(ctx, ma)
42
+
43
+
44
+ def make_polymorphism_unmarshaler(
45
+ impls: Impls,
46
+ tt: TypeTagging,
47
+ ctx: UnmarshalContext,
48
+ ) -> Unmarshaler:
49
+ m = {
50
+ t: u
51
+ for i in impls
52
+ for u in [ctx.make(i.ty)]
53
+ for t in [i.tag, *i.alts]
54
+ }
55
+ if isinstance(tt, WrapperTypeTagging):
56
+ return WrapperPolymorphismUnmarshaler(m)
57
+ elif isinstance(tt, FieldTypeTagging):
58
+ return FieldPolymorphismUnmarshaler(m, tt.field)
59
+ else:
60
+ raise TypeError(tt)
61
+
62
+
63
+ @dc.dataclass(frozen=True)
64
+ class PolymorphismUnmarshalerFactory(UnmarshalerFactory):
65
+ p: Polymorphism
66
+ tt: TypeTagging = WrapperTypeTagging()
67
+
68
+ def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
69
+ return rty is self.p.ty
70
+
71
+ def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
72
+ check.is_(rty, self.p.ty)
73
+ return make_polymorphism_unmarshaler(self.p.impls, self.tt, ctx)
File without changes
@@ -1,13 +1,13 @@
1
1
  import typing as ta
2
2
 
3
- from .. import reflect as rfl
4
- from .base import MarshalContext
5
- from .base import Marshaler
6
- from .base import TypeMapMarshalerFactory
7
- from .base import TypeMapUnmarshalerFactory
8
- from .base import UnmarshalContext
9
- from .base import Unmarshaler
10
- from .values import Value
3
+ from ... import reflect as rfl
4
+ from ..base import MarshalContext
5
+ from ..base import Marshaler
6
+ from ..base import TypeMapMarshalerFactory
7
+ from ..base import TypeMapUnmarshalerFactory
8
+ from ..base import UnmarshalContext
9
+ from ..base import Unmarshaler
10
+ from ..values import Value
11
11
 
12
12
 
13
13
  class AnyMarshalerUnmarshaler(Marshaler, Unmarshaler):
@@ -5,15 +5,15 @@ FIXME:
5
5
  import base64
6
6
  import typing as ta
7
7
 
8
- from .. import check
9
- from .. import dataclasses as dc
10
- from .base import MarshalContext
11
- from .base import Marshaler
12
- from .base import TypeMapMarshalerFactory
13
- from .base import TypeMapUnmarshalerFactory
14
- from .base import UnmarshalContext
15
- from .base import Unmarshaler
16
- from .values import Value
8
+ from ... import check
9
+ from ... import dataclasses as dc
10
+ from ..base import MarshalContext
11
+ from ..base import Marshaler
12
+ from ..base import TypeMapMarshalerFactory
13
+ from ..base import TypeMapUnmarshalerFactory
14
+ from ..base import UnmarshalContext
15
+ from ..base import Unmarshaler
16
+ from ..values import Value
17
17
 
18
18
 
19
19
  T = ta.TypeVar('T')