ominfra 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.
Files changed (42) hide show
  1. ominfra/clouds/aws/models/base.py +1 -2
  2. ominfra/clouds/aws/models/services/ec2.py +45 -0
  3. ominfra/clouds/aws/models/services/rds.py +10 -0
  4. ominfra/manage/commands/base.py +5 -4
  5. ominfra/manage/deploy/conf/specs.py +2 -2
  6. ominfra/manage/deploy/paths/owners.py +3 -2
  7. ominfra/manage/deploy/paths/paths.py +4 -3
  8. ominfra/manage/deploy/tags.py +8 -8
  9. ominfra/manage/inject.py +2 -1
  10. ominfra/manage/remote/channel.py +2 -1
  11. ominfra/manage/remote/execution.py +4 -4
  12. ominfra/manage/remote/spawning.py +2 -1
  13. ominfra/manage/system/packages.py +2 -1
  14. ominfra/manage/system/platforms.py +3 -3
  15. ominfra/manage/targets/connection.py +2 -1
  16. ominfra/manage/targets/targets.py +5 -5
  17. ominfra/scripts/journald2aws.py +436 -133
  18. ominfra/scripts/manage.py +2957 -2655
  19. ominfra/scripts/supervisor.py +2806 -2468
  20. ominfra/supervisor/dispatchers.py +3 -0
  21. ominfra/supervisor/dispatchersimpl.py +5 -2
  22. ominfra/supervisor/events.py +6 -6
  23. ominfra/supervisor/groups.py +3 -0
  24. ominfra/supervisor/groupsimpl.py +3 -0
  25. ominfra/supervisor/inject.py +3 -0
  26. ominfra/supervisor/pipes.py +3 -0
  27. ominfra/supervisor/privileges.py +3 -0
  28. ominfra/supervisor/setup.py +4 -2
  29. ominfra/supervisor/signals.py +3 -0
  30. ominfra/supervisor/spawning.py +3 -0
  31. ominfra/supervisor/types.py +9 -8
  32. ominfra/supervisor/utils/collections.py +7 -2
  33. ominfra/supervisor/utils/diag.py +3 -0
  34. ominfra/supervisor/utils/fds.py +3 -0
  35. ominfra/supervisor/utils/fs.py +3 -0
  36. ominfra/threadworkers.py +2 -1
  37. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/METADATA +3 -3
  38. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/RECORD +42 -42
  39. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/WHEEL +0 -0
  40. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/entry_points.txt +0 -0
  41. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/licenses/LICENSE +0 -0
  42. {ominfra-0.0.0.dev420.dist-info → ominfra-0.0.0.dev422.dist-info}/top_level.txt +0 -0
@@ -1184,6 +1184,126 @@ class TomlWriter:
1184
1184
  return out.getvalue()
1185
1185
 
1186
1186
 
