omlish 0.0.0.dev419__py3-none-any.whl → 0.0.0.dev421__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 (96) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/asyncs/bluelet/core.py +2 -2
  3. omlish/asyncs/bluelet/events.py +4 -3
  4. omlish/asyncs/bluelet/files.py +2 -2
  5. omlish/asyncs/bluelet/sockets.py +2 -2
  6. omlish/collections/frozen.py +1 -1
  7. omlish/collections/kv/base.py +1 -1
  8. omlish/collections/multimaps.py +1 -1
  9. omlish/collections/persistent/treapmap.py +2 -1
  10. omlish/concurrent/threadlets.py +2 -2
  11. omlish/configs/all.py +39 -32
  12. omlish/configs/formats.py +5 -4
  13. omlish/configs/processing/all.py +32 -26
  14. omlish/configs/processing/flattening.py +2 -1
  15. omlish/configs/processing/rewriting.py +2 -2
  16. omlish/configs/shadow.py +3 -2
  17. omlish/daemons/spawning.py +2 -2
  18. omlish/daemons/targets.py +1 -1
  19. omlish/daemons/waiting.py +2 -1
  20. omlish/dataclasses/impl/generation/base.py +3 -2
  21. omlish/dataclasses/impl/generation/compilation.py +2 -1
  22. omlish/dataclasses/impl/generation/ops.py +2 -2
  23. omlish/dataclasses/impl/generation/processor.py +1 -1
  24. omlish/dataclasses/metaclass/meta.py +1 -0
  25. omlish/dataclasses/tools/static.py +5 -1
  26. omlish/formats/dotenv.py +3 -1
  27. omlish/formats/json/backends/default.py +14 -7
  28. omlish/formats/logfmt.py +111 -0
  29. omlish/formats/yaml.py +1 -1
  30. omlish/funcs/builders.py +2 -1
  31. omlish/funcs/match.py +1 -1
  32. omlish/funcs/pairs.py +41 -23
  33. omlish/funcs/pipes.py +3 -1
  34. omlish/http/asgi.py +2 -1
  35. omlish/http/coro/client/io.py +3 -2
  36. omlish/http/coro/server/server.py +2 -2
  37. omlish/http/handlers.py +2 -1
  38. omlish/http/jwt.py +1 -1
  39. omlish/http/parsing.py +2 -2
  40. omlish/io/compress/base.py +3 -2
  41. omlish/io/coro/readers.py +4 -3
  42. omlish/io/fdio/handlers.py +3 -2
  43. omlish/io/fdio/pollers.py +3 -1
  44. omlish/lang/__init__.py +20 -8
  45. omlish/lang/attrs.py +3 -1
  46. omlish/lang/casing.py +3 -1
  47. omlish/lang/classes/abstract.py +35 -96
  48. omlish/lang/classes/virtual.py +2 -2
  49. omlish/lang/contextmanagers.py +6 -4
  50. omlish/lang/generators.py +2 -2
  51. omlish/lang/iterables.py +6 -6
  52. omlish/lang/objects.py +0 -58
  53. omlish/lang/outcomes.py +3 -1
  54. omlish/lang/typing.py +5 -24
  55. omlish/lite/abstract.py +119 -0
  56. omlish/lite/contextmanagers.py +4 -1
  57. omlish/lite/inject.py +9 -9
  58. omlish/lite/marshal.py +230 -114
  59. omlish/lite/maybes.py +3 -1
  60. omlish/lite/maysync.py +4 -2
  61. omlish/lite/objects.py +81 -0
  62. omlish/lite/reflect.py +0 -15
  63. omlish/lite/timeouts.py +3 -1
  64. omlish/lite/wrappers.py +23 -0
  65. omlish/logs/abc.py +21 -5
  66. omlish/logs/all.py +56 -38
  67. omlish/logs/configs.py +13 -10
  68. omlish/logs/levels.py +4 -0
  69. omlish/logs/protocol.py +77 -39
  70. omlish/marshal/__init__.py +1 -0
  71. omlish/os/atomics.py +3 -2
  72. omlish/os/deathpacts/base.py +4 -2
  73. omlish/os/forkhooks.py +2 -2
  74. omlish/os/pidfiles/pinning.py +2 -1
  75. omlish/reflect/types.py +4 -3
  76. omlish/secrets/crypto.py +1 -1
  77. omlish/sockets/bind.py +2 -1
  78. omlish/sockets/handlers.py +3 -2
  79. omlish/sockets/server/handlers.py +2 -1
  80. omlish/sockets/server/server.py +4 -3
  81. omlish/sql/api/base.py +2 -2
  82. omlish/subprocesses/asyncs.py +2 -1
  83. omlish/subprocesses/base.py +2 -2
  84. omlish/subprocesses/maysync.py +1 -2
  85. omlish/subprocesses/run.py +2 -1
  86. omlish/subprocesses/sync.py +2 -1
  87. omlish/term/coloring.py +3 -1
  88. omlish/testing/pytest/plugins/asyncs/backends/base.py +3 -1
  89. omlish/testing/unittest/loading.py +2 -2
  90. omlish/text/asdl.py +4 -3
  91. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/METADATA +1 -1
  92. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/RECORD +96 -91
  93. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/WHEEL +0 -0
  94. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/entry_points.txt +0 -0
  95. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/licenses/LICENSE +0 -0
  96. {omlish-0.0.0.dev419.dist-info → omlish-0.0.0.dev421.dist-info}/top_level.txt +0 -0
