aspyx 1.0.0__py3-none-any.whl → 1.0.1__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 aspyx might be problematic. Click here for more details.
- aspyx/di/__init__.py +4 -1
- aspyx/di/aop/__init__.py +4 -1
- aspyx/di/aop/aop.py +56 -76
- aspyx/di/configuration/__init__.py +4 -1
- aspyx/di/configuration/configuration.py +20 -15
- aspyx/di/di.py +98 -113
- aspyx/reflection/__init__.py +4 -1
- aspyx/reflection/proxy.py +10 -7
- aspyx/reflection/reflection.py +29 -21
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/METADATA +94 -33
- aspyx-1.0.1.dist-info/RECORD +14 -0
- aspyx-1.0.0.dist-info/RECORD +0 -14
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/WHEEL +0 -0
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/top_level.txt +0 -0
aspyx/di/di.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The deoendency injection module provides a framework for managing dependencies and lifecycle of objects in Python applications.
|
|
3
|
+
"""
|
|
1
4
|
from __future__ import annotations
|
|
2
5
|
|
|
3
6
|
import inspect
|
|
@@ -25,8 +28,8 @@ class Factory(ABC, Generic[T]):
|
|
|
25
28
|
|
|
26
29
|
class InjectorException(Exception):
|
|
27
30
|
"""
|
|
28
|
-
Exception raised for errors in the injector.
|
|
29
|
-
|
|
31
|
+
Exception raised for errors in the injector.
|
|
32
|
+
"""
|
|
30
33
|
|
|
31
34
|
class AbstractInstanceProvider(ABC, Generic[T]):
|
|
32
35
|
"""
|
|
@@ -53,7 +56,7 @@ class AbstractInstanceProvider(ABC, Generic[T]):
|
|
|
53
56
|
pass
|
|
54
57
|
|
|
55
58
|
@abstractmethod
|
|
56
|
-
def create(self,
|
|
59
|
+
def create(self, environment: Environment, *args):
|
|
57
60
|
pass
|
|
58
61
|
|
|
59
62
|
@abstractmethod
|
|
@@ -193,15 +196,15 @@ class Scopes:
|
|
|
193
196
|
|
|
194
197
|
@classmethod
|
|
195
198
|
def get(cls, scope: str, environment: Environment):
|
|
196
|
-
|
|
197
|
-
if
|
|
199
|
+
scope_type = Scopes.scopes.get(scope, None)
|
|
200
|
+
if scope_type is None:
|
|
198
201
|
raise InjectorException(f"unknown scope type {scope}")
|
|
199
202
|
|
|
200
|
-
return environment.get(
|
|
203
|
+
return environment.get(scope_type)
|
|
201
204
|
|
|
202
205
|
@classmethod
|
|
203
|
-
def register(cls,
|
|
204
|
-
Scopes.scopes[name] =
|
|
206
|
+
def register(cls, scope_type: Type, name: str):
|
|
207
|
+
Scopes.scopes[name] = scope_type
|
|
205
208
|
|
|
206
209
|
class Scope:
|
|
207
210
|
# properties
|
|
@@ -216,15 +219,15 @@ class Scope:
|
|
|
216
219
|
|
|
217
220
|
# public
|
|
218
221
|
|
|
219
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
220
|
-
return provider.create(environment, *
|
|
222
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
223
|
+
return provider.create(environment, *arg_provider())
|
|
221
224
|
|
|
222
225
|
class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
223
226
|
# properties
|
|
224
227
|
|
|
225
228
|
__slots__ = [
|
|
226
229
|
"environment",
|
|
227
|
-
"
|
|
230
|
+
"scope_instance",
|
|
228
231
|
"provider",
|
|
229
232
|
"dependencies",
|
|
230
233
|
]
|
|
@@ -238,8 +241,7 @@ class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
|
238
241
|
self.provider = provider
|
|
239
242
|
self.dependencies : list[AbstractInstanceProvider] = []
|
|
240
243
|
|
|
241
|
-
self.
|
|
242
|
-
print()
|
|
244
|
+
self.scope_instance = Scopes.get(provider.get_scope(), environment)
|
|
243
245
|
|
|
244
246
|
# implement
|
|
245
247
|
|
|
@@ -260,21 +262,19 @@ class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
|
260
262
|
|
|
261
263
|
# custom logic
|
|
262
264
|
|
|
263
|
-
def
|
|
265
|
+
def tweak_dependencies(self, providers: dict[Type, AbstractInstanceProvider]):
|
|
264
266
|
for dependency in self.provider.get_dependencies():
|
|
265
|
-
|
|
266
|
-
if
|
|
267
|
+
instance_provider = providers.get(dependency.get_type(), None)
|
|
268
|
+
if instance_provider is None:
|
|
267
269
|
raise InjectorException(f"missing import for {dependency.get_type()} ")
|
|
268
270
|
|
|
269
|
-
self.dependencies.append(
|
|
270
|
-
pass
|
|
271
|
-
pass
|
|
271
|
+
self.dependencies.append(instance_provider)
|
|
272
272
|
|
|
273
273
|
def get_dependencies(self) -> list[AbstractInstanceProvider]:
|
|
274
274
|
return self.provider.get_dependencies()
|
|
275
275
|
|
|
276
|
-
def create(self,
|
|
277
|
-
return self.
|
|
276
|
+
def create(self, environment: Environment, *args):
|
|
277
|
+
return self.scope_instance.get(self.provider, self.environment, lambda: [provider.create(environment) for provider in self.dependencies]) # already scope property!
|
|
278
278
|
|
|
279
279
|
def __str__(self):
|
|
280
280
|
return f"EnvironmentInstanceProvider({self.provider})"
|
|
@@ -309,18 +309,18 @@ class ClassInstanceProvider(InstanceProvider):
|
|
|
309
309
|
if init is None:
|
|
310
310
|
raise InjectorException(f"{self.type.__name__} does not implement __init__")
|
|
311
311
|
|
|
312
|
-
for param in init.
|
|
313
|
-
provider = Providers.
|
|
312
|
+
for param in init.param_types:
|
|
313
|
+
provider = Providers.get_provider(param)
|
|
314
314
|
self.params += 1
|
|
315
315
|
if self.add_dependency(provider):
|
|
316
316
|
provider.resolve(context)
|
|
317
317
|
|
|
318
318
|
# check @inject
|
|
319
319
|
|
|
320
|
-
for method in TypeDescriptor.for_type(self.type).
|
|
320
|
+
for method in TypeDescriptor.for_type(self.type).get_methods():
|
|
321
321
|
if method.has_decorator(inject):
|
|
322
|
-
for param in method.
|
|
323
|
-
provider = Providers.
|
|
322
|
+
for param in method.param_types:
|
|
323
|
+
provider = Providers.get_provider(param)
|
|
324
324
|
|
|
325
325
|
if self.add_dependency(provider):
|
|
326
326
|
provider.resolve(context)
|
|
@@ -330,7 +330,7 @@ class ClassInstanceProvider(InstanceProvider):
|
|
|
330
330
|
return self
|
|
331
331
|
|
|
332
332
|
def create(self, environment: Environment, *args):
|
|
333
|
-
Environment.logger.debug(
|
|
333
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
334
334
|
|
|
335
335
|
return environment.created(self.type(*args[:self.params]))
|
|
336
336
|
|
|
@@ -363,7 +363,7 @@ class FunctionInstanceProvider(InstanceProvider):
|
|
|
363
363
|
|
|
364
364
|
context.add(self)
|
|
365
365
|
|
|
366
|
-
provider = Providers.
|
|
366
|
+
provider = Providers.get_provider(self.host)
|
|
367
367
|
if self.add_dependency(provider):
|
|
368
368
|
provider.resolve(context)
|
|
369
369
|
else: # check if the dependencies crate a cycle
|
|
@@ -372,7 +372,7 @@ class FunctionInstanceProvider(InstanceProvider):
|
|
|
372
372
|
return self
|
|
373
373
|
|
|
374
374
|
def create(self, environment: Environment, *args):
|
|
375
|
-
Environment.logger.debug(
|
|
375
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
376
376
|
|
|
377
377
|
instance = self.method(*args)
|
|
378
378
|
|
|
@@ -391,13 +391,13 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
391
391
|
# class method
|
|
392
392
|
|
|
393
393
|
@classmethod
|
|
394
|
-
def
|
|
395
|
-
return TypeDescriptor.for_type(clazz).
|
|
394
|
+
def get_factory_type(cls, clazz):
|
|
395
|
+
return TypeDescriptor.for_type(clazz).get_method("create", local=True).return_type
|
|
396
396
|
|
|
397
397
|
# constructor
|
|
398
398
|
|
|
399
399
|
def __init__(self, factory: Type, eager: bool, scope: str):
|
|
400
|
-
super().__init__(factory, FactoryInstanceProvider.
|
|
400
|
+
super().__init__(factory, FactoryInstanceProvider.get_factory_type(factory), eager, scope)
|
|
401
401
|
|
|
402
402
|
# implement
|
|
403
403
|
|
|
@@ -407,7 +407,7 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
407
407
|
|
|
408
408
|
context.add(self)
|
|
409
409
|
|
|
410
|
-
provider = Providers.
|
|
410
|
+
provider = Providers.get_provider(self.host)
|
|
411
411
|
if self.add_dependency(provider):
|
|
412
412
|
provider.resolve(context)
|
|
413
413
|
|
|
@@ -417,7 +417,7 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
417
417
|
return self
|
|
418
418
|
|
|
419
419
|
def create(self, environment: Environment, *args):
|
|
420
|
-
Environment.logger.debug(
|
|
420
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
421
421
|
|
|
422
422
|
return environment.created(args[0].create())
|
|
423
423
|
|
|
@@ -453,7 +453,7 @@ class LifecycleProcessor(ABC):
|
|
|
453
453
|
# methods
|
|
454
454
|
|
|
455
455
|
@abstractmethod
|
|
456
|
-
def
|
|
456
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
457
457
|
pass
|
|
458
458
|
|
|
459
459
|
class PostProcessor(LifecycleProcessor):
|
|
@@ -462,15 +462,11 @@ class PostProcessor(LifecycleProcessor):
|
|
|
462
462
|
"""
|
|
463
463
|
__slots__ = []
|
|
464
464
|
|
|
465
|
-
# constructor
|
|
466
|
-
|
|
467
|
-
def __init__(self):
|
|
468
|
-
super().__init__()
|
|
469
465
|
|
|
470
466
|
def process(self, instance: object, environment: Environment):
|
|
471
467
|
pass
|
|
472
468
|
|
|
473
|
-
def
|
|
469
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
474
470
|
if lifecycle == Lifecycle.ON_INIT:
|
|
475
471
|
self.process(instance, environment)
|
|
476
472
|
|
|
@@ -490,11 +486,11 @@ class Providers:
|
|
|
490
486
|
def add(self, *providers: AbstractInstanceProvider):
|
|
491
487
|
for provider in providers:
|
|
492
488
|
if next((p for p in self.dependencies if p.get_type() is provider.get_type()), None) is not None:
|
|
493
|
-
raise InjectorException(self.
|
|
489
|
+
raise InjectorException(self.cycle_report(provider))
|
|
494
490
|
|
|
495
491
|
self.dependencies.append(provider)
|
|
496
492
|
|
|
497
|
-
def
|
|
493
|
+
def cycle_report(self, provider: AbstractInstanceProvider):
|
|
498
494
|
cycle = ""
|
|
499
495
|
|
|
500
496
|
first = True
|
|
@@ -513,16 +509,16 @@ class Providers:
|
|
|
513
509
|
|
|
514
510
|
# class properties
|
|
515
511
|
|
|
516
|
-
check: list[AbstractInstanceProvider] =
|
|
512
|
+
check: list[AbstractInstanceProvider] = []
|
|
517
513
|
|
|
518
|
-
providers : Dict[Type,AbstractInstanceProvider] =
|
|
519
|
-
cache: Dict[Type, AbstractInstanceProvider] =
|
|
514
|
+
providers : Dict[Type,AbstractInstanceProvider] = {}
|
|
515
|
+
cache: Dict[Type, AbstractInstanceProvider] = {}
|
|
520
516
|
|
|
521
517
|
resolved = False
|
|
522
518
|
|
|
523
519
|
@classmethod
|
|
524
520
|
def register(cls, provider: AbstractInstanceProvider):
|
|
525
|
-
Environment.logger.debug(
|
|
521
|
+
Environment.logger.debug("register provider %s(%s)", provider.get_type().__qualname__, provider.get_type().__name__)
|
|
526
522
|
|
|
527
523
|
# local functions
|
|
528
524
|
|
|
@@ -541,7 +537,7 @@ class Providers:
|
|
|
541
537
|
|
|
542
538
|
return True
|
|
543
539
|
|
|
544
|
-
def
|
|
540
|
+
def cache_provider_for_type(provider: AbstractInstanceProvider, type: Type):
|
|
545
541
|
existing_provider = Providers.cache.get(type)
|
|
546
542
|
if existing_provider is None:
|
|
547
543
|
Providers.cache[type] = provider
|
|
@@ -557,9 +553,9 @@ class Providers:
|
|
|
557
553
|
|
|
558
554
|
# recursion
|
|
559
555
|
|
|
560
|
-
for
|
|
561
|
-
if is_injectable(
|
|
562
|
-
|
|
556
|
+
for super_class in type.__bases__:
|
|
557
|
+
if is_injectable(super_class):
|
|
558
|
+
cache_provider_for_type(provider, super_class)
|
|
563
559
|
|
|
564
560
|
# go
|
|
565
561
|
|
|
@@ -569,7 +565,7 @@ class Providers:
|
|
|
569
565
|
|
|
570
566
|
# cache providers
|
|
571
567
|
|
|
572
|
-
|
|
568
|
+
cache_provider_for_type(provider, provider.get_type())
|
|
573
569
|
|
|
574
570
|
@classmethod
|
|
575
571
|
def resolve(cls):
|
|
@@ -586,20 +582,20 @@ class Providers:
|
|
|
586
582
|
print(f"provider {provider.get_type().__qualname__}")
|
|
587
583
|
|
|
588
584
|
@classmethod
|
|
589
|
-
def
|
|
585
|
+
def get_provider(cls, type: Type) -> AbstractInstanceProvider:
|
|
590
586
|
provider = Providers.cache.get(type, None)
|
|
591
587
|
if provider is None:
|
|
592
588
|
raise InjectorException(f"{type.__name__} not registered as injectable")
|
|
593
589
|
|
|
594
590
|
return provider
|
|
595
591
|
|
|
596
|
-
def
|
|
592
|
+
def register_factories(cls: Type):
|
|
597
593
|
descriptor = TypeDescriptor.for_type(cls)
|
|
598
594
|
|
|
599
|
-
for method in descriptor.
|
|
595
|
+
for method in descriptor.get_methods():
|
|
600
596
|
if method.has_decorator(create):
|
|
601
597
|
create_decorator = method.get_decorator(create)
|
|
602
|
-
Providers.register(FunctionInstanceProvider(cls, method.method, method.
|
|
598
|
+
Providers.register(FunctionInstanceProvider(cls, method.method, method.return_type, create_decorator.args[0],
|
|
603
599
|
create_decorator.args[1]))
|
|
604
600
|
def order(prio = 0):
|
|
605
601
|
def decorator(cls):
|
|
@@ -681,7 +677,7 @@ def environment(imports: Optional[list[Type]] = None):
|
|
|
681
677
|
Decorators.add(cls, environment, imports)
|
|
682
678
|
Decorators.add(cls, injectable) # do we need that?
|
|
683
679
|
|
|
684
|
-
|
|
680
|
+
register_factories(cls)
|
|
685
681
|
|
|
686
682
|
return cls
|
|
687
683
|
|
|
@@ -721,7 +717,7 @@ class Environment:
|
|
|
721
717
|
__slots__ = [
|
|
722
718
|
"type",
|
|
723
719
|
"providers",
|
|
724
|
-
"
|
|
720
|
+
"lifecycle_processors",
|
|
725
721
|
"parent",
|
|
726
722
|
"instances"
|
|
727
723
|
]
|
|
@@ -743,12 +739,12 @@ class Environment:
|
|
|
743
739
|
if self.parent is None and env is not BootEnvironment:
|
|
744
740
|
self.parent = BootEnvironment.get_instance() # inherit environment including its manged instances!
|
|
745
741
|
|
|
746
|
-
self.providers: Dict[Type, AbstractInstanceProvider] =
|
|
747
|
-
self.
|
|
742
|
+
self.providers: Dict[Type, AbstractInstanceProvider] = {}
|
|
743
|
+
self.lifecycle_processors: list[LifecycleProcessor] = []
|
|
748
744
|
|
|
749
745
|
if self.parent is not None:
|
|
750
746
|
self.providers |= self.parent.providers
|
|
751
|
-
self.
|
|
747
|
+
self.lifecycle_processors += self.parent.lifecycle_processors
|
|
752
748
|
|
|
753
749
|
self.instances = []
|
|
754
750
|
|
|
@@ -761,7 +757,7 @@ class Environment:
|
|
|
761
757
|
loaded = set()
|
|
762
758
|
|
|
763
759
|
def add_provider(type: Type, provider: AbstractInstanceProvider):
|
|
764
|
-
Environment.logger.debug(
|
|
760
|
+
Environment.logger.debug("\tadd provider %s for %s", provider, type)
|
|
765
761
|
|
|
766
762
|
self.providers[type] = provider
|
|
767
763
|
|
|
@@ -773,7 +769,7 @@ class Environment:
|
|
|
773
769
|
|
|
774
770
|
def load_environment(env: Type):
|
|
775
771
|
if env not in loaded:
|
|
776
|
-
Environment.logger.debug(
|
|
772
|
+
Environment.logger.debug("load environment %s", env.__qualname__)
|
|
777
773
|
|
|
778
774
|
loaded.add(env)
|
|
779
775
|
|
|
@@ -794,31 +790,31 @@ class Environment:
|
|
|
794
790
|
|
|
795
791
|
# load providers
|
|
796
792
|
|
|
797
|
-
|
|
793
|
+
local_providers = {type: provider for type, provider in Providers.cache.items() if provider.get_module().startswith(scan)}
|
|
798
794
|
|
|
799
795
|
# register providers
|
|
800
796
|
|
|
801
797
|
# make sure, that for every type ony a single EnvironmentInstanceProvider is created!
|
|
802
798
|
# otherwise inheritance will fuck it up
|
|
803
799
|
|
|
804
|
-
|
|
800
|
+
environment_providers : dict[AbstractInstanceProvider, EnvironmentInstanceProvider] = {}
|
|
805
801
|
|
|
806
|
-
for type, provider in
|
|
807
|
-
|
|
808
|
-
if
|
|
809
|
-
|
|
810
|
-
|
|
802
|
+
for type, provider in local_providers.items():
|
|
803
|
+
environment_provider = environment_providers.get(provider, None)
|
|
804
|
+
if environment_provider is None:
|
|
805
|
+
environment_provider = EnvironmentInstanceProvider(self, provider)
|
|
806
|
+
environment_providers[provider] = environment_provider
|
|
811
807
|
|
|
812
|
-
add_provider(type,
|
|
808
|
+
add_provider(type, environment_provider)
|
|
813
809
|
|
|
814
810
|
# tweak dependencies
|
|
815
811
|
|
|
816
|
-
for type, provider in
|
|
817
|
-
cast(EnvironmentInstanceProvider, self.providers[type]).
|
|
812
|
+
for type, provider in local_providers.items():
|
|
813
|
+
cast(EnvironmentInstanceProvider, self.providers[type]).tweak_dependencies(self.providers)
|
|
818
814
|
|
|
819
815
|
# return local providers
|
|
820
816
|
|
|
821
|
-
return
|
|
817
|
+
return environment_providers.values()
|
|
822
818
|
else:
|
|
823
819
|
return []
|
|
824
820
|
|
|
@@ -829,27 +825,21 @@ class Environment:
|
|
|
829
825
|
provider.create(self)
|
|
830
826
|
# internal
|
|
831
827
|
|
|
832
|
-
def
|
|
833
|
-
for processor in self.
|
|
834
|
-
processor.
|
|
828
|
+
def execute_processors(self, lifecycle: Lifecycle, instance: T) -> T:
|
|
829
|
+
for processor in self.lifecycle_processors:
|
|
830
|
+
processor.process_lifecycle(lifecycle, instance, self)
|
|
835
831
|
|
|
836
832
|
return instance
|
|
837
833
|
|
|
838
834
|
def created(self, instance: T) -> T:
|
|
839
|
-
def get_order(type: TypeDescriptor) -> int:
|
|
840
|
-
if type.has_decorator(order):
|
|
841
|
-
return type.get_decorator(order).args[0]
|
|
842
|
-
else:
|
|
843
|
-
return 10
|
|
844
|
-
|
|
845
835
|
# remember lifecycle processors
|
|
846
836
|
|
|
847
837
|
if isinstance(instance, LifecycleProcessor):
|
|
848
|
-
self.
|
|
838
|
+
self.lifecycle_processors.append(instance)
|
|
849
839
|
|
|
850
840
|
# sort immediately
|
|
851
841
|
|
|
852
|
-
self.
|
|
842
|
+
self.lifecycle_processors.sort(key=lambda processor: processor.order)
|
|
853
843
|
|
|
854
844
|
# remember instance
|
|
855
845
|
|
|
@@ -857,7 +847,7 @@ class Environment:
|
|
|
857
847
|
|
|
858
848
|
# execute processors
|
|
859
849
|
|
|
860
|
-
return self.
|
|
850
|
+
return self.execute_processors(Lifecycle.ON_INIT, instance)
|
|
861
851
|
|
|
862
852
|
# public
|
|
863
853
|
|
|
@@ -866,7 +856,7 @@ class Environment:
|
|
|
866
856
|
destroy all managed instances by calling the appropriate lifecycle methods
|
|
867
857
|
"""
|
|
868
858
|
for instance in self.instances:
|
|
869
|
-
self.
|
|
859
|
+
self.execute_processors(Lifecycle.ON_DESTROY, instance)
|
|
870
860
|
|
|
871
861
|
self.instances.clear() # make the cy happy
|
|
872
862
|
|
|
@@ -881,7 +871,7 @@ class Environment:
|
|
|
881
871
|
"""
|
|
882
872
|
provider = self.providers.get(type, None)
|
|
883
873
|
if provider is None:
|
|
884
|
-
Environment.logger.error(
|
|
874
|
+
Environment.logger.error("%s is not supported", type)
|
|
885
875
|
raise InjectorException(f"{type} is not supported")
|
|
886
876
|
|
|
887
877
|
return provider.create(self)
|
|
@@ -915,18 +905,18 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
915
905
|
__slots__ = [
|
|
916
906
|
"decorator",
|
|
917
907
|
"method",
|
|
918
|
-
"
|
|
908
|
+
"lifecycle_callable"
|
|
919
909
|
]
|
|
920
910
|
|
|
921
911
|
# constructor
|
|
922
912
|
|
|
923
|
-
def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor,
|
|
913
|
+
def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor, lifecycle_callable: LifecycleCallable):
|
|
924
914
|
self.decorator = decorator
|
|
925
915
|
self.method = method
|
|
926
|
-
self.
|
|
916
|
+
self.lifecycle_callable = lifecycle_callable
|
|
927
917
|
|
|
928
918
|
def execute(self, instance, environment: Environment):
|
|
929
|
-
self.method.method(instance, *self.
|
|
919
|
+
self.method.method(instance, *self.lifecycle_callable.args(self.decorator, self.method, environment))
|
|
930
920
|
|
|
931
921
|
def __str__(self):
|
|
932
922
|
return f"MethodCall({self.method.method.__name__})"
|
|
@@ -936,31 +926,31 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
936
926
|
def __init__(self):
|
|
937
927
|
super().__init__()
|
|
938
928
|
|
|
939
|
-
self.callables : Dict[object,LifecycleCallable] =
|
|
940
|
-
self.cache : Dict[Type,list[CallableProcessor.MethodCall]] =
|
|
929
|
+
self.callables : Dict[object,LifecycleCallable] = {}
|
|
930
|
+
self.cache : Dict[Type,list[CallableProcessor.MethodCall]] = {}
|
|
941
931
|
|
|
942
|
-
def
|
|
932
|
+
def compute_callables(self, type: Type) -> list[CallableProcessor.MethodCall] :
|
|
943
933
|
descriptor = TypeDescriptor.for_type(type)
|
|
944
934
|
|
|
945
935
|
result = []
|
|
946
936
|
|
|
947
|
-
for method in descriptor.
|
|
937
|
+
for method in descriptor.get_methods():
|
|
948
938
|
for decorator in method.decorators:
|
|
949
939
|
if self.callables.get(decorator.decorator) is not None:
|
|
950
940
|
result.append(CallableProcessor.MethodCall(method, decorator, self.callables[decorator.decorator]))
|
|
951
941
|
|
|
952
942
|
# sort according to order
|
|
953
943
|
|
|
954
|
-
result.sort(key=lambda call: call.
|
|
944
|
+
result.sort(key=lambda call: call.lifecycle_callable.order)
|
|
955
945
|
|
|
956
946
|
# done
|
|
957
947
|
|
|
958
948
|
return result
|
|
959
949
|
|
|
960
|
-
def
|
|
950
|
+
def callables_for(self, type: Type)-> list[CallableProcessor.MethodCall]:
|
|
961
951
|
callables = self.cache.get(type, None)
|
|
962
952
|
if callables is None:
|
|
963
|
-
callables = self.
|
|
953
|
+
callables = self.compute_callables(type)
|
|
964
954
|
self.cache[type] = callables
|
|
965
955
|
|
|
966
956
|
return callables
|
|
@@ -970,10 +960,10 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
970
960
|
|
|
971
961
|
# implement
|
|
972
962
|
|
|
973
|
-
def
|
|
974
|
-
callables = self.
|
|
963
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
964
|
+
callables = self.callables_for(type(instance))
|
|
975
965
|
for callable in callables:
|
|
976
|
-
if callable.
|
|
966
|
+
if callable.lifecycle_callable.lifecycle is lifecycle:
|
|
977
967
|
callable.execute(instance, environment)
|
|
978
968
|
|
|
979
969
|
@injectable()
|
|
@@ -1014,7 +1004,7 @@ class InjectLifecycleCallable(LifecycleCallable):
|
|
|
1014
1004
|
# override
|
|
1015
1005
|
|
|
1016
1006
|
def args(self, decorator: DecoratorDescriptor, method: TypeDescriptor.MethodDescriptor, environment: Environment):
|
|
1017
|
-
return [environment.get(type) for type in method.
|
|
1007
|
+
return [environment.get(type) for type in method.param_types]
|
|
1018
1008
|
|
|
1019
1009
|
def scope(name: str):
|
|
1020
1010
|
def decorator(cls):
|
|
@@ -1036,15 +1026,10 @@ class RequestScope(Scope):
|
|
|
1036
1026
|
__slots__ = [
|
|
1037
1027
|
]
|
|
1038
1028
|
|
|
1039
|
-
# constructor
|
|
1040
|
-
|
|
1041
|
-
def __init__(self):
|
|
1042
|
-
super().__init__()
|
|
1043
|
-
|
|
1044
1029
|
# public
|
|
1045
1030
|
|
|
1046
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
1047
|
-
return provider.create(environment, *
|
|
1031
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
1032
|
+
return provider.create(environment, *arg_provider())
|
|
1048
1033
|
|
|
1049
1034
|
@scope("singleton")
|
|
1050
1035
|
class SingletonScope(Scope):
|
|
@@ -1065,11 +1050,11 @@ class SingletonScope(Scope):
|
|
|
1065
1050
|
|
|
1066
1051
|
# override
|
|
1067
1052
|
|
|
1068
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
1053
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
1069
1054
|
if self.value is None:
|
|
1070
1055
|
with self.lock:
|
|
1071
|
-
if self.value is None:
|
|
1072
|
-
self.value = provider.create(environment, *
|
|
1056
|
+
if self.value is None:
|
|
1057
|
+
self.value = provider.create(environment, *arg_provider())
|
|
1073
1058
|
|
|
1074
1059
|
return self.value
|
|
1075
1060
|
|
|
@@ -1095,4 +1080,4 @@ class BootEnvironment:
|
|
|
1095
1080
|
# constructor
|
|
1096
1081
|
|
|
1097
1082
|
def __init__(self):
|
|
1098
|
-
pass
|
|
1083
|
+
pass
|
aspyx/reflection/__init__.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides tools for dynamic proxy creation and reflection
|
|
3
|
+
"""
|
|
1
4
|
from .proxy import DynamicProxy
|
|
2
5
|
from .reflection import Decorators, TypeDescriptor, DecoratorDescriptor
|
|
3
6
|
|
|
@@ -6,4 +9,4 @@ __all__ = [
|
|
|
6
9
|
"Decorators",
|
|
7
10
|
"DecoratorDescriptor",
|
|
8
11
|
"TypeDescriptor"
|
|
9
|
-
]
|
|
12
|
+
]
|
aspyx/reflection/proxy.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dynamic proxies for method interception and delegation.
|
|
3
|
+
"""
|
|
1
4
|
from typing import Generic, TypeVar, Type
|
|
2
5
|
|
|
3
6
|
T = TypeVar("T")
|
|
@@ -22,7 +25,7 @@ class DynamicProxy(Generic[T]):
|
|
|
22
25
|
|
|
23
26
|
Attributes:
|
|
24
27
|
type: The proxied class type.
|
|
25
|
-
|
|
28
|
+
invocation_handler: The handler that processes intercepted method calls.
|
|
26
29
|
"""
|
|
27
30
|
# inner class
|
|
28
31
|
|
|
@@ -40,19 +43,19 @@ class DynamicProxy(Generic[T]):
|
|
|
40
43
|
# class methods
|
|
41
44
|
|
|
42
45
|
@classmethod
|
|
43
|
-
def create(cls, type: Type[T],
|
|
44
|
-
return DynamicProxy(type,
|
|
46
|
+
def create(cls, type: Type[T], invocation_handler: 'DynamicProxy.InvocationHandler') -> T:
|
|
47
|
+
return DynamicProxy(type, invocation_handler)
|
|
45
48
|
|
|
46
49
|
# constructor
|
|
47
50
|
|
|
48
|
-
def __init__(self, type: Type[T],
|
|
51
|
+
def __init__(self, type: Type[T], invocation_handler: 'DynamicProxy.InvocationHandler'):
|
|
49
52
|
self.type = type
|
|
50
|
-
self.
|
|
53
|
+
self.invocation_handler = invocation_handler
|
|
51
54
|
|
|
52
55
|
# public
|
|
53
56
|
|
|
54
57
|
def __getattr__(self, name):
|
|
55
58
|
def wrapper(*args, **kwargs):
|
|
56
|
-
return self.
|
|
59
|
+
return self.invocation_handler.invoke(DynamicProxy.Invocation(self.type, name, *args, **kwargs))
|
|
57
60
|
|
|
58
|
-
return wrapper
|
|
61
|
+
return wrapper
|