1187
+ ########################################
1188
+ # ../../../../../omlish/lite/abstract.py
1189
+
1190
+
1191
+ ##
1192
+
1193
+
1194
+ _ABSTRACT_METHODS_ATTR = '__abstractmethods__'
1195
+ _IS_ABSTRACT_METHOD_ATTR = '__isabstractmethod__'
1196
+
1197
+
1198
+ def is_abstract_method(obj: ta.Any) -> bool:
1199
+ return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
1200
+
1201
+
1202
+ def update_abstracts(cls, *, force=False):
1203
+ if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
1204
+ # Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
1205
+ # implementation (especially during testing), and we want to handle both cases.
1206
+ return cls
1207
+
1208
+ abstracts: ta.Set[str] = set()
1209
+
1210
+ for scls in cls.__bases__:
1211
+ for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
1212
+ value = getattr(cls, name, None)
1213
+ if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
1214
+ abstracts.add(name)
1215
+
1216
+ for name, value in cls.__dict__.items():
1217
+ if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
1218
+ abstracts.add(name)
1219
+
1220
+ setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
1221
+ return cls
1222
+
1223
+
1224
+ #
1225
+
1226
+
1227
+ class AbstractTypeError(TypeError):
1228
+ pass
1229
+
1230
+
1231
+ _FORCE_ABSTRACT_ATTR = '__forceabstract__'
1232
+
1233
+
1234
+ class Abstract:
1235
+ """
1236
+ Different from, but interoperable with, abc.ABC / abc.ABCMeta:
1237
+
1238
+ - This raises AbstractTypeError during class creation, not instance instantiation - unless Abstract or abc.ABC are
1239
+ explicitly present in the class's direct bases.
1240
+ - This will forbid instantiation of classes with Abstract in their direct bases even if there are no
1241
+ abstractmethods left on the class.
1242
+ - This is a mixin, not a metaclass.
1243
+ - As it is not an ABCMeta, this does not support virtual base classes. As a result, operations like `isinstance`
1244
+ and `issubclass` are ~7x faster.
1245
+ - It additionally enforces a base class order of (Abstract, abc.ABC) to preemptively prevent common mro conflicts.
1246
+
1247
+ If not mixed-in with an ABCMeta, it will update __abstractmethods__ itself.
1248
+ """
1249
+
1250
+ __slots__ = ()
1251
+
1252
+ __abstractmethods__: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
1253
+
1254
+ #
1255
+
1256
+ def __forceabstract__(self):
1257
+ raise TypeError
1258
+
1259
+ # This is done manually, rather than through @abc.abstractmethod, to mask it from static analysis.
1260
+ setattr(__forceabstract__, _IS_ABSTRACT_METHOD_ATTR, True)
1261
+
1262
+ #
1263
+
1264
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
1265
+ setattr(
1266
+ cls,
1267
+ _FORCE_ABSTRACT_ATTR,
1268
+ getattr(Abstract, _FORCE_ABSTRACT_ATTR) if Abstract in cls.__bases__ else False,
1269
+ )
1270
+
1271
+ super().__init_subclass__(**kwargs)
1272
+
1273
+ if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
1274
+ ams = {a: cls for a, o in cls.__dict__.items() if is_abstract_method(o)}
1275
+
1276
+ seen = set(cls.__dict__)
1277
+ for b in cls.__bases__:
1278
+ ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
1279
+ seen.update(dir(b))
1280
+
1281
+ if ams:
1282
+ raise AbstractTypeError(
1283
+ f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
1284
+ ', '.join(sorted([
1285
+ '.'.join([
1286
+ *([m] if (m := getattr(c, '__module__')) else []),
1287
+ getattr(c, '__qualname__', getattr(c, '__name__')),
1288
+ a,
1289
+ ])
1290
+ for a, c in ams.items()
1291
+ ])),
1292
+ )
1293
+
1294
+ xbi = (Abstract, abc.ABC) # , ta.Generic ?
1295
+ bis = [(cls.__bases__.index(b), b) for b in xbi if b in cls.__bases__]
1296
+ if bis != sorted(bis):
1297
+ raise TypeError(
1298
+ f'Abstract subclass {cls.__name__} must have proper base class order of '
1299
+ f'({", ".join(getattr(b, "__name__") for b in xbi)}), got: '
1300
+ f'({", ".join(getattr(b, "__name__") for _, b in sorted(bis))})',
1301
+ )
1302
+
1303
+ if not isinstance(cls, abc.ABCMeta):
1304
+ update_abstracts(cls, force=True)
1305
+
1306
+
1187
1307
  ########################################
1188
1308
  # ../../../../../omlish/lite/cached.py
1189
1309
 
@@ -1916,7 +2036,7 @@ def attr_setting(obj, attr, val, *, default=None): # noqa
1916
2036
  ##
1917
2037
 
1918
2038
 
1919
- class aclosing(contextlib.AbstractAsyncContextManager): # noqa
2039
+ class AsyncClosingManager(contextlib.AbstractAsyncContextManager):
1920
2040
  def __init__(self, thing):
1921
2041
  self.thing = thing
1922
2042
 
@@ -1927,6 +2047,9 @@ class aclosing(contextlib.AbstractAsyncContextManager): # noqa
1927
2047
  await self.thing.aclose()
1928
2048
 
1929
2049
 
2050
+ aclosing = AsyncClosingManager
2051
+
2052
+
1930
2053
  ########################################
1931
2054
  # ../../../../../omlish/lite/json.py
1932
2055
 
@@ -1965,6 +2088,86 @@ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON
1965
2088
  log = logging.getLogger(__name__)
1966
2089
 
1967
2090
 