omlish/lite/marshal.py CHANGED
@@ -1,9 +1,9 @@
1
+ # ruff: noqa: UP006 UP007 UP045
1
2
  """
2
3
  TODO:
3
4
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
4
5
  - Options.sequence_cls = list, mapping_cls = dict, ... - def with_mutable_containers() -> Options
5
6
  """
6
- # ruff: noqa: UP006 UP007 UP045
7
7
  import abc
8
8
  import base64
9
9
  import collections.abc
@@ -19,8 +19,9 @@ import typing as ta
19
19
  import uuid
20
20
  import weakref
21
21
 
22
+ from .abstract import Abstract
22
23
  from .check import check
23
- from .reflect import deep_subclasses
24
+ from .objects import deep_subclasses
24
25
  from .reflect import get_literal_type_args
25
26
  from .reflect import get_new_type_supertype
26
27
  from .reflect import is_generic_alias
@@ -42,7 +43,7 @@ class ObjMarshalOptions:
42
43
  non_strict_fields: bool = False
43
44
 
44
45
 
45
- class ObjMarshaler(abc.ABC):
46
+ class ObjMarshaler(Abstract):
46
47
  @abc.abstractmethod
47
48
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
48
49
  raise NotImplementedError
@@ -60,26 +61,30 @@ class NopObjMarshaler(ObjMarshaler):
60
61
  return o
61
62
 
62
63
 
63
- @dc.dataclass()
64
64
  class ProxyObjMarshaler(ObjMarshaler):
65
- m: ta.Optional[ObjMarshaler] = None
65
+ def __init__(self, m: ta.Optional[ObjMarshaler] = None) -> None:
66
+ super().__init__()
67
+
68
+ self._m = m
66
69
 
67
70
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
68
- return check.not_none(self.m).marshal(o, ctx)
71
+ return check.not_none(self._m).marshal(o, ctx)
69
72
 
70
73
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
71
- return check.not_none(self.m).unmarshal(o, ctx)
74
+ return check.not_none(self._m).unmarshal(o, ctx)
72
75
 
73
76
 
74
- @dc.dataclass(frozen=True)
75
77
  class CastObjMarshaler(ObjMarshaler):
76
- ty: type
78
+ def __init__(self, ty: type) -> None:
79
+ super().__init__()
80
+
81
+ self._ty = ty
77
82
 
78
83
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
79
84
  return o
80
85
 
