omlish 0.0.0.dev414__py3-none-any.whl → 0.0.0.dev416__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. omlish/__about__.py +2 -3
  2. omlish/codecs/registry.py +1 -1
  3. omlish/dataclasses/__init__.py +139 -113
  4. omlish/dataclasses/impl/api/classes/make.py +5 -3
  5. omlish/dataclasses/impl/configs.py +29 -29
  6. omlish/lang/__init__.py +486 -473
  7. omlish/lang/imports/proxyinit.py +161 -48
  8. omlish/lang/maybes.py +8 -0
  9. omlish/lite/maysyncs.py +1 -0
  10. omlish/manifests/base.py +1 -1
  11. omlish/marshal/__init__.py +98 -57
  12. omlish/marshal/base/__init__.py +0 -0
  13. omlish/marshal/base/contexts.py +78 -0
  14. omlish/marshal/{errors.py → base/errors.py} +1 -1
  15. omlish/marshal/base/options.py +2 -0
  16. omlish/marshal/base/overrides.py +34 -0
  17. omlish/marshal/{registries.py → base/registries.py} +11 -9
  18. omlish/marshal/base/types.py +122 -0
  19. omlish/marshal/{values.py → base/values.py} +1 -13
  20. omlish/marshal/composite/iterables.py +7 -7
  21. omlish/marshal/composite/literals.py +7 -7
  22. omlish/marshal/composite/mappings.py +7 -7
  23. omlish/marshal/composite/maybes.py +7 -7
  24. omlish/marshal/composite/newtypes.py +6 -6
  25. omlish/marshal/composite/optionals.py +7 -7
  26. omlish/marshal/composite/special.py +6 -6
  27. omlish/marshal/composite/wrapped.py +5 -5
  28. omlish/marshal/factories/__init__.py +0 -0
  29. omlish/marshal/factories/func.py +28 -0
  30. omlish/marshal/factories/match.py +34 -0
  31. omlish/marshal/factories/multi.py +55 -0
  32. omlish/marshal/factories/recursive.py +120 -0
  33. omlish/marshal/factories/simple.py +28 -0
  34. omlish/marshal/factories/typecache.py +91 -0
  35. omlish/marshal/factories/typemap.py +65 -0
  36. omlish/marshal/globals.py +35 -25
  37. omlish/marshal/naming.py +1 -1
  38. omlish/marshal/objects/dataclasses.py +7 -7
  39. omlish/marshal/objects/marshal.py +4 -4
  40. omlish/marshal/objects/metadata.py +4 -4
  41. omlish/marshal/objects/namedtuples.py +7 -7
  42. omlish/marshal/objects/unmarshal.py +4 -4
  43. omlish/marshal/polymorphism/marshal.py +4 -4
  44. omlish/marshal/polymorphism/metadata.py +1 -1
  45. omlish/marshal/polymorphism/standard.py +2 -2
  46. omlish/marshal/polymorphism/unions.py +7 -7
  47. omlish/marshal/polymorphism/unmarshal.py +4 -4
  48. omlish/marshal/singular/base64.py +7 -7
  49. omlish/marshal/singular/datetimes.py +7 -7
  50. omlish/marshal/singular/enums.py +7 -7
  51. omlish/marshal/singular/numbers.py +7 -7
  52. omlish/marshal/singular/primitives.py +7 -7
  53. omlish/marshal/singular/uuids.py +7 -7
  54. omlish/marshal/standard.py +8 -8
  55. omlish/marshal/trivial/any.py +7 -7
  56. omlish/marshal/trivial/forbidden.py +7 -7
  57. omlish/marshal/trivial/nop.py +5 -5
  58. omlish/reflect/__init__.py +57 -47
  59. omlish/reflect/types.py +144 -15
  60. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/METADATA +14 -9
  61. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/RECORD +65 -56
  62. omlish/inject/.dataclasses.json +0 -3
  63. omlish/marshal/.dataclasses.json +0 -3
  64. omlish/marshal/base.py +0 -472
  65. omlish/marshal/factories.py +0 -116
  66. omlish/marshal/proxy.py +0 -26
  67. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/WHEEL +0 -0
  68. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/entry_points.txt +0 -0
  69. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/licenses/LICENSE +0 -0
  70. {omlish-0.0.0.dev414.dist-info → omlish-0.0.0.dev416.dist-info}/top_level.txt +0 -0