2091
+ ########################################
2092
+ # ../../../../../omlish/lite/objects.py
2093
+
2094
+
2095
+ ##
2096
+
2097
+
2098
+ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2099
+ seen = set()
2100
+ todo = list(reversed(cls.__subclasses__()))
2101
+ while todo:
2102
+ cur = todo.pop()
2103
+ if cur in seen:
2104
+ continue
2105
+ seen.add(cur)
2106
+ yield cur
2107
+ todo.extend(reversed(cur.__subclasses__()))
2108
+
2109
+
2110
+ ##
2111
+
2112
+
2113
+ def mro_owner_dict(
2114
+ instance_cls: type,
2115
+ owner_cls: ta.Optional[type] = None,
2116
+ *,
2117
+ bottom_up_key_order: bool = False,
2118
+ sort_keys: bool = False,
2119
+ ) -> ta.Mapping[str, ta.Tuple[type, ta.Any]]:
2120
+ if owner_cls is None:
2121
+ owner_cls = instance_cls
2122
+
2123
+ mro = instance_cls.__mro__[-2::-1]
2124
+ try:
2125
+ pos = mro.index(owner_cls)
2126
+ except ValueError:
2127
+ raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
2128
+
2129
+ dct: ta.Dict[str, ta.Tuple[type, ta.Any]] = {}
2130
+ if not bottom_up_key_order:
2131
+ for cur_cls in mro[:pos + 1][::-1]:
2132
+ for k, v in cur_cls.__dict__.items():
2133
+ if k not in dct:
2134
+ dct[k] = (cur_cls, v)
2135
+
2136
+ else:
2137
+ for cur_cls in mro[:pos + 1]:
2138
+ dct.update({k: (cur_cls, v) for k, v in cur_cls.__dict__.items()})
2139
+
2140
+ if sort_keys:
2141
+ dct = dict(sorted(dct.items(), key=lambda t: t[0]))
2142
+
2143
+ return dct
2144
+
2145
+
2146
+ def mro_dict(
2147
+ instance_cls: type,
2148
+ owner_cls: ta.Optional[type] = None,
2149
+ *,
2150
+ bottom_up_key_order: bool = False,
2151
+ sort_keys: bool = False,
2152
+ ) -> ta.Mapping[str, ta.Any]:
2153
+ return {
2154
+ k: v
2155
+ for k, (o, v) in mro_owner_dict(
2156
+ instance_cls,
2157
+ owner_cls,
2158
+ bottom_up_key_order=bottom_up_key_order,
2159
+ sort_keys=sort_keys,
2160
+ ).items()
2161
+ }
2162
+
2163
+
2164
+ def dir_dict(o: ta.Any) -> ta.Dict[str, ta.Any]:
2165
+ return {
2166
+ a: getattr(o, a)
2167
+ for a in dir(o)
2168
+ }
2169
+
2170
+
1968
2171
  ########################################
1969
2172
  # ../../../../../omlish/lite/reflect.py
1970
2173
 
@@ -2054,21 +2257,6 @@ def get_literal_type_args(spec: ta.Any) -> ta.Iterable[ta.Any]:
2054
2257
  return spec.__args__
2055
2258
 
2056
2259
 
2057
- ##
2058
-
2059
-
2060
- def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2061
- seen = set()
2062
- todo = list(reversed(cls.__subclasses__()))
2063
- while todo:
2064
- cur = todo.pop()
2065
- if cur in seen:
2066
- continue
2067
- seen.add(cur)
2068
- yield cur
2069
- todo.extend(reversed(cur.__subclasses__()))
2070
-
2071
-
2072
2260
  ########################################
2073
2261
  # ../../../../../omlish/lite/strings.py
2074
2262
 
@@ -2942,7 +3130,7 @@ TODO:
2942
3130
  ##
2943
3131
 
2944
3132
 
