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.

Files changed (211) hide show
  1. omdev/{.manifests.json → .omlish-manifests.json} +23 -47
  2. omdev/README.md +51 -0
  3. omdev/__about__.py +12 -8
  4. omdev/amalg/cli/main.py +1 -2
  5. omdev/amalg/gen/gen.py +49 -6
  6. omdev/amalg/gen/imports.py +1 -1
  7. omdev/amalg/gen/manifests.py +1 -1
  8. omdev/amalg/gen/resources.py +1 -1
  9. omdev/amalg/gen/srcfiles.py +26 -3
  10. omdev/amalg/gen/strip.py +1 -1
  11. omdev/amalg/gen/types.py +1 -1
  12. omdev/amalg/gen/typing.py +1 -1
  13. omdev/amalg/info.py +32 -0
  14. omdev/cache/compute/storage.py +3 -1
  15. omdev/cache/data/actions.py +1 -1
  16. omdev/cache/data/cache.py +2 -2
  17. omdev/cache/data/specs.py +1 -1
  18. omdev/cexts/_boilerplate.cc +2 -3
  19. omdev/cexts/_distutils/build_ext.py +5 -2
  20. omdev/cexts/_distutils/compilers/ccompiler.py +5 -2
  21. omdev/cexts/_distutils/compilers/options.py +3 -0
  22. omdev/cexts/_distutils/compilers/unixccompiler.py +6 -2
  23. omdev/cexts/_distutils/dir_util.py +6 -2
  24. omdev/cexts/_distutils/errors.py +3 -0
  25. omdev/cexts/_distutils/extension.py +3 -0
  26. omdev/cexts/_distutils/file_util.py +6 -2
  27. omdev/cexts/_distutils/modified.py +3 -0
  28. omdev/cexts/_distutils/spawn.py +6 -2
  29. omdev/cexts/_distutils/sysconfig.py +3 -0
  30. omdev/cexts/_distutils/util.py +6 -2
  31. omdev/cexts/_distutils/version.py +3 -0
  32. omdev/cexts/cmake.py +5 -3
  33. omdev/cexts/scan.py +1 -2
  34. omdev/ci/cache.py +7 -3
  35. omdev/ci/cli.py +6 -4
  36. omdev/ci/docker/buildcaching.py +3 -1
  37. omdev/ci/docker/cache.py +2 -1
  38. omdev/ci/docker/cacheserved/cache.py +4 -1
  39. omdev/ci/docker/cacheserved/manifests.py +2 -2
  40. omdev/ci/docker/dataserver.py +2 -2
  41. omdev/ci/docker/imagepulling.py +2 -1
  42. omdev/ci/docker/packing.py +1 -1
  43. omdev/ci/docker/repositories.py +2 -1
  44. omdev/ci/github/api/clients.py +8 -4
  45. omdev/ci/github/api/v1/client.py +4 -1
  46. omdev/ci/github/api/v2/api.py +2 -0
  47. omdev/ci/github/api/v2/azure.py +4 -1
  48. omdev/ci/github/api/v2/client.py +4 -1
  49. omdev/cli/clicli.py +37 -7
  50. omdev/clipboard/clipboard.py +1 -1
  51. omdev/cmake.py +2 -1
  52. omdev/cmdlog/cli.py +1 -2
  53. omdev/dataclasses/_dumping.py +1960 -0
  54. omdev/dataclasses/_template.py +22 -0
  55. omdev/dataclasses/cli.py +7 -2
  56. omdev/dataclasses/codegen.py +342 -62
  57. omdev/dataclasses/dumping.py +200 -0
  58. omdev/dataserver/handlers.py +3 -2
  59. omdev/dataserver/targets.py +2 -2
  60. omdev/imgur.py +2 -2
  61. omdev/interp/cli.py +1 -1
  62. omdev/interp/inspect.py +2 -1
  63. omdev/interp/providers/base.py +3 -2
  64. omdev/interp/providers/standalone.py +4 -1
  65. omdev/interp/providers/system.py +2 -2
  66. omdev/interp/pyenv/install.py +2 -1
  67. omdev/interp/pyenv/provider.py +2 -2
  68. omdev/interp/types.py +3 -2
  69. omdev/interp/uv/provider.py +40 -2
  70. omdev/interp/uv/uv.py +2 -2
  71. omdev/interp/venvs.py +3 -2
  72. omdev/irc/messages/base.py +50 -0
  73. omdev/irc/messages/formats.py +92 -0
  74. omdev/irc/messages/messages.py +775 -0
  75. omdev/irc/messages/parsing.py +99 -0
  76. omdev/irc/numerics/formats.py +97 -0
  77. omdev/irc/numerics/numerics.py +865 -0
  78. omdev/irc/numerics/types.py +59 -0
  79. omdev/irc/protocol/LICENSE +11 -0
  80. omdev/irc/protocol/__init__.py +61 -0
  81. omdev/irc/protocol/consts.py +6 -0
  82. omdev/irc/protocol/errors.py +30 -0
  83. omdev/irc/protocol/message.py +21 -0
  84. omdev/irc/protocol/nuh.py +55 -0
  85. omdev/irc/protocol/parsing.py +158 -0
  86. omdev/irc/protocol/rendering.py +153 -0
  87. omdev/irc/protocol/tags.py +102 -0
  88. omdev/irc/protocol/utils.py +30 -0
  89. omdev/manifests/_dumping.py +529 -136
  90. omdev/manifests/building.py +6 -3
  91. omdev/manifests/main.py +1 -1
  92. omdev/markdown/__init__.py +0 -0
  93. omdev/markdown/incparse.py +116 -0
  94. omdev/markdown/tokens.py +51 -0
  95. omdev/oci/data.py +2 -2
  96. omdev/oci/datarefs.py +2 -2
  97. omdev/oci/media.py +2 -2
  98. omdev/oci/repositories.py +3 -2
  99. omdev/packaging/marshal.py +9 -9
  100. omdev/packaging/requires.py +6 -6
  101. omdev/packaging/revisions.py +5 -2
  102. omdev/packaging/specifiers.py +41 -42
  103. omdev/packaging/versions.py +10 -10
  104. omdev/packaging/wheelfile.py +4 -2
  105. omdev/precheck/blanklines.py +66 -0
  106. omdev/precheck/caches.py +1 -1
  107. omdev/precheck/imports.py +14 -1
  108. omdev/precheck/lite.py +2 -2
  109. omdev/precheck/main.py +5 -5
  110. omdev/precheck/unicode.py +39 -15
  111. omdev/py/asts/__init__.py +0 -0
  112. omdev/py/asts/parents.py +28 -0
  113. omdev/py/asts/toplevel.py +123 -0
  114. omdev/py/asts/visitors.py +18 -0
  115. omdev/py/attrdocs.py +6 -7
  116. omdev/py/bracepy.py +12 -4
  117. omdev/py/docstrings/numpydoc.py +4 -4
  118. omdev/py/reprs.py +32 -0
  119. omdev/py/scripts/execstat.py +31 -26
  120. omdev/py/srcheaders.py +1 -1
  121. omdev/py/tokens/__init__.py +0 -0
  122. omdev/{tokens → py/tokens}/utils.py +2 -1
  123. omdev/py/tools/importscan.py +2 -2
  124. omdev/py/tools/mkrelimp.py +3 -4
  125. omdev/py/tools/pipdepup.py +686 -0
  126. omdev/pyproject/cli.py +1 -1
  127. omdev/pyproject/pkg.py +197 -48
  128. omdev/pyproject/reqs.py +36 -10
  129. omdev/pyproject/tools/__init__.py +0 -0
  130. omdev/pyproject/tools/aboutdeps.py +60 -0
  131. omdev/pyproject/venvs.py +12 -2
  132. omdev/rs/__init__.py +0 -0
  133. omdev/scripts/ci.py +9551 -6982
  134. omdev/scripts/interp.py +1323 -892
  135. omdev/scripts/lib/__init__.py +0 -0
  136. omdev/scripts/lib/inject.py +2086 -0
  137. omdev/scripts/lib/logs.py +2175 -0
  138. omdev/scripts/lib/marshal.py +1731 -0
  139. omdev/scripts/pyproject.py +4979 -1874
  140. omdev/tools/docker.py +19 -7
  141. omdev/tools/git/cli.py +56 -16
  142. omdev/tools/git/messages.py +2 -2
  143. omdev/tools/json/cli.py +6 -6
  144. omdev/tools/json/formats.py +2 -0
  145. omdev/tools/json/parsing.py +5 -5
  146. omdev/tools/json/processing.py +6 -3
  147. omdev/tools/json/rendering.py +2 -2
  148. omdev/tools/jsonview/cli.py +49 -65
  149. omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
  150. omdev/tools/pawk/README.md +195 -0
  151. omdev/tools/pawk/pawk.py +2 -2
  152. omdev/tools/pip.py +8 -0
  153. omdev/tui/__init__.py +0 -0
  154. omdev/tui/apps/__init__.py +0 -0
  155. omdev/tui/apps/edit/__init__.py +0 -0
  156. omdev/tui/apps/edit/main.py +167 -0
  157. omdev/tui/apps/irc/__init__.py +0 -0
  158. omdev/tui/apps/irc/__main__.py +4 -0
  159. omdev/tui/apps/irc/app.py +286 -0
  160. omdev/tui/apps/irc/client.py +187 -0
  161. omdev/tui/apps/irc/commands.py +175 -0
  162. omdev/tui/apps/irc/main.py +26 -0
  163. omdev/tui/apps/markdown/__init__.py +0 -0
  164. omdev/tui/apps/markdown/__main__.py +11 -0
  165. omdev/{ptk → tui/apps}/markdown/cli.py +5 -7
  166. omdev/tui/rich/__init__.py +46 -0
  167. omdev/tui/rich/console2.py +20 -0
  168. omdev/tui/rich/markdown2.py +186 -0
  169. omdev/tui/textual/__init__.py +265 -0
  170. omdev/tui/textual/app2.py +16 -0
  171. omdev/tui/textual/autocomplete/LICENSE +21 -0
  172. omdev/tui/textual/autocomplete/__init__.py +33 -0
  173. omdev/tui/textual/autocomplete/matching.py +226 -0
  174. omdev/tui/textual/autocomplete/paths.py +202 -0
  175. omdev/tui/textual/autocomplete/widget.py +612 -0
  176. omdev/tui/textual/debug/__init__.py +10 -0
  177. omdev/tui/textual/debug/dominfo.py +151 -0
  178. omdev/tui/textual/debug/screen.py +24 -0
  179. omdev/tui/textual/devtools.py +187 -0
  180. omdev/tui/textual/drivers2.py +55 -0
  181. omdev/tui/textual/logging2.py +20 -0
  182. omdev/tui/textual/types.py +45 -0
  183. {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/METADATA +18 -12
  184. omdev-0.0.0.dev500.dist-info/RECORD +386 -0
  185. omdev/ptk/__init__.py +0 -103
  186. omdev/ptk/apps/ncdu.py +0 -167
  187. omdev/ptk/confirm.py +0 -60
  188. omdev/ptk/markdown/LICENSE +0 -22
  189. omdev/ptk/markdown/__init__.py +0 -10
  190. omdev/ptk/markdown/__main__.py +0 -11
  191. omdev/ptk/markdown/border.py +0 -94
  192. omdev/ptk/markdown/markdown.py +0 -390
  193. omdev/ptk/markdown/parser.py +0 -42
  194. omdev/ptk/markdown/styles.py +0 -29
  195. omdev/ptk/markdown/tags.py +0 -299
  196. omdev/ptk/markdown/utils.py +0 -366
  197. omdev/pyproject/cexts.py +0 -110
  198. omdev/tools/antlr/__main__.py +0 -11
  199. omdev/tools/antlr/cli.py +0 -62
  200. omdev/tools/antlr/consts.py +0 -7
  201. omdev/tools/antlr/gen.py +0 -188
  202. omdev-0.0.0.dev416.dist-info/RECORD +0 -332
  203. /omdev/{ptk/apps → irc}/__init__.py +0 -0
  204. /omdev/{tokens → irc/messages}/__init__.py +0 -0
  205. /omdev/{tools/antlr → irc/numerics}/__init__.py +0 -0
  206. /omdev/{tokens → py/tokens}/all.py +0 -0
  207. /omdev/{tokens → py/tokens}/tokenizert.py +0 -0
  208. {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/WHEEL +0 -0
  209. {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/entry_points.txt +0 -0
  210. {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/licenses/LICENSE +0 -0
  211. {omdev-0.0.0.dev416.dist-info → omdev-0.0.0.dev500.dist-info}/top_level.txt +0 -0
@@ -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/cached.py
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(abc.ABC):
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.m).marshal(o, ctx)
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.m).unmarshal(o, ctx)
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.ty(o)
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.ty(base64.b64decode(o))
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.m.marshal(o, ctx)
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.m.unmarshal(o, ctx)
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.ty.__members__[o] # type: ignore
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.item.marshal(o, ctx)
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.item.unmarshal(o, ctx)
1208
+ return self._item.unmarshal(o, ctx)
919
1209
 
920
1210
 
921
- @dc.dataclass(frozen=True)
922
1211
  class PrimitiveUnionObjMarshaler(ObjMarshaler):
923
- pt: ta.Tuple[type, ...]
924
- x: ta.Optional[ObjMarshaler] = None
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.pt):
1223
+ if isinstance(o, self._pt):
928
1224
  return o
929
- elif self.x is not None:
930
- return self.x.marshal(o, ctx)
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.pt):
1231
+ if isinstance(o, self._pt):
936
1232
  return o