81
86
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
82
- return self.ty(o)
87
+ return self._ty(o)
83
88
 
84
89
 
85
90
  class DynamicObjMarshaler(ObjMarshaler):
@@ -90,121 +95,151 @@ class DynamicObjMarshaler(ObjMarshaler):
90
95
  return o
91
96
 
92
97
 
93
- @dc.dataclass(frozen=True)
94
98
  class Base64ObjMarshaler(ObjMarshaler):
95
- ty: type
99
+ def __init__(self, ty: type) -> None:
100
+ super().__init__()
101
+
102
+ self._ty = ty
96
103
 
97
104
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
98
105
  return base64.b64encode(o).decode('ascii')
99
106
 
100
107
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
101
- return self.ty(base64.b64decode(o))
108
+ return self._ty(base64.b64decode(o))
102
109
 
103
110
 
104
- @dc.dataclass(frozen=True)
105
111
  class BytesSwitchedObjMarshaler(ObjMarshaler):
106
- m: ObjMarshaler
112
+ def __init__(self, m: ObjMarshaler) -> None:
113
+ super().__init__()
114
+
115
+ self._m = m
107
116
 
108
117
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
109
118
  if ctx.options.raw_bytes:
110
119
  return o
111
- return self.m.marshal(o, ctx)
120
+ return self._m.marshal(o, ctx)
112
121
 
113
122
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
114
123
  if ctx.options.raw_bytes:
115
124
  return o
116
- return self.m.unmarshal(o, ctx)
125
+ return self._m.unmarshal(o, ctx)
117
126
 
118
127
 
119
- @dc.dataclass(frozen=True)
120
128
  class EnumObjMarshaler(ObjMarshaler):
121
- ty: type
129
+ def __init__(self, ty: type) -> None:
130
+ super().__init__()
131
+
132
+ self._ty = ty
122
133
 
123
134
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
124
135
  return o.name
125
136
 
126
137
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
127
- return self.ty.__members__[o] # type: ignore
138
+ return self._ty.__members__[o] # type: ignore
128
139
 
129
140
 
130
- @dc.dataclass(frozen=True)
131
141
  class OptionalObjMarshaler(ObjMarshaler):
132
- item: ObjMarshaler
142
+ def __init__(self, item: ObjMarshaler) -> None:
143
+ super().__init__()
144
+
145
+ self._item = item
133
146
 
134
147
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
135
148
  if o is None:
136
149
  return None
137
- return self.item.marshal(o, ctx)
150
+ return self._item.marshal(o, ctx)
138
151
 
139
152
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
140
153
  if o is None:
141
154
  return None
142
- return self.item.unmarshal(o, ctx)
155
+ return self._item.unmarshal(o, ctx)
143
156
 
144
157
 
145
- @dc.dataclass(frozen=True)
146
158
  class PrimitiveUnionObjMarshaler(ObjMarshaler):
147
- pt: ta.Tuple[type, ...]
148
- x: ta.Optional[ObjMarshaler] = None
159
+ def __init__(
160
+ self,
161
+ pt: ta.Tuple[type, ...],
162
+ x: ta.Optional[ObjMarshaler] = None,
163
+ ) -> None:
164
+ super().__init__()
165
+
166
+ self._pt = pt
167
+ self._x = x
149
168
 
150
169
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
151
- if isinstance(o, self.pt):
170
+ if isinstance(o, self._pt):
152
171
  return o
153
- elif self.x is not None:
154
- return self.x.marshal(o, ctx)
172
+ elif self._x is not None:
173
+ return self._x.marshal(o, ctx)
155
174
  else:
156
175
  raise TypeError(o)
157
176
 
158
177
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
159
- if isinstance(o, self.pt):
178
+ if isinstance(o, self._pt):
160
179
  return o
161
- elif self.x is not None:
162
- return self.x.unmarshal(o, ctx)
180
+ elif self._x is not None:
181
+ return self._x.unmarshal(o, ctx)
163
182
  else:
164
183
  raise TypeError(o)
165
184
 
166
185
 
167
- @dc.dataclass(frozen=True)
168
186
  class LiteralObjMarshaler(ObjMarshaler):
169
- item: ObjMarshaler
170
- vs: frozenset
187
+ def __init__(
188
+ self,
189
+ item: ObjMarshaler,
190
+ vs: frozenset,
191
+ ) -> None:
192
+ super().__init__()
193
+
194
+ self._item = item
195
+ self._vs = vs
171
196
 
172
197
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
173
- return self.item.marshal(check.in_(o, self.vs), ctx)
198
+ return self._item.marshal(check.in_(o, self._vs), ctx)
174
199
 
175
200
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
176
- return check.in_(self.item.unmarshal(o, ctx), self.vs)
201
+ return check.in_(self._item.unmarshal(o, ctx), self._vs)
177
202
 
178
203
 
179
- @dc.dataclass(frozen=True)
180
204
  class MappingObjMarshaler(ObjMarshaler):
181
- ty: type
182
- km: ObjMarshaler
183
- vm: ObjMarshaler
205
+ def __init__(
206
+ self,
207
+ ty: type,
208
+ km: ObjMarshaler,
209
+ vm: ObjMarshaler,
210
+ ) -> None:
211
+ super().__init__()
212
+
213
+ self._ty = ty
214
+ self._km = km
215
+ self._vm = vm
184
216
 
185
217
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
186
- return {self.km.marshal(k, ctx): self.vm.marshal(v, ctx) for k, v in o.items()}
218
+ return {self._km.marshal(k, ctx): self._vm.marshal(v, ctx) for k, v in o.items()}
187
219
 
188
220
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
189
- return self.ty((self.km.unmarshal(k, ctx), self.vm.unmarshal(v, ctx)) for k, v in o.items())
221
+ return self._ty((self._km.unmarshal(k, ctx), self._vm.unmarshal(v, ctx)) for k, v in o.items())
190
222
 
191
223
 
192
- @dc.dataclass(frozen=True)
193
224
  class IterableObjMarshaler(ObjMarshaler):
194
- ty: type
195
- item: ObjMarshaler
225
+ def __init__(
226
+ self,
227
+ ty: type,
228
+ item: ObjMarshaler,
229
+ ) -> None:
230
+ super().__init__()
231
+
232
+ self._ty = ty
233
+ self._item = item
196
234
 
197
235
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
198
- return [self.item.marshal(e, ctx) for e in o]
236
+ return [self._item.marshal(e, ctx) for e in o]
199
237
 
200
238
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
201
- return self.ty(self.item.unmarshal(e, ctx) for e in o)
239
+ return self._ty(self._item.unmarshal(e, ctx) for e in o)
202
240
 
203
241
 
204
- @dc.dataclass(frozen=True)
205
242
  class FieldsObjMarshaler(ObjMarshaler):
206
- ty: type
207
-
208
243
  @dc.dataclass(frozen=True)
209
244
  class Field:
210
245
  att: str
@@ -213,31 +248,43 @@ class FieldsObjMarshaler(ObjMarshaler):
213
248
 
214
249
  omit_if_none: bool = False
215
250
 
216
- fs: ta.Sequence[Field]
217
-
218
- non_strict: bool = False
219
-
220
- #
251
+ def __init__(
252
+ self,
253
+ ty: type,
254
+ fs: ta.Sequence[Field],
255
+ *,
256
+ non_strict: bool = False,
257
+ ) -> None:
258
+ super().__init__()
221
259
 
222
- _fs_by_att: ta.ClassVar[ta.Mapping[str, Field]]
223
- _fs_by_key: ta.ClassVar[ta.Mapping[str, Field]]
260
+ self._ty = ty
261
+ self._fs = fs
262
+ self._non_strict = non_strict
224
263
 
225
- def __post_init__(self) -> None:
226
264
  fs_by_att: dict = {}