2945
- class ThreadWorker(ExitStacked, abc.ABC):
3133
+ class ThreadWorker(ExitStacked, Abstract):
2946
3134
  def __init__(
2947
3135
  self,
2948
3136
  *,
@@ -3131,7 +3319,7 @@ TODO:
3131
3319
 
3132
3320
 
3133
3321
  @dc.dataclass(frozen=True)
3134
- class ConfigData(abc.ABC): # noqa
3322
+ class ConfigData(Abstract):
3135
3323
  @abc.abstractmethod
3136
3324
  def as_map(self) -> ConfigMap:
3137
3325
  raise NotImplementedError
@@ -3140,7 +3328,7 @@ class ConfigData(abc.ABC): # noqa
3140
3328
  #
3141
3329
 
3142
3330
 
3143
- class ConfigLoader(abc.ABC, ta.Generic[ConfigDataT]):
3331
+ class ConfigLoader(Abstract, ta.Generic[ConfigDataT]):
3144
3332
  @property
3145
3333
  def file_exts(self) -> ta.Sequence[str]:
3146
3334
  return ()
@@ -3162,7 +3350,7 @@ class ConfigLoader(abc.ABC, ta.Generic[ConfigDataT]):
3162
3350
  #
3163
3351
 
3164
3352
 
3165
- class ConfigRenderer(abc.ABC, ta.Generic[ConfigDataT]):
3353
+ class ConfigRenderer(Abstract, ta.Generic[ConfigDataT]):
3166
3354
  @property
3167
3355
  @abc.abstractmethod
3168
3356
  def data_cls(self) -> ta.Type[ConfigDataT]:
@@ -3182,7 +3370,7 @@ class ConfigRenderer(abc.ABC, ta.Generic[ConfigDataT]):
3182
3370
 
3183
3371
 
3184
3372
  @dc.dataclass(frozen=True)
3185
- class ObjConfigData(ConfigData, abc.ABC):
3373
+ class ObjConfigData(ConfigData, Abstract):
3186
3374
  obj: ta.Any
3187
3375
 
3188
3376
  def as_map(self) -> ConfigMap:
@@ -3654,7 +3842,7 @@ class ObjMarshalOptions:
3654
3842
  non_strict_fields: bool = False
3655
3843
 
3656
3844
 
3657
- class ObjMarshaler(abc.ABC):
3845
+ class ObjMarshaler(Abstract):
3658
3846
  @abc.abstractmethod
3659
3847
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3660
3848
  raise NotImplementedError
@@ -3672,26 +3860,30 @@ class NopObjMarshaler(ObjMarshaler):
3672
3860
  return o
3673
3861
 
3674
3862
 
3675
- @dc.dataclass()
3676
3863
  class ProxyObjMarshaler(ObjMarshaler):
3677
- m: ta.Optional[ObjMarshaler] = None
3864
+ def __init__(self, m: ta.Optional[ObjMarshaler] = None) -> None:
3865
+ super().__init__()
3866
+
3867
+ self._m = m
3678
3868
 
3679
3869
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3680
- return check.not_none(self.m).marshal(o, ctx)
3870
+ return check.not_none(self._m).marshal(o, ctx)
3681
3871
 
3682
3872
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3683
- return check.not_none(self.m).unmarshal(o, ctx)
3873
+ return check.not_none(self._m).unmarshal(o, ctx)
3684
3874
 
3685
3875
 
3686
- @dc.dataclass(frozen=True)
3687
3876
  class CastObjMarshaler(ObjMarshaler):
3688
- ty: type
3877
+ def __init__(self, ty: type) -> None:
3878
+ super().__init__()
3879
+
3880
+ self._ty = ty
3689
3881
 
3690
3882
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3691
3883
  return o
3692
3884
 
3693
3885
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3694
- return self.ty(o)
3886
+ return self._ty(o)
3695
3887
 
3696
3888
 
3697
3889
  class DynamicObjMarshaler(ObjMarshaler):
@@ -3702,121 +3894,151 @@ class DynamicObjMarshaler(ObjMarshaler):
3702
3894
  return o
3703
3895
 
3704
3896
 
3705
- @dc.dataclass(frozen=True)
3706
3897
  class Base64ObjMarshaler(ObjMarshaler):
3707
- ty: type
3898
+ def __init__(self, ty: type) -> None:
3899
+ super().__init__()
3900
+
3901
+ self._ty = ty
3708
3902
 
3709
3903
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3710
3904
  return base64.b64encode(o).decode('ascii')
3711
3905
 
3712
3906
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3713
- return self.ty(base64.b64decode(o))
3907
+ return self._ty(base64.b64decode(o))
3714
3908
 
3715
3909
 
3716
- @dc.dataclass(frozen=True)
3717
3910
  class BytesSwitchedObjMarshaler(ObjMarshaler):
3718
- m: ObjMarshaler
3911
+ def __init__(self, m: ObjMarshaler) -> None:
3912
+ super().__init__()
3913
+
3914
+ self._m = m
3719
3915
 
3720
3916
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3721
3917
  if ctx.options.raw_bytes:
3722
3918
  return o
3723
- return self.m.marshal(o, ctx)
3919
+ return self._m.marshal(o, ctx)
3724
3920
 
3725
3921
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3726
3922
  if ctx.options.raw_bytes:
3727
3923
  return o
3728
- return self.m.unmarshal(o, ctx)
3924
+ return self._m.unmarshal(o, ctx)
3729
3925
 
3730
3926
 
3731
- @dc.dataclass(frozen=True)
3732
3927
  class EnumObjMarshaler(ObjMarshaler):
3733
- ty: type
3928
+ def __init__(self, ty: type) -> None:
3929
+ super().__init__()
3930
+
3931
+ self._ty = ty
3734
3932
 
3735
3933
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3736
3934
  return o.name
3737
3935
 
3738
3936
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3739
- return self.ty.__members__[o] # type: ignore
3937
+ return self._ty.__members__[o] # type: ignore
3740
3938
 
3741
3939
 
3742
- @dc.dataclass(frozen=True)
3743
3940
  class OptionalObjMarshaler(ObjMarshaler):
3744
- item: ObjMarshaler
3941
+ def __init__(self, item: ObjMarshaler) -> None:
3942
+ super().__init__()
3943
+
3944
+ self._item = item
3745
3945
 
3746
3946
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3747
3947
  if o is None:
3748
3948
  return None
3749
- return self.item.marshal(o, ctx)
3949
+ return self._item.marshal(o, ctx)
3750
3950
 
3751
3951
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3752
3952
  if o is None:
3753
3953
  return None
3754
- return self.item.unmarshal(o, ctx)
3954
+ return self._item.unmarshal(o, ctx)
3755
3955
 
3756
3956
 
3757
- @dc.dataclass(frozen=True)
3758
3957
  class PrimitiveUnionObjMarshaler(ObjMarshaler):
3759
- pt: ta.Tuple[type, ...]
3760
- x: ta.Optional[ObjMarshaler] = None
3958
+ def __init__(
3959
+ self,
3960
+ pt: ta.Tuple[type, ...],
3961
+ x: ta.Optional[ObjMarshaler] = None,
3962
+ ) -> None:
3963
+ super().__init__()
3964
+
3965
+ self._pt = pt
3966
+ self._x = x
3761
3967
 
3762
3968
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3763
- if isinstance(o, self.pt):
3969
+ if isinstance(o, self._pt):
3764
3970
  return o
3765
- elif self.x is not None:
3766
- return self.x.marshal(o, ctx)
3971
+ elif self._x is not None:
3972
+ return self._x.marshal(o, ctx)
3767
3973
  else:
3768
3974
  raise TypeError(o)
3769
3975
 
3770
3976
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3771
- if isinstance(o, self.pt):
3977
+ if isinstance(o, self._pt):
3772
3978
  return o
3773
- elif self.x is not None:
3774
- return self.x.unmarshal(o, ctx)
3979
+ elif self._x is not None:
3980
+ return self._x.unmarshal(o, ctx)
3775
3981
  else:
3776
3982
  raise TypeError(o)
3777
3983
 
3778
3984
 
3779
- @dc.dataclass(frozen=True)
3780
3985
  class LiteralObjMarshaler(ObjMarshaler):
3781
- item: ObjMarshaler
3782
- vs: frozenset
3986
+ def __init__(
3987
+ self,
3988
+ item: ObjMarshaler,
3989
+ vs: frozenset,
3990
+ ) -> None:
3991
+ super().__init__()
3992
+
3993
+ self._item = item
3994
+ self._vs = vs
3783
3995
 
3784
3996
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3785
- return self.item.marshal(check.in_(o, self.vs), ctx)
3997
+ return self._item.marshal(check.in_(o, self._vs), ctx)
3786
3998
 
3787
3999
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3788
- return check.in_(self.item.unmarshal(o, ctx), self.vs)
4000
+ return check.in_(self._item.unmarshal(o, ctx), self._vs)
3789
4001
 
3790
4002
 
3791
- @dc.dataclass(frozen=True)
3792
4003
  class MappingObjMarshaler(ObjMarshaler):
3793
- ty: type
3794
- km: ObjMarshaler
3795
- vm: ObjMarshaler
4004
+ def __init__(
4005
+ self,
4006
+ ty: type,
4007
+ km: ObjMarshaler,
4008
+ vm: ObjMarshaler,
4009
+ ) -> None:
4010
+ super().__init__()
4011
+
4012
+ self._ty = ty
4013
+ self._km = km
4014
+ self._vm = vm
3796
4015
 
3797
4016
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3798
- return {self.km.marshal(k, ctx): self.vm.marshal(v, ctx) for k, v in o.items()}
4017
+ return {self._km.marshal(k, ctx): self._vm.marshal(v, ctx) for k, v in o.items()}
3799
4018
 
3800
4019
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3801
- return self.ty((self.km.unmarshal(k, ctx), self.vm.unmarshal(v, ctx)) for k, v in o.items())
4020
+ return self._ty((self._km.unmarshal(k, ctx), self._vm.unmarshal(v, ctx)) for k, v in o.items())
3802
4021
 
3803
4022
 
3804
- @dc.dataclass(frozen=True)
3805
4023
  class IterableObjMarshaler(ObjMarshaler):
3806
- ty: type
3807
- item: ObjMarshaler
4024
+ def __init__(
4025
+ self,
4026
+ ty: type,
4027
+ item: ObjMarshaler,
4028
+ ) -> None:
4029
+ super().__init__()
4030
+
4031
+ self._ty = ty
4032
+ self._item = item
3808
4033
 
3809
4034
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3810
- return [self.item.marshal(e, ctx) for e in o]
4035
+ return [self._item.marshal(e, ctx) for e in o]
3811
4036
 
3812
4037
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3813
- return self.ty(self.item.unmarshal(e, ctx) for e in o)
4038
+ return self._ty(self._item.unmarshal(e, ctx) for e in o)
3814
4039
 
3815
4040
 
3816
- @dc.dataclass(frozen=True)
3817
4041
  class FieldsObjMarshaler(ObjMarshaler):
3818
- ty: type
3819
-
3820
4042
  @dc.dataclass(frozen=True)
3821
4043
  class Field:
3822
4044
  att: str
@@ -3825,31 +4047,43 @@ class FieldsObjMarshaler(ObjMarshaler):
3825
4047
 
3826
4048
  omit_if_none: bool = False
3827
4049
 
3828
- fs: ta.Sequence[Field]
3829
-
3830
- non_strict: bool = False
3831
-
3832
- #
4050
+ def __init__(
4051
+ self,
4052
+ ty: type,
4053
+ fs: ta.Sequence[Field],
4054
+ *,
4055
+ non_strict: bool = False,
4056
+ ) -> None:
4057
+ super().__init__()
3833
4058
 
3834
- _fs_by_att: ta.ClassVar[ta.Mapping[str, Field]]
3835
- _fs_by_key: ta.ClassVar[ta.Mapping[str, Field]]
4059
+ self._ty = ty
4060
+ self._fs = fs
4061
+ self._non_strict = non_strict
3836
4062
 
3837
- def __post_init__(self) -> None:
3838
4063
  fs_by_att: dict = {}
3839
4064
  fs_by_key: dict = {}
3840
- for f in self.fs:
4065
+ for f in self._fs:
3841
4066
  check.not_in(check.non_empty_str(f.att), fs_by_att)
3842
4067
  check.not_in(check.non_empty_str(f.key), fs_by_key)
3843
4068
  fs_by_att[f.att] = f
3844
4069
  fs_by_key[f.key] = f
3845
- self.__dict__['_fs_by_att'] = fs_by_att
3846
- self.__dict__['_fs_by_key'] = fs_by_key
4070
+
4071
+ self._fs_by_att: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_att
4072
+ self._fs_by_key: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_key
4073
+
4074
+ @property
4075
+ def ty(self) -> type:
4076
+ return self._ty
4077
+
4078
+ @property
4079
+ def fs(self) -> ta.Sequence[Field]:
4080
+ return self._fs
3847
4081
 
3848
4082
  #
3849
4083
 
3850
4084
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3851
4085
  d = {}
3852
- for f in self.fs:
4086
+ for f in self._fs:
3853
4087
  mv = f.m.marshal(getattr(o, f.att), ctx)
3854
4088
  if mv is None and f.omit_if_none:
3855
4089
  continue
@@ -3860,34 +4094,46 @@ class FieldsObjMarshaler(ObjMarshaler):
3860
4094
  kw = {}
3861
4095
  for k, v in o.items():
3862
4096
  if (f := self._fs_by_key.get(k)) is None:
3863
- if not (self.non_strict or ctx.options.non_strict_fields):
4097
+ if not (self._non_strict or ctx.options.non_strict_fields):
3864
4098
  raise KeyError(k)
3865
4099
  continue
3866
4100
  kw[f.att] = f.m.unmarshal(v, ctx)
3867
- return self.ty(**kw)
4101
+ return self._ty(**kw)
3868
4102
 
3869
4103
 
3870
- @dc.dataclass(frozen=True)
3871
4104
  class SingleFieldObjMarshaler(ObjMarshaler):
3872
- ty: type
3873
- fld: str
4105
+ def __init__(
4106
+ self,
4107
+ ty: type,
4108
+ fld: str,
4109
+ ) -> None:
4110
+ super().__init__()
4111
+
4112
+ self._ty = ty
4113
+ self._fld = fld
3874
4114
 
3875
4115
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3876
- return getattr(o, self.fld)
4116
+ return getattr(o, self._fld)
3877
4117
 
3878
4118
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3879
- return self.ty(**{self.fld: o})
4119
+ return self._ty(**{self._fld: o})
3880
4120
 
3881
4121
 
3882
- @dc.dataclass(frozen=True)
3883
4122
  class PolymorphicObjMarshaler(ObjMarshaler):
3884
4123
  class Impl(ta.NamedTuple):
3885
4124
  ty: type
3886
4125
  tag: str
3887
4126
  m: ObjMarshaler
3888
4127
 
3889
- impls_by_ty: ta.Mapping[type, Impl]
3890
- impls_by_tag: ta.Mapping[str, Impl]
4128
+ def __init__(
4129
+ self,
4130
+ impls_by_ty: ta.Mapping[type, Impl],
4131
+ impls_by_tag: ta.Mapping[str, Impl],
4132
+ ) -> None:
4133
+ super().__init__()
4134
+
4135
+ self._impls_by_ty = impls_by_ty
4136
+ self._impls_by_tag = impls_by_tag
3891
4137
 
3892
4138
  @classmethod
3893
4139
  def of(cls, impls: ta.Iterable[Impl]) -> 'PolymorphicObjMarshaler':
@@ -3897,24 +4143,29 @@ class PolymorphicObjMarshaler(ObjMarshaler):
3897
4143
  )
