omlish 0.0.0.dev415__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.
@@ -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
@@ -195,12 +195,12 @@ from .trivial.nop import ( # noqa
195
195
  )
196
196
 
197
197
  from .globals import ( # noqa
198
- GLOBAL_REGISTRY,
199
-
198
+ global_registry,
200
199
  global_marshaler_factory,
201
- marshal,
202
-
203
200
  global_unmarshaler_factory,
201
+ global_marshaling,
202
+
203
+ marshal,
204
204
  unmarshal,
205
205
 
206
206
  register_global,
@@ -9,12 +9,15 @@ from ...funcs import match as mfs
9
9
  from .errors import UnhandledTypeError
10
10
  from .options import Option
11
11
  from .overrides import ReflectOverride
12
- from .registries import Registry
13
- from .types import Marshaler
14
- from .types import MarshalerFactory
15
- from .types import Unmarshaler
16
- from .types import UnmarshalerFactory
17
- from .values import Value
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
18
21
 
19
22
 
20
23
  T = ta.TypeVar('T')
@@ -25,7 +28,7 @@ T = ta.TypeVar('T')
25
28
 
26
29
  @dc.dataclass(frozen=True)
27
30
  class BaseContext(lang.Abstract):
28
- registry: Registry
31
+ registry: 'Registry'
29
32
  options: col.TypeMap[Option] = col.TypeMap()
30
33
 
31
34
  def _reflect(self, o: ta.Any) -> rfl.Type:
@@ -39,24 +42,24 @@ class BaseContext(lang.Abstract):
39
42
 
40
43
  @dc.dataclass(frozen=True)
41
44
  class MarshalContext(BaseContext, lang.Final):
42
- factory: MarshalerFactory | None = None
45
+ factory: ta.Optional['MarshalerFactory'] = None
43
46
 
44
- def make(self, o: ta.Any) -> Marshaler:
47
+ def make(self, o: ta.Any) -> 'Marshaler':
45
48
  rty = self._reflect(o)
46
49
  try:
47
50
  return check.not_none(self.factory).make_marshaler(self, rty)
48
51
  except mfs.MatchGuardError:
49
52
  raise UnhandledTypeError(rty) # noqa
50
53
 
51
- def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> Value:
54
+ def marshal(self, obj: ta.Any, ty: ta.Any | None = None) -> 'Value':
52
55
  return self.make(ty if ty is not None else type(obj)).marshal(self, obj)
53
56
 
54
57
 
55
58
  @dc.dataclass(frozen=True)
56
59
  class UnmarshalContext(BaseContext, lang.Final):
57
- factory: UnmarshalerFactory | None = None
60
+ factory: ta.Optional['UnmarshalerFactory'] = None
58
61
 
59
- def make(self, o: ta.Any) -> Unmarshaler:
62
+ def make(self, o: ta.Any) -> 'Unmarshaler':
60
63
  rty = self._reflect(o)
61
64
  try:
62
65
  return check.not_none(self.factory).make_unmarshaler(self, rty)
@@ -64,11 +67,11 @@ class UnmarshalContext(BaseContext, lang.Final):
64
67
  raise UnhandledTypeError(rty) # noqa
65
68
 
66
69
  @ta.overload
67
- def unmarshal(self, v: Value, ty: type[T]) -> T:
70
+ def unmarshal(self, v: 'Value', ty: type[T]) -> T:
68
71
  ...
69
72
 
70
73
  @ta.overload
71
- def unmarshal(self, v: Value, ty: ta.Any) -> ta.Any:
74
+ def unmarshal(self, v: 'Value', ty: ta.Any) -> ta.Any:
72
75
  ...
73
76
 
74
77
  def unmarshal(self, v, ty):
@@ -1,11 +1,20 @@
1
+ import typing as ta
2
+
1
3
  from ... import dataclasses as dc
2
4
  from ... import lang
3
5
  from ... import reflect as rfl
4
6
  from .registries import RegistryItem
5
- from .types import Marshaler
6
- from .types import MarshalerFactory
7
- from .types import Unmarshaler
8
- from .types import UnmarshalerFactory
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__)
9
18
 
10
19
 
11
20
  ##
@@ -13,11 +22,11 @@ from .types import UnmarshalerFactory
13
22
 
14
23
  @dc.dataclass(frozen=True, kw_only=True)
15
24
  class Override(RegistryItem, lang.Final):
16
- marshaler: Marshaler | None = dc.xfield(None, check_type=(Marshaler, None))
17
- marshaler_factory: MarshalerFactory | None = None
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
18
27
 