@@ -183,6 +183,9 @@ class AutoProxyInitErrors:
183
183
  def __repr__(self) -> str:
184
184
  return f'{self.__class__.__qualname__}(unreferenced={self.unreferenced!r})'
185
185
 
186
+ class CaptureInProgressError(AutoProxyInitError):
187
+ pass
188
+
186
189
 
187
190
  class _AutoProxyInitCapture:
188
191
  class ModuleSpec(ta.NamedTuple):
@@ -418,20 +421,12 @@ class _AutoProxyInitCapture:
418
421
 
419
422
  #
420
423
 
421
- class ProxyInit(ta.NamedTuple):
422
- package: str
423
- attrs: ta.Sequence[tuple[str | None, str]]
424
-
425
- class BuiltProxyInits(ta.NamedTuple):
426
- proxy_inits: ta.Sequence['_AutoProxyInitCapture.ProxyInit']
427
- unreferenced: ta.Mapping[str, ta.Sequence[str | None]] | None
428
-
429
424
  def build_proxy_inits(
430
425
  self,
431
426
  init_globals: ta.MutableMapping[str, ta.Any], # noqa
432
427
  *,
433
428
  collect_unreferenced: bool = False,
434
- ) -> BuiltProxyInits:
429
+ ) -> 'AutoProxyInit.CapturedProxyInits':
435
430
  dct: dict[_AutoProxyInitCapture._Module, list[tuple[str | None, str]]] = {}
436
431
 
437
432
  rem_whole_mods: set[_AutoProxyInitCapture._Module] = set()
@@ -462,7 +457,7 @@ class _AutoProxyInitCapture:
462
457
  dct.setdefault(m, []).append((None, attr))
463
458
  rem_whole_mods.discard(m)
464
459
 
465
- lst: list[_AutoProxyInitCapture.ProxyInit] = []
460
+ lst: list[AutoProxyInit.ProxyInit] = []
466
461
  for m, ts in dct.items():
467
462
  if not m.spec.name:
468
463
  if not m.spec.level:
@@ -470,13 +465,13 @@ class _AutoProxyInitCapture:
470
465
  for imp_attr, as_attr in ts:
471
466
  if not imp_attr:
472
467
  raise RuntimeError
