omdev 0.0.0.dev416__py3-none-any.whl → 0.0.0.dev500__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/{.manifests.json → .omlish-manifests.json} +23 -47
- omdev/README.md +51 -0
- omdev/__about__.py +12 -8
- omdev/amalg/cli/main.py +1 -2
- omdev/amalg/gen/gen.py +49 -6
- omdev/amalg/gen/imports.py +1 -1
- omdev/amalg/gen/manifests.py +1 -1
- omdev/amalg/gen/resources.py +1 -1
- omdev/amalg/gen/srcfiles.py +26 -3
- omdev/amalg/gen/strip.py +1 -1
- omdev/amalg/gen/types.py +1 -1
- omdev/amalg/gen/typing.py +1 -1
- omdev/amalg/info.py +32 -0
- omdev/cache/compute/storage.py +3 -1
- omdev/cache/data/actions.py +1 -1
- omdev/cache/data/cache.py +2 -2
- omdev/cache/data/specs.py +1 -1
- omdev/cexts/_boilerplate.cc +2 -3
- omdev/cexts/_distutils/build_ext.py +5 -2
- omdev/cexts/_distutils/compilers/ccompiler.py +5 -2
- omdev/cexts/_distutils/compilers/options.py +3 -0
- omdev/cexts/_distutils/compilers/unixccompiler.py +6 -2
- omdev/cexts/_distutils/dir_util.py +6 -2
- omdev/cexts/_distutils/errors.py +3 -0
- omdev/cexts/_distutils/extension.py +3 -0
- omdev/cexts/_distutils/file_util.py +6 -2
- omdev/cexts/_distutils/modified.py +3 -0
- omdev/cexts/_distutils/spawn.py +6 -2
- omdev/cexts/_distutils/sysconfig.py +3 -0
- omdev/cexts/_distutils/util.py +6 -2
- omdev/cexts/_distutils/version.py +3 -0
- omdev/cexts/cmake.py +5 -3
- omdev/cexts/scan.py +1 -2
- omdev/ci/cache.py +7 -3
- omdev/ci/cli.py +6 -4
- omdev/ci/docker/buildcaching.py +3 -1
- omdev/ci/docker/cache.py +2 -1
- omdev/ci/docker/cacheserved/cache.py +4 -1
- omdev/ci/docker/cacheserved/manifests.py +2 -2
- omdev/ci/docker/dataserver.py +2 -2
- omdev/ci/docker/imagepulling.py +2 -1
- omdev/ci/docker/packing.py +1 -1
- omdev/ci/docker/repositories.py +2 -1
- omdev/ci/github/api/clients.py +8 -4
- omdev/ci/github/api/v1/client.py +4 -1
- omdev/ci/github/api/v2/api.py +2 -0
- omdev/ci/github/api/v2/azure.py +4 -1
- omdev/ci/github/api/v2/client.py +4 -1
- omdev/cli/clicli.py +37 -7
- omdev/clipboard/clipboard.py +1 -1
- omdev/cmake.py +2 -1
- omdev/cmdlog/cli.py +1 -2
- omdev/dataclasses/_dumping.py +1960 -0
- omdev/dataclasses/_template.py +22 -0
- omdev/dataclasses/cli.py +7 -2
- omdev/dataclasses/codegen.py +342 -62
- omdev/dataclasses/dumping.py +200 -0
- omdev/dataserver/handlers.py +3 -2
- omdev/dataserver/targets.py +2 -2
- omdev/imgur.py +2 -2
- omdev/interp/cli.py +1 -1
- omdev/interp/inspect.py +2 -1
- omdev/interp/providers/base.py +3 -2
- omdev/interp/providers/standalone.py +4 -1
- omdev/interp/providers/system.py +2 -2
- omdev/interp/pyenv/install.py +2 -1
- omdev/interp/pyenv/provider.py +2 -2
- omdev/interp/types.py +3 -2
- omdev/interp/uv/provider.py +40 -2
- omdev/interp/uv/uv.py +2 -2
- omdev/interp/venvs.py +3 -2
- omdev/irc/messages/base.py +50 -0
- omdev/irc/messages/formats.py +92 -0
- omdev/irc/messages/messages.py +775 -0
- omdev/irc/messages/parsing.py +99 -0
- omdev/irc/numerics/formats.py +97 -0
- omdev/irc/numerics/numerics.py +865 -0
- omdev/irc/numerics/types.py +59 -0
- omdev/irc/protocol/LICENSE +11 -0
- omdev/irc/protocol/__init__.py +61 -0
- omdev/irc/protocol/consts.py +6 -0
- omdev/irc/protocol/errors.py +30 -0
- omdev/irc/protocol/message.py +21 -0
- omdev/irc/protocol/nuh.py +55 -0
- omdev/irc/protocol/parsing.py +158 -0
- omdev/irc/protocol/rendering.py +153 -0
- omdev/irc/protocol/tags.py +102 -0
- omdev/irc/protocol/utils.py +30 -0
- omdev/manifests/_dumping.py +529 -136
- omdev/manifests/building.py +6 -3
- omdev/manifests/main.py +1 -1
- omdev/markdown/__init__.py +0 -0
- omdev/markdown/incparse.py +116 -0
- omdev/markdown/tokens.py +51 -0
- 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/packaging/marshal.py +9 -9
- omdev/packaging/requires.py +6 -6
- omdev/packaging/revisions.py +5 -2
- omdev/packaging/specifiers.py +41 -42
- omdev/packaging/versions.py +10 -10
- omdev/packaging/wheelfile.py +4 -2
- omdev/precheck/blanklines.py +66 -0
- omdev/precheck/caches.py +1 -1
- omdev/precheck/imports.py +14 -1
- omdev/precheck/lite.py +2 -2
- omdev/precheck/main.py +5 -5
- omdev/precheck/unicode.py +39 -15
- omdev/py/asts/__init__.py +0 -0
- omdev/py/asts/parents.py +28 -0
- omdev/py/asts/toplevel.py +123 -0
- omdev/py/asts/visitors.py +18 -0
- omdev/py/attrdocs.py +6 -7
- omdev/py/bracepy.py +12 -4
- omdev/py/docstrings/numpydoc.py +4 -4
- omdev/py/reprs.py +32 -0
- omdev/py/scripts/execstat.py +31 -26
- omdev/py/srcheaders.py +1 -1
- omdev/py/tokens/__init__.py +0 -0
- omdev/{tokens → py/tokens}/utils.py +2 -1
- omdev/py/tools/importscan.py +2 -2
- omdev/py/tools/mkrelimp.py +3 -4
- omdev/py/tools/pipdepup.py +686 -0
- omdev/pyproject/cli.py +1 -1
- omdev/pyproject/pkg.py +197 -48
- omdev/pyproject/reqs.py +36 -10
- omdev/pyproject/tools/__init__.py +0 -0
- omdev/pyproject/tools/aboutdeps.py +60 -0
- omdev/pyproject/venvs.py +12 -2
- omdev/rs/__init__.py +0 -0
- omdev/scripts/ci.py +9551 -6982
- omdev/scripts/interp.py +1323 -892
- omdev/scripts/lib/__init__.py +0 -0
- omdev/scripts/lib/inject.py +2086 -0
- omdev/scripts/lib/logs.py +2175 -0
- omdev/scripts/lib/marshal.py +1731 -0
- omdev/scripts/pyproject.py +4979 -1874
- omdev/tools/docker.py +19 -7
- omdev/tools/git/cli.py +56 -16
- omdev/tools/git/messages.py +2 -2
- omdev/tools/json/cli.py +6 -6
- omdev/tools/json/formats.py +2 -0
- omdev/tools/json/parsing.py +5 -5
- omdev/tools/json/processing.py +6 -3
- omdev/tools/json/rendering.py +2 -2
- omdev/tools/jsonview/cli.py +49 -65
- omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
- omdev/tools/pawk/README.md +195 -0
- omdev/tools/pawk/pawk.py +2 -2
- omdev/tools/pip.py +8 -0
- omdev/tui/__init__.py +0 -0
- omdev/tui/apps/__init__.py +0 -0
- omdev/tui/apps/edit/__init__.py +0 -0
- omdev/tui/apps/edit/main.py +167 -0
- omdev/tui/apps/irc/__init__.py +0 -0
- omdev/tui/apps/irc/__main__.py +4 -0
- omdev/tui/apps/irc/app.py +286 -0
- omdev/tui/apps/irc/client.py +187 -0
- omdev/tui/apps/irc/commands.py +175 -0
- omdev/tui/apps/irc/main.py +26 -0
- omdev/tui/apps/markdown/__init__.py +0 -0
- omdev/tui/apps/markdown/__main__.py +11 -0
- omdev/{ptk → tui/apps}/markdown/cli.py +5 -7
- omdev/tui/rich/__init__.py +46 -0
- omdev/tui/rich/console2.py +20 -0
- omdev/tui/rich/markdown2.py +186 -0
- omdev/tui/textual/__init__.py +265 -0
- omdev/tui/textual/app2.py +16 -0
- omdev/tui/textual/autocomplete/LICENSE +21 -0
- omdev/tui/textual/autocomplete/__init__.py +33 -0
- omdev/tui/textual/autocomplete/matching.py +226 -0
- omdev/tui/textual/autocomplete/paths.py +202 -0
- omdev/tui/textual/autocomplete/widget.py +612 -0
- omdev/tui/textual/debug/__init__.py +10 -0
- omdev/tui/textual/debug/dominfo.py +151 -0
- omdev/tui/textual/debug/screen.py +24 -0
- omdev/tui/textual/devtools.py +187 -0
- omdev/tui/textual/drivers2.py +55 -0
- omdev/tui/textual/logging2.py +20 -0
- omdev/tui/textual/types.py +45 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/METADATA +18 -12
- omdev-0.0.0.dev500.dist-info/RECORD +386 -0
- omdev/ptk/__init__.py +0 -103
- omdev/ptk/apps/ncdu.py +0 -167
- omdev/ptk/confirm.py +0 -60
- omdev/ptk/markdown/LICENSE +0 -22
- omdev/ptk/markdown/__init__.py +0 -10
- omdev/ptk/markdown/__main__.py +0 -11
- omdev/ptk/markdown/border.py +0 -94
- omdev/ptk/markdown/markdown.py +0 -390
- omdev/ptk/markdown/parser.py +0 -42
- omdev/ptk/markdown/styles.py +0 -29
- omdev/ptk/markdown/tags.py +0 -299
- omdev/ptk/markdown/utils.py +0 -366
- omdev/pyproject/cexts.py +0 -110
- omdev/tools/antlr/__main__.py +0 -11
- omdev/tools/antlr/cli.py +0 -62
- omdev/tools/antlr/consts.py +0 -7
- omdev/tools/antlr/gen.py +0 -188
- omdev-0.0.0.dev416.dist-info/RECORD +0 -332
- /omdev/{ptk/apps → irc}/__init__.py +0 -0
- /omdev/{tokens → irc/messages}/__init__.py +0 -0
- /omdev/{tools/antlr → irc/numerics}/__init__.py +0 -0
- /omdev/{tokens → py/tokens}/all.py +0 -0
- /omdev/{tokens → py/tokens}/tokenizert.py +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/top_level.txt +0 -0
omdev/manifests/_dumping.py
CHANGED
|
@@ -34,11 +34,28 @@ if sys.version_info < (3, 8):
|
|
|
34
34
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def __omlish_amalg__(): # noqa
|
|
38
|
+
return dict(
|
|
39
|
+
src_files=[
|
|
40
|
+
dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
41
|
+
dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
|
|
42
|
+
dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
43
|
+
dict(path='../../omlish/lite/objects.py', sha1='9566bbf3530fd71fcc56321485216b592fae21e9'),
|
|
44
|
+
dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
45
|
+
dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
|
|
46
|
+
dict(path='../../omlish/lite/marshal.py', sha1='96348f5f2a26dc27d842d33cc3927e9da163436b'),
|
|
47
|
+
dict(path='dumping.py', sha1='49acd06fdcc3427f4a255fea295d7042bb655a13'),
|
|
48
|
+
],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
37
52
|
########################################
|
|
38
53
|
|
|
39
54
|
|
|
40
|
-
# ../../omlish/lite/
|
|
55
|
+
# ../../omlish/lite/abstract.py
|
|
41
56
|
T = ta.TypeVar('T')
|
|
57
|
+
|
|
58
|
+
# ../../omlish/lite/cached.py
|
|
42
59
|
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
|
43
60
|
|
|
44
61
|
# ../../omlish/lite/check.py
|
|
@@ -50,6 +67,153 @@ CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
|
|
|
50
67
|
CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
|
|
51
68
|
|
|
52
69
|
|
|
70
|
+
########################################
|
|
71
|
+
# ../../../omlish/lite/abstract.py
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
_ABSTRACT_METHODS_ATTR = '__abstractmethods__'
|
|
78
|
+
_IS_ABSTRACT_METHOD_ATTR = '__isabstractmethod__'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def is_abstract_method(obj: ta.Any) -> bool:
|
|
82
|
+
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
86
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
87
|
+
|
|
88
|
+
# Stage 1: direct abstract methods
|
|
89
|
+
|
|
90
|
+
abstracts = {
|
|
91
|
+
a
|
|
92
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
93
|
+
for a, v in list(cls.__dict__.items())
|
|
94
|
+
if is_abstract_method(v)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Stage 2: inherited abstract methods
|
|
98
|
+
|
|
99
|
+
for base in cls.__bases__:
|
|
100
|
+
# Get __abstractmethods__ from base if it exists
|
|
101
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
# Iterate over abstract methods in base
|
|
105
|
+
for key in base_abstracts:
|
|
106
|
+
# Check if this class has an attribute with this name
|
|
107
|
+
try:
|
|
108
|
+
value = getattr(cls, key)
|
|
109
|
+
except AttributeError:
|
|
110
|
+
# Attribute not found in this class, skip
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
# Check if it's still abstract
|
|
114
|
+
if is_abstract_method(value):
|
|
115
|
+
abstracts.add(key)
|
|
116
|
+
|
|
117
|
+
return frozenset(abstracts)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
121
|
+
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
122
|
+
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
123
|
+
# implementation (especially during testing), and we want to handle both cases.
|
|
124
|
+
return cls
|
|
125
|
+
|
|
126
|
+
abstracts = compute_abstract_methods(cls)
|
|
127
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
128
|
+
return cls
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
#
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class AbstractTypeError(TypeError):
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
_FORCE_ABSTRACT_ATTR = '__forceabstract__'
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class Abstract:
|
|
142
|
+
"""
|
|
143
|
+
Different from, but interoperable with, abc.ABC / abc.ABCMeta:
|
|
144
|
+
|
|
145
|
+
- This raises AbstractTypeError during class creation, not instance instantiation - unless Abstract or abc.ABC are
|
|
146
|
+
explicitly present in the class's direct bases.
|
|
147
|
+
- This will forbid instantiation of classes with Abstract in their direct bases even if there are no
|
|
148
|
+
abstractmethods left on the class.
|
|
149
|
+
- This is a mixin, not a metaclass.
|
|
150
|
+
- As it is not an ABCMeta, this does not support virtual base classes. As a result, operations like `isinstance`
|
|
151
|
+
and `issubclass` are ~7x faster.
|
|
152
|
+
- It additionally enforces a base class order of (Abstract, abc.ABC) to preemptively prevent common mro conflicts.
|
|
153
|
+
|
|
154
|
+
If not mixed-in with an ABCMeta, it will update __abstractmethods__ itself.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
__slots__ = ()
|
|
158
|
+
|
|
159
|
+
__abstractmethods__: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
|
|
160
|
+
|
|
161
|
+
#
|
|
162
|
+
|
|
163
|
+
def __forceabstract__(self):
|
|
164
|
+
raise TypeError
|
|
165
|
+
|
|
166
|
+
# This is done manually, rather than through @abc.abstractmethod, to mask it from static analysis.
|
|
167
|
+
setattr(__forceabstract__, _IS_ABSTRACT_METHOD_ATTR, True)
|
|
168
|
+
|
|
169
|
+
#
|
|
170
|
+
|
|
171
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
172
|
+
setattr(
|
|
173
|
+
cls,
|
|
174
|
+
_FORCE_ABSTRACT_ATTR,
|
|
175
|
+
getattr(Abstract, _FORCE_ABSTRACT_ATTR) if Abstract in cls.__bases__ else False,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
super().__init_subclass__(**kwargs)
|
|
179
|
+
|
|
180
|
+
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
181
|
+
if ams := compute_abstract_methods(cls):
|
|
182
|
+
amd = {
|
|
183
|
+
a: mcls
|
|
184
|
+
for mcls in cls.__mro__[::-1]
|
|
185
|
+
for a in ams
|
|
186
|
+
if a in mcls.__dict__
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
raise AbstractTypeError(
|
|
190
|
+
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
191
|
+
', '.join(sorted([
|
|
192
|
+
'.'.join([
|
|
193
|
+
*([
|
|
194
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
195
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
196
|
+
] if c is not None else '?'),
|
|
197
|
+
a,
|
|
198
|
+
])
|
|
199
|
+
for a in ams
|
|
200
|
+
for c in [amd.get(a)]
|
|
201
|
+
])),
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
xbi = (Abstract, abc.ABC) # , ta.Generic ?
|
|
205
|
+
bis = [(cls.__bases__.index(b), b) for b in xbi if b in cls.__bases__]
|
|
206
|
+
if bis != sorted(bis):
|
|
207
|
+
raise TypeError(
|
|
208
|
+
f'Abstract subclass {cls.__name__} must have proper base class order of '
|
|
209
|
+
f'({", ".join(getattr(b, "__name__") for b in xbi)}), got: '
|
|
210
|
+
f'({", ".join(getattr(b, "__name__") for _, b in sorted(bis))})',
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
if not isinstance(cls, abc.ABCMeta):
|
|
214
|
+
update_abstracts(cls, force=True)
|
|
215
|
+
|
|
216
|
+
|
|
53
217
|
########################################
|
|
54
218
|
# ../../../omlish/lite/cached.py
|
|
55
219
|
|
|
@@ -68,7 +232,7 @@ class _AbstractCachedNullary:
|
|
|
68
232
|
def __call__(self, *args, **kwargs): # noqa
|
|
69
233
|
raise TypeError
|
|
70
234
|
|
|
71
|
-
def __get__(self, instance, owner): # noqa
|
|
235
|
+
def __get__(self, instance, owner=None): # noqa
|
|
72
236
|
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
|
73
237
|
return bound
|
|
74
238
|
|
|
@@ -107,6 +271,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
107
271
|
return _AsyncCachedNullary(fn)
|
|
108
272
|
|
|
109
273
|
|
|
274
|
+
##
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
cached_property = functools.cached_property
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class _cached_property: # noqa
|
|
281
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
|
282
|
+
|
|
283
|
+
def __init__(self, func):
|
|
284
|
+
self.func = func
|
|
285
|
+
self.attrname = None # noqa
|
|
286
|
+
self.__doc__ = func.__doc__
|
|
287
|
+
self.__module__ = func.__module__
|
|
288
|
+
|
|
289
|
+
_NOT_FOUND = object()
|
|
290
|
+
|
|
291
|
+
def __set_name__(self, owner, name):
|
|
292
|
+
if self.attrname is None:
|
|
293
|
+
self.attrname = name # noqa
|
|
294
|
+
elif name != self.attrname:
|
|
295
|
+
raise TypeError(
|
|
296
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def __get__(self, instance, owner=None):
|
|
300
|
+
if instance is None:
|
|
301
|
+
return self
|
|
302
|
+
if self.attrname is None:
|
|
303
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
cache = instance.__dict__
|
|
307
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
|
308
|
+
raise TypeError(
|
|
309
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
|
310
|
+
) from None
|
|
311
|
+
|
|
312
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
|
313
|
+
|
|
314
|
+
if val is self._NOT_FOUND:
|
|
315
|
+
val = self.func(instance)
|
|
316
|
+
try:
|
|
317
|
+
cache[self.attrname] = val
|
|
318
|
+
except TypeError:
|
|
319
|
+
raise TypeError(
|
|
320
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
|
321
|
+
f"assignment for caching {self.attrname!r} property.",
|
|
322
|
+
) from None
|
|
323
|
+
|
|
324
|
+
return val
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
globals()['cached_property'] = _cached_property
|
|
328
|
+
|
|
329
|
+
|
|
110
330
|
########################################
|
|
111
331
|
# ../../../omlish/lite/check.py
|
|
112
332
|
"""
|
|
@@ -598,6 +818,86 @@ class Checks:
|
|
|
598
818
|
check = Checks()
|
|
599
819
|
|
|
600
820
|
|
|
821
|
+
########################################
|
|
822
|
+
# ../../../omlish/lite/objects.py
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
##
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
|
829
|
+
seen = set()
|
|
830
|
+
todo = list(reversed(cls.__subclasses__()))
|
|
831
|
+
while todo:
|
|
832
|
+
cur = todo.pop()
|
|
833
|
+
if cur in seen:
|
|
834
|
+
continue
|
|
835
|
+
seen.add(cur)
|
|
836
|
+
yield cur
|
|
837
|
+
todo.extend(reversed(cur.__subclasses__()))
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
##
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
def mro_owner_dict(
|
|
844
|
+
instance_cls: type,
|
|
845
|
+
owner_cls: ta.Optional[type] = None,
|
|
846
|
+
*,
|
|
847
|
+
bottom_up_key_order: bool = False,
|
|
848
|
+
sort_keys: bool = False,
|
|
849
|
+
) -> ta.Mapping[str, ta.Tuple[type, ta.Any]]:
|
|
850
|
+
if owner_cls is None:
|
|
851
|
+
owner_cls = instance_cls
|
|
852
|
+
|
|
853
|
+
mro = instance_cls.__mro__[-2::-1]
|
|
854
|
+
try:
|
|
855
|
+
pos = mro.index(owner_cls)
|
|
856
|
+
except ValueError:
|
|
857
|
+
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
|
858
|
+
|
|
859
|
+
dct: ta.Dict[str, ta.Tuple[type, ta.Any]] = {}
|
|
860
|
+
if not bottom_up_key_order:
|
|
861
|
+
for cur_cls in mro[:pos + 1][::-1]:
|
|
862
|
+
for k, v in cur_cls.__dict__.items():
|
|
863
|
+
if k not in dct:
|
|
864
|
+
dct[k] = (cur_cls, v)
|
|
865
|
+
|
|
866
|
+
else:
|
|
867
|
+
for cur_cls in mro[:pos + 1]:
|
|
868
|
+
dct.update({k: (cur_cls, v) for k, v in cur_cls.__dict__.items()})
|
|
869
|
+
|
|
870
|
+
if sort_keys:
|
|
871
|
+
dct = dict(sorted(dct.items(), key=lambda t: t[0]))
|
|
872
|
+
|
|
873
|
+
return dct
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
def mro_dict(
|
|
877
|
+
instance_cls: type,
|
|
878
|
+
owner_cls: ta.Optional[type] = None,
|
|
879
|
+
*,
|
|
880
|
+
bottom_up_key_order: bool = False,
|
|
881
|
+
sort_keys: bool = False,
|
|
882
|
+
) -> ta.Mapping[str, ta.Any]:
|
|
883
|
+
return {
|
|
884
|
+
k: v
|
|
885
|
+
for k, (o, v) in mro_owner_dict(
|
|
886
|
+
instance_cls,
|
|
887
|
+
owner_cls,
|
|
888
|
+
bottom_up_key_order=bottom_up_key_order,
|
|
889
|
+
sort_keys=sort_keys,
|
|
890
|
+
).items()
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
def dir_dict(o: ta.Any) -> ta.Dict[str, ta.Any]:
|
|
895
|
+
return {
|
|
896
|
+
a: getattr(o, a)
|
|
897
|
+
for a in dir(o)
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
|
|
601
901
|
########################################
|
|
602
902
|
# ../../../omlish/lite/reflect.py
|
|
603
903
|
|
|
@@ -687,21 +987,6 @@ def get_literal_type_args(spec: ta.Any) -> ta.Iterable[ta.Any]:
|
|
|
687
987
|
return spec.__args__
|
|
688
988
|
|
|
689
989
|
|
|
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
990
|
########################################
|
|
706
991
|
# ../../../omlish/lite/strings.py
|
|
707
992
|
|
|
@@ -778,13 +1063,6 @@ def split_keep_delimiter(s, d):
|
|
|
778
1063
|
##
|
|
779
1064
|
|
|
780
1065
|
|
|
781
|
-
def attr_repr(obj: ta.Any, *attrs: str) -> str:
|
|
782
|
-
return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
##
|
|
786
|
-
|
|
787
|
-
|
|
788
1066
|
FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
|
|
789
1067
|
|
|
790
1068
|
|
|
@@ -818,7 +1096,7 @@ class ObjMarshalOptions:
|
|
|
818
1096
|
non_strict_fields: bool = False
|
|
819
1097
|
|
|
820
1098
|
|
|
821
|
-
class ObjMarshaler(
|
|
1099
|
+
class ObjMarshaler(Abstract):
|
|
822
1100
|
@abc.abstractmethod
|
|
823
1101
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
824
1102
|
raise NotImplementedError
|
|
@@ -836,26 +1114,30 @@ class NopObjMarshaler(ObjMarshaler):
|
|
|
836
1114
|
return o
|
|
837
1115
|
|
|
838
1116
|
|
|
839
|
-
@dc.dataclass()
|
|
840
1117
|
class ProxyObjMarshaler(ObjMarshaler):
|
|
841
|
-
m: ta.Optional[ObjMarshaler] = None
|
|
1118
|
+
def __init__(self, m: ta.Optional[ObjMarshaler] = None) -> None:
|
|
1119
|
+
super().__init__()
|
|
1120
|
+
|
|
1121
|
+
self._m = m
|
|
842
1122
|
|
|
843
1123
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
844
|
-
return check.not_none(self.
|
|
1124
|
+
return check.not_none(self._m).marshal(o, ctx)
|
|
845
1125
|
|
|
846
1126
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
847
|
-
return check.not_none(self.
|
|
1127
|
+
return check.not_none(self._m).unmarshal(o, ctx)
|
|
848
1128
|
|
|
849
1129
|
|
|
850
|
-
@dc.dataclass(frozen=True)
|
|
851
1130
|
class CastObjMarshaler(ObjMarshaler):
|
|
852
|
-
ty: type
|
|
1131
|
+
def __init__(self, ty: type) -> None:
|
|
1132
|
+
super().__init__()
|
|
1133
|
+
|
|
1134
|
+
self._ty = ty
|
|
853
1135
|
|
|
854
1136
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
855
1137
|
return o
|
|
856
1138
|
|
|
857
1139
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
858
|
-
return self.
|
|
1140
|
+
return self._ty(o)
|
|
859
1141
|
|
|
860
1142
|
|
|
861
1143
|
class DynamicObjMarshaler(ObjMarshaler):
|
|
@@ -866,121 +1148,151 @@ class DynamicObjMarshaler(ObjMarshaler):
|
|
|
866
1148
|
return o
|
|
867
1149
|
|
|
868
1150
|
|
|
869
|
-
@dc.dataclass(frozen=True)
|
|
870
1151
|
class Base64ObjMarshaler(ObjMarshaler):
|
|
871
|
-
ty: type
|
|
1152
|
+
def __init__(self, ty: type) -> None:
|
|
1153
|
+
super().__init__()
|
|
1154
|
+
|
|
1155
|
+
self._ty = ty
|
|
872
1156
|
|
|
873
1157
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
874
1158
|
return base64.b64encode(o).decode('ascii')
|
|
875
1159
|
|
|
876
1160
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
877
|
-
return self.
|
|
1161
|
+
return self._ty(base64.b64decode(o))
|
|
878
1162
|
|
|
879
1163
|
|
|
880
|
-
@dc.dataclass(frozen=True)
|
|
881
1164
|
class BytesSwitchedObjMarshaler(ObjMarshaler):
|
|
882
|
-
m: ObjMarshaler
|
|
1165
|
+
def __init__(self, m: ObjMarshaler) -> None:
|
|
1166
|
+
super().__init__()
|
|
1167
|
+
|
|
1168
|
+
self._m = m
|
|
883
1169
|
|
|
884
1170
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
885
1171
|
if ctx.options.raw_bytes:
|
|
886
1172
|
return o
|
|
887
|
-
return self.
|
|
1173
|
+
return self._m.marshal(o, ctx)
|
|
888
1174
|
|
|
889
1175
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
890
1176
|
if ctx.options.raw_bytes:
|
|
891
1177
|
return o
|
|
892
|
-
return self.
|
|
1178
|
+
return self._m.unmarshal(o, ctx)
|
|
893
1179
|
|
|
894
1180
|
|
|
895
|
-
@dc.dataclass(frozen=True)
|
|
896
1181
|
class EnumObjMarshaler(ObjMarshaler):
|
|
897
|
-
ty: type
|
|
1182
|
+
def __init__(self, ty: type) -> None:
|
|
1183
|
+
super().__init__()
|
|
1184
|
+
|
|
1185
|
+
self._ty = ty
|
|
898
1186
|
|
|
899
1187
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
900
1188
|
return o.name
|
|
901
1189
|
|
|
902
1190
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
903
|
-
return self.
|
|
1191
|
+
return self._ty.__members__[o] # type: ignore
|
|
904
1192
|
|
|
905
1193
|
|
|
906
|
-
@dc.dataclass(frozen=True)
|
|
907
1194
|
class OptionalObjMarshaler(ObjMarshaler):
|
|
908
|
-
item: ObjMarshaler
|
|
1195
|
+
def __init__(self, item: ObjMarshaler) -> None:
|
|
1196
|
+
super().__init__()
|
|
1197
|
+
|
|
1198
|
+
self._item = item
|
|
909
1199
|
|
|
910
1200
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
911
1201
|
if o is None:
|
|
912
1202
|
return None
|
|
913
|
-
return self.
|
|
1203
|
+
return self._item.marshal(o, ctx)
|
|
914
1204
|
|
|
915
1205
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
916
1206
|
if o is None:
|
|
917
1207
|
return None
|
|
918
|
-
return self.
|
|
1208
|
+
return self._item.unmarshal(o, ctx)
|
|
919
1209
|
|
|
920
1210
|
|
|
921
|
-
@dc.dataclass(frozen=True)
|
|
922
1211
|
class PrimitiveUnionObjMarshaler(ObjMarshaler):
|
|
923
|
-
|
|
924
|
-
|
|
1212
|
+
def __init__(
|
|
1213
|
+
self,
|
|
1214
|
+
pt: ta.Tuple[type, ...],
|
|
1215
|
+
x: ta.Optional[ObjMarshaler] = None,
|
|
1216
|
+
) -> None:
|
|
1217
|
+
super().__init__()
|
|
1218
|
+
|
|
1219
|
+
self._pt = pt
|
|
1220
|
+
self._x = x
|
|
925
1221
|
|
|
926
1222
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
927
|
-
if isinstance(o, self.
|
|
1223
|
+
if isinstance(o, self._pt):
|
|
928
1224
|
return o
|
|
929
|
-
elif self.
|
|
930
|
-
return self.
|
|
1225
|
+
elif self._x is not None:
|
|
1226
|
+
return self._x.marshal(o, ctx)
|
|
931
1227
|
else:
|
|
932
1228
|
raise TypeError(o)
|
|
933
1229
|
|
|
934
1230
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
935
|
-
if isinstance(o, self.
|
|
1231
|
+
if isinstance(o, self._pt):
|
|
936
1232
|
return o
|
|
937
|
-
elif self.
|
|
938
|
-
return self.
|
|
1233
|
+
elif self._x is not None:
|
|
1234
|
+
return self._x.unmarshal(o, ctx)
|
|
939
1235
|
else:
|
|
940
1236
|
raise TypeError(o)
|
|
941
1237
|
|
|
942
1238
|
|
|
943
|
-
@dc.dataclass(frozen=True)
|
|
944
1239
|
class LiteralObjMarshaler(ObjMarshaler):
|
|
945
|
-
|
|
946
|
-
|
|
1240
|
+
def __init__(
|
|
1241
|
+
self,
|
|
1242
|
+
item: ObjMarshaler,
|
|
1243
|
+
vs: frozenset,
|
|
1244
|
+
) -> None:
|
|
1245
|
+
super().__init__()
|
|
1246
|
+
|
|
1247
|
+
self._item = item
|
|
1248
|
+
self._vs = vs
|
|
947
1249
|
|
|
948
1250
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
949
|
-
return self.
|
|
1251
|
+
return self._item.marshal(check.in_(o, self._vs), ctx)
|
|
950
1252
|
|
|
951
1253
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
952
|
-
return check.in_(self.
|
|
1254
|
+
return check.in_(self._item.unmarshal(o, ctx), self._vs)
|
|
953
1255
|
|
|
954
1256
|
|
|
955
|
-
@dc.dataclass(frozen=True)
|
|
956
1257
|
class MappingObjMarshaler(ObjMarshaler):
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1258
|
+
def __init__(
|
|
1259
|
+
self,
|
|
1260
|
+
ty: type,
|
|
1261
|
+
km: ObjMarshaler,
|
|
1262
|
+
vm: ObjMarshaler,
|
|
1263
|
+
) -> None:
|
|
1264
|
+
super().__init__()
|
|
1265
|
+
|
|
1266
|
+
self._ty = ty
|
|
1267
|
+
self._km = km
|
|
1268
|
+
self._vm = vm
|
|
960
1269
|
|
|
961
1270
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
962
|
-
return {self.
|
|
1271
|
+
return {self._km.marshal(k, ctx): self._vm.marshal(v, ctx) for k, v in o.items()}
|
|
963
1272
|
|
|
964
1273
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
965
|
-
return self.
|
|
1274
|
+
return self._ty((self._km.unmarshal(k, ctx), self._vm.unmarshal(v, ctx)) for k, v in o.items())
|
|
966
1275
|
|
|
967
1276
|
|
|
968
|
-
@dc.dataclass(frozen=True)
|
|
969
1277
|
class IterableObjMarshaler(ObjMarshaler):
|
|
970
|
-
|
|
971
|
-
|
|
1278
|
+
def __init__(
|
|
1279
|
+
self,
|
|
1280
|
+
ty: type,
|
|
1281
|
+
item: ObjMarshaler,
|
|
1282
|
+
) -> None:
|
|
1283
|
+
super().__init__()
|
|
1284
|
+
|
|
1285
|
+
self._ty = ty
|
|
1286
|
+
self._item = item
|
|
972
1287
|
|
|
973
1288
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
974
|
-
return [self.
|
|
1289
|
+
return [self._item.marshal(e, ctx) for e in o]
|
|
975
1290
|
|
|
976
1291
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
977
|
-
return self.
|
|
1292
|
+
return self._ty(self._item.unmarshal(e, ctx) for e in o)
|
|
978
1293
|
|
|
979
1294
|
|
|
980
|
-
@dc.dataclass(frozen=True)
|
|
981
1295
|
class FieldsObjMarshaler(ObjMarshaler):
|
|
982
|
-
ty: type
|
|
983
|
-
|
|
984
1296
|
@dc.dataclass(frozen=True)
|
|
985
1297
|
class Field:
|
|
986
1298
|
att: str
|
|
@@ -989,31 +1301,43 @@ class FieldsObjMarshaler(ObjMarshaler):
|
|
|
989
1301
|
|
|
990
1302
|
omit_if_none: bool = False
|
|
991
1303
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1304
|
+
def __init__(
|
|
1305
|
+
self,
|
|
1306
|
+
ty: type,
|
|
1307
|
+
fs: ta.Sequence[Field],
|
|
1308
|
+
*,
|
|
1309
|
+
non_strict: bool = False,
|
|
1310
|
+
) -> None:
|
|
1311
|
+
super().__init__()
|
|
997
1312
|
|
|
998
|
-
|
|
999
|
-
|
|
1313
|
+
self._ty = ty
|
|
1314
|
+
self._fs = fs
|
|
1315
|
+
self._non_strict = non_strict
|
|
1000
1316
|
|
|
1001
|
-
def __post_init__(self) -> None:
|
|
1002
1317
|
fs_by_att: dict = {}
|
|
1003
1318
|
fs_by_key: dict = {}
|
|
1004
|
-
for f in self.
|
|
1319
|
+
for f in self._fs:
|
|
1005
1320
|
check.not_in(check.non_empty_str(f.att), fs_by_att)
|
|
1006
1321
|
check.not_in(check.non_empty_str(f.key), fs_by_key)
|
|
1007
1322
|
fs_by_att[f.att] = f
|
|
1008
1323
|
fs_by_key[f.key] = f
|
|
1009
|
-
|
|
1010
|
-
self.
|
|
1324
|
+
|
|
1325
|
+
self._fs_by_att: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_att
|
|
1326
|
+
self._fs_by_key: ta.Mapping[str, FieldsObjMarshaler.Field] = fs_by_key
|
|
1327
|
+
|
|
1328
|
+
@property
|
|
1329
|
+
def ty(self) -> type:
|
|
1330
|
+
return self._ty
|
|
1331
|
+
|
|
1332
|
+
@property
|
|
1333
|
+
def fs(self) -> ta.Sequence[Field]:
|
|
1334
|
+
return self._fs
|
|
1011
1335
|
|
|
1012
1336
|
#
|
|
1013
1337
|
|
|
1014
1338
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1015
1339
|
d = {}
|
|
1016
|
-
for f in self.
|
|
1340
|
+
for f in self._fs:
|
|
1017
1341
|
mv = f.m.marshal(getattr(o, f.att), ctx)
|
|
1018
1342
|
if mv is None and f.omit_if_none:
|
|
1019
1343
|
continue
|
|
@@ -1024,34 +1348,46 @@ class FieldsObjMarshaler(ObjMarshaler):
|
|
|
1024
1348
|
kw = {}
|
|
1025
1349
|
for k, v in o.items():
|
|
1026
1350
|
if (f := self._fs_by_key.get(k)) is None:
|
|
1027
|
-
if not (self.
|
|
1351
|
+
if not (self._non_strict or ctx.options.non_strict_fields):
|
|
1028
1352
|
raise KeyError(k)
|
|
1029
1353
|
continue
|
|
1030
1354
|
kw[f.att] = f.m.unmarshal(v, ctx)
|
|
1031
|
-
return self.
|
|
1355
|
+
return self._ty(**kw)
|
|
1032
1356
|
|
|
1033
1357
|
|
|
1034
|
-
@dc.dataclass(frozen=True)
|
|
1035
1358
|
class SingleFieldObjMarshaler(ObjMarshaler):
|
|
1036
|
-
|
|
1037
|
-
|
|
1359
|
+
def __init__(
|
|
1360
|
+
self,
|
|
1361
|
+
ty: type,
|
|
1362
|
+
fld: str,
|
|
1363
|
+
) -> None:
|
|
1364
|
+
super().__init__()
|
|
1365
|
+
|
|
1366
|
+
self._ty = ty
|
|
1367
|
+
self._fld = fld
|
|
1038
1368
|
|
|
1039
1369
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1040
|
-
return getattr(o, self.
|
|
1370
|
+
return getattr(o, self._fld)
|
|
1041
1371
|
|
|
1042
1372
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1043
|
-
return self.
|
|
1373
|
+
return self._ty(**{self._fld: o})
|
|
1044
1374
|
|
|
1045
1375
|
|
|
1046
|
-
@dc.dataclass(frozen=True)
|
|
1047
1376
|
class PolymorphicObjMarshaler(ObjMarshaler):
|
|
1048
1377
|
class Impl(ta.NamedTuple):
|
|
1049
1378
|
ty: type
|
|
1050
1379
|
tag: str
|
|
1051
1380
|
m: ObjMarshaler
|
|
1052
1381
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1382
|
+
def __init__(
|
|
1383
|
+
self,
|
|
1384
|
+
impls_by_ty: ta.Mapping[type, Impl],
|
|
1385
|
+
impls_by_tag: ta.Mapping[str, Impl],
|
|
1386
|
+
) -> None:
|
|
1387
|
+
super().__init__()
|
|
1388
|
+
|
|
1389
|
+
self._impls_by_ty = impls_by_ty
|
|
1390
|
+
self._impls_by_tag = impls_by_tag
|
|
1055
1391
|
|
|
1056
1392
|
@classmethod
|
|
1057
1393
|
def of(cls, impls: ta.Iterable[Impl]) -> 'PolymorphicObjMarshaler':
|
|
@@ -1061,24 +1397,29 @@ class PolymorphicObjMarshaler(ObjMarshaler):
|
|
|
1061
1397
|
)
|
|
1062
1398
|
|
|
1063
1399
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1064
|
-
impl = self.
|
|
1400
|
+
impl = self._impls_by_ty[type(o)]
|
|
1065
1401
|
return {impl.tag: impl.m.marshal(o, ctx)}
|
|
1066
1402
|
|
|
1067
1403
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1068
1404
|
[(t, v)] = o.items()
|
|
1069
|
-
impl = self.
|
|
1405
|
+
impl = self._impls_by_tag[t]
|
|
1070
1406
|
return impl.m.unmarshal(v, ctx)
|
|
1071
1407
|
|
|
1072
1408
|
|
|
1073
|
-
@dc.dataclass(frozen=True)
|
|
1074
1409
|
class DatetimeObjMarshaler(ObjMarshaler):
|
|
1075
|
-
|
|
1410
|
+
def __init__(
|
|
1411
|
+
self,
|
|
1412
|
+
ty: type,
|
|
1413
|
+
) -> None:
|
|
1414
|
+
super().__init__()
|
|
1415
|
+
|
|
1416
|
+
self._ty = ty
|
|
1076
1417
|
|
|
1077
1418
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1078
1419
|
return o.isoformat()
|
|
1079
1420
|
|
|
1080
1421
|
def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
|
1081
|
-
return self.
|
|
1422
|
+
return self._ty.fromisoformat(o) # type: ignore
|
|
1082
1423
|
|
|
1083
1424
|
|
|
1084
1425
|
class DecimalObjMarshaler(ObjMarshaler):
|
|
@@ -1186,7 +1527,78 @@ class OBJ_MARSHALER_OMIT_IF_NONE(ObjMarshalerFieldMetadata): # noqa
|
|
|
1186
1527
|
##
|
|
1187
1528
|
|
|
1188
1529
|
|
|
1189
|
-
class ObjMarshalerManager:
|
|
1530
|
+
class ObjMarshalerManager(Abstract):
|
|
1531
|
+
@abc.abstractmethod
|
|
1532
|
+
def make_obj_marshaler(
|
|
1533
|
+
self,
|
|
1534
|
+
ty: ta.Any,
|
|
1535
|
+
rec: ta.Callable[[ta.Any], ObjMarshaler],
|
|
1536
|
+
*,
|
|
1537
|
+
non_strict_fields: bool = False,
|
|
1538
|
+
) -> ObjMarshaler:
|
|
1539
|
+
raise NotImplementedError
|
|
1540
|
+
|
|
1541
|
+
@abc.abstractmethod
|
|
1542
|
+
def set_obj_marshaler(
|
|
1543
|
+
self,
|
|
1544
|
+
ty: ta.Any,
|
|
1545
|
+
m: ObjMarshaler,
|
|
1546
|
+
*,
|
|
1547
|
+
override: bool = False,
|
|
1548
|
+
) -> None:
|
|
1549
|
+
raise NotImplementedError
|
|
1550
|
+
|
|
1551
|
+
@abc.abstractmethod
|
|
1552
|
+
def get_obj_marshaler(
|
|
1553
|
+
self,
|
|
1554
|
+
ty: ta.Any,
|
|
1555
|
+
*,
|
|
1556
|
+
no_cache: bool = False,
|
|
1557
|
+
**kwargs: ta.Any,
|
|
1558
|
+
) -> ObjMarshaler:
|
|
1559
|
+
raise NotImplementedError
|
|
1560
|
+
|
|
1561
|
+
@abc.abstractmethod
|
|
1562
|
+
def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
|
1563
|
+
raise NotImplementedError
|
|
1564
|
+
|
|
1565
|
+
#
|
|
1566
|
+
|
|
1567
|
+
def marshal_obj(
|
|
1568
|
+
self,
|
|
1569
|
+
o: ta.Any,
|
|
1570
|
+
ty: ta.Any = None,
|
|
1571
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
|
1572
|
+
) -> ta.Any:
|
|
1573
|
+
m = self.get_obj_marshaler(ty if ty is not None else type(o))
|
|
1574
|
+
return m.marshal(o, self.make_context(opts))
|
|
1575
|
+
|
|
1576
|
+
def unmarshal_obj(
|
|
1577
|
+
self,
|
|
1578
|
+
o: ta.Any,
|
|
1579
|
+
ty: ta.Union[ta.Type[T], ta.Any],
|
|
1580
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
|
1581
|
+
) -> T:
|
|
1582
|
+
m = self.get_obj_marshaler(ty)
|
|
1583
|
+
return m.unmarshal(o, self.make_context(opts))
|
|
1584
|
+
|
|
1585
|
+
def roundtrip_obj(
|
|
1586
|
+
self,
|
|
1587
|
+
o: ta.Any,
|
|
1588
|
+
ty: ta.Any = None,
|
|
1589
|
+
opts: ta.Optional[ObjMarshalOptions] = None,
|
|
1590
|
+
) -> ta.Any:
|
|
1591
|
+
if ty is None:
|
|
1592
|
+
ty = type(o)
|
|
1593
|
+
m: ta.Any = self.marshal_obj(o, ty, opts)
|
|
1594
|
+
u: ta.Any = self.unmarshal_obj(m, ty, opts)
|
|
1595
|
+
return u
|
|
1596
|
+
|
|
1597
|
+
|
|
1598
|
+
#
|
|
1599
|
+
|
|
1600
|
+
|
|
1601
|
+
class ObjMarshalerManagerImpl(ObjMarshalerManager):
|
|
1190
1602
|
def __init__(
|
|
1191
1603
|
self,
|
|
1192
1604
|
*,
|
|
@@ -1213,6 +1625,12 @@ class ObjMarshalerManager:
|
|
|
1213
1625
|
|
|
1214
1626
|
#
|
|
1215
1627
|
|
|
1628
|
+
@classmethod
|
|
1629
|
+
def _is_abstract(cls, ty: type) -> bool:
|
|
1630
|
+
return abc.ABC in ty.__bases__ or Abstract in ty.__bases__
|
|
1631
|
+
|
|
1632
|
+
#
|
|
1633
|
+
|
|
1216
1634
|
def make_obj_marshaler(
|
|
1217
1635
|
self,
|
|
1218
1636
|
ty: ta.Any,
|
|
@@ -1224,12 +1642,12 @@ class ObjMarshalerManager:
|
|
|
1224
1642
|
if (reg := self._registered_obj_marshalers.get(ty)) is not None:
|
|
1225
1643
|
return reg
|
|
1226
1644
|
|
|
1227
|
-
if
|
|
1645
|
+
if self._is_abstract(ty):
|
|
1228
1646
|
tn = ty.__name__
|
|
1229
1647
|
impls: ta.List[ta.Tuple[type, str]] = [ # type: ignore[var-annotated]
|
|
1230
1648
|
(ity, ity.__name__)
|
|
1231
1649
|
for ity in deep_subclasses(ty)
|
|
1232
|
-
if
|
|
1650
|
+
if not self._is_abstract(ity)
|
|
1233
1651
|
]
|
|
1234
1652
|
|
|
1235
1653
|
if all(itn.endswith(tn) for _, itn in impls):
|
|
@@ -1395,49 +1813,24 @@ class ObjMarshalerManager:
|
|
|
1395
1813
|
m = self.make_obj_marshaler(ty, rec, **kwargs)
|
|
1396
1814
|
finally:
|
|
1397
1815
|
del self._proxies[ty]
|
|
1398
|
-
p.
|
|
1816
|
+
p._m = m # noqa
|
|
1399
1817
|
|
|
1400
1818
|
if not no_cache:
|
|
1401
1819
|
self._obj_marshalers[ty] = m
|
|
1402
1820
|
return m
|
|
1403
1821
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
def _make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
|
1822
|
+
def make_context(self, opts: ta.Optional[ObjMarshalOptions]) -> 'ObjMarshalContext':
|
|
1407
1823
|
return ObjMarshalContext(
|
|
1408
1824
|
options=opts or self._default_options,
|
|
1409
1825
|
manager=self,
|
|
1410
1826
|
)
|
|
1411
1827
|
|
|
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
1828
|
|
|
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))
|
|
1829
|
+
def new_obj_marshaler_manager(**kwargs: ta.Any) -> ObjMarshalerManager:
|
|
1830
|
+
return ObjMarshalerManagerImpl(**kwargs)
|
|
1429
1831
|
|
|
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
|
|
1832
|
+
|
|
1833
|
+
##
|
|
1441
1834
|
|
|
1442
1835
|
|
|
1443
1836
|
@dc.dataclass(frozen=True)
|
|
@@ -1449,7 +1842,7 @@ class ObjMarshalContext:
|
|
|
1449
1842
|
##
|
|
1450
1843
|
|
|
1451
1844
|
|
|
1452
|
-
OBJ_MARSHALER_MANAGER =
|
|
1845
|
+
OBJ_MARSHALER_MANAGER = new_obj_marshaler_manager()
|
|
1453
1846
|
|
|
1454
1847
|
set_obj_marshaler = OBJ_MARSHALER_MANAGER.set_obj_marshaler
|
|
1455
1848
|
get_obj_marshaler = OBJ_MARSHALER_MANAGER.get_obj_marshaler
|