937
- elif self.x is not None:
938
- return self.x.unmarshal(o, ctx)
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
- item: ObjMarshaler
946
- vs: frozenset
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.item.marshal(check.in_(o, self.vs), ctx)
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.item.unmarshal(o, ctx), self.vs)
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
- ty: type
958
- km: ObjMarshaler
959
- vm: ObjMarshaler
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.km.marshal(k, ctx): self.vm.marshal(v, ctx) for k, v in o.items()}
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.ty((self.km.unmarshal(k, ctx), self.vm.unmarshal(v, ctx)) for k, v in o.items())
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
- ty: type
971
- item: ObjMarshaler
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.item.marshal(e, ctx) for e in o]
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.ty(self.item.unmarshal(e, ctx) for e in o)
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
- fs: ta.Sequence[Field]
993
-
994
- non_strict: bool = False
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
- _fs_by_att: ta.ClassVar[ta.Mapping[str, Field]]
999
- _fs_by_key: ta.ClassVar[ta.Mapping[str, Field]]
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.fs:
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
- self.__dict__['_fs_by_att'] = fs_by_att
1010
- self.__dict__['_fs_by_key'] = fs_by_key
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.fs:
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.non_strict or ctx.options.non_strict_fields):
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.ty(**kw)
1355
+ return self._ty(**kw)
1032
1356
 
1033
1357
 
1034
- @dc.dataclass(frozen=True)
1035
1358
  class SingleFieldObjMarshaler(ObjMarshaler):
1036
- ty: type
1037
- fld: str
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.fld)
1370
+ return getattr(o, self._fld)
1041
1371
 
1042
1372
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
1043
- return self.ty(**{self.fld: o})
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
- impls_by_ty: ta.Mapping[type, Impl]
1054
- impls_by_tag: ta.Mapping[str, Impl]
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.impls_by_ty[type(o)]
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.impls_by_tag[t]
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
- ty: type
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.ty.fromisoformat(o) # type: ignore
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 abc.ABC in ty.__bases__:
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 abc.ABC not in ity.__bases__
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.m = m
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
- def unmarshal_obj(
1422
- self,
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
- def roundtrip_obj(
1431
- self,
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 = ObjMarshalerManager()
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