473
- lst.append(_AutoProxyInitCapture.ProxyInit(
468
+ lst.append(AutoProxyInit.ProxyInit(
474
469
  '.' * m.spec.level + imp_attr,
475
470
  [(None, as_attr)],
476
471
  ))
477
472
 
478
473
  else:
479
- lst.append(_AutoProxyInitCapture.ProxyInit(
474
+ lst.append(AutoProxyInit.ProxyInit(
480
475
  str(m.spec),
481
476
  ts,
482
477
  ))
@@ -490,12 +485,152 @@ class _AutoProxyInitCapture:
490
485
  m, a = self._attrs[ma]
491
486
  unreferenced.setdefault(str(m.spec), []).append(a)
492
487
 
493
- return _AutoProxyInitCapture.BuiltProxyInits(
488
+ return AutoProxyInit.CapturedProxyInits(
494
489
  lst,
495
490
  unreferenced,
496
491
  )
497
492
 
498
493
 
494
+ class AutoProxyInit:
495
+ class ProxyInit(ta.NamedTuple):
496
+ package: str
497
+ attrs: ta.Sequence[tuple[str | None, str]]
498
+
499
+ class CapturedProxyInits(ta.NamedTuple):
500
+ proxy_inits: ta.Sequence['AutoProxyInit.ProxyInit']
501
+ unreferenced: ta.Mapping[str, ta.Sequence[str | None]] | None
502
+
503
+ @property
504
+ def attrs(self) -> ta.Iterator[str]:
505
+ for pi in self.proxy_inits:
506
+ for _, a in pi.attrs:
507
+ yield a
508
+
509
+ #
510
+
511
+ def __init__(
512
+ self,
513
+ init_globals: ta.MutableMapping[str, ta.Any],
514
+ *,
515
+ disable: bool,
516
+ eager: bool,
517
+ ) -> None:
518
+ super().__init__()
519
+
520
+ self._init_globals = init_globals
521
+
522
+ self._disable = disable
523
+ self._eager = eager
524
+
525
+ @property
526
+ def disable(self) -> bool:
527
+ return self._disable
528
+
529
+ @property
530
+ def eager(self) -> bool:
531
+ return self._eager
532
+
533
+ #
534
+
535
+ class _Result(ta.NamedTuple):
536
+ captured: 'AutoProxyInit.CapturedProxyInits'
537
+
538
+ _result_: _Result | None = None
539
+
540
+ @property
541
+ def _result(self) -> _Result:
542
+ if (rs := self._result_) is None:
543
+ raise AutoProxyInitErrors.CaptureInProgressError
544
+ return rs
545
+
546
+ @property
547
+ def is_complete(self) -> bool:
548
+ return self._result_ is not None
549
+
550
+ @property
551
+ def captured(self) -> CapturedProxyInits:
552
+ return self._result.captured
553
+
554
+ #
555
+
556
+ @contextlib.contextmanager
557
+ def _capture(
558
+ self,
559
+ *,
560
+ unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
561
+ raise_unreferenced: bool = False,
562
+ ) -> ta.Iterator[None]:
563
+ if self._result_ is not None:
564
+ raise AutoProxyInitError('capture already complete')
565
+
566
+ if self._disable:
567
+ self._result_ = AutoProxyInit._Result(
568
+ AutoProxyInit.CapturedProxyInits(
569
+ [],
570
+ None,
571
+ ),
572
+ )
573
+ yield
574
+ return
575
+
576
+ cap = _AutoProxyInitCapture()
577
+
578
+ with cap.hook_context(self._init_globals):
579
+ yield
580
+
581
+ cap.verify_state(self._init_globals)
582
+
583
+ blt = cap.build_proxy_inits(
584
+ self._init_globals,
585
+ collect_unreferenced=unreferenced_callback is not None or raise_unreferenced,
586
+ )
587
+
588
+ if blt.unreferenced:
589
+ if unreferenced_callback:
590
+ unreferenced_callback(blt.unreferenced)
591
+ if raise_unreferenced:
592
+ raise AutoProxyInitErrors.UnreferencedImportsError(blt.unreferenced)
593
+
594
+ for pi in blt.proxy_inits:
595
+ for _, a in pi.attrs:
596
+ del self._init_globals[a]
597
+
598
+ proxy_init(
599
+ self._init_globals,
600
+ pi.package,
601
+ pi.attrs,
602
+ )
603
+
604
+ if self._eager:
605
+ lg = LazyGlobals.install(self._init_globals)
606
+
607
+ for a in blt.attrs:
608
+ lg.get(a)
609
+
610
+ self._result_ = AutoProxyInit._Result(
611
+ blt,
612
+ )
613
+
614
+ #
615
+
616
+ def update_exports(self) -> None:
617
+ cap = self._result.captured
618
+
619
+ try:
620
+ al: ta.Any = self._init_globals['__all__']
621
+ except KeyError:
622
+ al = self._init_globals['__all__'] = [k for k in self._init_globals if not k.startswith('_')]
623
+ else:
624
+ if not isinstance(al, ta.MutableSequence):
625
+ al = self._init_globals['__all__'] = list(al)
626
+
627
+ al_s = set(al)
628
+ for a in cap.attrs:
629
+ if a not in al_s:
630
+ al.append(a)
631
+ al_s.add(a)
632
+
633
+
499
634
  @contextlib.contextmanager
500
635
  def auto_proxy_init(
501
636
  init_globals: ta.MutableMapping[str, ta.Any],
@@ -505,48 +640,26 @@ def auto_proxy_init(
505
640
 
506
641
  unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
507
642
  raise_unreferenced: bool = False,
508
- ) -> ta.Iterator[None]:
643
+
644
+ update_exports: bool = False,
645
+ ) -> ta.Iterator[AutoProxyInit]:
509
646
  """
510
647
  This is a bit extreme - use sparingly. It relies on an interpreter-global import lock, but much of the ecosystem
511
648
  implicitly does anyway. It further relies on temporarily patching `__builtins__.__import__`, but could be switched
512
649
  to use any number of other import hooks.
513
650
  """
514
651
 
515
- if disable:
516
- yield
517
- return
518
-
519
- cap = _AutoProxyInitCapture()
520
-
521
- with cap.hook_context(init_globals):
522
- yield
523
-
524
- cap.verify_state(init_globals)
525
-
526
- blt = cap.build_proxy_inits(
652
+ inst = AutoProxyInit(
527
653
  init_globals,
528
- collect_unreferenced=unreferenced_callback is not None or raise_unreferenced,
654
+ disable=disable,
655
+ eager=eager,
529
656
  )
530
657
 
531
- if blt.unreferenced:
532
- if unreferenced_callback:
533
- unreferenced_callback(blt.unreferenced)
534
- if raise_unreferenced:
535
- raise AutoProxyInitErrors.UnreferencedImportsError(blt.unreferenced)
536
-
537
- for pi in blt.proxy_inits:
538
- for _, a in pi.attrs:
539
- del init_globals[a]
540
-
541
- proxy_init(
542
- init_globals,
543
- pi.package,
544
- pi.attrs,
545
- )
546
-
547
- if eager:
548
- lg = LazyGlobals.install(init_globals)
658
+ with inst._capture( # noqa
659
+ unreferenced_callback=unreferenced_callback,
660
+ raise_unreferenced=raise_unreferenced,
661
+ ):
662
+ yield inst
549
663
 
550
- for pi in blt.proxy_inits:
551
- for _, a in pi.attrs:
552
- lg.get(a)
664
+ if update_exports:
665
+ inst.update_exports()
omlish/lang/maybes.py ADDED
@@ -0,0 +1,8 @@
1
+ from ..lite.maybes import Maybe
2
+
3
+
4
+ ##
5
+
6
+
7
+ empty = Maybe.empty
8
+ just = Maybe.just
omlish/lite/maysyncs.py CHANGED
@@ -100,6 +100,7 @@ class AnyMaysyncFn(abc.ABC, ta.Generic[_MaysyncRS, _MaysyncRA]): # noqa
100
100
  raise NotImplementedError
101
101
 
102
102
 
103
+ @ta.final
103
104
  class MaywaitableAlreadyConsumedError(Exception):
104
105
  pass
105
106
 
omlish/manifests/base.py CHANGED
@@ -15,7 +15,7 @@ class ModAttrManifest:
15
15
  module: str
16
16
  attr: str
17
17
 
18
- def load(self) -> ta.Any:
18
+ def resolve(self) -> ta.Any:
19
19
  import importlib # noqa
20
20
 
21
21
  mod = importlib.import_module(self.module)
@@ -1,4 +1,48 @@
1
- from .base import ( # noqa
1
+ """
2
+ TODO:
3
+ - redacted
4
+ - strongly typed MarshalerFactory base class?
5
+ - strongly typed Composite/Cached Marshaler/Unmarshaler factories - footgun
6
+ - streaming? Start/EndObject, etc..
7
+ - lang.Marker - class name, handle type[Foo]
8
+ - can't disambiguate from str - can't coexist in bare union
9
+ - factories being free MatchFns does more harm than good - in practice these are such big guns you want to write a
10
+ class body if only ceremonially
11
+
12
+ See:
13
+ - https://github.com/python-attrs/cattrs
14
+ - https://github.com/jcrist/msgspec
15
+ - https://github.com/Fatal1ty/mashumaro
16
+ - https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#custom-serializers
17
+ """
18
+
19
+
20
+ from .base.contexts import ( # noqa
21
+ BaseContext,
22
+ MarshalContext,
23
+ UnmarshalContext,
24
+ )
25
+
26
+ from .base.errors import ( # noqa
27
+ ForbiddenTypeError,
28
+ MarshalError,
29
+ UnhandledTypeError,
30
+ )
31
+
32
+ from .base.options import ( # noqa
33
+ Option,
34
+ )
35
+
36
+ from .base.overrides import ( # noqa
37
+ Override,
38
+ ReflectOverride,
39
+ )
40
+
41
+ from .base.registries import ( # noqa
42
+ Registry,
43
+ )
44
+
45
+ from .base.types import ( # noqa
2
46
  Marshaler,
3
47
  Unmarshaler,
4
48
 
@@ -10,67 +54,55 @@ from .base import ( # noqa
10
54
 
11
55
  MarshalerFactory_,
12
56
  UnmarshalerFactory_,
57
+ )
58
+
59
+ from .base.values import ( # noqa
60
+ Value,
61
+ )
13
62
 
63
+ from .composite.iterables import ( # noqa
64
+ IterableMarshaler,
65
+ IterableUnmarshaler,
66
+ )
67
+
68
+ from .composite.wrapped import ( # noqa
69
+ WrappedMarshaler,
70
+ WrappedUnmarshaler,
71
+ )
72
+
73
+ from .factories.simple import ( # noqa
14
74
  SimpleMarshalerFactory,
15
75
  SimpleUnmarshalerFactory,
76
+ )
16
77
 
78
+ from .factories.match import ( # noqa
17
79
  MarshalerFactoryMatchClass,
18
80
  UnmarshalerFactoryMatchClass,
81
+ )
19
82
 
83
+ from .factories.multi import ( # noqa
20
84
  MultiMarshalerFactory,
21
85
  MultiUnmarshalerFactory,
86
+ )
22
87
 
88
+ from .factories.typemap import ( # noqa
23
89
  TypeMapMarshalerFactory,
24
90
  TypeMapUnmarshalerFactory,
91
+ )
25
92
 
93
+ from .factories.typecache import ( # noqa
26
94
  TypeCacheMarshalerFactory,
27
95
  TypeCacheUnmarshalerFactory,
96
+ )
28
97
 
98
+ from .factories.func import ( # noqa
29
99
  FuncMarshaler,
30
100
  FuncUnmarshaler,
101
+ )
31
102
 
32
- BaseContext,
33
- MarshalContext,
34
- UnmarshalContext,
35
-
103
+ from .factories.recursive import ( # noqa
36
104
  RecursiveMarshalerFactory,
37
105
  RecursiveUnmarshalerFactory,
38
-
39
- Override,
40
- ReflectOverride,
41
- )
42
-
43
- from .composite.iterables import ( # noqa
44
- IterableMarshaler,
45
- IterableUnmarshaler,
46
- )
47
-
48
- from .composite.wrapped import ( # noqa
49
- WrappedMarshaler,
50
- WrappedUnmarshaler,
51
- )
52
-
53
- from .errors import ( # noqa
54
- ForbiddenTypeError,
55
- MarshalError,
56
- UnhandledTypeError,
57
- )
58
-
59
- from .globals import ( # noqa
60
- GLOBAL_REGISTRY,
61
-
62
- global_marshaler_factory,
63
- marshal,
64
-
65
- global_unmarshaler_factory,
66
- unmarshal,
67
-
68
- register_global,
69
- )
70
-
71
- from .naming import ( # noqa
72
- Naming,
73
- translate_name,
74
106
  )
75
107
 
76
108
  from .objects.dataclasses import ( # noqa
@@ -152,20 +184,6 @@ from .singular.primitives import ( # noqa
152
184
  PRIMITIVE_TYPES,
153
185
  )
154
186
 
155
- from .registries import ( # noqa
156
- Registry,
157
- )
158
-
159
- from .standard import ( # noqa
160
- STANDARD_MARSHALER_FACTORIES,
161
- new_standard_marshaler_factory,
162
-
163
- STANDARD_UNMARSHALER_FACTORIES,
164
- new_standard_unmarshaler_factory,
165
-
166
- install_standard_factories,
167
- )
168
-
169
187
  from .trivial.forbidden import ( # noqa
170
188
  ForbiddenTypeMarshalerFactory,
171
189
  ForbiddenTypeUnmarshalerFactory,
@@ -176,8 +194,31 @@ from .trivial.nop import ( # noqa
176
194
  NopMarshalerUnmarshaler,
177
195
  )
178
196
 
179
- from .values import ( # noqa
180
- Value,
197
+ from .globals import ( # noqa
198
+ global_registry,
199
+ global_marshaler_factory,
200
+ global_unmarshaler_factory,
201
+ global_marshaling,
202
+
203
+ marshal,
204
+ unmarshal,
205
+
206
+ register_global,
207
+ )
208
+
209
+ from .naming import ( # noqa
210
+ Naming,
211
+ translate_name,
212
+ )
213
+
214
+ from .standard import ( # noqa
215
+ STANDARD_MARSHALER_FACTORIES,
216
+ new_standard_marshaler_factory,
217
+
218
+ STANDARD_UNMARSHALER_FACTORIES,
219
+ new_standard_unmarshaler_factory,
220
+
221
+ install_standard_factories,
181
222
  )
182
223
 
183
224
 
File without changes
@@ -0,0 +1,78 @@
1
+ import typing as ta
2
+
3
+ from ... import check
4
+ from ... import collections as col
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ... import reflect as rfl
8
+ from ...funcs import match as mfs
9
+ from .errors import UnhandledTypeError
10
+ from .options import Option
11
+ from .overrides import ReflectOverride
12
+
13
+
14
+ if ta.TYPE_CHECKING:
15
+ from .registries import Registry
16
+ from .types import Marshaler
17
+ from .types import MarshalerFactory
18
+ from .types import Unmarshaler
19
+ from .types import UnmarshalerFactory
20
+ from .values import Value
21
+
22
+
23
+ T = ta.TypeVar('T')
24
+
25
+
26
+ ##
27
+
28
+
29
+ @dc.dataclass(frozen=True)
30
+ class BaseContext(lang.Abstract):
31
+ registry: 'Registry'
32
+ options: col.TypeMap[Option] = col.TypeMap()
33
+
34
+ def _reflect(self, o: ta.Any) -> rfl.Type:
35
+ def override(o):
36
+ if (ovr := self.registry.get_of(o, ReflectOverride)):
37
+ return ovr[-1].rty
38
+ return None
39
+
40
+ return rfl.Reflector(override=override).type(o)
41
+
42
+
43
+ @dc.dataclass(frozen=True)
44
+ class MarshalContext(BaseContext, lang.Final):
45
+ factory: ta.Optional['MarshalerFactory'] = None
46
+
47
+ def make(self, o: ta.Any) -> 'Marshaler':
48
+ rty = self._reflect(o)
49
+ try:
50
+ return check.not_none(self.factory).make_marshaler(self, rty)
51
+ except mfs.MatchGuardError:
52
+ raise UnhandledTypeError(rty) # noqa
53
+
54
+ def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> 'Value':
55
+ return self.make(ty if ty is not None else type(obj)).marshal(self, obj)
56
+
57
+
58
+ @dc.dataclass(frozen=True)
59
+ class UnmarshalContext(BaseContext, lang.Final):
60
+ factory: ta.Optional['UnmarshalerFactory'] = None
61
+
62
+ def make(self, o: ta.Any) -> 'Unmarshaler':
63
+ rty = self._reflect(o)
64
+ try:
65
+ return check.not_none(self.factory).make_unmarshaler(self, rty)
66
+ except mfs.MatchGuardError:
67
+ raise UnhandledTypeError(rty) # noqa
68
+
69
+ @ta.overload
70
+ def unmarshal(self, v: 'Value', ty: type[T]) -> T:
71
+ ...
72
+
73
+ @ta.overload
74
+ def unmarshal(self, v: 'Value', ty: ta.Any) -> ta.Any:
75
+ ...
76
+
77
+ def unmarshal(self, v, ty):
78
+ return self.make(ty).unmarshal(self, v)
@@ -1,4 +1,4 @@
1
- from .. import reflect as rfl
1
+ from ... import reflect as rfl
2
2
 
3
3
 
4
4
  ##
@@ -0,0 +1,2 @@
1
+ class Option:
2
+ pass
@@ -0,0 +1,34 @@
1
+ import typing as ta
2
+
3
+ from ... import dataclasses as dc
4
+ from ... import lang
5
+ from ... import reflect as rfl
6
+ from .registries import RegistryItem
7
+
8
+
9
+ if ta.TYPE_CHECKING:
10
+ from . import types as _types
11
+ from .types import Marshaler
12
+ from .types import MarshalerFactory
13
+ from .types import Unmarshaler
14
+ from .types import UnmarshalerFactory
15
+
16
+ else:
17
+ _types = lang.proxy_import('.types', __package__)
18
+
19
+
20
+ ##
21
+
22
+
23
+ @dc.dataclass(frozen=True, kw_only=True)
24
+ class Override(RegistryItem, lang.Final):
25
+ marshaler: ta.Optional['Marshaler'] = dc.xfield(None, validate=lambda v: isinstance(v, (_types.Marshaler, type(None)))) # noqa
26
+ marshaler_factory: ta.Optional['MarshalerFactory'] = None
27
+
28
+ unmarshaler: ta.Optional['Unmarshaler'] = dc.xfield(None, validate=lambda v: isinstance(v, (_types.Unmarshaler, type(None)))) # noqa
29
+ unmarshaler_factory: ta.Optional['UnmarshalerFactory'] = None
30
+
31
+
32
+ @dc.dataclass(frozen=True)
33
+ class ReflectOverride(RegistryItem, lang.Final):
34
+ rty: rfl.Type
@@ -1,13 +1,9 @@
1
- """
2
- TODO:
3
- - inheritance
4
- """
5
1
  import dataclasses as dc
6
2
  import threading
7
3
  import typing as ta
8
4
 
9
- from .. import collections as col
10
- from .. import lang
5
+ from ... import collections as col
6
+ from ... import lang
11
7
 
12
8
 
13
9
  ##
@@ -33,10 +29,16 @@ class _KeyRegistryItems:
33
29
 
34
30
 
35
31
  class Registry:
36
- def __init__(self) -> None:
32
+ def __init__(
33
+ self,
34
+ *,
35
+ lock: ta.Optional[threading.RLock] = None, # noqa
36
+ ) -> None:
37
37
  super().__init__()
38
38
 
39
- self._mtx = threading.Lock()
39
+ if lock is None:
40
+ lock = threading.RLock()
41
+ self._lock = lock
40
42
  self._idct: ta.MutableMapping[ta.Any, _KeyRegistryItems] = col.IdentityKeyDict()
41
43
  self._dct: dict[ta.Any, _KeyRegistryItems] = {}
42
44
 
@@ -46,7 +48,7 @@ class Registry:
46
48
  *items: RegistryItem,
47
49
  identity: bool = False,
48
50
  ) -> 'Registry':
49
- with self._mtx:
51
+ with self._lock:
50
52
  dct: ta.Any = self._idct if identity else self._dct
51
53
  if (sr := dct.get(key)) is None:
52
54
  sr = dct[key] = _KeyRegistryItems(key)