omlish 0.0.0.dev176__py3-none-any.whl → 0.0.0.dev178__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/__about__.py +2 -2
- omlish/inject/scopes.py +1 -1
- omlish/lite/inject.py +205 -11
- omlish/testing/pytest/inject/harness.py +1 -1
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/RECORD +10 -10
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev176.dist-info → omlish-0.0.0.dev178.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/inject/scopes.py
CHANGED
omlish/lite/inject.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
import abc
|
3
3
|
import contextlib
|
4
|
+
import contextvars
|
4
5
|
import dataclasses as dc
|
5
6
|
import functools
|
6
7
|
import inspect
|
@@ -70,6 +71,10 @@ class InjectorBinding:
|
|
70
71
|
key: InjectorKey
|
71
72
|
provider: InjectorProvider
|
72
73
|
|
74
|
+
def __post_init__(self) -> None:
|
75
|
+
check.isinstance(self.key, InjectorKey)
|
76
|
+
check.isinstance(self.provider, InjectorProvider)
|
77
|
+
|
73
78
|
|
74
79
|
class InjectorBindings(abc.ABC):
|
75
80
|
@abc.abstractmethod
|
@@ -333,6 +338,164 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
333
338
|
return pm
|
334
339
|
|
335
340
|
|
341
|
+
###
|
342
|
+
# scopes
|
343
|
+
|
344
|
+
|
345
|
+
class InjectorScope(abc.ABC): # noqa
|
346
|
+
def __init__(
|
347
|
+
self,
|
348
|
+
*,
|
349
|
+
_i: Injector,
|
350
|
+
) -> None:
|
351
|
+
check.not_in(abc.ABC, type(self).__bases__)
|
352
|
+
|
353
|
+
super().__init__()
|
354
|
+
|
355
|
+
self._i = _i
|
356
|
+
|
357
|
+
all_seeds: ta.Iterable[_InjectorScopeSeed] = self._i.provide(InjectorKey(_InjectorScopeSeed, array=True))
|
358
|
+
self._sks = {s.k for s in all_seeds if s.sc is type(self)}
|
359
|
+
|
360
|
+
#
|
361
|
+
|
362
|
+
@dc.dataclass(frozen=True)
|
363
|
+
class State:
|
364
|
+
seeds: ta.Dict[InjectorKey, ta.Any]
|
365
|
+
prvs: ta.Dict[InjectorKey, ta.Any] = dc.field(default_factory=dict)
|
366
|
+
|
367
|
+
def new_state(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> State:
|
368
|
+
vs = dict(vs)
|
369
|
+
check.equal(set(vs.keys()), self._sks)
|
370
|
+
return InjectorScope.State(vs)
|
371
|
+
|
372
|
+
#
|
373
|
+
|
374
|
+
@abc.abstractmethod
|
375
|
+
def state(self) -> State:
|
376
|
+
raise NotImplementedError
|
377
|
+
|
378
|
+
@abc.abstractmethod
|
379
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.ContextManager[None]:
|
380
|
+
raise NotImplementedError
|
381
|
+
|
382
|
+
|
383
|
+
class ExclusiveInjectorScope(InjectorScope, abc.ABC):
|
384
|
+
_st: ta.Optional[InjectorScope.State] = None
|
385
|
+
|
386
|
+
def state(self) -> InjectorScope.State:
|
387
|
+
return check.not_none(self._st)
|
388
|
+
|
389
|
+
@contextlib.contextmanager
|
390
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.Iterator[None]:
|
391
|
+
check.none(self._st)
|
392
|
+
self._st = self.new_state(vs)
|
393
|
+
try:
|
394
|
+
yield
|
395
|
+
finally:
|
396
|
+
self._st = None
|
397
|
+
|
398
|
+
|
399
|
+
class ContextvarInjectorScope(InjectorScope, abc.ABC):
|
400
|
+
_cv: contextvars.ContextVar
|
401
|
+
|
402
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
403
|
+
super().__init_subclass__(**kwargs)
|
404
|
+
check.not_in(abc.ABC, cls.__bases__)
|
405
|
+
check.state(not hasattr(cls, '_cv'))
|
406
|
+
cls._cv = contextvars.ContextVar(f'{cls.__name__}_cv')
|
407
|
+
|
408
|
+
def state(self) -> InjectorScope.State:
|
409
|
+
return self._cv.get()
|
410
|
+
|
411
|
+
@contextlib.contextmanager
|
412
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.Iterator[None]:
|
413
|
+
try:
|
414
|
+
self._cv.get()
|
415
|
+
except LookupError:
|
416
|
+
pass
|
417
|
+
else:
|
418
|
+
raise RuntimeError(f'Scope already entered: {self}')
|
419
|
+
st = self.new_state(vs)
|
420
|
+
tok = self._cv.set(st)
|
421
|
+
try:
|
422
|
+
yield
|
423
|
+
finally:
|
424
|
+
self._cv.reset(tok)
|
425
|
+
|
426
|
+
|
427
|
+
#
|
428
|
+
|
429
|
+
|
430
|
+
@dc.dataclass(frozen=True)
|
431
|
+
class ScopedInjectorProvider(InjectorProvider):
|
432
|
+
p: InjectorProvider
|
433
|
+
k: InjectorKey
|
434
|
+
sc: ta.Type[InjectorScope]
|
435
|
+
|
436
|
+
def __post_init__(self) -> None:
|
437
|
+
check.isinstance(self.p, InjectorProvider)
|
438
|
+
check.isinstance(self.k, InjectorKey)
|
439
|
+
check.issubclass(self.sc, InjectorScope)
|
440
|
+
|
441
|
+
def provider_fn(self) -> InjectorProviderFn:
|
442
|
+
def pfn(i: Injector) -> ta.Any:
|
443
|
+
st = i[self.sc].state()
|
444
|
+
try:
|
445
|
+
return st.prvs[self.k]
|
446
|
+
except KeyError:
|
447
|
+
pass
|
448
|
+
v = ufn(i)
|
449
|
+
st.prvs[self.k] = v
|
450
|
+
return v
|
451
|
+
|
452
|
+
ufn = self.p.provider_fn()
|
453
|
+
return pfn
|
454
|
+
|
455
|
+
|
456
|
+
@dc.dataclass(frozen=True)
|
457
|
+
class _ScopeSeedInjectorProvider(InjectorProvider):
|
458
|
+
k: InjectorKey
|
459
|
+
sc: ta.Type[InjectorScope]
|
460
|
+
|
461
|
+
def __post_init__(self) -> None:
|
462
|
+
check.isinstance(self.k, InjectorKey)
|
463
|
+
check.issubclass(self.sc, InjectorScope)
|
464
|
+
|
465
|
+
def provider_fn(self) -> InjectorProviderFn:
|
466
|
+
def pfn(i: Injector) -> ta.Any:
|
467
|
+
st = i[self.sc].state()
|
468
|
+
return st.seeds[self.k]
|
469
|
+
return pfn
|
470
|
+
|
471
|
+
|
472
|
+
def bind_injector_scope(sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
473
|
+
return as_injector_bindings(
|
474
|
+
InjectorBinder.bind(sc, singleton=True),
|
475
|
+
)
|
476
|
+
|
477
|
+
|
478
|
+
#
|
479
|
+
|
480
|
+
|
481
|
+
@dc.dataclass(frozen=True)
|
482
|
+
class _InjectorScopeSeed:
|
483
|
+
sc: ta.Type['InjectorScope']
|
484
|
+
k: InjectorKey
|
485
|
+
|
486
|
+
def __post_init__(self) -> None:
|
487
|
+
check.issubclass(self.sc, InjectorScope)
|
488
|
+
check.isinstance(self.k, InjectorKey)
|
489
|
+
|
490
|
+
|
491
|
+
def bind_injector_scope_seed(k: ta.Any, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
492
|
+
kk = as_injector_key(k)
|
493
|
+
return as_injector_bindings(
|
494
|
+
InjectorBinding(kk, _ScopeSeedInjectorProvider(kk, sc)),
|
495
|
+
InjectorBinder.bind(_InjectorScopeSeed(sc, kk), array=True),
|
496
|
+
)
|
497
|
+
|
498
|
+
|
336
499
|
###
|
337
500
|
# inspection
|
338
501
|
|
@@ -477,13 +640,21 @@ _INJECTOR_EAGER_ARRAY_KEY: InjectorKey[_InjectorEager] = InjectorKey(_InjectorEa
|
|
477
640
|
|
478
641
|
|
479
642
|
class _Injector(Injector):
|
643
|
+
_DEFAULT_BINDINGS: ta.ClassVar[ta.List[InjectorBinding]] = []
|
644
|
+
|
480
645
|
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
481
646
|
super().__init__()
|
482
647
|
|
483
648
|
self._bs = check.isinstance(bs, InjectorBindings)
|
484
649
|
self._p: ta.Optional[Injector] = check.isinstance(p, (Injector, type(None)))
|
485
650
|
|
486
|
-
self._pfm = {
|
651
|
+
self._pfm = {
|
652
|
+
k: v.provider_fn()
|
653
|
+
for k, v in build_injector_provider_map(as_injector_bindings(
|
654
|
+
*self._DEFAULT_BINDINGS,
|
655
|
+
bs,
|
656
|
+
)).items()
|
657
|
+
}
|
487
658
|
|
488
659
|
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
489
660
|
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
@@ -650,6 +821,7 @@ class InjectorBinder:
|
|
650
821
|
to_const: ta.Any = None,
|
651
822
|
to_key: ta.Any = None,
|
652
823
|
|
824
|
+
in_: ta.Optional[ta.Type[InjectorScope]] = None,
|
653
825
|
singleton: bool = False,
|
654
826
|
|
655
827
|
eager: bool = False,
|
@@ -659,12 +831,12 @@ class InjectorBinder:
|
|
659
831
|
if isinstance(obj, cls._BANNED_BIND_TYPES):
|
660
832
|
raise TypeError(obj)
|
661
833
|
|
662
|
-
|
834
|
+
#
|
663
835
|
|
664
836
|
if key is not None:
|
665
837
|
key = as_injector_key(key)
|
666
838
|
|
667
|
-
|
839
|
+
#
|
668
840
|
|
669
841
|
has_to = (
|
670
842
|
to_fn is not None or
|
@@ -694,7 +866,7 @@ class InjectorBinder:
|
|
694
866
|
key = InjectorKey(type(obj))
|
695
867
|
del has_to
|
696
868
|
|
697
|
-
|
869
|
+
#
|
698
870
|
|
699
871
|
if tag is not None:
|
700
872
|
if key.tag is not None:
|
@@ -704,7 +876,7 @@ class InjectorBinder:
|
|
704
876
|
if array is not None:
|
705
877
|
key = dc.replace(key, array=array)
|
706
878
|
|
707
|
-
|
879
|
+
#
|
708
880
|
|
709
881
|
providers: ta.List[InjectorProvider] = []
|
710
882
|
if to_fn is not None:
|
@@ -719,23 +891,34 @@ class InjectorBinder:
|
|
719
891
|
raise TypeError('Must specify provider')
|
720
892
|
if len(providers) > 1:
|
721
893
|
raise TypeError('May not specify multiple providers')
|
722
|
-
provider
|
894
|
+
provider = check.single(providers)
|
723
895
|
|
724
|
-
|
896
|
+
#
|
725
897
|
|
898
|
+
pws: ta.List[ta.Any] = []
|
899
|
+
if in_ is not None:
|
900
|
+
check.issubclass(in_, InjectorScope)
|
901
|
+
check.not_in(abc.ABC, in_.__bases__)
|
902
|
+
pws.append(functools.partial(ScopedInjectorProvider, k=key, sc=in_))
|
726
903
|
if singleton:
|
727
|
-
|
904
|
+
pws.append(SingletonInjectorProvider)
|
905
|
+
if len(pws) > 1:
|
906
|
+
raise TypeError('May not specify multiple provider wrappers')
|
907
|
+
elif pws:
|
908
|
+
provider = check.single(pws)(provider)
|
909
|
+
|
910
|
+
#
|
728
911
|
|
729
912
|
binding = InjectorBinding(key, provider)
|
730
913
|
|
731
|
-
|
914
|
+
#
|
732
915
|
|
733
916
|
extras: ta.List[InjectorBinding] = []
|
734
917
|
|
735
918
|
if eager:
|
736
919
|
extras.append(bind_injector_eager_key(key))
|
737
920
|
|
738
|
-
|
921
|
+
#
|
739
922
|
|
740
923
|
if extras:
|
741
924
|
return as_injector_bindings(binding, *extras)
|
@@ -808,7 +991,8 @@ def bind_injector_eager_key(key: ta.Any) -> InjectorBinding:
|
|
808
991
|
return InjectorBinding(_INJECTOR_EAGER_ARRAY_KEY, ConstInjectorProvider(_InjectorEager(as_injector_key(key))))
|
809
992
|
|
810
993
|
|
811
|
-
|
994
|
+
###
|
995
|
+
# api
|
812
996
|
|
813
997
|
|
814
998
|
class InjectionApi:
|
@@ -831,6 +1015,14 @@ class InjectionApi:
|
|
831
1015
|
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
832
1016
|
return injector_override(p, *args)
|
833
1017
|
|
1018
|
+
# scopes
|
1019
|
+
|
1020
|
+
def bind_scope(self, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
1021
|
+
return bind_injector_scope(sc)
|
1022
|
+
|
1023
|
+
def bind_scope_seed(self, k: ta.Any, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
1024
|
+
return bind_injector_scope_seed(k, sc)
|
1025
|
+
|
834
1026
|
# injector
|
835
1027
|
|
836
1028
|
def create_injector(self, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
@@ -851,6 +1043,7 @@ class InjectionApi:
|
|
851
1043
|
to_const: ta.Any = None,
|
852
1044
|
to_key: ta.Any = None,
|
853
1045
|
|
1046
|
+
in_: ta.Optional[ta.Type[InjectorScope]] = None,
|
854
1047
|
singleton: bool = False,
|
855
1048
|
|
856
1049
|
eager: bool = False,
|
@@ -867,6 +1060,7 @@ class InjectionApi:
|
|
867
1060
|
to_const=to_const,
|
868
1061
|
to_key=to_key,
|
869
1062
|
|
1063
|
+
in_=in_,
|
870
1064
|
singleton=singleton,
|
871
1065
|
|
872
1066
|
eager=eager,
|
@@ -54,7 +54,7 @@ class Harness:
|
|
54
54
|
*[
|
55
55
|
inj.as_elements(
|
56
56
|
inj.bind_scope(ss),
|
57
|
-
inj.bind_scope_seed(
|
57
|
+
inj.bind_scope_seed(inj.Key(pytest.FixtureRequest, tag=pts), ss),
|
58
58
|
)
|
59
59
|
for pts, ss in _SCOPES_BY_PYTEST_SCOPE.items()
|
60
60
|
],
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=lRkBDFxlAbf6lN5upo3WSf-owW8YG1T21dfpbQL-XHM,7598
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=d7Vqq3YraWwcnd0sR_ExiQePePaN2h_hwFfJ-RBD7IQ,3409
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
4
4
|
omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
|
5
5
|
omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
|
@@ -294,7 +294,7 @@ omlish/inject/origins.py,sha256=OVQkiuRxx6ZtE8ZliufdndtFexcfpj-wZSDkUeGUCYM,534
|
|
294
294
|
omlish/inject/overrides.py,sha256=hrm243slCw_DDRbn3dK5QK1jfHezVokG-WYO2JaQOV8,535
|
295
295
|
omlish/inject/privates.py,sha256=hZOa_keY3KlXAzyiZ-sfN697UKXpkfXXNUIEmGT5TAA,641
|
296
296
|
omlish/inject/providers.py,sha256=Z6UzNCwRhKHHR0L5CyBMo4F-1M_xElLkPA6EKQWcqlw,754
|
297
|
-
omlish/inject/scopes.py,sha256=
|
297
|
+
omlish/inject/scopes.py,sha256=iQ8gD5V2z6ahkJhfy7zycMnUky-scfT_M-GjLjKN6Uw,1989
|
298
298
|
omlish/inject/types.py,sha256=11WVEPkZ-_8cv1BeTDRU-soIYxB_6x7dyWtsa2Iej9U,251
|
299
299
|
omlish/inject/utils.py,sha256=_UOZqA8IcLWPqf4Mcg9iIusQ5yxP_6Txg6PWtUYl23o,408
|
300
300
|
omlish/inject/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -379,7 +379,7 @@ omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
|
|
379
379
|
omlish/lite/check.py,sha256=0PD-GKtaDqDX6jU5KbzbMvH-vl6jH82xgYfplmfTQkg,12941
|
380
380
|
omlish/lite/contextmanagers.py,sha256=m9JO--p7L7mSl4cycXysH-1AO27weDKjP3DZG61cwwM,1683
|
381
381
|
omlish/lite/dataclasses.py,sha256=M6UD4VwGo0Ky7RNzKWbO0IOy7iBZVCIbTiC6EYbFnX8,1035
|
382
|
-
omlish/lite/inject.py,sha256=
|
382
|
+
omlish/lite/inject.py,sha256=yolrXQPZ903FcZwbSrUXsXNCylZ31W1vesjLelRWGgo,28758
|
383
383
|
omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
|
384
384
|
omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
|
385
385
|
omlish/lite/marshal.py,sha256=O_v_slgjAAiSGWComdRhqLXdumuIlBDc3SvoG_p00QM,15863
|
@@ -550,7 +550,7 @@ omlish/testing/pytest/helpers.py,sha256=TJpD60mBtLi9FtxX4TThfuXvg5FIRPSiZk1aeRwe
|
|
550
550
|
omlish/testing/pytest/marks.py,sha256=4-3WgunN_fcmhkmQ6mtX_AFo5QRDwflNSH7NoyoXui4,432
|
551
551
|
omlish/testing/pytest/skip.py,sha256=NxTkAQiS3HKZR3sfFdxOR2LCFwtCveY6Ap-qtexiZbw,839
|
552
552
|
omlish/testing/pytest/inject/__init__.py,sha256=pdRKv1HcDmJ_yArKJbYITPXXZthRSGgBJWqITr0Er38,117
|
553
|
-
omlish/testing/pytest/inject/harness.py,sha256=
|
553
|
+
omlish/testing/pytest/inject/harness.py,sha256=_Qf7lLcYc_dpauYOE68u_a65jPCFWmQUYv9m_OOdNqs,5724
|
554
554
|
omlish/testing/pytest/plugins/__init__.py,sha256=ys1zXrYrNm7Uo6YOIVJ6Bd3dQo6kv387k7MbTYlqZSI,467
|
555
555
|
omlish/testing/pytest/plugins/_registry.py,sha256=IK04KlBgiOJxKAyCCgjpX2R-9tE-btalYJkgjLc8Te8,77
|
556
556
|
omlish/testing/pytest/plugins/asyncs.py,sha256=CG-cWWxCtxVIyKJKEjxfFV0MVwYBHPo1mb-umCGz9X8,5532
|
@@ -570,9 +570,9 @@ omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,329
|
|
570
570
|
omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
|
571
571
|
omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
|
572
572
|
omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
|
573
|
-
omlish-0.0.0.
|
574
|
-
omlish-0.0.0.
|
575
|
-
omlish-0.0.0.
|
576
|
-
omlish-0.0.0.
|
577
|
-
omlish-0.0.0.
|
578
|
-
omlish-0.0.0.
|
573
|
+
omlish-0.0.0.dev178.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
574
|
+
omlish-0.0.0.dev178.dist-info/METADATA,sha256=Zltjh6LQhgQnlgh8RPDJgnQHdnTVpzHEP3rMc3OcjJU,4264
|
575
|
+
omlish-0.0.0.dev178.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
576
|
+
omlish-0.0.0.dev178.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
577
|
+
omlish-0.0.0.dev178.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
578
|
+
omlish-0.0.0.dev178.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|