3898
4144
 
3899
4145
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3900
- impl = self.impls_by_ty[type(o)]
4146
+ impl = self._impls_by_ty[type(o)]
3901
4147
  return {impl.tag: impl.m.marshal(o, ctx)}
3902
4148
 
3903
4149
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3904
4150
  [(t, v)] = o.items()
3905
- impl = self.impls_by_tag[t]
4151
+ impl = self._impls_by_tag[t]
3906
4152
  return impl.m.unmarshal(v, ctx)
3907
4153
 
3908
4154
 
3909
- @dc.dataclass(frozen=True)
3910
4155
  class DatetimeObjMarshaler(ObjMarshaler):
3911
- ty: type
4156
+ def __init__(
4157
+ self,
4158
+ ty: type,
4159
+ ) -> None:
4160
+ super().__init__()
4161
+
4162
+ self._ty = ty
3912
4163
 
3913
4164
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3914
4165
  return o.isoformat()
3915
4166
 
3916
4167
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
3917
- return self.ty.fromisoformat(o) # type: ignore
4168
+ return self._ty.fromisoformat(o) # type: ignore
3918
4169
 
3919
4170
 
3920
4171
  class DecimalObjMarshaler(ObjMarshaler):
@@ -4022,7 +4273,78 @@ class OBJ_MARSHALER_OMIT_IF_NONE(ObjMarshalerFieldMetadata): # noqa
4022
4273
  ##