19
- unmarshaler: Unmarshaler | None = dc.xfield(None, check_type=(Unmarshaler, None))
20
- unmarshaler_factory: UnmarshalerFactory | None = None
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
21
30
 
22
31
 
23
32
  @dc.dataclass(frozen=True)
@@ -29,10 +29,16 @@ class _KeyRegistryItems:
29
29
 
30
30
 
31
31
  class Registry:
32
- def __init__(self) -> None:
32
+ def __init__(
33
+ self,
34
+ *,
35
+ lock: ta.Optional[threading.RLock] = None, # noqa
36
+ ) -> None:
33
37
  super().__init__()
34
38
 
35
- self._lock = threading.Lock()
39
+ if lock is None:
40
+ lock = threading.RLock()
41
+ self._lock = lock
36
42
  self._idct: ta.MutableMapping[ta.Any, _KeyRegistryItems] = col.IdentityKeyDict()
37
43
  self._dct: dict[ta.Any, _KeyRegistryItems] = {}
38
44
 
@@ -5,12 +5,13 @@ from ... import dataclasses as dc
5
5
  from ... import lang
6
6
  from ... import reflect as rfl
7
7
  from ...funcs import match as mfs
8
+ from .contexts import MarshalContext
9
+ from .contexts import UnmarshalContext
10
+ from .registries import Registry
8
11
  from .values import Value
9
12
 
10
13
 
11
- if ta.TYPE_CHECKING:
12
- from .contexts import MarshalContext
13
- from .contexts import UnmarshalContext
14
+ T = ta.TypeVar('T')
14
15
 
15
16
 
16
17
  ##
@@ -18,21 +19,21 @@ if ta.TYPE_CHECKING:
18
19
 
19
20
  class Marshaler(lang.Abstract):
20
21
  @abc.abstractmethod
21
- def marshal(self, ctx: 'MarshalContext', o: ta.Any) -> Value:
22
+ def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
22
23
  raise NotImplementedError
23
24
 
24
25
 
25
26
  class Unmarshaler(lang.Abstract):
26
27
  @abc.abstractmethod
27
- def unmarshal(self, ctx: 'UnmarshalContext', v: Value) -> ta.Any:
28
+ def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
28
29
  raise NotImplementedError
29
30
 
30
31
 
31
32
  ##
32
33
 
33
34
 
34
- MarshalerMaker: ta.TypeAlias = mfs.MatchFn[['MarshalContext', rfl.Type], Marshaler]
35
- UnmarshalerMaker: ta.TypeAlias = mfs.MatchFn[['UnmarshalContext', rfl.Type], Unmarshaler]
35
+ MarshalerMaker: ta.TypeAlias = mfs.MatchFn[[MarshalContext, rfl.Type], Marshaler]
36
+ UnmarshalerMaker: ta.TypeAlias = mfs.MatchFn[[UnmarshalContext, rfl.Type], Unmarshaler]
36
37
 
37
38
 
38
39
  class MarshalerFactory(lang.Abstract):
@@ -68,3 +69,54 @@ class UnmarshalerFactory_(UnmarshalerFactory): # noqa
68
69
  @property
69
70
  def make_unmarshaler(self) -> UnmarshalerMaker:
70
71
  return self.fn
72
+
73
+
74
+ ##
75
+
76
+
77
+ class Marshaling(lang.Abstract):
78
+ @abc.abstractmethod
79
+ def registry(self) -> Registry:
80
+ raise NotImplementedError
81
+
82
+ @abc.abstractmethod
83
+ def marshaler_factory(self) -> MarshalerFactory:
84
+ raise NotImplementedError
85
+
86
+ @abc.abstractmethod
87
+ def unmarshaler_factory(self) -> UnmarshalerFactory:
88
+ raise NotImplementedError
89
+
90
+ #
91
+
92
+ def new_marshal_context(self, **kwargs: ta.Any) -> MarshalContext:
93
+ return MarshalContext(
94
+ self.registry(),
95
+ factory=self.marshaler_factory(),
96
+ **kwargs,
97
+ )
98
+
99
+ def new_unmarshal_context(self, **kwargs: ta.Any) -> UnmarshalContext:
100
+ return UnmarshalContext(
101
+ self.registry(),
102
+ factory=self.unmarshaler_factory(),
103
+ **kwargs,
104
+ )
105
+
106
+ #
107
+
108
+ @ta.final
109
+ def marshal(self, obj: ta.Any, ty: ta.Any | None = None, **kwargs: ta.Any) -> Value:
110
+ return self.new_marshal_context(**kwargs).marshal(obj, ty)
111
+
112
+ @ta.overload
113
+ def unmarshal(self, v: Value, ty: type[T], **kwargs: ta.Any) -> T:
114
+ ...
115
+
116
+ @ta.overload
117
+ def unmarshal(self, v: Value, ty: ta.Any, **kwargs: ta.Any) -> ta.Any:
118
+ ...
119
+
120
+ @ta.final
121
+ def unmarshal(self, v, ty, **kwargs):
122
+ return self.new_unmarshal_context(**kwargs).unmarshal(v, ty)
omlish/marshal/globals.py CHANGED
@@ -1,11 +1,11 @@
1
+ import threading
1
2
  import typing as ta
