omlish 0.0.0.dev244__py3-none-any.whl → 0.0.0.dev246__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.
- omlish/__about__.py +2 -2
- omlish/cached.py +4 -3
- omlish/collections/__init__.py +0 -1
- omlish/collections/frozen.py +2 -2
- omlish/collections/hasheq.py +1 -2
- omlish/collections/identity.py +1 -2
- omlish/collections/mappings.py +0 -16
- omlish/collections/sorted/sorted.py +1 -2
- omlish/daemons/services.py +7 -0
- omlish/dataclasses/__init__.py +3 -0
- omlish/dataclasses/utils.py +14 -0
- omlish/http/handlers.py +16 -0
- omlish/lang/__init__.py +46 -16
- omlish/lang/attrs.py +161 -0
- omlish/lang/cached/__init__.py +0 -0
- omlish/lang/{cached.py → cached/function.py} +125 -83
- omlish/lang/cached/property.py +118 -0
- omlish/lang/classes/__init__.py +0 -41
- omlish/lang/collections.py +50 -0
- omlish/marshal/__init__.py +23 -0
- omlish/marshal/composite/wrapped.py +26 -0
- omlish/marshal/objects/dataclasses.py +36 -11
- omlish/marshal/objects/namedtuples.py +9 -9
- omlish/marshal/polymorphism/marshal.py +16 -2
- omlish/marshal/polymorphism/unmarshal.py +16 -2
- omlish/os/pidfiles/pidfile.py +20 -4
- omlish/os/signals.py +5 -1
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/RECORD +33 -28
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/WHEEL +1 -1
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev244.dist-info → omlish-0.0.0.dev246.dist-info}/top_level.txt +0 -0
@@ -2,37 +2,43 @@
|
|
2
2
|
TODO:
|
3
3
|
- integrate / expose with collections.cache
|
4
4
|
- weakrefs (selectable by arg)
|
5
|
-
-
|
5
|
+
- more rigorous descriptor pickling
|
6
|
+
- must support free functions (which have no instance nor owner)
|
7
|
+
- 'staticmethod' or effective equiv - which must resolve to the shared instance
|
8
|
+
- and must be transient?
|
9
|
+
- use __transient_dict__ to support common state nuking
|
6
10
|
"""
|
7
11
|
import dataclasses as dc
|
8
12
|
import functools
|
9
13
|
import inspect
|
10
14
|
import typing as ta
|
11
15
|
|
12
|
-
from .
|
13
|
-
from
|
14
|
-
from
|
15
|
-
from
|
16
|
+
from ..classes.abstract import Abstract
|
17
|
+
from ..contextmanagers import DefaultLockable
|
18
|
+
from ..contextmanagers import default_lock
|
19
|
+
from ..descriptors import unwrap_func
|
20
|
+
from ..descriptors import unwrap_func_with_partials
|
16
21
|
|
17
22
|
|
18
23
|
P = ta.ParamSpec('P')
|
19
24
|
T = ta.TypeVar('T')
|
20
25
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
21
26
|
|
22
|
-
|
27
|
+
|
28
|
+
##
|
23
29
|
|
24
30
|
|
25
|
-
def
|
31
|
+
def _nullary_cache_key_maker():
|
26
32
|
return ()
|
27
33
|
|
28
34
|
|
29
|
-
def
|
35
|
+
def _simple_cache_key_maker(*args, **kwargs):
|
30
36
|
return (args, tuple(sorted(kwargs.items())))
|
31
37
|
|
32
38
|
|
33
|
-
def
|
39
|
+
def _make_cache_key_maker(fn, *, simple=False, bound=False):
|
34
40
|
if simple:
|
35
|
-
return
|
41
|
+
return _simple_cache_key_maker
|
36
42
|
|
37
43
|
fn, partials = unwrap_func_with_partials(fn)
|
38
44
|
|
@@ -42,7 +48,7 @@ def _make_cache_keyer(fn, *, simple=False, bound=False):
|
|
42
48
|
sig = inspect.signature(fn)
|
43
49
|
sig_params = list(sig.parameters.values())[1 if bound else 0:]
|
44
50
|
if not sig_params:
|
45
|
-
return
|
51
|
+
return _nullary_cache_key_maker
|
46
52
|
|
47
53
|
ns = {}
|
48
54
|
src_params = []
|
@@ -92,19 +98,23 @@ def _make_cache_keyer(fn, *, simple=False, bound=False):
|
|
92
98
|
return kfn
|
93
99
|
|
94
100
|
|
95
|
-
|
101
|
+
##
|
102
|
+
|
103
|
+
|
104
|
+
class _CachedFunction(ta.Generic[T], Abstract):
|
96
105
|
@dc.dataclass(frozen=True)
|
97
106
|
class Opts:
|
98
107
|
map_maker: ta.Callable[[], ta.MutableMapping] = dict
|
99
108
|
simple_key: bool = False
|
100
109
|
lock: DefaultLockable = None
|
110
|
+
transient: bool = False
|
101
111
|
|
102
112
|
def __init__(
|
103
113
|
self,
|
104
114
|
fn: ta.Callable[P, T],
|
105
115
|
*,
|
106
116
|
opts: Opts = Opts(),
|
107
|
-
|
117
|
+
key_maker: ta.Callable[..., tuple] | None = None,
|
108
118
|
values: ta.MutableMapping | None = None,
|
109
119
|
value_fn: ta.Callable[P, T] | None = None,
|
110
120
|
) -> None:
|
@@ -112,7 +122,7 @@ class _CachedFunction(ta.Generic[T]):
|
|
112
122
|
|
113
123
|
self._fn = (fn,)
|
114
124
|
self._opts = opts
|
115
|
-
self.
|
125
|
+
self._key_maker = key_maker if key_maker is not None else _make_cache_key_maker(fn, simple=opts.simple_key)
|
116
126
|
|
117
127
|
self._lock = default_lock(opts.lock, False)() if opts.lock is not None else None
|
118
128
|
self._values = values if values is not None else opts.map_maker()
|
@@ -134,7 +144,7 @@ class _CachedFunction(ta.Generic[T]):
|
|
134
144
|
raise TypeError
|
135
145
|
|
136
146
|
def __call__(self, *args, **kwargs) -> T:
|
137
|
-
k = self.
|
147
|
+
k = self._key_maker(*args, **kwargs)
|
138
148
|
|
139
149
|
try:
|
140
150
|
return self._values[k]
|
@@ -157,11 +167,42 @@ class _CachedFunction(ta.Generic[T]):
|
|
157
167
|
return value
|
158
168
|
|
159
169
|
|
160
|
-
|
170
|
+
#
|
171
|
+
|
172
|
+
|
173
|
+
class _FreeCachedFunction(_CachedFunction[T]):
|
174
|
+
@classmethod
|
175
|
+
def _unpickle(
|
176
|
+
cls,
|
177
|
+
fn,
|
178
|
+
opts,
|
179
|
+
values,
|
180
|
+
):
|
181
|
+
return cls(
|
182
|
+
fn,
|
183
|
+
opts=opts,
|
184
|
+
values=values,
|
185
|
+
)
|
186
|
+
|
187
|
+
def __reduce__(self):
|
188
|
+
return (
|
189
|
+
_FreeCachedFunction._unpickle,
|
190
|
+
(
|
191
|
+
self._fn,
|
192
|
+
self._opts,
|
193
|
+
self._values if not self._opts.transient else None,
|
194
|
+
),
|
195
|
+
)
|
196
|
+
|
197
|
+
|
198
|
+
#
|
199
|
+
|
200
|
+
|
201
|
+
class _DescriptorCachedFunction(_CachedFunction[T]):
|
161
202
|
def __init__(
|
162
203
|
self,
|
163
204
|
fn: ta.Callable[P, T],
|
164
|
-
scope: ta.Any,
|
205
|
+
scope: ta.Any, # classmethod | None
|
165
206
|
*,
|
166
207
|
instance: ta.Any = None,
|
167
208
|
owner: ta.Any = None,
|
@@ -174,9 +215,61 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
|
|
174
215
|
self._instance = instance
|
175
216
|
self._owner = owner
|
176
217
|
self._name = name if name is not None else unwrap_func(fn).__name__
|
177
|
-
self.
|
218
|
+
self._bound_key_maker = None
|
178
219
|
|
179
|
-
|
220
|
+
@classmethod
|
221
|
+
def _unpickle(
|
222
|
+
cls,
|
223
|
+
scope,
|
224
|
+
instance,
|
225
|
+
owner,
|
226
|
+
name,
|
227
|
+
values,
|
228
|
+
):
|
229
|
+
if scope is not None:
|
230
|
+
raise NotImplementedError
|
231
|
+
|
232
|
+
if instance is None:
|
233
|
+
raise RuntimeError
|
234
|
+
obj = type(instance)
|
235
|
+
|
236
|
+
desc: _DescriptorCachedFunction = object.__getattribute__(obj, name)
|
237
|
+
if not isinstance(desc, cls):
|
238
|
+
raise TypeError(desc)
|
239
|
+
if (desc._instance is not None or desc._owner is not None):
|
240
|
+
raise RuntimeError
|
241
|
+
|
242
|
+
return desc._bind(
|
243
|
+
instance,
|
244
|
+
owner,
|
245
|
+
values=values,
|
246
|
+
)
|
247
|
+
|
248
|
+
def __reduce__(self):
|
249
|
+
if self._scope is not None:
|
250
|
+
raise NotImplementedError
|
251
|
+
|
252
|
+
if not (self._instance is not None or self._owner is not None):
|
253
|
+
raise RuntimeError
|
254
|
+
|
255
|
+
return (
|
256
|
+
_DescriptorCachedFunction._unpickle,
|
257
|
+
(
|
258
|
+
self._scope,
|
259
|
+
self._instance,
|
260
|
+
self._owner,
|
261
|
+
self._name,
|
262
|
+
self._values if not self._opts.transient else None,
|
263
|
+
),
|
264
|
+
)
|
265
|
+
|
266
|
+
def _bind(
|
267
|
+
self,
|
268
|
+
instance,
|
269
|
+
owner=None,
|
270
|
+
*,
|
271
|
+
values: ta.MutableMapping | None = None,
|
272
|
+
):
|
180
273
|
scope = self._scope
|
181
274
|
if owner is self._owner and (instance is self._instance or scope is classmethod):
|
182
275
|
return self
|
@@ -184,8 +277,8 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
|
|
184
277
|
fn, = self._fn
|
185
278
|
name = self._name
|
186
279
|
bound_fn = fn.__get__(instance, owner)
|
187
|
-
if self.
|
188
|
-
self.
|
280
|
+
if self._bound_key_maker is None:
|
281
|
+
self._bound_key_maker = _make_cache_key_maker(fn, simple=self._opts.simple_key, bound=True)
|
189
282
|
|
190
283
|
bound = self.__class__(
|
191
284
|
fn,
|
@@ -194,8 +287,9 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
|
|
194
287
|
instance=instance,
|
195
288
|
owner=owner,
|
196
289
|
name=name,
|
197
|
-
|
198
|
-
# values=None if scope is classmethod else self._values,
|
290
|
+
key_maker=self._bound_key_maker,
|
291
|
+
# values=None if scope is classmethod else self._values, # FIXME: ?
|
292
|
+
values=values,
|
199
293
|
value_fn=bound_fn,
|
200
294
|
)
|
201
295
|
|
@@ -206,76 +300,24 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
|
|
206
300
|
|
207
301
|
return bound
|
208
302
|
|
303
|
+
def __get__(self, instance, owner=None):
|
304
|
+
return self._bind(instance, owner)
|
305
|
+
|
306
|
+
|
307
|
+
#
|
308
|
+
|
209
309
|
|
210
310
|
def cached_function(fn=None, **kwargs): # noqa
|
211
311
|
if fn is None:
|
212
312
|
return functools.partial(cached_function, **kwargs)
|
213
313
|
opts = _CachedFunction.Opts(**kwargs)
|
214
314
|
if isinstance(fn, staticmethod):
|
215
|
-
return
|
315
|
+
return _FreeCachedFunction(fn, opts=opts, value_fn=unwrap_func(fn))
|
216
316
|
scope = classmethod if isinstance(fn, classmethod) else None
|
217
|
-
return
|
317
|
+
return _DescriptorCachedFunction(fn, scope, opts=opts)
|
218
318
|
|
219
319
|
|
220
320
|
def static_init(fn: CallableT) -> CallableT:
|
221
321
|
fn = cached_function(fn)
|
222
322
|
fn()
|
223
323
|
return fn
|
224
|
-
|
225
|
-
|
226
|
-
##
|
227
|
-
|
228
|
-
|
229
|
-
class _CachedProperty(property):
|
230
|
-
def __init__(
|
231
|
-
self,
|
232
|
-
fn,
|
233
|
-
*,
|
234
|
-
name=None,
|
235
|
-
ignore_if=lambda _: False,
|
236
|
-
clear_on_init=False,
|
237
|
-
):
|
238
|
-
if isinstance(fn, property):
|
239
|
-
fn = fn.fget
|
240
|
-
super().__init__(fn)
|
241
|
-
self._fn = fn
|
242
|
-
self._ignore_if = ignore_if
|
243
|
-
self._name = name
|
244
|
-
self._clear_on_init = clear_on_init
|
245
|
-
|
246
|
-
def __set_name__(self, owner, name):
|
247
|
-
if self._name is None:
|
248
|
-
self._name = name
|
249
|
-
|
250
|
-
def __get__(self, instance, owner=None):
|
251
|
-
if instance is None:
|
252
|
-
return self
|
253
|
-
if self._name is None:
|
254
|
-
raise TypeError(self)
|
255
|
-
|
256
|
-
try:
|
257
|
-
return instance.__dict__[self._name]
|
258
|
-
except KeyError:
|
259
|
-
pass
|
260
|
-
|
261
|
-
value = self._fn.__get__(instance, owner)()
|
262
|
-
if value is _IGNORE:
|
263
|
-
return None
|
264
|
-
instance.__dict__[self._name] = value
|
265
|
-
return value
|
266
|
-
|
267
|
-
def __set__(self, instance, value):
|
268
|
-
if self._ignore_if(value):
|
269
|
-
return
|
270
|
-
if instance.__dict__[self._name] == value:
|
271
|
-
return
|
272
|
-
raise TypeError(self._name)
|
273
|
-
|
274
|
-
def __delete__(self, instance):
|
275
|
-
raise TypeError
|
276
|
-
|
277
|
-
|
278
|
-
def cached_property(fn=None, **kwargs): # noqa
|
279
|
-
if fn is None:
|
280
|
-
return functools.partial(cached_property, **kwargs)
|
281
|
-
return _CachedProperty(fn, **kwargs)
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import abc
|
2
|
+
import functools
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from ..attrs import transient_getattr
|
6
|
+
from ..attrs import transient_setattr
|
7
|
+
from ..classes.abstract import Abstract
|
8
|
+
|
9
|
+
|
10
|
+
_IGNORE = object()
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
|
15
|
+
|
16
|
+
class _CachedProperty(property, Abstract):
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
fn,
|
20
|
+
*,
|
21
|
+
name=None,
|
22
|
+
ignore_if=lambda _: False,
|
23
|
+
):
|
24
|
+
if isinstance(fn, property):
|
25
|
+
fn = fn.fget
|
26
|
+
|
27
|
+
super().__init__(fn)
|
28
|
+
|
29
|
+
self._fn = fn
|
30
|
+
self._ignore_if = ignore_if
|
31
|
+
|
32
|
+
self._name = name
|
33
|
+
|
34
|
+
def __set_name__(self, owner, name):
|
35
|
+
if self._name is None:
|
36
|
+
self._name = name
|
37
|
+
|
38
|
+
@abc.abstractmethod
|
39
|
+
def _instance_get(self, instance: ta.Any) -> tuple[ta.Any, bool]:
|
40
|
+
raise NotImplementedError
|
41
|
+
|
42
|
+
@abc.abstractmethod
|
43
|
+
def _instance_set(self, instance: ta.Any, value: ta.Any) -> None:
|
44
|
+
raise NotImplementedError
|
45
|
+
|
46
|
+
def __get__(self, instance, owner=None):
|
47
|
+
if instance is None:
|
48
|
+
return self
|
49
|
+
if self._name is None:
|
50
|
+
raise TypeError(self)
|
51
|
+
|
52
|
+
value, ok = self._instance_get(instance)
|
53
|
+
if ok:
|
54
|
+
return value
|
55
|
+
|
56
|
+
value = self._fn.__get__(instance, owner)()
|
57
|
+
if value is _IGNORE:
|
58
|
+
return None
|
59
|
+
|
60
|
+
self._instance_set(instance, value)
|
61
|
+
return value
|
62
|
+
|
63
|
+
def __set__(self, instance, value):
|
64
|
+
if self._ignore_if(value):
|
65
|
+
return
|
66
|
+
|
67
|
+
ev, ok = self._instance_get(instance)
|
68
|
+
if ok and ev == value:
|
69
|
+
return
|
70
|
+
|
71
|
+
raise TypeError(self._name)
|
72
|
+
|
73
|
+
def __delete__(self, instance):
|
74
|
+
raise TypeError
|
75
|
+
|
76
|
+
|
77
|
+
#
|
78
|
+
|
79
|
+
|
80
|
+
class _DictCachedProperty(_CachedProperty):
|
81
|
+
def _instance_get(self, instance: ta.Any) -> tuple[ta.Any, bool]:
|
82
|
+
try:
|
83
|
+
value = instance.__dict__[self._name]
|
84
|
+
except KeyError:
|
85
|
+
return None, False
|
86
|
+
else:
|
87
|
+
return value, True
|
88
|
+
|
89
|
+
def _instance_set(self, instance: ta.Any, value: ta.Any) -> None:
|
90
|
+
instance.__dict__[self._name] = value
|
91
|
+
|
92
|
+
|
93
|
+
#
|
94
|
+
|
95
|
+
|
96
|
+
class _TransientCachedProperty(_CachedProperty):
|
97
|
+
def _instance_get(self, instance: ta.Any) -> tuple[ta.Any, bool]:
|
98
|
+
try:
|
99
|
+
value = transient_getattr(instance, self._name)
|
100
|
+
except AttributeError:
|
101
|
+
return None, False
|
102
|
+
else:
|
103
|
+
return value, True
|
104
|
+
|
105
|
+
def _instance_set(self, instance: ta.Any, value: ta.Any) -> None:
|
106
|
+
transient_setattr(instance, self._name, value)
|
107
|
+
|
108
|
+
|
109
|
+
#
|
110
|
+
|
111
|
+
|
112
|
+
def cached_property(fn=None, *, transient=False, **kwargs): # noqa
|
113
|
+
if fn is None:
|
114
|
+
return functools.partial(cached_property, transient=transient, **kwargs)
|
115
|
+
if transient:
|
116
|
+
return _TransientCachedProperty(fn, **kwargs)
|
117
|
+
else:
|
118
|
+
return _DictCachedProperty(fn, **kwargs)
|
omlish/lang/classes/__init__.py
CHANGED
@@ -1,41 +0,0 @@
|
|
1
|
-
from .abstract import ( # noqa
|
2
|
-
Abstract,
|
3
|
-
AbstractTypeError,
|
4
|
-
get_abstract_methods,
|
5
|
-
is_abstract,
|
6
|
-
is_abstract_class,
|
7
|
-
is_abstract_method,
|
8
|
-
make_abstract,
|
9
|
-
unabstract_class,
|
10
|
-
)
|
11
|
-
|
12
|
-
from .restrict import ( # noqa
|
13
|
-
AnySensitive,
|
14
|
-
Final,
|
15
|
-
FinalTypeError,
|
16
|
-
NoBool,
|
17
|
-
NotInstantiable,
|
18
|
-
NotPicklable,
|
19
|
-
PackageSealed,
|
20
|
-
SENSITIVE_ATTR,
|
21
|
-
Sealed,
|
22
|
-
SealedError,
|
23
|
-
Sensitive,
|
24
|
-
no_bool,
|
25
|
-
)
|
26
|
-
|
27
|
-
from .simple import ( # noqa
|
28
|
-
LazySingleton,
|
29
|
-
Marker,
|
30
|
-
Namespace,
|
31
|
-
SimpleMetaDict,
|
32
|
-
Singleton,
|
33
|
-
)
|
34
|
-
|
35
|
-
from .virtual import ( # noqa
|
36
|
-
Callable,
|
37
|
-
Descriptor,
|
38
|
-
Picklable,
|
39
|
-
Virtual,
|
40
|
-
virtual_check,
|
41
|
-
)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import collections.abc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
K = ta.TypeVar('K')
|
6
|
+
V = ta.TypeVar('V')
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
def yield_dict_init(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterable[tuple[ta.Any, ta.Any]]:
|
13
|
+
if len(args) > 1:
|
14
|
+
raise TypeError
|
15
|
+
if args:
|
16
|
+
[src] = args
|
17
|
+
if isinstance(src, collections.abc.Mapping):
|
18
|
+
for k in src:
|
19
|
+
yield (k, src[k])
|
20
|
+
else:
|
21
|
+
for k, v in src:
|
22
|
+
yield (k, v)
|
23
|
+
for k, v in kwargs.items():
|
24
|
+
yield (k, v)
|
25
|
+
|
26
|
+
|
27
|
+
def merge_dicts(
|
28
|
+
*dcts: ta.Mapping[K, V],
|
29
|
+
pair_fn: ta.Callable[[K, V], tuple[K, V] | None] | None = None,
|
30
|
+
conflict_fn: ta.Callable[[K, V, V], tuple[K, V] | None] | None = None,
|
31
|
+
) -> dict[K, V]:
|
32
|
+
out: dict[K, V] = {}
|
33
|
+
|
34
|
+
for d in dcts:
|
35
|
+
for k_v in d.items():
|
36
|
+
if pair_fn is not None and (k_v := pair_fn(*k_v)) is None: # type: ignore[assignment]
|
37
|
+
continue
|
38
|
+
|
39
|
+
k, v = k_v
|
40
|
+
if k in out:
|
41
|
+
if conflict_fn is None:
|
42
|
+
raise KeyError(k)
|
43
|
+
|
44
|
+
if (k_v := conflict_fn(k, out[k], v)) is None: # type: ignore[assignment]
|
45
|
+
continue
|
46
|
+
k, v = k_v
|
47
|
+
|
48
|
+
out[k] = v
|
49
|
+
|
50
|
+
return out
|
omlish/marshal/__init__.py
CHANGED
@@ -28,6 +28,16 @@ from .base import ( # noqa
|
|
28
28
|
ReflectOverride,
|
29
29
|
)
|
30
30
|
|
31
|
+
from .composite.iterables import ( # noqa
|
32
|
+
IterableMarshaler,
|
33
|
+
IterableUnmarshaler,
|
34
|
+
)
|
35
|
+
|
36
|
+
from .composite.wrapped import ( # noqa
|
37
|
+
WrappedMarshaler,
|
38
|
+
WrappedUnmarshaler,
|
39
|
+
)
|
40
|
+
|
31
41
|
from .exceptions import ( # noqa
|
32
42
|
ForbiddenTypeError,
|
33
43
|
MarshalError,
|
@@ -49,6 +59,14 @@ from .naming import ( # noqa
|
|
49
59
|
translate_name,
|
50
60
|
)
|
51
61
|
|
62
|
+
from .objects.dataclasses import ( # noqa
|
63
|
+
AbstractDataclassFactory,
|
64
|
+
DataclassMarshalerFactory,
|
65
|
+
DataclassUnmarshalerFactory,
|
66
|
+
get_dataclass_field_infos,
|
67
|
+
get_dataclass_metadata,
|
68
|
+
)
|
69
|
+
|
52
70
|
from .objects.helpers import ( # noqa
|
53
71
|
update_field_metadata,
|
54
72
|
update_fields_metadata,
|
@@ -75,14 +93,18 @@ from .objects.unmarshal import ( # noqa
|
|
75
93
|
)
|
76
94
|
|
77
95
|
from .polymorphism.marshal import ( # noqa
|
96
|
+
PolymorphismMarshaler,
|
78
97
|
PolymorphismMarshalerFactory,
|
79
98
|
make_polymorphism_marshaler,
|
80
99
|
)
|
81
100
|
|
82
101
|
from .polymorphism.metadata import ( # noqa
|
102
|
+
FieldTypeTagging,
|
83
103
|
Impl,
|
84
104
|
Impls,
|
85
105
|
Polymorphism,
|
106
|
+
TypeTagging,
|
107
|
+
WrapperTypeTagging,
|
86
108
|
polymorphism_from_subclasses,
|
87
109
|
)
|
88
110
|
|
@@ -97,6 +119,7 @@ from .polymorphism.unions import ( # noqa
|
|
97
119
|
)
|
98
120
|
|
99
121
|
from .polymorphism.unmarshal import ( # noqa
|
122
|
+
PolymorphismUnmarshaler,
|
100
123
|
PolymorphismUnmarshalerFactory,
|
101
124
|
make_polymorphism_unmarshaler,
|
102
125
|
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from ..base import MarshalContext
|
5
|
+
from ..base import Marshaler
|
6
|
+
from ..base import UnmarshalContext
|
7
|
+
from ..base import Unmarshaler
|
8
|
+
from ..values import Value
|
9
|
+
|
10
|
+
|
11
|
+
@dc.dataclass(frozen=True)
|
12
|
+
class WrappedMarshaler(Marshaler):
|
13
|
+
wrapper: ta.Callable[[MarshalContext, ta.Any], ta.Any]
|
14
|
+
m: Marshaler
|
15
|
+
|
16
|
+
def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
|
17
|
+
return self.m.marshal(ctx, self.wrapper(ctx, o))
|
18
|
+
|
19
|
+
|
20
|
+
@dc.dataclass(frozen=True)
|
21
|
+
class WrappedUnmarshaler(Unmarshaler):
|
22
|
+
unwrapper: ta.Callable[[UnmarshalContext, ta.Any], ta.Any]
|
23
|
+
u: Unmarshaler
|
24
|
+
|
25
|
+
def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
|
26
|
+
return self.unwrapper(ctx, self.u.unmarshal(ctx, v))
|