aspyx 0.1.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 +98 -88
- aspyx/di/configuration/__init__.py +4 -1
- aspyx/di/configuration/configuration.py +21 -14
- aspyx/di/di.py +137 -109
- aspyx/reflection/__init__.py +4 -1
- aspyx/reflection/proxy.py +10 -7
- aspyx/reflection/reflection.py +35 -22
- {aspyx-0.1.0.dist-info → aspyx-1.0.1.dist-info}/METADATA +147 -43
- aspyx-1.0.1.dist-info/RECORD +14 -0
- aspyx-0.1.0.dist-info/RECORD +0 -14
- {aspyx-0.1.0.dist-info → aspyx-1.0.1.dist-info}/WHEEL +0 -0
- {aspyx-0.1.0.dist-info → aspyx-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {aspyx-0.1.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
|
|
@@ -5,6 +8,7 @@ import logging
|
|
|
5
8
|
|
|
6
9
|
from abc import abstractmethod, ABC
|
|
7
10
|
from enum import Enum, auto
|
|
11
|
+
import threading
|
|
8
12
|
from typing import Type, Dict, TypeVar, Generic, Optional, cast, Callable
|
|
9
13
|
|
|
10
14
|
from aspyx.reflection import Decorators, TypeDescriptor, DecoratorDescriptor
|
|
@@ -24,8 +28,8 @@ class Factory(ABC, Generic[T]):
|
|
|
24
28
|
|
|
25
29
|
class InjectorException(Exception):
|
|
26
30
|
"""
|
|
27
|
-
Exception raised for errors in the injector.
|
|
28
|
-
|
|
31
|
+
Exception raised for errors in the injector.
|
|
32
|
+
"""
|
|
29
33
|
|
|
30
34
|
class AbstractInstanceProvider(ABC, Generic[T]):
|
|
31
35
|
"""
|
|
@@ -52,7 +56,7 @@ class AbstractInstanceProvider(ABC, Generic[T]):
|
|
|
52
56
|
pass
|
|
53
57
|
|
|
54
58
|
@abstractmethod
|
|
55
|
-
def create(self,
|
|
59
|
+
def create(self, environment: Environment, *args):
|
|
56
60
|
pass
|
|
57
61
|
|
|
58
62
|
@abstractmethod
|
|
@@ -192,15 +196,15 @@ class Scopes:
|
|
|
192
196
|
|
|
193
197
|
@classmethod
|
|
194
198
|
def get(cls, scope: str, environment: Environment):
|
|
195
|
-
|
|
196
|
-
if
|
|
199
|
+
scope_type = Scopes.scopes.get(scope, None)
|
|
200
|
+
if scope_type is None:
|
|
197
201
|
raise InjectorException(f"unknown scope type {scope}")
|
|
198
202
|
|
|
199
|
-
return environment.get(
|
|
203
|
+
return environment.get(scope_type)
|
|
200
204
|
|
|
201
205
|
@classmethod
|
|
202
|
-
def register(cls,
|
|
203
|
-
Scopes.scopes[name] =
|
|
206
|
+
def register(cls, scope_type: Type, name: str):
|
|
207
|
+
Scopes.scopes[name] = scope_type
|
|
204
208
|
|
|
205
209
|
class Scope:
|
|
206
210
|
# properties
|
|
@@ -215,15 +219,15 @@ class Scope:
|
|
|
215
219
|
|
|
216
220
|
# public
|
|
217
221
|
|
|
218
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
219
|
-
return provider.create(environment, *
|
|
222
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
223
|
+
return provider.create(environment, *arg_provider())
|
|
220
224
|
|
|
221
225
|
class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
222
226
|
# properties
|
|
223
227
|
|
|
224
228
|
__slots__ = [
|
|
225
229
|
"environment",
|
|
226
|
-
"
|
|
230
|
+
"scope_instance",
|
|
227
231
|
"provider",
|
|
228
232
|
"dependencies",
|
|
229
233
|
]
|
|
@@ -237,8 +241,7 @@ class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
|
237
241
|
self.provider = provider
|
|
238
242
|
self.dependencies : list[AbstractInstanceProvider] = []
|
|
239
243
|
|
|
240
|
-
self.
|
|
241
|
-
print()
|
|
244
|
+
self.scope_instance = Scopes.get(provider.get_scope(), environment)
|
|
242
245
|
|
|
243
246
|
# implement
|
|
244
247
|
|
|
@@ -259,21 +262,19 @@ class EnvironmentInstanceProvider(AbstractInstanceProvider):
|
|
|
259
262
|
|
|
260
263
|
# custom logic
|
|
261
264
|
|
|
262
|
-
def
|
|
265
|
+
def tweak_dependencies(self, providers: dict[Type, AbstractInstanceProvider]):
|
|
263
266
|
for dependency in self.provider.get_dependencies():
|
|
264
|
-
|
|
265
|
-
if
|
|
267
|
+
instance_provider = providers.get(dependency.get_type(), None)
|
|
268
|
+
if instance_provider is None:
|
|
266
269
|
raise InjectorException(f"missing import for {dependency.get_type()} ")
|
|
267
270
|
|
|
268
|
-
self.dependencies.append(
|
|
269
|
-
pass
|
|
270
|
-
pass
|
|
271
|
+
self.dependencies.append(instance_provider)
|
|
271
272
|
|
|
272
273
|
def get_dependencies(self) -> list[AbstractInstanceProvider]:
|
|
273
274
|
return self.provider.get_dependencies()
|
|
274
275
|
|
|
275
|
-
def create(self,
|
|
276
|
-
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!
|
|
277
278
|
|
|
278
279
|
def __str__(self):
|
|
279
280
|
return f"EnvironmentInstanceProvider({self.provider})"
|
|
@@ -308,18 +309,18 @@ class ClassInstanceProvider(InstanceProvider):
|
|
|
308
309
|
if init is None:
|
|
309
310
|
raise InjectorException(f"{self.type.__name__} does not implement __init__")
|
|
310
311
|
|
|
311
|
-
for param in init.
|
|
312
|
-
provider = Providers.
|
|
312
|
+
for param in init.param_types:
|
|
313
|
+
provider = Providers.get_provider(param)
|
|
313
314
|
self.params += 1
|
|
314
315
|
if self.add_dependency(provider):
|
|
315
316
|
provider.resolve(context)
|
|
316
317
|
|
|
317
318
|
# check @inject
|
|
318
319
|
|
|
319
|
-
for method in TypeDescriptor.for_type(self.type).
|
|
320
|
+
for method in TypeDescriptor.for_type(self.type).get_methods():
|
|
320
321
|
if method.has_decorator(inject):
|
|
321
|
-
for param in method.
|
|
322
|
-
provider = Providers.
|
|
322
|
+
for param in method.param_types:
|
|
323
|
+
provider = Providers.get_provider(param)
|
|
323
324
|
|
|
324
325
|
if self.add_dependency(provider):
|
|
325
326
|
provider.resolve(context)
|
|
@@ -329,7 +330,7 @@ class ClassInstanceProvider(InstanceProvider):
|
|
|
329
330
|
return self
|
|
330
331
|
|
|
331
332
|
def create(self, environment: Environment, *args):
|
|
332
|
-
Environment.logger.debug(
|
|
333
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
333
334
|
|
|
334
335
|
return environment.created(self.type(*args[:self.params]))
|
|
335
336
|
|
|
@@ -362,7 +363,7 @@ class FunctionInstanceProvider(InstanceProvider):
|
|
|
362
363
|
|
|
363
364
|
context.add(self)
|
|
364
365
|
|
|
365
|
-
provider = Providers.
|
|
366
|
+
provider = Providers.get_provider(self.host)
|
|
366
367
|
if self.add_dependency(provider):
|
|
367
368
|
provider.resolve(context)
|
|
368
369
|
else: # check if the dependencies crate a cycle
|
|
@@ -371,7 +372,7 @@ class FunctionInstanceProvider(InstanceProvider):
|
|
|
371
372
|
return self
|
|
372
373
|
|
|
373
374
|
def create(self, environment: Environment, *args):
|
|
374
|
-
Environment.logger.debug(
|
|
375
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
375
376
|
|
|
376
377
|
instance = self.method(*args)
|
|
377
378
|
|
|
@@ -390,13 +391,13 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
390
391
|
# class method
|
|
391
392
|
|
|
392
393
|
@classmethod
|
|
393
|
-
def
|
|
394
|
-
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
|
|
395
396
|
|
|
396
397
|
# constructor
|
|
397
398
|
|
|
398
399
|
def __init__(self, factory: Type, eager: bool, scope: str):
|
|
399
|
-
super().__init__(factory, FactoryInstanceProvider.
|
|
400
|
+
super().__init__(factory, FactoryInstanceProvider.get_factory_type(factory), eager, scope)
|
|
400
401
|
|
|
401
402
|
# implement
|
|
402
403
|
|
|
@@ -406,7 +407,7 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
406
407
|
|
|
407
408
|
context.add(self)
|
|
408
409
|
|
|
409
|
-
provider = Providers.
|
|
410
|
+
provider = Providers.get_provider(self.host)
|
|
410
411
|
if self.add_dependency(provider):
|
|
411
412
|
provider.resolve(context)
|
|
412
413
|
|
|
@@ -416,7 +417,7 @@ class FactoryInstanceProvider(InstanceProvider):
|
|
|
416
417
|
return self
|
|
417
418
|
|
|
418
419
|
def create(self, environment: Environment, *args):
|
|
419
|
-
Environment.logger.debug(
|
|
420
|
+
Environment.logger.debug("%s create class %s", self, self.type.__qualname__)
|
|
420
421
|
|
|
421
422
|
return environment.created(args[0].create())
|
|
422
423
|
|
|
@@ -438,17 +439,21 @@ class LifecycleProcessor(ABC):
|
|
|
438
439
|
"""
|
|
439
440
|
A LifecycleProcessor is used to perform any side effects on managed objects during their lifecycle.
|
|
440
441
|
"""
|
|
441
|
-
__slots__ = [
|
|
442
|
+
__slots__ = [
|
|
443
|
+
"order"
|
|
444
|
+
]
|
|
442
445
|
|
|
443
446
|
# constructor
|
|
444
447
|
|
|
445
448
|
def __init__(self):
|
|
446
|
-
|
|
449
|
+
self.order = 0
|
|
450
|
+
if TypeDescriptor.for_type(type(self)).has_decorator(order):
|
|
451
|
+
self.order = TypeDescriptor.for_type(type(self)).get_decorator(order).args[0]
|
|
447
452
|
|
|
448
453
|
# methods
|
|
449
454
|
|
|
450
455
|
@abstractmethod
|
|
451
|
-
def
|
|
456
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
452
457
|
pass
|
|
453
458
|
|
|
454
459
|
class PostProcessor(LifecycleProcessor):
|
|
@@ -457,15 +462,11 @@ class PostProcessor(LifecycleProcessor):
|
|
|
457
462
|
"""
|
|
458
463
|
__slots__ = []
|
|
459
464
|
|
|
460
|
-
# constructor
|
|
461
|
-
|
|
462
|
-
def __init__(self):
|
|
463
|
-
super().__init__()
|
|
464
465
|
|
|
465
466
|
def process(self, instance: object, environment: Environment):
|
|
466
467
|
pass
|
|
467
468
|
|
|
468
|
-
def
|
|
469
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
469
470
|
if lifecycle == Lifecycle.ON_INIT:
|
|
470
471
|
self.process(instance, environment)
|
|
471
472
|
|
|
@@ -485,11 +486,11 @@ class Providers:
|
|
|
485
486
|
def add(self, *providers: AbstractInstanceProvider):
|
|
486
487
|
for provider in providers:
|
|
487
488
|
if next((p for p in self.dependencies if p.get_type() is provider.get_type()), None) is not None:
|
|
488
|
-
raise InjectorException(self.
|
|
489
|
+
raise InjectorException(self.cycle_report(provider))
|
|
489
490
|
|
|
490
491
|
self.dependencies.append(provider)
|
|
491
492
|
|
|
492
|
-
def
|
|
493
|
+
def cycle_report(self, provider: AbstractInstanceProvider):
|
|
493
494
|
cycle = ""
|
|
494
495
|
|
|
495
496
|
first = True
|
|
@@ -508,16 +509,16 @@ class Providers:
|
|
|
508
509
|
|
|
509
510
|
# class properties
|
|
510
511
|
|
|
511
|
-
check: list[AbstractInstanceProvider] =
|
|
512
|
+
check: list[AbstractInstanceProvider] = []
|
|
512
513
|
|
|
513
|
-
providers : Dict[Type,AbstractInstanceProvider] =
|
|
514
|
-
cache: Dict[Type, AbstractInstanceProvider] =
|
|
514
|
+
providers : Dict[Type,AbstractInstanceProvider] = {}
|
|
515
|
+
cache: Dict[Type, AbstractInstanceProvider] = {}
|
|
515
516
|
|
|
516
517
|
resolved = False
|
|
517
518
|
|
|
518
519
|
@classmethod
|
|
519
520
|
def register(cls, provider: AbstractInstanceProvider):
|
|
520
|
-
Environment.logger.debug(
|
|
521
|
+
Environment.logger.debug("register provider %s(%s)", provider.get_type().__qualname__, provider.get_type().__name__)
|
|
521
522
|
|
|
522
523
|
# local functions
|
|
523
524
|
|
|
@@ -536,7 +537,7 @@ class Providers:
|
|
|
536
537
|
|
|
537
538
|
return True
|
|
538
539
|
|
|
539
|
-
def
|
|
540
|
+
def cache_provider_for_type(provider: AbstractInstanceProvider, type: Type):
|
|
540
541
|
existing_provider = Providers.cache.get(type)
|
|
541
542
|
if existing_provider is None:
|
|
542
543
|
Providers.cache[type] = provider
|
|
@@ -552,9 +553,9 @@ class Providers:
|
|
|
552
553
|
|
|
553
554
|
# recursion
|
|
554
555
|
|
|
555
|
-
for
|
|
556
|
-
if is_injectable(
|
|
557
|
-
|
|
556
|
+
for super_class in type.__bases__:
|
|
557
|
+
if is_injectable(super_class):
|
|
558
|
+
cache_provider_for_type(provider, super_class)
|
|
558
559
|
|
|
559
560
|
# go
|
|
560
561
|
|
|
@@ -564,7 +565,7 @@ class Providers:
|
|
|
564
565
|
|
|
565
566
|
# cache providers
|
|
566
567
|
|
|
567
|
-
|
|
568
|
+
cache_provider_for_type(provider, provider.get_type())
|
|
568
569
|
|
|
569
570
|
@classmethod
|
|
570
571
|
def resolve(cls):
|
|
@@ -581,21 +582,28 @@ class Providers:
|
|
|
581
582
|
print(f"provider {provider.get_type().__qualname__}")
|
|
582
583
|
|
|
583
584
|
@classmethod
|
|
584
|
-
def
|
|
585
|
+
def get_provider(cls, type: Type) -> AbstractInstanceProvider:
|
|
585
586
|
provider = Providers.cache.get(type, None)
|
|
586
587
|
if provider is None:
|
|
587
588
|
raise InjectorException(f"{type.__name__} not registered as injectable")
|
|
588
589
|
|
|
589
590
|
return provider
|
|
590
591
|
|
|
591
|
-
def
|
|
592
|
+
def register_factories(cls: Type):
|
|
592
593
|
descriptor = TypeDescriptor.for_type(cls)
|
|
593
594
|
|
|
594
|
-
for method in descriptor.
|
|
595
|
+
for method in descriptor.get_methods():
|
|
595
596
|
if method.has_decorator(create):
|
|
596
597
|
create_decorator = method.get_decorator(create)
|
|
597
|
-
Providers.register(FunctionInstanceProvider(cls, method.method, method.
|
|
598
|
+
Providers.register(FunctionInstanceProvider(cls, method.method, method.return_type, create_decorator.args[0],
|
|
598
599
|
create_decorator.args[1]))
|
|
600
|
+
def order(prio = 0):
|
|
601
|
+
def decorator(cls):
|
|
602
|
+
Decorators.add(cls, order, prio)
|
|
603
|
+
|
|
604
|
+
return cls
|
|
605
|
+
|
|
606
|
+
return decorator
|
|
599
607
|
|
|
600
608
|
def injectable(eager=True, scope="singleton"):
|
|
601
609
|
"""
|
|
@@ -669,7 +677,7 @@ def environment(imports: Optional[list[Type]] = None):
|
|
|
669
677
|
Decorators.add(cls, environment, imports)
|
|
670
678
|
Decorators.add(cls, injectable) # do we need that?
|
|
671
679
|
|
|
672
|
-
|
|
680
|
+
register_factories(cls)
|
|
673
681
|
|
|
674
682
|
return cls
|
|
675
683
|
|
|
@@ -709,12 +717,13 @@ class Environment:
|
|
|
709
717
|
__slots__ = [
|
|
710
718
|
"type",
|
|
711
719
|
"providers",
|
|
712
|
-
"
|
|
720
|
+
"lifecycle_processors",
|
|
713
721
|
"parent",
|
|
714
722
|
"instances"
|
|
715
723
|
]
|
|
716
724
|
|
|
717
725
|
# constructor
|
|
726
|
+
|
|
718
727
|
def __init__(self, env: Type, parent : Optional[Environment] = None):
|
|
719
728
|
"""
|
|
720
729
|
Creates a new Environment instance.
|
|
@@ -730,12 +739,12 @@ class Environment:
|
|
|
730
739
|
if self.parent is None and env is not BootEnvironment:
|
|
731
740
|
self.parent = BootEnvironment.get_instance() # inherit environment including its manged instances!
|
|
732
741
|
|
|
733
|
-
self.providers: Dict[Type, AbstractInstanceProvider] =
|
|
734
|
-
self.
|
|
742
|
+
self.providers: Dict[Type, AbstractInstanceProvider] = {}
|
|
743
|
+
self.lifecycle_processors: list[LifecycleProcessor] = []
|
|
735
744
|
|
|
736
745
|
if self.parent is not None:
|
|
737
746
|
self.providers |= self.parent.providers
|
|
738
|
-
self.
|
|
747
|
+
self.lifecycle_processors += self.parent.lifecycle_processors
|
|
739
748
|
|
|
740
749
|
self.instances = []
|
|
741
750
|
|
|
@@ -748,7 +757,7 @@ class Environment:
|
|
|
748
757
|
loaded = set()
|
|
749
758
|
|
|
750
759
|
def add_provider(type: Type, provider: AbstractInstanceProvider):
|
|
751
|
-
Environment.logger.debug(
|
|
760
|
+
Environment.logger.debug("\tadd provider %s for %s", provider, type)
|
|
752
761
|
|
|
753
762
|
self.providers[type] = provider
|
|
754
763
|
|
|
@@ -760,7 +769,7 @@ class Environment:
|
|
|
760
769
|
|
|
761
770
|
def load_environment(env: Type):
|
|
762
771
|
if env not in loaded:
|
|
763
|
-
Environment.logger.debug(
|
|
772
|
+
Environment.logger.debug("load environment %s", env.__qualname__)
|
|
764
773
|
|
|
765
774
|
loaded.add(env)
|
|
766
775
|
|
|
@@ -781,31 +790,31 @@ class Environment:
|
|
|
781
790
|
|
|
782
791
|
# load providers
|
|
783
792
|
|
|
784
|
-
|
|
793
|
+
local_providers = {type: provider for type, provider in Providers.cache.items() if provider.get_module().startswith(scan)}
|
|
785
794
|
|
|
786
795
|
# register providers
|
|
787
796
|
|
|
788
797
|
# make sure, that for every type ony a single EnvironmentInstanceProvider is created!
|
|
789
798
|
# otherwise inheritance will fuck it up
|
|
790
799
|
|
|
791
|
-
|
|
800
|
+
environment_providers : dict[AbstractInstanceProvider, EnvironmentInstanceProvider] = {}
|
|
792
801
|
|
|
793
|
-
for type, provider in
|
|
794
|
-
|
|
795
|
-
if
|
|
796
|
-
|
|
797
|
-
|
|
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
|
|
798
807
|
|
|
799
|
-
add_provider(type,
|
|
808
|
+
add_provider(type, environment_provider)
|
|
800
809
|
|
|
801
810
|
# tweak dependencies
|
|
802
811
|
|
|
803
|
-
for type, provider in
|
|
804
|
-
cast(EnvironmentInstanceProvider, self.providers[type]).
|
|
812
|
+
for type, provider in local_providers.items():
|
|
813
|
+
cast(EnvironmentInstanceProvider, self.providers[type]).tweak_dependencies(self.providers)
|
|
805
814
|
|
|
806
815
|
# return local providers
|
|
807
816
|
|
|
808
|
-
return
|
|
817
|
+
return environment_providers.values()
|
|
809
818
|
else:
|
|
810
819
|
return []
|
|
811
820
|
|
|
@@ -816,9 +825,9 @@ class Environment:
|
|
|
816
825
|
provider.create(self)
|
|
817
826
|
# internal
|
|
818
827
|
|
|
819
|
-
def
|
|
820
|
-
for processor in self.
|
|
821
|
-
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)
|
|
822
831
|
|
|
823
832
|
return instance
|
|
824
833
|
|
|
@@ -826,7 +835,11 @@ class Environment:
|
|
|
826
835
|
# remember lifecycle processors
|
|
827
836
|
|
|
828
837
|
if isinstance(instance, LifecycleProcessor):
|
|
829
|
-
self.
|
|
838
|
+
self.lifecycle_processors.append(instance)
|
|
839
|
+
|
|
840
|
+
# sort immediately
|
|
841
|
+
|
|
842
|
+
self.lifecycle_processors.sort(key=lambda processor: processor.order)
|
|
830
843
|
|
|
831
844
|
# remember instance
|
|
832
845
|
|
|
@@ -834,7 +847,7 @@ class Environment:
|
|
|
834
847
|
|
|
835
848
|
# execute processors
|
|
836
849
|
|
|
837
|
-
return self.
|
|
850
|
+
return self.execute_processors(Lifecycle.ON_INIT, instance)
|
|
838
851
|
|
|
839
852
|
# public
|
|
840
853
|
|
|
@@ -843,7 +856,7 @@ class Environment:
|
|
|
843
856
|
destroy all managed instances by calling the appropriate lifecycle methods
|
|
844
857
|
"""
|
|
845
858
|
for instance in self.instances:
|
|
846
|
-
self.
|
|
859
|
+
self.execute_processors(Lifecycle.ON_DESTROY, instance)
|
|
847
860
|
|
|
848
861
|
self.instances.clear() # make the cy happy
|
|
849
862
|
|
|
@@ -858,7 +871,7 @@ class Environment:
|
|
|
858
871
|
"""
|
|
859
872
|
provider = self.providers.get(type, None)
|
|
860
873
|
if provider is None:
|
|
861
|
-
Environment.logger.error(
|
|
874
|
+
Environment.logger.error("%s is not supported", type)
|
|
862
875
|
raise InjectorException(f"{type} is not supported")
|
|
863
876
|
|
|
864
877
|
return provider.create(self)
|
|
@@ -866,12 +879,17 @@ class Environment:
|
|
|
866
879
|
class LifecycleCallable:
|
|
867
880
|
__slots__ = [
|
|
868
881
|
"decorator",
|
|
869
|
-
"lifecycle"
|
|
882
|
+
"lifecycle",
|
|
883
|
+
"order"
|
|
870
884
|
]
|
|
871
885
|
|
|
872
886
|
def __init__(self, decorator, processor: CallableProcessor, lifecycle: Lifecycle):
|
|
873
887
|
self.decorator = decorator
|
|
874
888
|
self.lifecycle = lifecycle
|
|
889
|
+
self.order = 0
|
|
890
|
+
|
|
891
|
+
if TypeDescriptor.for_type(type(self)).has_decorator(order):
|
|
892
|
+
self.order = TypeDescriptor.for_type(type(self)).get_decorator(order).args[0]
|
|
875
893
|
|
|
876
894
|
processor.register(self)
|
|
877
895
|
|
|
@@ -879,6 +897,7 @@ class LifecycleCallable:
|
|
|
879
897
|
return []
|
|
880
898
|
|
|
881
899
|
@injectable()
|
|
900
|
+
@order(1)
|
|
882
901
|
class CallableProcessor(LifecycleProcessor):
|
|
883
902
|
# local classes
|
|
884
903
|
|
|
@@ -886,18 +905,18 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
886
905
|
__slots__ = [
|
|
887
906
|
"decorator",
|
|
888
907
|
"method",
|
|
889
|
-
"
|
|
908
|
+
"lifecycle_callable"
|
|
890
909
|
]
|
|
891
910
|
|
|
892
911
|
# constructor
|
|
893
912
|
|
|
894
|
-
def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor,
|
|
913
|
+
def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor, lifecycle_callable: LifecycleCallable):
|
|
895
914
|
self.decorator = decorator
|
|
896
915
|
self.method = method
|
|
897
|
-
self.
|
|
916
|
+
self.lifecycle_callable = lifecycle_callable
|
|
898
917
|
|
|
899
918
|
def execute(self, instance, environment: Environment):
|
|
900
|
-
self.method.method(instance, *self.
|
|
919
|
+
self.method.method(instance, *self.lifecycle_callable.args(self.decorator, self.method, environment))
|
|
901
920
|
|
|
902
921
|
def __str__(self):
|
|
903
922
|
return f"MethodCall({self.method.method.__name__})"
|
|
@@ -907,25 +926,31 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
907
926
|
def __init__(self):
|
|
908
927
|
super().__init__()
|
|
909
928
|
|
|
910
|
-
self.callables : Dict[object,LifecycleCallable] =
|
|
911
|
-
self.cache : Dict[Type,list[CallableProcessor.MethodCall]] =
|
|
929
|
+
self.callables : Dict[object,LifecycleCallable] = {}
|
|
930
|
+
self.cache : Dict[Type,list[CallableProcessor.MethodCall]] = {}
|
|
912
931
|
|
|
913
|
-
def
|
|
932
|
+
def compute_callables(self, type: Type) -> list[CallableProcessor.MethodCall] :
|
|
914
933
|
descriptor = TypeDescriptor.for_type(type)
|
|
915
934
|
|
|
916
935
|
result = []
|
|
917
936
|
|
|
918
|
-
for method in descriptor.
|
|
937
|
+
for method in descriptor.get_methods():
|
|
919
938
|
for decorator in method.decorators:
|
|
920
939
|
if self.callables.get(decorator.decorator) is not None:
|
|
921
940
|
result.append(CallableProcessor.MethodCall(method, decorator, self.callables[decorator.decorator]))
|
|
922
941
|
|
|
942
|
+
# sort according to order
|
|
943
|
+
|
|
944
|
+
result.sort(key=lambda call: call.lifecycle_callable.order)
|
|
945
|
+
|
|
946
|
+
# done
|
|
947
|
+
|
|
923
948
|
return result
|
|
924
949
|
|
|
925
|
-
def
|
|
950
|
+
def callables_for(self, type: Type)-> list[CallableProcessor.MethodCall]:
|
|
926
951
|
callables = self.cache.get(type, None)
|
|
927
952
|
if callables is None:
|
|
928
|
-
callables = self.
|
|
953
|
+
callables = self.compute_callables(type)
|
|
929
954
|
self.cache[type] = callables
|
|
930
955
|
|
|
931
956
|
return callables
|
|
@@ -935,13 +960,14 @@ class CallableProcessor(LifecycleProcessor):
|
|
|
935
960
|
|
|
936
961
|
# implement
|
|
937
962
|
|
|
938
|
-
def
|
|
939
|
-
callables = self.
|
|
963
|
+
def process_lifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
|
|
964
|
+
callables = self.callables_for(type(instance))
|
|
940
965
|
for callable in callables:
|
|
941
|
-
if callable.
|
|
966
|
+
if callable.lifecycle_callable.lifecycle is lifecycle:
|
|
942
967
|
callable.execute(instance, environment)
|
|
943
968
|
|
|
944
969
|
@injectable()
|
|
970
|
+
@order(1000)
|
|
945
971
|
class OnInitLifecycleCallable(LifecycleCallable):
|
|
946
972
|
__slots__ = []
|
|
947
973
|
|
|
@@ -949,6 +975,7 @@ class OnInitLifecycleCallable(LifecycleCallable):
|
|
|
949
975
|
super().__init__(on_init, processor, Lifecycle.ON_INIT)
|
|
950
976
|
|
|
951
977
|
@injectable()
|
|
978
|
+
@order(1001)
|
|
952
979
|
class OnDestroyLifecycleCallable(LifecycleCallable):
|
|
953
980
|
__slots__ = []
|
|
954
981
|
|
|
@@ -956,6 +983,7 @@ class OnDestroyLifecycleCallable(LifecycleCallable):
|
|
|
956
983
|
super().__init__(on_destroy, processor, Lifecycle.ON_DESTROY)
|
|
957
984
|
|
|
958
985
|
@injectable()
|
|
986
|
+
@order(9)
|
|
959
987
|
class EnvironmentAwareLifecycleCallable(LifecycleCallable):
|
|
960
988
|
__slots__ = []
|
|
961
989
|
|
|
@@ -966,6 +994,7 @@ class EnvironmentAwareLifecycleCallable(LifecycleCallable):
|
|
|
966
994
|
return [environment]
|
|
967
995
|
|
|
968
996
|
@injectable()
|
|
997
|
+
@order(10)
|
|
969
998
|
class InjectLifecycleCallable(LifecycleCallable):
|
|
970
999
|
__slots__ = []
|
|
971
1000
|
|
|
@@ -975,7 +1004,7 @@ class InjectLifecycleCallable(LifecycleCallable):
|
|
|
975
1004
|
# override
|
|
976
1005
|
|
|
977
1006
|
def args(self, decorator: DecoratorDescriptor, method: TypeDescriptor.MethodDescriptor, environment: Environment):
|
|
978
|
-
return [environment.get(type) for type in method.
|
|
1007
|
+
return [environment.get(type) for type in method.param_types]
|
|
979
1008
|
|
|
980
1009
|
def scope(name: str):
|
|
981
1010
|
def decorator(cls):
|
|
@@ -997,22 +1026,18 @@ class RequestScope(Scope):
|
|
|
997
1026
|
__slots__ = [
|
|
998
1027
|
]
|
|
999
1028
|
|
|
1000
|
-
# constructor
|
|
1001
|
-
|
|
1002
|
-
def __init__(self):
|
|
1003
|
-
super().__init__()
|
|
1004
|
-
|
|
1005
1029
|
# public
|
|
1006
1030
|
|
|
1007
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
1008
|
-
return provider.create(environment, *
|
|
1031
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
1032
|
+
return provider.create(environment, *arg_provider())
|
|
1009
1033
|
|
|
1010
1034
|
@scope("singleton")
|
|
1011
1035
|
class SingletonScope(Scope):
|
|
1012
1036
|
# properties
|
|
1013
1037
|
|
|
1014
1038
|
__slots__ = [
|
|
1015
|
-
"value"
|
|
1039
|
+
"value",
|
|
1040
|
+
"lock"
|
|
1016
1041
|
]
|
|
1017
1042
|
|
|
1018
1043
|
# constructor
|
|
@@ -1021,12 +1046,15 @@ class SingletonScope(Scope):
|
|
|
1021
1046
|
super().__init__()
|
|
1022
1047
|
|
|
1023
1048
|
self.value = None
|
|
1049
|
+
self.lock = threading.Lock()
|
|
1024
1050
|
|
|
1025
1051
|
# override
|
|
1026
1052
|
|
|
1027
|
-
def get(self, provider: AbstractInstanceProvider, environment: Environment,
|
|
1028
|
-
if self.value is None:
|
|
1029
|
-
self.
|
|
1053
|
+
def get(self, provider: AbstractInstanceProvider, environment: Environment, arg_provider: Callable[[],list]):
|
|
1054
|
+
if self.value is None:
|
|
1055
|
+
with self.lock:
|
|
1056
|
+
if self.value is None:
|
|
1057
|
+
self.value = provider.create(environment, *arg_provider())
|
|
1030
1058
|
|
|
1031
1059
|
return self.value
|
|
1032
1060
|
|
|
@@ -1052,4 +1080,4 @@ class BootEnvironment:
|
|
|
1052
1080
|
# constructor
|
|
1053
1081
|
|
|
1054
1082
|
def __init__(self):
|
|
1055
|
-
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
|
+
]
|