227
265
  fs_by_key: dict = {}
228
- for f in self.fs:
266
+ for f in self._fs:
229
267
  check.not_in(check.non_empty_str(f.att), fs_by_att)
230
268
  check.not_in(check.non_empty_str(f.key), fs_by_key)
231
269
  fs_by_att[f.att] = f
232
270
  fs_by_key[f.key] = f
233
- self.__dict__['_fs_by_att'] = fs_by_att
234
- self.__dict__['_fs_by_key'] = fs_by_key
271
+
272
+ self._fs_by_att: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_att
273
+ self._fs_by_key: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_key
274
+
275
+ @property
276
+ def ty(self) -> type:
277
+ return self._ty
278
+
279
+ @property
280
+ def fs(self) -> ta.Sequence[Field]:
281
+ return self._fs
235
282
 
236
283
  #
237
284
 
238
285
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
239
286
  d = {}
240
- for f in self.fs:
287
+ for f in self._fs:
241
288
  mv = f.m.marshal(getattr(o, f.att), ctx)
242
289
  if mv is None and f.omit_if_none:
243
290
  continue
@@ -248,34 +295,46 @@ class FieldsObjMarshaler(ObjMarshaler):
248
295
  kw = {}
249
296
  for k, v in o.items():
250
297
  if (f := self._fs_by_key.get(k)) is None:
251
- if not (self.non_strict or ctx.options.non_strict_fields):
298
+ if not (self._non_strict or ctx.options.non_strict_fields):
252
299
  raise KeyError(k)
253
300
  continue
254
301
  kw[f.att] = f.m.unmarshal(v, ctx)
255
- return self.ty(**kw)
302
+ return self._ty(**kw)
256
303
 
257
304
 
258
- @dc.dataclass(frozen=True)
259
305
  class SingleFieldObjMarshaler(ObjMarshaler):
260
- ty: type
261
- fld: str
306
+ def __init__(
307
+ self,
308
+ ty: type,
309
+ fld: str,
310
+ ) -> None:
311
+ super().__init__()
312
+
313
+ self._ty = ty
314
+ self._fld = fld
262
315
 
263
316
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
264
- return getattr(o, self.fld)
317
+ return getattr(o, self._fld)
265
318
 
266
319
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
267
- return self.ty(**{self.fld: o})
320
+ return self._ty(**{self._fld: o})
268
321
 
269
322
 
270
- @dc.dataclass(frozen=True)
271
323
  class PolymorphicObjMarshaler(ObjMarshaler):
272
324
  class Impl(ta.NamedTuple):
273
325
  ty: type
274
326
  tag: str
275
327
  m: ObjMarshaler
276
328
 
277
- impls_by_ty: ta.Mapping[type, Impl]
278
- impls_by_tag: ta.Mapping[str, Impl]
329
+ def __init__(
330
+ self,
331
+ impls_by_ty: ta.Mapping[type, Impl],
332
+ impls_by_tag: ta.Mapping[str, Impl],
333
+ ) -> None:
334
+ super().__init__()
335
+
336
+ self._impls_by_ty = impls_by_ty
337
+ self._impls_by_tag = impls_by_tag
279
338
 
280
339
  @classmethod
281
340
  def of(cls, impls: ta.Iterable[Impl]) -> 'PolymorphicObjMarshaler':
@@ -285,24 +344,29 @@ class PolymorphicObjMarshaler(ObjMarshaler):
285
344
  )
286
345
 
287
346
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
288
- impl = self.impls_by_ty[type(o)]
347
+ impl = self._impls_by_ty[type(o)]
289
348
  return {impl.tag: impl.m.marshal(o, ctx)}
290
349
 
291
350
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
292
351
  [(t, v)] = o.items()
293
- impl = self.impls_by_tag[t]
352
+ impl = self._impls_by_tag[t]
294
353
  return impl.m.unmarshal(v, ctx)
295
354
 
296
355
 
