omdev 0.0.0.dev420__py3-none-any.whl → 0.0.0.dev422__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.
- omdev/cache/compute/storage.py +3 -1
- omdev/ci/cache.py +3 -2
- omdev/ci/docker/buildcaching.py +3 -1
- omdev/ci/docker/cache.py +2 -1
- omdev/ci/docker/cacheserved/manifests.py +2 -2
- omdev/ci/docker/imagepulling.py +2 -1
- omdev/ci/docker/repositories.py +2 -1
- omdev/ci/github/api/clients.py +4 -3
- omdev/clipboard/clipboard.py +1 -1
- omdev/cmake.py +2 -1
- omdev/dataserver/handlers.py +3 -2
- omdev/dataserver/targets.py +2 -2
- omdev/interp/providers/base.py +3 -2
- omdev/interp/pyenv/install.py +2 -1
- omdev/manifests/_dumping.py +427 -127
- omdev/oci/data.py +2 -2
- omdev/oci/datarefs.py +2 -2
- omdev/oci/media.py +2 -2
- omdev/oci/repositories.py +3 -2
- omdev/pyproject/pkg.py +2 -1
- omdev/scripts/ci.py +3969 -3667
- omdev/scripts/interp.py +1000 -896
- omdev/scripts/pyproject.py +2384 -2085
- omdev/tools/git/messages.py +2 -2
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/RECORD +30 -30
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev420.dist-info → omdev-0.0.0.dev422.dist-info}/top_level.txt +0 -0
omdev/manifests/_dumping.py
CHANGED
@@ -50,6 +50,126 @@ CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
|
50
50
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
51
51
|
|
52
52
|
|
53
|
+
########################################
|
54
|
+
# ../../../omlish/lite/abstract.py
|
55
|
+
|
56
|
+
|
57
|
+
##
|
58
|
+
|
59
|
+
|
60
|
+
_ABSTRACT_METHODS_ATTR = '__abstractmethods__'
|
61
|
+
_IS_ABSTRACT_METHOD_ATTR = '__isabstractmethod__'
|
62
|
+
|
63
|
+
|
64
|
+
def is_abstract_method(obj: ta.Any) -> bool:
|
65
|
+
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
66
|
+
|
67
|
+
|
68
|
+
def update_abstracts(cls, *, force=False):
|
69
|
+
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
70
|
+
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
71
|
+
# implementation (especially during testing), and we want to handle both cases.
|
72
|
+
return cls
|
73
|
+
|
74
|
+
abstracts: ta.Set[str] = set()
|
75
|
+
|
76
|
+
for scls in cls.__bases__:
|
77
|
+
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
78
|
+
value = getattr(cls, name, None)
|
79
|
+
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
80
|
+
abstracts.add(name)
|
81
|
+
|
82
|
+
for name, value in cls.__dict__.items():
|
83
|
+
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
84
|
+
abstracts.add(name)
|
85
|
+
|
86
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
87
|
+
return cls
|
88
|
+
|
89
|
+
|
90
|
+
#
|
91
|
+
|
92
|
+
|
93
|
+
class AbstractTypeError(TypeError):
|
94
|
+
pass
|
95
|
+
|
96
|
+
|
97
|
+
_FORCE_ABSTRACT_ATTR = '__forceabstract__'
|
98
|
+
|
99
|
+
|
100
|
+
class Abstract:
|
101
|
+
"""
|
102
|
+
Different from, but interoperable with, abc.ABC / abc.ABCMeta:
|
103
|
+
|
104
|
+
- This raises AbstractTypeError during class creation, not instance instantiation - unless Abstract or abc.ABC are
|
105
|
+
explicitly present in the class's direct bases.
|
106
|
+
- This will forbid instantiation of classes with Abstract in their direct bases even if there are no
|
107
|
+
abstractmethods left on the class.
|
108
|
+
- This is a mixin, not a metaclass.
|
109
|
+
- As it is not an ABCMeta, this does not support virtual base classes. As a result, operations like `isinstance`
|
110
|
+
and `issubclass` are ~7x faster.
|
111
|
+
- It additionally enforces a base class order of (Abstract, abc.ABC) to preemptively prevent common mro conflicts.
|
112
|
+
|
113
|
+
If not mixed-in with an ABCMeta, it will update __abstractmethods__ itself.
|
114
|
+
"""
|
115
|
+
|
116
|
+
__slots__ = ()
|
117
|
+
|
118
|
+
__abstractmethods__: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
|
119
|
+
|
120
|
+
#
|
121
|
+
|
122
|
+
def __forceabstract__(self):
|
123
|
+
raise TypeError
|
124
|
+
|
125
|
+
# This is done manually, rather than through @abc.abstractmethod, to mask it from static analysis.
|
126
|
+
setattr(__forceabstract__, _IS_ABSTRACT_METHOD_ATTR, True)
|
127
|
+
|
128
|
+
#
|
129
|
+
|
130
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
131
|
+
setattr(
|
132
|
+
cls,
|
133
|
+
_FORCE_ABSTRACT_ATTR,
|
134
|
+
getattr(Abstract, _FORCE_ABSTRACT_ATTR) if Abstract in cls.__bases__ else False,
|
135
|
+
)
|
136
|
+
|
137
|
+
super().__init_subclass__(**kwargs)
|
138
|
+
|
139
|
+
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
140
|
+
ams = {a: cls for a, o in cls.__dict__.items() if is_abstract_method(o)}
|
141
|
+
|
142
|
+
seen = set(cls.__dict__)
|
143
|
+
for b in cls.__bases__:
|
144
|
+
ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
|
145
|
+
seen.update(dir(b))
|
146
|
+
|
147
|
+
if ams:
|
148
|
+
raise AbstractTypeError(
|
149
|
+
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
150
|
+
', '.join(sorted([
|
151
|
+
'.'.join([
|
152
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
153
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
154
|
+
a,
|
155
|
+
])
|
156
|
+
for a, c in ams.items()
|
157
|
+
])),
|
158
|
+
)
|
159
|
+
|
160
|
+
xbi = (Abstract, abc.ABC) # , ta.Generic ?
|
161
|
+
bis = [(cls.__bases__.index(b), b) for b in xbi if b in cls.__bases__]
|
162
|
+
if bis != sorted(bis):
|
163
|
+
raise TypeError(
|
164
|
+
f'Abstract subclass {cls.__name__} must have proper base class order of '
|
165
|
+
f'({", ".join(getattr(b, "__name__") for b in xbi)}), got: '
|
166
|
+
f'({", ".join(getattr(b, "__name__") for _, b in sorted(bis))})',
|
167
|
+
)
|
168
|
+
|
169
|
+
if not isinstance(cls, abc.ABCMeta):
|
170
|
+
update_abstracts(cls, force=True)
|
171
|
+
|
172
|
+
|
53
173
|
########################################
|
54
174
|
# ../../../omlish/lite/cached.py
|
55
175
|
|
@@ -598,6 +718,86 @@ class Checks:
|
|
598
718
|
check = Checks()
|
599
719
|
|
600
720
|
|
721
|
+
########################################
|
722
|
+
# ../../../omlish/lite/objects.py
|
723
|
+
|
724
|
+
|
725
|
+
##
|
726
|
+
|
727
|
+
|
728
|
+
def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
729
|
+
seen = set()
|
730
|
+
todo = list(reversed(cls.__subclasses__()))
|
731
|
+
while todo:
|
732
|
+
cur = todo.pop()
|
733
|
+
if cur in seen:
|
734
|
+
continue
|
735
|
+
seen.add(cur)
|
736
|
+
yield cur
|
737
|
+
todo.extend(reversed(cur.__subclasses__()))
|
738
|
+
|
739
|
+
|
740
|
+
##
|
741
|
+
|
742
|
+
|
743
|
+
def mro_owner_dict(
|
744
|
+
instance_cls: type,
|
745
|
+
owner_cls: ta.Optional[type] = None,
|
746
|
+
*,
|
747
|
+
bottom_up_key_order: bool = False,
|
748
|
+
sort_keys: bool = False,
|
749
|
+
) -> ta.Mapping[str, ta.Tuple[type, ta.Any]]:
|
750
|
+
if owner_cls is None:
|
751
|
+
owner_cls = instance_cls
|
752
|
+
|
753
|
+
mro = instance_cls.__mro__[-2::-1]
|
754
|
+
try:
|
755
|
+
pos = mro.index(owner_cls)
|
756
|
+
except ValueError:
|
757
|
+
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
758
|
+
|
759
|
+
dct: ta.Dict[str, ta.Tuple[type, ta.Any]] = {}
|
760
|
+
if not bottom_up_key_order:
|
761
|
+
for cur_cls in mro[:pos + 1][::-1]:
|
762
|
+
for k, v in cur_cls.__dict__.items():
|
763
|
+
if k not in dct:
|
764
|
+
dct[k] = (cur_cls, v)
|
765
|
+
|
766
|
+
else:
|
767
|
+
for cur_cls in mro[:pos + 1]:
|
768
|
+
dct.update({k: (cur_cls, v) for k, v in cur_cls.__dict__.items()})
|
769
|
+
|
770
|
+
if sort_keys:
|
771
|
+
dct = dict(sorted(dct.items(), key=lambda t: t[0]))
|
772
|
+
|
773
|
+
return dct
|
774
|
+
|
775
|
+
|
776
|
+
def mro_dict(
|
777
|
+
instance_cls: type,
|
778
|
+
owner_cls: ta.Optional[type] = None,
|
779
|
+
*,
|
780
|
+
bottom_up_key_order: bool = False,
|
781
|
+
sort_keys: bool = False,
|
782
|
+
) -> ta.Mapping[str, ta.Any]:
|
783
|
+
return {
|
784
|
+
k: v
|
785
|
+
for k, (o, v) in mro_owner_dict(
|
786
|
+
instance_cls,
|
787
|
+
owner_cls,
|
788
|
+
bottom_up_key_order=bottom_up_key_order,
|
789
|
+
sort_keys=sort_keys,
|
790
|
+
).items()
|
791
|
+
}
|
792
|
+
|
793
|
+
|
794
|
+
def dir_dict(o: ta.Any) -> ta.Dict[str, ta.Any]:
|
795
|
+
return {
|
796
|
+
a: getattr(o, a)
|
797
|
+
for a in dir(o)
|
798
|
+
}
|
799
|
+
|
800
|
+
|
601
801
|
########################################
|
602
802
|
# ../../../omlish/lite/reflect.py
|
603
803
|
|
@@ -687,21 +887,6 @@ def get_literal_type_args(spec: ta.Any) -> ta.Iterable[ta.Any]:
|
|
687
887
|
return spec.__args__
|
688
888
|
|
689
889
|
|
690
|
-
##
|
691
|
-
|
692
|
-
|
693
|
-
def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
694
|
-
seen = set()
|
695
|
-
todo = list(reversed(cls.__subclasses__()))
|
696
|
-
while todo:
|
697
|
-
cur = todo.pop()
|
698
|
-
if cur in seen:
|
699
|
-
continue
|
700
|
-
seen.add(cur)
|
701
|
-
yield cur
|
702
|
-
todo.extend(reversed(cur.__subclasses__()))
|
703
|
-
|
704
|
-
|
705
890
|
########################################
|
706
891
|
# ../../../omlish/lite/strings.py
|
707
892
|
|
@@ -818,7 +1003,7 @@ class ObjMarshalOptions:
|
|
818
1003
|
non_strict_fields: bool = False
|
819
1004
|
|
820
1005
|
|
821
|
-
class ObjMarshaler(
|
1006
|
+
class ObjMarshaler(Abstract):
|
822
1007
|
@abc.abstractmethod
|
823
1008
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
824
1009
|
raise NotImplementedError
|
@@ -836,26 +1021,30 @@ class NopObjMarshaler(ObjMarshaler):
|
|
836
1021
|
return o
|
837
1022
|
|
838
1023
|
|
839
|
-
@dc.dataclass()
|
840
1024
|
class ProxyObjMarshaler(ObjMarshaler):
|
841
|
-
m: ta.Optional[ObjMarshaler] = None
|
1025
|
+
def __init__(self, m: ta.Optional[ObjMarshaler] = None) -> None:
|
1026
|
+
super().__init__()
|
1027
|
+
|
1028
|
+
self._m = m
|
842
1029
|
|
843
1030
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
844
|
-
return check.not_none(self.
|
1031
|
+
return check.not_none(self._m).marshal(o, ctx)
|
845
1032
|
|
846
1033
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
847
|
-
return check.not_none(self.
|
1034
|
+
return check.not_none(self._m).unmarshal(o, ctx)
|
848
1035
|
|
849
1036
|
|
850
|
-
@dc.dataclass(frozen=True)
|
851
1037
|
class CastObjMarshaler(ObjMarshaler):
|
852
|
-
ty: type
|
1038
|
+
def __init__(self, ty: type) -> None:
|
1039
|
+
super().__init__()
|
1040
|
+
|
1041
|
+
self._ty = ty
|
853
1042
|
|
854
1043
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
855
1044
|
return o
|
856
1045
|
|
857
1046
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
858
|
-
return self.
|
1047
|
+
return self._ty(o)
|
859
1048
|
|
860
1049
|
|
861
1050
|
class DynamicObjMarshaler(ObjMarshaler):
|
@@ -866,121 +1055,151 @@ class DynamicObjMarshaler(ObjMarshaler):
|
|
866
1055
|
return o
|
867
1056
|
|
868
1057
|
|
869
|
-
@dc.dataclass(frozen=True)
|
870
1058
|
class Base64ObjMarshaler(ObjMarshaler):
|
871
|
-
ty: type
|
1059
|
+
def __init__(self, ty: type) -> None:
|
1060
|
+
super().__init__()
|
1061
|
+
|
1062
|
+
self._ty = ty
|
872
1063
|
|
873
1064
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
874
1065
|
return base64.b64encode(o).decode('ascii')
|
875
1066
|
|
876
1067
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
877
|
-
return self.
|
1068
|
+
return self._ty(base64.b64decode(o))
|
878
1069
|
|
879
1070
|
|
880
|
-
@dc.dataclass(frozen=True)
|
881
1071
|
class BytesSwitchedObjMarshaler(ObjMarshaler):
|
882
|
-
m: ObjMarshaler
|
1072
|
+
def __init__(self, m: ObjMarshaler) -> None:
|
1073
|
+
super().__init__()
|
1074
|
+
|
1075
|
+
self._m = m
|
883
1076
|
|
884
1077
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
885
1078
|
if ctx.options.raw_bytes:
|
886
1079
|
return o
|
887
|
-
return self.
|
1080
|
+
return self._m.marshal(o, ctx)
|
888
1081
|
|
889
1082
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
890
1083
|
if ctx.options.raw_bytes:
|
891
1084
|
return o
|
892
|
-
return self.
|
1085
|
+
return self._m.unmarshal(o, ctx)
|
893
1086
|
|
894
1087
|
|
895
|
-
@dc.dataclass(frozen=True)
|
896
1088
|
class EnumObjMarshaler(ObjMarshaler):
|
897
|
-
ty: type
|
1089
|
+
def __init__(self, ty: type) -> None:
|
1090
|
+
super().__init__()
|
1091
|
+
|
1092
|
+
self._ty = ty
|
898
1093
|
|
899
1094
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
900
1095
|
return o.name
|
901
1096
|
|
902
1097
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
903
|
-
return self.
|
1098
|
+
return self._ty.__members__[o] # type: ignore
|
904
1099
|
|
905
1100
|
|
906
|
-
@dc.dataclass(frozen=True)
|
907
1101
|
class OptionalObjMarshaler(ObjMarshaler):
|
908
|
-
item: ObjMarshaler
|
1102
|
+
def __init__(self, item: ObjMarshaler) -> None:
|
1103
|
+
super().__init__()
|
1104
|
+
|
1105
|
+
self._item = item
|
909
1106
|
|
910
1107
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
911
1108
|
if o is None:
|
912
1109
|
return None
|
913
|
-
return self.
|
1110
|
+
return self._item.marshal(o, ctx)
|
914
1111
|
|
915
1112
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
916
1113
|
if o is None:
|
917
1114
|
return None
|
918
|
-
return self.
|
1115
|
+
return self._item.unmarshal(o, ctx)
|
919
1116
|
|
920
1117
|
|
921
|
-
@dc.dataclass(frozen=True)
|
922
1118
|
class PrimitiveUnionObjMarshaler(ObjMarshaler):
|
923
|
-
|
924
|
-
|
1119
|
+
def __init__(
|
1120
|
+
self,
|
1121
|
+
pt: ta.Tuple[type, ...],
|
1122
|
+
x: ta.Optional[ObjMarshaler] = None,
|
1123
|
+
) -> None:
|
1124
|
+
super().__init__()
|
1125
|
+
|
1126
|
+
self._pt = pt
|
1127
|
+
self._x = x
|
925
1128
|
|
926
1129
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
927
|
-
if isinstance(o, self.
|
1130
|
+
if isinstance(o, self._pt):
|
928
1131
|
return o
|
929
|
-
elif self.
|
930
|
-
return self.
|
1132
|
+
elif self._x is not None:
|
1133
|
+
return self._x.marshal(o, ctx)
|
931
1134
|
else:
|
932
1135
|
raise TypeError(o)
|
933
1136
|
|
934
1137
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
935
|
-
if isinstance(o, self.
|
1138
|
+
if isinstance(o, self._pt):
|
936
1139
|
return o
|
937
|
-
elif self.
|
938
|
-
return self.
|
1140
|
+
elif self._x is not None:
|
1141
|
+
return self._x.unmarshal(o, ctx)
|
939
1142
|
else:
|
940
1143
|
raise TypeError(o)
|
941
1144
|
|
942
1145
|
|
943
|
-
@dc.dataclass(frozen=True)
|
944
1146
|
class LiteralObjMarshaler(ObjMarshaler):
|
945
|
-
|
946
|
-
|
1147
|
+
def __init__(
|
1148
|
+
self,
|
1149
|
+
item: ObjMarshaler,
|
1150
|
+
vs: frozenset,
|
1151
|
+
) -> None:
|
1152
|
+
super().__init__()
|
1153
|
+
|
1154
|
+
self._item = item
|
1155
|
+
self._vs = vs
|
947
1156
|
|
948
1157
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
949
|
-
return self.
|
1158
|
+
return self._item.marshal(check.in_(o, self._vs), ctx)
|
950
1159
|
|
951
1160
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
952
|
-
return check.in_(self.
|
1161
|
+
return check.in_(self._item.unmarshal(o, ctx), self._vs)
|
953
1162
|
|
954
1163
|
|
955
|
-
@dc.dataclass(frozen=True)
|
956
1164
|
class MappingObjMarshaler(ObjMarshaler):
|
957
|
-
|
958
|
-
|
959
|
-
|
1165
|
+
def __init__(
|
1166
|
+
self,
|
1167
|
+
ty: type,
|
1168
|
+
km: ObjMarshaler,
|
1169
|
+
vm: ObjMarshaler,
|
1170
|
+
) -> None:
|
1171
|
+
super().__init__()
|
1172
|
+
|
1173
|
+
self._ty = ty
|
1174
|
+
self._km = km
|
1175
|
+
self._vm = vm
|
960
1176
|
|
961
1177
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
962
|
-
return {self.
|
1178
|
+
return {self._km.marshal(k, ctx): self._vm.marshal(v, ctx) for k, v in o.items()}
|
963
1179
|
|
964
1180
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
965
|
-
return self.
|
1181
|
+
return self._ty((self._km.unmarshal(k, ctx), self._vm.unmarshal(v, ctx)) for k, v in o.items())
|
966
1182
|
|
967
1183
|
|
968
|
-
@dc.dataclass(frozen=True)
|
969
1184
|
class IterableObjMarshaler(ObjMarshaler):
|
970
|
-
|
971
|
-
|
1185
|
+
def __init__(
|
1186
|
+
self,
|
1187
|
+
ty: type,
|
1188
|
+
item: ObjMarshaler,
|
1189
|
+
) -> None:
|
1190
|
+
super().__init__()
|
1191
|
+
|
1192
|
+
self._ty = ty
|
1193
|
+
self._item = item
|
972
1194
|
|
973
1195
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
974
|
-
return [self.
|
1196
|
+
return [self._item.marshal(e, ctx) for e in o]
|
975
1197
|
|
976
1198
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
977
|
-
return self.
|
1199
|
+
return self._ty(self._item.unmarshal(e, ctx) for e in o)
|
978
1200
|
|
979
1201
|
|
980
|
-
@dc.dataclass(frozen=True)
|
981
1202
|
class FieldsObjMarshaler(ObjMarshaler):
|
982
|
-
ty: type
|
983
|
-
|
984
1203
|
@dc.dataclass(frozen=True)
|
985
1204
|
class Field:
|
986
1205
|
att: str
|
@@ -989,31 +1208,43 @@ class FieldsObjMarshaler(ObjMarshaler):
|
|
989
1208
|
|
990
1209
|
omit_if_none: bool = False
|
991
1210
|
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
1211
|
+
def __init__(
|
1212
|
+
self,
|
1213
|
+
ty: type,
|
1214
|
+
fs: ta.Sequence[Field],
|
1215
|
+
*,
|
1216
|
+
non_strict: bool = False,
|
1217
|
+
) -> None:
|
1218
|
+
super().__init__()
|
997
1219
|
|
998
|
-
|
999
|
-
|
1220
|
+
self._ty = ty
|
1221
|
+
self._fs = fs
|
1222
|
+
self._non_strict = non_strict
|
1000
1223
|
|
1001
|
-
def __post_init__(self) -> None:
|
1002
1224
|
fs_by_att: dict = {}
|
1003
1225
|
fs_by_key: dict = {}
|
1004
|
-
for f in self.
|
1226
|
+
for f in self._fs:
|
1005
1227
|
check.not_in(check.non_empty_str(f.att), fs_by_att)
|
1006
1228
|
check.not_in(check.non_empty_str(f.key), fs_by_key)
|
1007
1229
|
fs_by_att[f.att] = f
|
1008
1230
|
fs_by_key[f.key] = f
|
1009
|
-
|
1010
|
-
self.
|
1231
|
+
|
1232
|
+
self._fs_by_att: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_att
|
1233
|
+
self._fs_by_key: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_key
|
1234
|
+
|
1235
|
+
@property
|
1236
|
+
def ty(self) -> type:
|
1237
|
+
return self._ty
|
1238
|
+
|
1239
|
+
@property
|
1240
|
+
def fs(self) -> ta.Sequence[Field]:
|
1241
|
+
return self._fs
|
1011
1242
|
|
1012
1243
|
#
|
1013
1244
|
|
1014
1245
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1015
1246
|
d = {}
|
1016
|
-
for f in self.
|
1247
|
+
for f in self._fs:
|
1017
1248
|
mv = f.m.marshal(getattr(o, f.att), ctx)
|
1018
1249
|
if mv is None and f.omit_if_none:
|
1019
1250
|
continue
|
@@ -1024,34 +1255,46 @@ class FieldsObjMarshaler(ObjMarshaler):
|
|
1024
1255
|
kw = {}
|
1025
1256
|
for k, v in o.items():
|
1026
1257
|
if (f := self._fs_by_key.get(k)) is None:
|
1027
|
-
if not (self.
|
1258
|
+
if not (self._non_strict or ctx.options.non_strict_fields):
|
1028
1259
|
raise KeyError(k)
|
1029
1260
|
continue
|
1030
1261
|
kw[f.att] = f.m.unmarshal(v, ctx)
|
1031
|
-
return self.
|
1262
|
+
return self._ty(**kw)
|
1032
1263
|
|
1033
1264
|
|
1034
|
-
@dc.dataclass(frozen=True)
|
1035
1265
|
class SingleFieldObjMarshaler(ObjMarshaler):
|
1036
|
-
|
1037
|
-
|
1266
|
+
def __init__(
|
1267
|
+
self,
|
1268
|
+
ty: type,
|
1269
|
+
fld: str,
|
1270
|
+
) -> None:
|
1271
|
+
super().__init__()
|
1272
|
+
|
1273
|
+
self._ty = ty
|
1274
|
+
self._fld = fld
|
1038
1275
|
|
1039
1276
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1040
|
-
return getattr(o, self.
|
1277
|
+
return getattr(o, self._fld)
|
1041
1278
|
|
1042
1279
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1043
|
-
return self.
|
1280
|
+
return self._ty(**{self._fld: o})
|
1044
1281
|
|
1045
1282
|
|
1046
|
-
@dc.dataclass(frozen=True)
|
1047
1283
|
class PolymorphicObjMarshaler(ObjMarshaler):
|
1048
1284
|
class Impl(ta.NamedTuple):
|
1049
1285
|
ty: type
|
1050
1286
|
tag: str
|
1051
1287
|
m: ObjMarshaler
|
1052
1288
|
|
1053
|
-
|
1054
|
-
|
1289
|
+
def __init__(
|
1290
|
+
self,
|
1291
|
+
impls_by_ty: ta.Mapping[type, Impl],
|
1292
|
+
impls_by_tag: ta.Mapping[str, Impl],
|
1293
|
+
) -> None:
|
1294
|
+
super().__init__()
|
1295
|
+
|
1296
|
+
self._impls_by_ty = impls_by_ty
|
1297
|
+
self._impls_by_tag = impls_by_tag
|
1055
1298
|
|
1056
1299
|
@classmethod
|
1057
1300
|
def of(cls, impls: ta.Iterable[Impl]) -> 'PolymorphicObjMarshaler':
|
@@ -1061,24 +1304,29 @@ class PolymorphicObjMarshaler(ObjMarshaler):
|
|
1061
1304
|
)
|
1062
1305
|
|
1063
1306
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1064
|
-
impl = self.
|
1307
|
+
impl = self._impls_by_ty[type(o)]
|
1065
1308
|
return {impl.tag: impl.m.marshal(o, ctx)}
|
1066
1309
|
|
1067
1310
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1068
1311
|
[(t, v)] = o.items()
|
1069
|
-
impl = self.
|
1312
|
+
impl = self._impls_by_tag[t]
|
1070
1313
|
return impl.m.unmarshal(v, ctx)
|
1071
1314
|
|
1072
1315
|
|
1073
|
-
@dc.dataclass(frozen=True)
|
1074
1316
|
class DatetimeObjMarshaler(ObjMarshaler):
|
1075
|
-
|
1317
|
+
def __init__(
|
1318
|
+
self,
|
1319
|
+
ty: type,
|
1320
|
+
) -> None:
|
1321
|
+
super().__init__()
|
1322
|
+
|
1323
|
+
self._ty = ty
|
1076
1324
|
|
1077
1325
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1078
1326
|
return o.isoformat()
|
1079
1327
|
|
1080
1328
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
1081
|
-
return self.
|
1329
|
+
return self._ty.fromisoformat(o) # type: ignore
|
1082
1330
|
|
1083
1331
|
|
1084
1332
|
class DecimalObjMarshaler(ObjMarshaler):
|
@@ -1186,7 +1434,78 @@ class OBJ_MARSHALER_OMIT_IF_NONE(ObjMarshalerFieldMetadata): # noqa
|
|
1186
1434
|
##
|
1187
1435
|
|
1188
1436
|
|
1189
|
-
class ObjMarshalerManager:
|
1437
|
+
class ObjMarshalerManager(Abstract):
|
1438
|
+
@abc.abstractmethod
|
1439
|
+
def make_obj_marshaler(
|
1440
|
+
self,
|
1441
|
+
ty: ta.Any,
|
1442
|
+
rec: ta.Callable[[ta.Any], ObjMarshaler],
|
1443
|
+
*,
|
1444
|
+
non_strict_fields: bool = False,
|
1445
|
+
) -> ObjMarshaler:
|
1446
|
+
raise NotImplementedError
|
1447
|
+
|
1448
|
+
@abc.abstractmethod
|
1449
|
+
def set_obj_marshaler(
|
1450
|
+
self,
|
1451
|
+
ty: ta.Any,
|
1452
|
+
m: ObjMarshaler,
|
1453
|
+
*,
|
1454
|
+
override: bool = False,
|
1455
|
+
) -> None:
|
1456
|
+
raise NotImplementedError
|
1457
|
+
|
1458
|
+
@abc.abstractmethod
|
1459
|
+
def get_obj_marshaler(
|
1460
|
+
self,
|
1461
|
+
ty: ta.Any,
|
1462
|
+
*,
|
1463
|
+
no_cache: bool = False,
|
1464
|
+
**kwargs: ta.Any,
|
1465
|
+
) -> ObjMarshaler:
|
1466
|
+
raise NotImplementedError
|
1467
|
+
|
1468
|
+
@abc.abstractmethod
|
1469
|
+
def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
1470
|
+
raise NotImplementedError
|
1471
|
+
|
1472
|
+
#
|
1473
|
+
|
1474
|
+
def marshal_obj(
|
1475
|
+
self,
|
1476
|
+
o: ta.Any,
|
1477
|
+
ty: ta.Any = None,
|
1478
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
1479
|
+
) -> ta.Any:
|
1480
|
+
m = self.get_obj_marshaler(ty if ty is not None else type(o))
|
1481
|
+
return m.marshal(o, self.make_context(opts))
|
1482
|
+
|
1483
|
+
def unmarshal_obj(
|
1484
|
+
self,
|
1485
|
+
o: ta.Any,
|
1486
|
+
ty: ta.Union[ta.Type[T], ta.Any],
|
1487
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
1488
|
+
) -> T:
|
1489
|
+
m = self.get_obj_marshaler(ty)
|
1490
|
+
return m.unmarshal(o, self.make_context(opts))
|
1491
|
+
|
1492
|
+
def roundtrip_obj(
|
1493
|
+
self,
|
1494
|
+
o: ta.Any,
|
1495
|
+
ty: ta.Any = None,
|
1496
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
1497
|
+
) -> ta.Any:
|
1498
|
+
if ty is None:
|
1499
|
+
ty = type(o)
|
1500
|
+
m: ta.Any = self.marshal_obj(o, ty, opts)
|
1501
|
+
u: ta.Any = self.unmarshal_obj(m, ty, opts)
|
1502
|
+
return u
|
1503
|
+
|
1504
|
+
|
1505
|
+
#
|
1506
|
+
|
1507
|
+
|
1508
|
+
class ObjMarshalerManagerImpl(ObjMarshalerManager):
|
1190
1509
|
def __init__(
|
1191
1510
|
self,
|
1192
1511
|
*,
|
@@ -1213,6 +1532,12 @@ class ObjMarshalerManager:
|
|
1213
1532
|
|
1214
1533
|
#
|
1215
1534
|
|
1535
|
+
@classmethod
|
1536
|
+
def _is_abstract(cls, ty: type) -> bool:
|
1537
|
+
return abc.ABC in ty.__bases__ or Abstract in ty.__bases__
|
1538
|
+
|
1539
|
+
#
|
1540
|
+
|
1216
1541
|
def make_obj_marshaler(
|
1217
1542
|
self,
|
1218
1543
|
ty: ta.Any,
|
@@ -1224,12 +1549,12 @@ class ObjMarshalerManager:
|
|
1224
1549
|
if (reg := self._registered_obj_marshalers.get(ty)) is not None:
|
1225
1550
|
return reg
|
1226
1551
|
|
1227
|
-
if
|
1552
|
+
if self._is_abstract(ty):
|
1228
1553
|
tn = ty.__name__
|
1229
1554
|
impls: ta.List[ta.Tuple[type, str]] = [ # type: ignore[var-annotated]
|
1230
1555
|
(ity, ity.__name__)
|
1231
1556
|
for ity in deep_subclasses(ty)
|
1232
|
-
if
|
1557
|
+
if not self._is_abstract(ity)
|
1233
1558
|
]
|
1234
1559
|
|
1235
1560
|
if all(itn.endswith(tn) for _, itn in impls):
|
@@ -1395,49 +1720,24 @@ class ObjMarshalerManager:
|
|
1395
1720
|
m = self.make_obj_marshaler(ty, rec, **kwargs)
|
1396
1721
|
finally:
|
1397
1722
|
del self._proxies[ty]
|
1398
|
-
p.
|
1723
|
+
p._m = m # noqa
|
1399
1724
|
|
1400
1725
|
if not no_cache:
|
1401
1726
|
self._obj_marshalers[ty] = m
|
1402
1727
|
return m
|
1403
1728
|
|
1404
|
-
|
1405
|
-
|
1406
|
-
def _make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
1729
|
+
def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
1407
1730
|
return ObjMarshalContext(
|
1408
1731
|
options=opts or self._default_options,
|
1409
1732
|
manager=self,
|
1410
1733
|
)
|
1411
1734
|
|
1412
|
-
def marshal_obj(
|
1413
|
-
self,
|
1414
|
-
o: ta.Any,
|
1415
|
-
ty: ta.Any = None,
|
1416
|
-
opts: ta.Optional[ObjMarshalOptions] = None,
|
1417
|
-
) -> ta.Any:
|
1418
|
-
m = self.get_obj_marshaler(ty if ty is not None else type(o))
|
1419
|
-
return m.marshal(o, self._make_context(opts))
|
1420
1735
|
|
1421
|
-
|
1422
|
-
|
1423
|
-
o: ta.Any,
|
1424
|
-
ty: ta.Union[ta.Type[T], ta.Any],
|
1425
|
-
opts: ta.Optional[ObjMarshalOptions] = None,
|
1426
|
-
) -> T:
|
1427
|
-
m = self.get_obj_marshaler(ty)
|
1428
|
-
return m.unmarshal(o, self._make_context(opts))
|
1736
|
+
def new_obj_marshaler_manager(**kwargs: ta.Any) -> ObjMarshalerManager:
|
1737
|
+
return ObjMarshalerManagerImpl(**kwargs)
|
1429
1738
|
|
1430
|
-
|
1431
|
-
|
1432
|
-
o: ta.Any,
|
1433
|
-
ty: ta.Any = None,
|
1434
|
-
opts: ta.Optional[ObjMarshalOptions] = None,
|
1435
|
-
) -> ta.Any:
|
1436
|
-
if ty is None:
|
1437
|
-
ty = type(o)
|
1438
|
-
m: ta.Any = self.marshal_obj(o, ty, opts)
|
1439
|
-
u: ta.Any = self.unmarshal_obj(m, ty, opts)
|
1440
|
-
return u
|
1739
|
+
|
1740
|
+
##
|
1441
1741
|
|
1442
1742
|
|
1443
1743
|
@dc.dataclass(frozen=True)
|
@@ -1449,7 +1749,7 @@ class ObjMarshalContext:
|
|
1449
1749
|
##
|
1450
1750
|
|
1451
1751
|
|
1452
|
-
OBJ_MARSHALER_MANAGER =
|
1752
|
+
OBJ_MARSHALER_MANAGER = new_obj_marshaler_manager()
|
1453
1753
|
|
1454
1754
|
set_obj_marshaler = OBJ_MARSHALER_MANAGER.set_obj_marshaler
|
1455
1755
|
get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
|