4023
4274
 
4024
4275
 
4025
- class ObjMarshalerManager:
4276
+ class ObjMarshalerManager(Abstract):
4277
+ @abc.abstractmethod
4278
+ def make_obj_marshaler(
4279
+ self,
4280
+ ty: ta.Any,
4281
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
4282
+ *,
4283
+ non_strict_fields: bool = False,
4284
+ ) -> ObjMarshaler:
4285
+ raise NotImplementedError
4286
+
4287
+ @abc.abstractmethod
4288
+ def set_obj_marshaler(
4289
+ self,
4290
+ ty: ta.Any,
4291
+ m: ObjMarshaler,
4292
+ *,
4293
+ override: bool = False,
4294
+ ) -> None:
4295
+ raise NotImplementedError
4296
+
4297
+ @abc.abstractmethod
4298
+ def get_obj_marshaler(
4299
+ self,
4300
+ ty: ta.Any,
4301
+ *,
4302
+ no_cache: bool = False,
4303
+ **kwargs: ta.Any,
4304
+ ) -> ObjMarshaler:
4305
+ raise NotImplementedError
4306
+
4307
+ @abc.abstractmethod
4308
+ def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
4309
+ raise NotImplementedError
4310
+
4311
+ #
4312
+
4313
+ def marshal_obj(
4314
+ self,
4315
+ o: ta.Any,
4316
+ ty: ta.Any = None,
4317
+ opts: ta.Optional[ObjMarshalOptions] = None,
4318
+ ) -> ta.Any:
4319
+ m = self.get_obj_marshaler(ty if ty is not None else type(o))
4320
+ return m.marshal(o, self.make_context(opts))
4321
+
4322
+ def unmarshal_obj(
4323
+ self,
4324
+ o: ta.Any,
4325
+ ty: ta.Union[ta.Type[T], ta.Any],
4326
+ opts: ta.Optional[ObjMarshalOptions] = None,
4327
+ ) -> T:
4328
+ m = self.get_obj_marshaler(ty)
4329
+ return m.unmarshal(o, self.make_context(opts))
4330
+
4331
+ def roundtrip_obj(
4332
+ self,
4333
+ o: ta.Any,
4334
+ ty: ta.Any = None,
4335
+ opts: ta.Optional[ObjMarshalOptions] = None,
4336
+ ) -> ta.Any:
4337
+ if ty is None:
4338
+ ty = type(o)
4339
+ m: ta.Any = self.marshal_obj(o, ty, opts)
4340
+ u: ta.Any = self.unmarshal_obj(m, ty, opts)
4341
+ return u
4342
+
4343
+
4344
+ #
4345
+
4346
+
4347
+ class ObjMarshalerManagerImpl(ObjMarshalerManager):
4026
4348
  def __init__(
4027
4349
  self,
4028
4350
  *,
@@ -4049,6 +4371,12 @@ class ObjMarshalerManager:
4049
4371
 
4050
4372
  #
4051
4373
 
4374
+ @classmethod
4375
+ def _is_abstract(cls, ty: type) -> bool:
4376
+ return abc.ABC in ty.__bases__ or Abstract in ty.__bases__
4377
+
4378
+ #
4379
+
4052
4380
  def make_obj_marshaler(
4053
4381
  self,
4054
4382
  ty: ta.Any,
@@ -4060,12 +4388,12 @@ class ObjMarshalerManager:
4060
4388
  if (reg := self._registered_obj_marshalers.get(ty)) is not None:
4061
4389
  return reg
4062
4390
 
4063
- if abc.ABC in ty.__bases__:
4391
+ if self._is_abstract(ty):
4064
4392
  tn = ty.__name__
4065
4393
  impls: ta.List[ta.Tuple[type, str]] = [ # type: ignore[var-annotated]
4066
4394
  (ity, ity.__name__)
4067
4395
  for ity in deep_subclasses(ty)
4068
- if abc.ABC not in ity.__bases__
4396
+ if not self._is_abstract(ity)
4069
4397
  ]
4070
4398
 
4071
4399
  if all(itn.endswith(tn) for _, itn in impls):
@@ -4231,49 +4559,24 @@ class ObjMarshalerManager:
4231
4559
  m = self.make_obj_marshaler(ty, rec, **kwargs)
4232
4560
  finally:
4233
4561
  del self._proxies[ty]
4234
- p.m = m
4562
+ p._m = m # noqa
4235
4563
 
4236
4564
  if not no_cache:
4237
4565
  self._obj_marshalers[ty] = m
4238
4566
  return m
4239
4567
 
4240
- #
4241
-
4242
- def _make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
4568
+ def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
4243
4569
  return ObjMarshalContext(
4244
4570
  options=opts or self._default_options,
4245
4571
  manager=self,
4246
4572
  )
4247
4573
 
4248
- def marshal_obj(
4249
- self,
4250
- o: ta.Any,
4251
- ty: ta.Any = None,
4252
- opts: ta.Optional[ObjMarshalOptions] = None,
4253
- ) -> ta.Any:
4254
- m = self.get_obj_marshaler(ty if ty is not None else type(o))
4255
- return m.marshal(o, self._make_context(opts))
4256
4574
 
4257
- def unmarshal_obj(
4258
- self,
4259
- o: ta.Any,
4260
- ty: ta.Union[ta.Type[T], ta.Any],
4261
- opts: ta.Optional[ObjMarshalOptions] = None,
4262
- ) -> T:
4263
- m = self.get_obj_marshaler(ty)
4264
- return m.unmarshal(o, self._make_context(opts))
4575
+ def new_obj_marshaler_manager(**kwargs: ta.Any) -> ObjMarshalerManager:
4576
+ return ObjMarshalerManagerImpl(**kwargs)
4265
4577
 
4266
- def roundtrip_obj(
4267
- self,
4268
- o: ta.Any,
4269
- ty: ta.Any = None,
4270
- opts: ta.Optional[ObjMarshalOptions] = None,
4271
- ) -> ta.Any:
4272
- if ty is None:
4273
- ty = type(o)
4274
- m: ta.Any = self.marshal_obj(o, ty, opts)
4275
- u: ta.Any = self.unmarshal_obj(m, ty, opts)
4276
- return u
4578
+
4579
+ ##
4277
4580
 
4278
4581
 
4279
4582
  @dc.dataclass(frozen=True)
@@ -4285,7 +4588,7 @@ class ObjMarshalContext:
4285
4588
  ##
4286
4589
 
4287
4590
 
4288
- OBJ_MARSHALER_MANAGER = ObjMarshalerManager()
4591
+ OBJ_MARSHALER_MANAGER = new_obj_marshaler_manager()
4289
4592
 
4290
4593
  set_obj_marshaler = OBJ_MARSHALER_MANAGER.set_obj_marshaler
4291
4594
  get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler