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/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
- pass
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, env: Environment, *args):
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
- scopeType = Scopes.scopes.get(scope, None)
196
- if scopeType is None:
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(scopeType)
203
+ return environment.get(scope_type)
200
204
 
201
205
  @classmethod
202
- def register(cls, scopeClass: Type, name: str):
203
- Scopes.scopes[name] = scopeClass
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, argProvider: Callable[[],list]):
219
- return provider.create(environment, *argProvider())
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
- "scopeInstance",
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.scopeInstance = Scopes.get(provider.get_scope(), environment)
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 tweakDependencies(self, providers: dict[Type, AbstractInstanceProvider]):
265
+ def tweak_dependencies(self, providers: dict[Type, AbstractInstanceProvider]):
263
266
  for dependency in self.provider.get_dependencies():
264
- instanceProvider = providers.get(dependency.get_type(), None)
265
- if instanceProvider is None:
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(instanceProvider)
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, env: Environment, *args):
276
- return self.scopeInstance.get(self.provider, self.environment, lambda: [provider.create(env) for provider in self.dependencies] ) # already scope property!
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.paramTypes:
312
- provider = Providers.getProvider(param)
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).methods.values():
320
+ for method in TypeDescriptor.for_type(self.type).get_methods():
320
321
  if method.has_decorator(inject):
321
- for param in method.paramTypes:
322
- provider = Providers.getProvider(param)
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(f"{self} create class {self.type.__qualname__}")
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.getProvider(self.host)
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(f"{self} create class {self.type.__qualname__}")
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 getFactoryType(cls, clazz):
394
- return TypeDescriptor.for_type(clazz).get_local_method("create").returnType
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.getFactoryType(factory), eager, scope)
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.getProvider(self.host)
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(f"{self} create class {self.type.__qualname__}")
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
- pass
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 processLifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
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 processLifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
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.cycleReport(provider))
489
+ raise InjectorException(self.cycle_report(provider))
489
490
 
490
491
  self.dependencies.append(provider)
491
492
 
492
- def cycleReport(self, provider: AbstractInstanceProvider):
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] = list()
512
+ check: list[AbstractInstanceProvider] = []
512
513
 
513
- providers : Dict[Type,AbstractInstanceProvider] = dict()
514
- cache: Dict[Type, AbstractInstanceProvider] = dict()
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(f"register provider {provider.get_type().__qualname__}({provider.get_type().__name__})")
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 cacheProviderForType(provider: AbstractInstanceProvider, type: Type):
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 superClass in type.__bases__:
556
- if is_injectable(superClass):
557
- cacheProviderForType(provider, superClass)
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
- cacheProviderForType(provider, provider.get_type())
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 getProvider(cls, type: Type) -> AbstractInstanceProvider:
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 registerFactories(cls: Type):
592
+ def register_factories(cls: Type):
592
593
  descriptor = TypeDescriptor.for_type(cls)
593
594
 
594
- for method in descriptor.methods.values():
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.returnType, create_decorator.args[0],
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
- registerFactories(cls)
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
- "lifecycleProcessors",
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] = dict()
734
- self.lifecycleProcessors: list[LifecycleProcessor] = []
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.lifecycleProcessors += self.parent.lifecycleProcessors
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(f"\tadd provider {provider} for {type})")
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(f"load environment {env.__qualname__}")
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
- localProviders = {type: provider for type, provider in Providers.cache.items() if provider.get_module().startswith(scan)}
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
- environmentProviders : dict[AbstractInstanceProvider, EnvironmentInstanceProvider] = {}
800
+ environment_providers : dict[AbstractInstanceProvider, EnvironmentInstanceProvider] = {}
792
801
 
793
- for type, provider in localProviders.items():
794
- environmentProvider = environmentProviders.get(provider, None)
795
- if environmentProvider is None:
796
- environmentProvider = EnvironmentInstanceProvider(self, provider)
797
- environmentProviders[provider] = environmentProvider
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, environmentProvider)
808
+ add_provider(type, environment_provider)
800
809
 
801
810
  # tweak dependencies
802
811
 
803
- for type, provider in localProviders.items():
804
- cast(EnvironmentInstanceProvider, self.providers[type]).tweakDependencies(self.providers)
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 environmentProviders.values()
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 executeProcessors(self, lifecycle: Lifecycle, instance: T) -> T:
820
- for processor in self.lifecycleProcessors:
821
- processor.processLifecycle(lifecycle, instance, self)
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.lifecycleProcessors.append(instance)
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.executeProcessors(Lifecycle.ON_INIT, instance)
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.executeProcessors(Lifecycle.ON_DESTROY, instance)
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(f"{type} is not supported")
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
- "lifecycleCallable"
908
+ "lifecycle_callable"
890
909
  ]
891
910
 
892
911
  # constructor
893
912
 
894
- def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor, lifecycleCallable: LifecycleCallable):
913
+ def __init__(self, method: TypeDescriptor.MethodDescriptor, decorator: DecoratorDescriptor, lifecycle_callable: LifecycleCallable):
895
914
  self.decorator = decorator
896
915
  self.method = method
897
- self.lifecycleCallable = lifecycleCallable
916
+ self.lifecycle_callable = lifecycle_callable
898
917
 
899
918
  def execute(self, instance, environment: Environment):
900
- self.method.method(instance, *self.lifecycleCallable.args(self.decorator, self.method, environment))
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] = dict()
911
- self.cache : Dict[Type,list[CallableProcessor.MethodCall]] = dict()
929
+ self.callables : Dict[object,LifecycleCallable] = {}
930
+ self.cache : Dict[Type,list[CallableProcessor.MethodCall]] = {}
912
931
 
913
- def computeCallables(self, type: Type) -> list[CallableProcessor.MethodCall] :
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.methods.values():
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 callablesFor(self, type: Type)-> list[CallableProcessor.MethodCall]:
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.computeCallables(type)
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 processLifecycle(self, lifecycle: Lifecycle, instance: object, environment: Environment) -> object:
939
- callables = self.callablesFor(type(instance))
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.lifecycleCallable.lifecycle is lifecycle:
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.paramTypes]
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, argProvider: Callable[[],list]):
1008
- return provider.create(environment, *argProvider())
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, argProvider: Callable[[],list]):
1028
- if self.value is None: # TODO thread-safe
1029
- self.value = provider.create(environment, *argProvider())
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
@@ -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
+ ]