2
3
 
3
4
  from .. import lang
4
- from .base.contexts import MarshalContext
5
- from .base.contexts import UnmarshalContext
6
5
  from .base.registries import Registry
7
6
  from .base.registries import RegistryItem
8
7
  from .base.types import MarshalerFactory
8
+ from .base.types import Marshaling
9
9
  from .base.types import UnmarshalerFactory
10
10
  from .base.values import Value
11
11
  from .standard import new_standard_marshaler_factory
@@ -18,31 +18,45 @@ T = ta.TypeVar('T')
18
18
  ##
19
19
 
20
20
 
21
- GLOBAL_REGISTRY: Registry = Registry()
21
+ _GLOBAL_LOCK = threading.RLock()
22
22
 
23
23
 
24
- ##
24
+ @lang.cached_function(lock=_GLOBAL_LOCK)
25
+ def global_registry() -> Registry:
26
+ return Registry(lock=_GLOBAL_LOCK)
25
27
 
26
28
 
27
- @lang.cached_function(lock=True)
29
+ @lang.cached_function(lock=_GLOBAL_LOCK)
28
30
  def global_marshaler_factory() -> MarshalerFactory:
29
31
  return new_standard_marshaler_factory()
30
32
 
31
33
 
32
- def marshal(obj: ta.Any, ty: ta.Any | None = None, **kwargs: ta.Any) -> Value:
33
- return MarshalContext(
34
- GLOBAL_REGISTRY,
35
- factory=global_marshaler_factory(),
36
- **kwargs,
37
- ).marshal(obj, ty)
34
+ @lang.cached_function(lock=_GLOBAL_LOCK)
35
+ def global_unmarshaler_factory() -> UnmarshalerFactory:
36
+ return new_standard_unmarshaler_factory()
37
+
38
+
39
+ class _GlobalMarshaling(Marshaling, lang.Final):
40
+ def registry(self) -> Registry:
41
+ return global_registry()
42
+
43
+ def marshaler_factory(self) -> MarshalerFactory:
44
+ return global_marshaler_factory()
45
+
46
+ def unmarshaler_factory(self) -> UnmarshalerFactory:
47
+ return global_unmarshaler_factory()
48
+
49
+
50
+ @lang.cached_function(lock=_GLOBAL_LOCK)
51
+ def global_marshaling() -> Marshaling:
52
+ return _GlobalMarshaling()
38
53
 
39
54
 
40
55
  ##
41
56
 
42
57
 
43
- @lang.cached_function(lock=True)
44
- def global_unmarshaler_factory() -> UnmarshalerFactory:
45
- return new_standard_unmarshaler_factory()
58
+ def marshal(obj: ta.Any, ty: ta.Any | None = None, **kwargs: ta.Any) -> Value:
59
+ return global_marshaling().marshal(obj, ty, **kwargs)
46
60
 
47
61
 
48
62
  @ta.overload
@@ -56,11 +70,7 @@ def unmarshal(v: Value, ty: ta.Any, **kwargs: ta.Any) -> ta.Any:
56
70
 
57
71
 
58
72
  def unmarshal(v, ty, **kwargs):
59
- return UnmarshalContext(
60
- GLOBAL_REGISTRY,
61
- factory=global_unmarshaler_factory(),
62
- **kwargs,
63
- ).unmarshal(v, ty)
73
+ return global_marshaling().unmarshal(v, ty, **kwargs)
64
74
 
65
75
 
66
76
  ##
@@ -71,7 +81,7 @@ def register_global(
71
81
  *items: RegistryItem,
72
82
  identity: bool = False,
73
83
  ) -> None:
74
- GLOBAL_REGISTRY.register(
84
+ global_registry().register(
75
85
  key,
76
86
  *items,
77
87
  identity=identity,