297
- @dc.dataclass(frozen=True)
298
356
  class DatetimeObjMarshaler(ObjMarshaler):
299
- ty: type
357
+ def __init__(
358
+ self,
359
+ ty: type,
360
+ ) -> None:
361
+ super().__init__()
362
+
363
+ self._ty = ty
300
364
 
301
365
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
302
366
  return o.isoformat()
303
367
 
304
368
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
305
- return self.ty.fromisoformat(o) # type: ignore
369
+ return self._ty.fromisoformat(o) # type: ignore
306
370
 
307
371
 
308
372
  class DecimalObjMarshaler(ObjMarshaler):
@@ -410,7 +474,78 @@ class OBJ_MARSHALER_OMIT_IF_NONE(ObjMarshalerFieldMetadata): # noqa
410
474
  ##
411
475
 
412
476
 
413
- class ObjMarshalerManager:
477
+ class ObjMarshalerManager(Abstract):
478
+ @abc.abstractmethod
479
+ def make_obj_marshaler(
480
+ self,
481
+ ty: ta.Any,
482
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
483
+ *,
484
+ non_strict_fields: bool = False,
485
+ ) -> ObjMarshaler:
486
+ raise NotImplementedError
487
+
488
+ @abc.abstractmethod
489
+ def set_obj_marshaler(
490
+ self,
491
+ ty: ta.Any,
492
+ m: ObjMarshaler,
493
+ *,
494
+ override: bool = False,
495
+ ) -> None:
496
+ raise NotImplementedError
497
+
498
+ @abc.abstractmethod
499
+ def get_obj_marshaler(
500
+ self,
501
+ ty: ta.Any,
502
+ *,
503
+ no_cache: bool = False,
504
+ **kwargs: ta.Any,
505
+ ) -> ObjMarshaler:
506
+ raise NotImplementedError
507
+
508
+ @abc.abstractmethod
509
+ def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
510
+ raise NotImplementedError
511
+
512
+ #
513
+
514
+ def marshal_obj(
515
+ self,
516
+ o: ta.Any,
517
+ ty: ta.Any = None,
518
+ opts: ta.Optional[ObjMarshalOptions] = None,
519
+ ) -> ta.Any:
520
+ m = self.get_obj_marshaler(ty if ty is not None else type(o))
521
+ return m.marshal(o, self.make_context(opts))
522
+
523
+ def unmarshal_obj(
524
+ self,
525
+ o: ta.Any,
526
+ ty: ta.Union[ta.Type[T], ta.Any],
527
+ opts: ta.Optional[ObjMarshalOptions] = None,
528
+ ) -> T:
529
+ m = self.get_obj_marshaler(ty)
530
+ return m.unmarshal(o, self.make_context(opts))
531
+
532
+ def roundtrip_obj(
533
+ self,
534
+ o: ta.Any,
535
+ ty: ta.Any = None,
536
+ opts: ta.Optional[ObjMarshalOptions] = None,
537
+ ) -> ta.Any:
538
+ if ty is None:
539
+ ty = type(o)
540
+ m: ta.Any = self.marshal_obj(o, ty, opts)
541
+ u: ta.Any = self.unmarshal_obj(m, ty, opts)
542
+ return u
543
+
544
+
545
+ #
546
+
547
+
548
+ class ObjMarshalerManagerImpl(ObjMarshalerManager):
414
549
  def __init__(
415
550
  self,
416
551
  *,
@@ -437,6 +572,12 @@ class ObjMarshalerManager:
437
572
 
438
573
  #
439
574
 
575
+ @classmethod
576
+ def _is_abstract(cls, ty: type) -> bool:
577
+ return abc.ABC in ty.__bases__ or Abstract in ty.__bases__
578
+
579
+ #
580
+
440
581
  def make_obj_marshaler(
441
582
  self,
442
583
  ty: ta.Any,
@@ -448,12 +589,12 @@ class ObjMarshalerManager:
448
589
  if (reg := self._registered_obj_marshalers.get(ty)) is not None:
449
590
  return reg
450
591
 
451
- if abc.ABC in ty.__bases__:
592
+ if self._is_abstract(ty):
452
593
  tn = ty.__name__
453
594
  impls: ta.List[ta.Tuple[type, str]] = [ # type: ignore[var-annotated]
454
595
  (ity, ity.__name__)
455
596
  for ity in deep_subclasses(ty)
456
- if abc.ABC not in ity.__bases__
597
+ if not self._is_abstract(ity)
457
598
  ]
458
599
 
459
600
  if all(itn.endswith(tn) for _, itn in impls):
@@ -619,49 +760,24 @@ class ObjMarshalerManager:
619
760
  m = self.make_obj_marshaler(ty, rec, **kwargs)
620
761
  finally:
621
762
  del self._proxies[ty]
622
- p.m = m
763
+ p._m = m # noqa
623
764
 
624
765
  if not no_cache:
625
766
  self._obj_marshalers[ty] = m
626
767
  return m
627
768
 
628
- #
629
-
630
- def _make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
769
+ def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
631
770
  return ObjMarshalContext(
632
771
  options=opts or self._default_options,
633
772
  manager=self,
634
773
  )
635
774
 
636
- def marshal_obj(
637
- self,
638
- o: ta.Any,
639
- ty: ta.Any = None,
640
- opts: ta.Optional[ObjMarshalOptions] = None,
641
- ) -> ta.Any:
642
- m = self.get_obj_marshaler(ty if ty is not None else type(o))
643
- return m.marshal(o, self._make_context(opts))
644
775
 
645
- def unmarshal_obj(
646
- self,
647
- o: ta.Any,
648
- ty: ta.Union[ta.Type[T], ta.Any],
649
- opts: ta.Optional[ObjMarshalOptions] = None,
650
- ) -> T:
651
- m = self.get_obj_marshaler(ty)
652
- return m.unmarshal(o, self._make_context(opts))
776
+ def new_obj_marshaler_manager(**kwargs: ta.Any) -> ObjMarshalerManager:
777
+ return ObjMarshalerManagerImpl(**kwargs)
653
778
 
654
- def roundtrip_obj(
655
- self,
656
- o: ta.Any,
657
- ty: ta.Any = None,
658
- opts: ta.Optional[ObjMarshalOptions] = None,
659
- ) -> ta.Any:
660
- if ty is None:
661
- ty = type(o)
662
- m: ta.Any = self.marshal_obj(o, ty, opts)
663
- u: ta.Any = self.unmarshal_obj(m, ty, opts)
664
- return u
779
+
780
+ ##
665
781
 
666
782
 
667
783
  @dc.dataclass(frozen=True)
@@ -673,7 +789,7 @@ class ObjMarshalContext:
673
789
  ##
674
790
 
675
791
 
676
- OBJ_MARSHALER_MANAGER = ObjMarshalerManager()
792
+ OBJ_MARSHALER_MANAGER = new_obj_marshaler_manager()
677
793
 
678
794
  set_obj_marshaler = OBJ_MARSHALER_MANAGER.set_obj_marshaler
679
795
  get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
omlish/lite/maybes.py CHANGED
@@ -3,6 +3,8 @@ import abc
3
3
  import functools
4
4
  import typing as ta
5
5
 
6
+ from .abstract import Abstract
7
+
6
8
 
7
9
  T = ta.TypeVar('T')
8
10
  U = ta.TypeVar('U')
@@ -134,7 +136,7 @@ class Maybe(ta.Generic[T]):
134
136
  ##
135
137
 
136
138
 
137
- class _Maybe(Maybe[T], abc.ABC):
139
+ class _Maybe(Maybe[T], Abstract):
138
140
  def __lt__(self, other):
139
141
  if not isinstance(other, _Maybe):
140
142
  return NotImplemented
omlish/lite/maysync.py CHANGED
@@ -45,6 +45,8 @@ import sys
45
45
  import threading
46
46
  import typing as ta
47
47
 
48
+ from .abstract import Abstract
49
+
48
50
 
49
51
  T = ta.TypeVar('T')
50
52
  O = ta.TypeVar('O')
@@ -58,7 +60,7 @@ _MaysyncRA = ta.TypeVar('_MaysyncRA')
58
60
  ##
59
61
 
60
62
 
61
- class AnyMaysyncFn(abc.ABC, ta.Generic[_MaysyncRS, _MaysyncRA]): # noqa
63
+ class AnyMaysyncFn(Abstract, ta.Generic[_MaysyncRS, _MaysyncRA]):
62
64
  def __init__(
63
65
  self,
64
66
  s: ta.Callable[..., _MaysyncRS],
@@ -105,7 +107,7 @@ class MaywaitableAlreadyConsumedError(Exception):
105
107
  pass
106
108
 
107
109
 
108
- class AnyMaywaitable(abc.ABC, ta.Generic[_MaysyncX]):
110
+ class AnyMaywaitable(Abstract, ta.Generic[_MaysyncX]):
109
111
  @ta.final
110
112
  def __init__(
111
113
  self,
omlish/lite/objects.py ADDED
@@ -0,0 +1,81 @@
1
+ # ruff: noqa: UP006 UP036 UP045
2
+ import typing as ta
3
+
4
+
5
+ T = ta.TypeVar('T')
6
+
7
+
8
+ ##
9
+
10
+
11
+ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
12
+ seen = set()
13
+ todo = list(reversed(cls.__subclasses__()))
14
+ while todo:
15
+ cur = todo.pop()
16
+ if cur in seen:
17
+ continue
18
+ seen.add(cur)
19
+ yield cur
20
+ todo.extend(reversed(cur.__subclasses__()))
21
+
22
+
23
+ ##
24
+
25
+
26
+ def mro_owner_dict(
27
+ instance_cls: type,
28
+ owner_cls: ta.Optional[type] = None,
29
+ *,
30
+ bottom_up_key_order: bool = False,
31
+ sort_keys: bool = False,
32
+ ) -> ta.Mapping[str, ta.Tuple[type, ta.Any]]:
33
+ if owner_cls is None:
34
+ owner_cls = instance_cls
35
+
36
+ mro = instance_cls.__mro__[-2::-1]
37
+ try:
38
+ pos = mro.index(owner_cls)
39
+ except ValueError:
40
+ raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
41
+
42
+ dct: ta.Dict[str, ta.Tuple[type, ta.Any]] = {}
43
+ if not bottom_up_key_order:
44
+ for cur_cls in mro[:pos + 1][::-1]:
45
+ for k, v in cur_cls.__dict__.items():
46
+ if k not in dct:
47
+ dct[k] = (cur_cls, v)
48
+
49
+ else:
50
+ for cur_cls in mro[:pos + 1]:
51
+ dct.update({k: (cur_cls, v) for k, v in cur_cls.__dict__.items()})
52
+
53
+ if sort_keys:
54
+ dct = dict(sorted(dct.items(), key=lambda t: t[0]))
55
+
56
+ return dct
57
+
58
+
59
+ def mro_dict(
60
+ instance_cls: type,
61
+ owner_cls: ta.Optional[type] = None,
62
+ *,
63
+ bottom_up_key_order: bool = False,
64
+ sort_keys: bool = False,
65
+ ) -> ta.Mapping[str, ta.Any]:
66
+ return {
67
+ k: v
68
+ for k, (o, v) in mro_owner_dict(
69
+ instance_cls,
70
+ owner_cls,
71
+ bottom_up_key_order=bottom_up_key_order,
72
+ sort_keys=sort_keys,
73
+ ).items()
74
+ }
75
+
76
+
77
+ def dir_dict(o: ta.Any) -> ta.Dict[str, ta.Any]:
78
+ return {
79
+ a: getattr(o, a)
80
+ for a in dir(o)
81
+ }