orionis 0.652.0__py3-none-any.whl → 0.654.0__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.
- orionis/container/container.py +250 -155
- orionis/foundation/application.py +1 -7
- orionis/metadata/framework.py +1 -1
- {orionis-0.652.0.dist-info → orionis-0.654.0.dist-info}/METADATA +1 -1
- {orionis-0.652.0.dist-info → orionis-0.654.0.dist-info}/RECORD +8 -8
- {orionis-0.652.0.dist-info → orionis-0.654.0.dist-info}/WHEEL +0 -0
- {orionis-0.652.0.dist-info → orionis-0.654.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.652.0.dist-info → orionis-0.654.0.dist-info}/top_level.txt +0 -0
orionis/container/container.py
CHANGED
|
@@ -88,37 +88,38 @@ class Container(IContainer):
|
|
|
88
88
|
|
|
89
89
|
def __init__(self) -> None:
|
|
90
90
|
"""
|
|
91
|
-
Initializes
|
|
91
|
+
Initializes the internal state of the container instance.
|
|
92
92
|
|
|
93
|
-
This constructor sets up the internal dictionaries for bindings
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
This constructor sets up the internal dictionaries for service bindings, aliases,
|
|
94
|
+
singleton cache, and resolution cache. Initialization is performed only once per
|
|
95
|
+
instance, even if `__init__` is called multiple times due to inheritance or other
|
|
96
|
+
instantiation patterns. The container also registers itself under the `IContainer`
|
|
97
|
+
interface for dependency injection.
|
|
96
98
|
|
|
97
99
|
Notes
|
|
98
100
|
-----
|
|
99
|
-
- The `__bindings` dictionary
|
|
100
|
-
- The `__aliases` dictionary
|
|
101
|
-
-
|
|
102
|
-
- The
|
|
101
|
+
- The `__bindings` dictionary stores service bindings by abstract type.
|
|
102
|
+
- The `__aliases` dictionary maps aliases to their corresponding bindings.
|
|
103
|
+
- The `__singleton_cache` dictionary caches singleton instances.
|
|
104
|
+
- The `__resolution_cache` dictionary tracks types being resolved to prevent circular dependencies.
|
|
105
|
+
- Initialization is guarded to ensure it only occurs once per instance.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
None
|
|
110
|
+
This method does not return any value.
|
|
103
111
|
"""
|
|
104
112
|
|
|
105
|
-
#
|
|
113
|
+
# Only initialize if this instance hasn't been initialized before
|
|
106
114
|
if not hasattr(self, '_Container__initialized'):
|
|
107
115
|
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
# Set up the container's internal dictionaries for service management
|
|
117
|
+
self.__bindings = {} # Stores service bindings by abstract type
|
|
118
|
+
self.__aliases = {} # Maps aliases to bindings
|
|
119
|
+
self.__resolution_cache = {} # Tracks types currently being resolved
|
|
120
|
+
self.__singleton_cache = {} # Caches singleton instances
|
|
111
121
|
|
|
112
|
-
#
|
|
113
|
-
self.__valid_namespaces = set(('app', 'orionis', 'requests', 'rich', 'apscheduler', 'dotenv', current_project_namespace))
|
|
114
|
-
|
|
115
|
-
# Initialize the container's internal state
|
|
116
|
-
self.__bindings = {}
|
|
117
|
-
self.__aliases = {}
|
|
118
|
-
self.__resolution_cache = {}
|
|
119
|
-
self.__singleton_cache = {}
|
|
120
|
-
|
|
121
|
-
# Mark this instance as initialized
|
|
122
|
+
# Mark this instance as initialized to prevent re-initialization
|
|
122
123
|
self.__initialized = True
|
|
123
124
|
|
|
124
125
|
def __handleSyncAsyncResult(
|
|
@@ -487,6 +488,12 @@ class Container(IContainer):
|
|
|
487
488
|
"""
|
|
488
489
|
Registers a service with a transient lifetime.
|
|
489
490
|
|
|
491
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
492
|
+
in the container, ensuring that a new instance of the concrete class is created
|
|
493
|
+
each time the service is requested. It validates the abstract and concrete types,
|
|
494
|
+
enforces decoupling rules if specified, checks that all abstract methods are implemented,
|
|
495
|
+
and manages service aliases.
|
|
496
|
+
|
|
490
497
|
Parameters
|
|
491
498
|
----------
|
|
492
499
|
abstract : Callable[..., Any]
|
|
@@ -497,13 +504,14 @@ class Container(IContainer):
|
|
|
497
504
|
An alternative name to register the service under. If not provided, a default alias is generated
|
|
498
505
|
using the abstract's module and class name.
|
|
499
506
|
enforce_decoupling : bool, optional
|
|
500
|
-
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
501
|
-
requires that the concrete class is a subclass of the abstract.
|
|
507
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
508
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
502
509
|
|
|
503
510
|
Returns
|
|
504
511
|
-------
|
|
505
512
|
bool or None
|
|
506
|
-
Returns True if the service was registered successfully.
|
|
513
|
+
Returns True if the service was registered successfully.
|
|
514
|
+
Returns None if registration fails due to an exception.
|
|
507
515
|
|
|
508
516
|
Raises
|
|
509
517
|
------
|
|
@@ -514,11 +522,12 @@ class Container(IContainer):
|
|
|
514
522
|
|
|
515
523
|
Notes
|
|
516
524
|
-----
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
abstract and concrete types, checks decoupling rules, ensures all abstract methods
|
|
520
|
-
|
|
521
|
-
it is removed before registering
|
|
525
|
+
- Registers the given concrete implementation to the abstract type with a transient lifetime,
|
|
526
|
+
meaning a new instance will be created each time the service is requested.
|
|
527
|
+
- Validates the abstract and concrete types, checks decoupling rules, ensures all abstract methods
|
|
528
|
+
are implemented, and manages service aliases.
|
|
529
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering
|
|
530
|
+
the new binding.
|
|
522
531
|
"""
|
|
523
532
|
|
|
524
533
|
try:
|
|
@@ -529,11 +538,10 @@ class Container(IContainer):
|
|
|
529
538
|
# Ensure that concrete is a concrete class
|
|
530
539
|
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
531
540
|
|
|
532
|
-
#
|
|
533
|
-
# otherwise ensure it is a subclass
|
|
541
|
+
# Enforce decoupling or subclass relationship as specified
|
|
534
542
|
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
535
543
|
|
|
536
|
-
# Ensure
|
|
544
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
537
545
|
self.__implementsAbstractMethods(
|
|
538
546
|
abstract=abstract,
|
|
539
547
|
concrete=concrete
|
|
@@ -581,7 +589,8 @@ class Container(IContainer):
|
|
|
581
589
|
This method validates the abstract type, the instance, and the alias (if provided).
|
|
582
590
|
It ensures that the instance is a valid implementation of the abstract class or interface,
|
|
583
591
|
optionally enforces decoupling, and registers the instance in the container under both
|
|
584
|
-
the abstract type and the alias.
|
|
592
|
+
the abstract type and the alias. The registered instance will be shared across all resolutions
|
|
593
|
+
of the abstract type or alias.
|
|
585
594
|
|
|
586
595
|
Parameters
|
|
587
596
|
----------
|
|
@@ -614,7 +623,7 @@ class Container(IContainer):
|
|
|
614
623
|
-----
|
|
615
624
|
- The instance is registered with singleton lifetime, meaning it will be shared
|
|
616
625
|
across all resolutions of the abstract type or alias.
|
|
617
|
-
-
|
|
626
|
+
- All abstract methods must be implemented by the instance.
|
|
618
627
|
- If a service is already registered under the same abstract or alias, it is removed
|
|
619
628
|
before registering the new instance.
|
|
620
629
|
"""
|
|
@@ -639,7 +648,7 @@ class Container(IContainer):
|
|
|
639
648
|
# Validate and generate the alias key (either provided or default)
|
|
640
649
|
alias = self.__makeAliasKey(abstract, alias)
|
|
641
650
|
|
|
642
|
-
#
|
|
651
|
+
# Remove any existing binding for this abstract or alias
|
|
643
652
|
self.drop(abstract, alias)
|
|
644
653
|
|
|
645
654
|
# Register the instance with singleton lifetime
|
|
@@ -664,14 +673,6 @@ class Container(IContainer):
|
|
|
664
673
|
f"Unexpected error registering instance: {e}"
|
|
665
674
|
) from e
|
|
666
675
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
676
|
def singleton(
|
|
676
677
|
self,
|
|
677
678
|
abstract: Callable[..., Any],
|
|
@@ -683,76 +684,91 @@ class Container(IContainer):
|
|
|
683
684
|
"""
|
|
684
685
|
Registers a service with a singleton lifetime.
|
|
685
686
|
|
|
687
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
688
|
+
in the container, ensuring that only one instance of the concrete class is created
|
|
689
|
+
and shared throughout the application's lifetime. It validates the abstract and
|
|
690
|
+
concrete types, enforces decoupling rules if specified, checks that all abstract
|
|
691
|
+
methods are implemented, and manages service aliases.
|
|
692
|
+
|
|
686
693
|
Parameters
|
|
687
694
|
----------
|
|
688
695
|
abstract : Callable[..., Any]
|
|
689
|
-
The abstract base type or interface to be bound.
|
|
696
|
+
The abstract base type or interface to be bound. Must be an abstract class or interface.
|
|
690
697
|
concrete : Callable[..., Any]
|
|
691
|
-
The concrete implementation to associate with the abstract type.
|
|
698
|
+
The concrete implementation to associate with the abstract type. Must be a concrete class.
|
|
692
699
|
alias : str, optional
|
|
693
|
-
An alternative name to register the service under. If not provided,
|
|
700
|
+
An alternative name to register the service under. If not provided, a default alias is generated
|
|
701
|
+
using the abstract's module and class name.
|
|
702
|
+
enforce_decoupling : bool, optional
|
|
703
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
704
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
694
705
|
|
|
695
706
|
Returns
|
|
696
707
|
-------
|
|
697
|
-
bool
|
|
698
|
-
True if the service was registered successfully.
|
|
708
|
+
bool or None
|
|
709
|
+
Returns True if the service was registered successfully.
|
|
710
|
+
Returns None if registration fails due to an exception.
|
|
699
711
|
|
|
700
712
|
Raises
|
|
701
713
|
------
|
|
702
714
|
OrionisContainerTypeError
|
|
703
|
-
If the abstract or concrete class
|
|
715
|
+
If the abstract or concrete class validation fails.
|
|
704
716
|
OrionisContainerException
|
|
705
|
-
If the
|
|
717
|
+
If the decoupling check fails or if an unexpected error occurs during registration.
|
|
706
718
|
|
|
707
719
|
Notes
|
|
708
720
|
-----
|
|
709
|
-
Registers the given concrete implementation to the abstract type with a singleton lifetime,
|
|
710
|
-
|
|
721
|
+
- Registers the given concrete implementation to the abstract type with a singleton lifetime,
|
|
722
|
+
meaning a single instance will be created and shared for all resolutions.
|
|
723
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering the new binding.
|
|
724
|
+
- All abstract methods must be implemented by the concrete class.
|
|
725
|
+
- Aliases are validated and managed for lookup.
|
|
711
726
|
"""
|
|
712
727
|
|
|
713
|
-
|
|
714
|
-
IsAbstractClass(abstract, Lifetime.SINGLETON)
|
|
728
|
+
try:
|
|
715
729
|
|
|
716
|
-
|
|
717
|
-
|
|
730
|
+
# Ensure that abstract is an abstract class
|
|
731
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
718
732
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
IsNotSubclass(abstract, concrete)
|
|
733
|
+
# Ensure that concrete is a concrete class
|
|
734
|
+
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
722
735
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
IsSubclass(abstract, concrete)
|
|
736
|
+
# Enforce decoupling or subclass relationship as specified
|
|
737
|
+
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
726
738
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
739
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
740
|
+
self.__implementsAbstractMethods(
|
|
741
|
+
abstract=abstract,
|
|
742
|
+
concrete=concrete
|
|
743
|
+
)
|
|
732
744
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
IsValidAlias(alias)
|
|
736
|
-
else:
|
|
737
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
745
|
+
# Validate and generate the alias key (either provided or default)
|
|
746
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
738
747
|
|
|
739
|
-
|
|
740
|
-
|
|
748
|
+
# If the service is already registered, remove the existing binding
|
|
749
|
+
self.drop(abstract, alias)
|
|
741
750
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
751
|
+
# Register the service with singleton lifetime
|
|
752
|
+
self.__bindings[abstract] = Binding(
|
|
753
|
+
contract = abstract,
|
|
754
|
+
concrete = concrete,
|
|
755
|
+
lifetime = Lifetime.SINGLETON,
|
|
756
|
+
enforce_decoupling = enforce_decoupling,
|
|
757
|
+
alias = alias
|
|
758
|
+
)
|
|
750
759
|
|
|
751
|
-
|
|
752
|
-
|
|
760
|
+
# Register the alias for lookup
|
|
761
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
753
762
|
|
|
754
|
-
|
|
755
|
-
|
|
763
|
+
# Return True to indicate successful registration
|
|
764
|
+
return True
|
|
765
|
+
|
|
766
|
+
except Exception as e:
|
|
767
|
+
|
|
768
|
+
# Raise a container exception with details if registration fails
|
|
769
|
+
raise OrionisContainerException(
|
|
770
|
+
f"Unexpected error registering {Lifetime.SINGLETON} service: {e}"
|
|
771
|
+
) from e
|
|
756
772
|
|
|
757
773
|
def scoped(
|
|
758
774
|
self,
|
|
@@ -765,76 +781,101 @@ class Container(IContainer):
|
|
|
765
781
|
"""
|
|
766
782
|
Registers a service with a scoped lifetime.
|
|
767
783
|
|
|
784
|
+
This method binds a concrete implementation to an abstract base type or interface
|
|
785
|
+
in the container, ensuring that a new instance of the concrete class is created
|
|
786
|
+
for each scope context. It validates the abstract and concrete types, enforces
|
|
787
|
+
decoupling rules if specified, checks that all abstract methods are implemented,
|
|
788
|
+
and manages service aliases.
|
|
789
|
+
|
|
768
790
|
Parameters
|
|
769
791
|
----------
|
|
770
792
|
abstract : Callable[..., Any]
|
|
771
|
-
The abstract base type or interface to be bound.
|
|
793
|
+
The abstract base type or interface to be bound. Must be an abstract class or interface.
|
|
772
794
|
concrete : Callable[..., Any]
|
|
773
|
-
The concrete implementation to associate with the abstract type.
|
|
795
|
+
The concrete implementation to associate with the abstract type. Must be a concrete class.
|
|
774
796
|
alias : str, optional
|
|
775
|
-
An alternative name to register the service under. If not provided,
|
|
797
|
+
An alternative name to register the service under. If not provided, a default alias is generated
|
|
798
|
+
using the abstract's module and class name.
|
|
799
|
+
enforce_decoupling : bool, optional
|
|
800
|
+
If True, enforces that the concrete class does NOT inherit from the abstract class.
|
|
801
|
+
If False, requires that the concrete class is a subclass of the abstract.
|
|
776
802
|
|
|
777
803
|
Returns
|
|
778
804
|
-------
|
|
779
|
-
bool
|
|
780
|
-
True if the service was registered successfully.
|
|
805
|
+
bool or None
|
|
806
|
+
Returns True if the service was registered successfully.
|
|
807
|
+
Returns None if registration fails due to an exception.
|
|
781
808
|
|
|
782
809
|
Raises
|
|
783
810
|
------
|
|
784
811
|
OrionisContainerTypeError
|
|
785
|
-
If the abstract or concrete class
|
|
812
|
+
If the abstract or concrete class validation fails.
|
|
786
813
|
OrionisContainerException
|
|
787
|
-
If the
|
|
814
|
+
If the decoupling check fails or if an unexpected error occurs during registration.
|
|
788
815
|
|
|
789
816
|
Notes
|
|
790
817
|
-----
|
|
791
|
-
Registers the given concrete implementation to the abstract type with a scoped lifetime,
|
|
792
|
-
|
|
818
|
+
- Registers the given concrete implementation to the abstract type with a scoped lifetime,
|
|
819
|
+
meaning a new instance will be created for each scope context.
|
|
820
|
+
- Validates the abstract and concrete types, checks decoupling rules, ensures all abstract methods
|
|
821
|
+
are implemented, and manages service aliases.
|
|
822
|
+
- If a service is already registered under the same abstract or alias, it is removed before registering
|
|
823
|
+
the new binding.
|
|
793
824
|
"""
|
|
794
825
|
|
|
795
|
-
|
|
796
|
-
|
|
826
|
+
try:
|
|
827
|
+
|
|
828
|
+
# Ensure that abstract is an abstract class
|
|
829
|
+
ReflectionAbstract.ensureIsAbstractClass(abstract)
|
|
830
|
+
|
|
831
|
+
# Ensure that concrete is a concrete class
|
|
832
|
+
ReflectionConcrete.ensureIsConcreteClass(concrete)
|
|
833
|
+
|
|
834
|
+
# Enforce decoupling or subclass relationship as specified
|
|
835
|
+
self.__decouplingCheck(abstract, concrete, enforce_decoupling)
|
|
836
|
+
|
|
837
|
+
# Ensure all abstract methods are implemented by the concrete class
|
|
838
|
+
self.__implementsAbstractMethods(
|
|
839
|
+
abstract=abstract,
|
|
840
|
+
concrete=concrete
|
|
841
|
+
)
|
|
842
|
+
|
|
843
|
+
# Validate and generate the alias key (either provided or default)
|
|
844
|
+
alias = self.__makeAliasKey(abstract, alias)
|
|
845
|
+
|
|
846
|
+
# If the service is already registered, remove the existing binding
|
|
847
|
+
self.drop(abstract, alias)
|
|
848
|
+
|
|
849
|
+
# Register the service with scoped lifetime
|
|
850
|
+
self.__bindings[abstract] = Binding(
|
|
851
|
+
contract = abstract,
|
|
852
|
+
concrete = concrete,
|
|
853
|
+
lifetime = Lifetime.SCOPED,
|
|
854
|
+
enforce_decoupling = enforce_decoupling,
|
|
855
|
+
alias = alias
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
# Register the alias for lookup
|
|
859
|
+
self.__aliases[alias] = self.__bindings[abstract]
|
|
860
|
+
|
|
861
|
+
# Return True to indicate successful registration
|
|
862
|
+
return True
|
|
863
|
+
|
|
864
|
+
except Exception as e:
|
|
865
|
+
|
|
866
|
+
# Raise a container exception with details if registration fails
|
|
867
|
+
raise OrionisContainerException(
|
|
868
|
+
f"Unexpected error registering {Lifetime.SCOPED} service: {e}"
|
|
869
|
+
) from e
|
|
797
870
|
|
|
798
|
-
# Ensure that concrete is a concrete class
|
|
799
|
-
IsConcreteClass(concrete, Lifetime.SCOPED)
|
|
800
871
|
|
|
801
|
-
# Ensure that concrete is NOT a subclass of abstract
|
|
802
|
-
if enforce_decoupling:
|
|
803
|
-
IsNotSubclass(abstract, concrete)
|
|
804
872
|
|
|
805
|
-
# Validate that concrete is a subclass of abstract
|
|
806
|
-
else:
|
|
807
|
-
IsSubclass(abstract, concrete)
|
|
808
873
|
|
|
809
|
-
# Ensure implementation
|
|
810
|
-
ImplementsAbstractMethods(
|
|
811
|
-
abstract=abstract,
|
|
812
|
-
concrete=concrete
|
|
813
|
-
)
|
|
814
874
|
|
|
815
|
-
# Ensure that the alias is a valid string if provided
|
|
816
|
-
if alias:
|
|
817
|
-
IsValidAlias(alias)
|
|
818
|
-
else:
|
|
819
|
-
alias = f"{abstract.__module__}.{abstract.__name__}"
|
|
820
875
|
|
|
821
|
-
# If the service is already registered, drop it
|
|
822
|
-
self.drop(abstract, alias)
|
|
823
876
|
|
|
824
|
-
# Register the service with scoped lifetime
|
|
825
|
-
self.__bindings[abstract] = Binding(
|
|
826
|
-
contract = abstract,
|
|
827
|
-
concrete = concrete,
|
|
828
|
-
lifetime = Lifetime.SCOPED,
|
|
829
|
-
enforce_decoupling = enforce_decoupling,
|
|
830
|
-
alias = alias
|
|
831
|
-
)
|
|
832
877
|
|
|
833
|
-
# Register the alias
|
|
834
|
-
self.__aliases[alias] = self.__bindings[abstract]
|
|
835
878
|
|
|
836
|
-
# Return True to indicate successful registration
|
|
837
|
-
return True
|
|
838
879
|
|
|
839
880
|
def scopedInstance(
|
|
840
881
|
self,
|
|
@@ -1635,6 +1676,7 @@ class Container(IContainer):
|
|
|
1635
1676
|
The singleton instance to store cross-references for.
|
|
1636
1677
|
"""
|
|
1637
1678
|
|
|
1679
|
+
# Determine the primary cache key for this binding
|
|
1638
1680
|
primary_key = self.__getSingletonCacheKey(binding)
|
|
1639
1681
|
|
|
1640
1682
|
# Store cross-reference for contract if it's not the primary key
|
|
@@ -1997,6 +2039,7 @@ class Container(IContainer):
|
|
|
1997
2039
|
"""
|
|
1998
2040
|
|
|
1999
2041
|
try:
|
|
2042
|
+
|
|
2000
2043
|
# If there are no dependencies, return empty dict
|
|
2001
2044
|
if not dependencies:
|
|
2002
2045
|
return {}
|
|
@@ -2013,6 +2056,7 @@ class Container(IContainer):
|
|
|
2013
2056
|
for param_name, dep in dependencies.resolved.items():
|
|
2014
2057
|
params[param_name] = self.__resolveSingleDependency(name, param_name, dep)
|
|
2015
2058
|
|
|
2059
|
+
# Return the dictionary of resolved parameters
|
|
2016
2060
|
return params
|
|
2017
2061
|
|
|
2018
2062
|
except Exception as e:
|
|
@@ -2146,43 +2190,61 @@ class Container(IContainer):
|
|
|
2146
2190
|
**kwargs
|
|
2147
2191
|
) -> Any:
|
|
2148
2192
|
"""
|
|
2149
|
-
|
|
2193
|
+
Resolves and instantiates a type or callable regardless of its registration in the container.
|
|
2194
|
+
|
|
2195
|
+
This method attempts to instantiate or invoke the provided type or callable, even if it is not
|
|
2196
|
+
registered in the container. It first tries direct instantiation/invocation if arguments are provided,
|
|
2197
|
+
then attempts auto-resolution for eligible types, and finally falls back to reflection-based instantiation.
|
|
2198
|
+
If the type cannot be resolved by any means, an exception is raised.
|
|
2150
2199
|
|
|
2151
2200
|
Parameters
|
|
2152
2201
|
----------
|
|
2153
2202
|
type_ : Callable[..., Any]
|
|
2154
|
-
The
|
|
2203
|
+
The class or callable to resolve and instantiate.
|
|
2155
2204
|
*args : tuple
|
|
2156
|
-
Positional arguments to pass to the constructor
|
|
2205
|
+
Positional arguments to pass to the constructor or callable.
|
|
2157
2206
|
**kwargs : dict
|
|
2158
|
-
Keyword arguments to pass to the constructor
|
|
2207
|
+
Keyword arguments to pass to the constructor or callable.
|
|
2159
2208
|
|
|
2160
2209
|
Returns
|
|
2161
2210
|
-------
|
|
2162
2211
|
Any
|
|
2163
|
-
The
|
|
2212
|
+
The instantiated object or the result of the callable. If the type is a class, a new instance is returned.
|
|
2213
|
+
If the type is a callable, the result of its invocation is returned.
|
|
2164
2214
|
|
|
2165
2215
|
Raises
|
|
2166
2216
|
------
|
|
2167
2217
|
OrionisContainerException
|
|
2168
|
-
If the type cannot be resolved.
|
|
2218
|
+
If the type cannot be resolved, is not a concrete class or callable, or if an error occurs during instantiation.
|
|
2219
|
+
|
|
2220
|
+
Notes
|
|
2221
|
+
-----
|
|
2222
|
+
- Direct instantiation/invocation is prioritized when arguments are provided.
|
|
2223
|
+
- Auto-resolution is attempted for types eligible for automatic dependency resolution.
|
|
2224
|
+
- Reflection-based instantiation is used as a fallback for concrete classes or callables.
|
|
2225
|
+
- If none of the resolution strategies succeed, an exception is raised.
|
|
2169
2226
|
"""
|
|
2227
|
+
|
|
2170
2228
|
try:
|
|
2171
|
-
|
|
2229
|
+
|
|
2230
|
+
# If explicit arguments are provided, attempt direct instantiation or invocation
|
|
2172
2231
|
if args or kwargs:
|
|
2173
2232
|
if isinstance(type_, type):
|
|
2233
|
+
# Instantiate the class directly with provided arguments
|
|
2174
2234
|
return type_(*args, **kwargs)
|
|
2175
2235
|
elif callable(type_):
|
|
2236
|
+
# Invoke the callable directly with provided arguments
|
|
2176
2237
|
return type_(*args, **kwargs)
|
|
2177
2238
|
|
|
2178
|
-
#
|
|
2239
|
+
# Attempt auto-resolution for eligible types
|
|
2179
2240
|
if self.__canAutoResolve(type_):
|
|
2180
2241
|
return self.__autoResolve(type_)
|
|
2181
2242
|
|
|
2182
|
-
# Use
|
|
2243
|
+
# Use reflection-based instantiation for concrete classes
|
|
2183
2244
|
if ReflectionConcrete.isConcreteClass(type_):
|
|
2184
2245
|
return self.__instantiateWithReflection(type_, is_class=True)
|
|
2185
2246
|
|
|
2247
|
+
# Use reflection-based invocation for callables that are not classes
|
|
2186
2248
|
if callable(type_) and not isinstance(type_, type):
|
|
2187
2249
|
return self.__instantiateWithReflection(type_, is_class=False)
|
|
2188
2250
|
|
|
@@ -2192,9 +2254,12 @@ class Container(IContainer):
|
|
|
2192
2254
|
)
|
|
2193
2255
|
|
|
2194
2256
|
except Exception as e:
|
|
2257
|
+
|
|
2258
|
+
# Re-raise container exceptions directly
|
|
2195
2259
|
if isinstance(e, OrionisContainerException):
|
|
2196
2260
|
raise e from None
|
|
2197
2261
|
|
|
2262
|
+
# Wrap other exceptions in an OrionisContainerException with context
|
|
2198
2263
|
raise OrionisContainerException(
|
|
2199
2264
|
f"Error resolving '{getattr(type_, '__name__', str(type_))}': {str(e)}"
|
|
2200
2265
|
) from e
|
|
@@ -2259,26 +2324,34 @@ class Container(IContainer):
|
|
|
2259
2324
|
|
|
2260
2325
|
def __isValidNamespace(self, type_: type) -> bool:
|
|
2261
2326
|
"""
|
|
2262
|
-
|
|
2327
|
+
Determines if a type belongs to a valid namespace for auto-resolution.
|
|
2328
|
+
|
|
2329
|
+
This method checks whether the provided type is defined within one of the namespaces
|
|
2330
|
+
considered valid for automatic dependency resolution by the container. Valid namespaces
|
|
2331
|
+
are typically application-specific modules or packages that are explicitly allowed
|
|
2332
|
+
for auto-resolution. Built-in types and types from external libraries are excluded.
|
|
2263
2333
|
|
|
2264
2334
|
Parameters
|
|
2265
2335
|
----------
|
|
2266
2336
|
type_ : type
|
|
2267
|
-
The type to check for valid namespace.
|
|
2337
|
+
The type to check for valid namespace membership.
|
|
2268
2338
|
|
|
2269
2339
|
Returns
|
|
2270
2340
|
-------
|
|
2271
2341
|
bool
|
|
2272
|
-
True if the type belongs to a valid namespace
|
|
2273
|
-
|
|
2342
|
+
True if the type belongs to a valid namespace (i.e., its `__module__` attribute
|
|
2343
|
+
matches one of the namespaces in `self.__valid_namespaces`), otherwise False.
|
|
2274
2344
|
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2345
|
+
Notes
|
|
2346
|
+
-----
|
|
2347
|
+
- The method relies on the presence of the `__module__` attribute on the type.
|
|
2348
|
+
- If the type does not have a `__module__` attribute, it cannot be considered valid.
|
|
2349
|
+
- The set of valid namespaces is initialized in the container and may include
|
|
2350
|
+
application modules, framework modules, and the current project namespace.
|
|
2351
|
+
"""
|
|
2279
2352
|
|
|
2280
|
-
#
|
|
2281
|
-
return
|
|
2353
|
+
# Ensure the type has a __module__ attribute before checking namespace validity
|
|
2354
|
+
return hasattr(type_, '__module__')
|
|
2282
2355
|
|
|
2283
2356
|
def __isInstantiable(self, type_: type) -> bool:
|
|
2284
2357
|
"""
|
|
@@ -2330,6 +2403,7 @@ class Container(IContainer):
|
|
|
2330
2403
|
return self.__canQuickInstantiate(type_)
|
|
2331
2404
|
|
|
2332
2405
|
except Exception:
|
|
2406
|
+
|
|
2333
2407
|
# If any check fails with an exception, consider it non-instantiable
|
|
2334
2408
|
return False
|
|
2335
2409
|
|
|
@@ -2354,22 +2428,31 @@ class Container(IContainer):
|
|
|
2354
2428
|
|
|
2355
2429
|
# Check if it inherits from ABC (safely)
|
|
2356
2430
|
try:
|
|
2431
|
+
|
|
2432
|
+
# Check if it inherits from abc.ABC
|
|
2357
2433
|
if issubclass(type_, abc.ABC):
|
|
2358
2434
|
return True
|
|
2435
|
+
|
|
2436
|
+
# type_ is not a class, so it can't be abstract
|
|
2359
2437
|
except TypeError:
|
|
2360
|
-
# type_ is not a class, so it can't be abstract
|
|
2361
2438
|
pass
|
|
2362
2439
|
|
|
2363
2440
|
# Check if it has abstract methods
|
|
2364
2441
|
try:
|
|
2365
2442
|
# Try to get abstract methods using reflection
|
|
2366
2443
|
for attr_name in dir(type_):
|
|
2444
|
+
|
|
2445
|
+
# Get the attribute
|
|
2367
2446
|
attr = getattr(type_, attr_name)
|
|
2447
|
+
|
|
2448
|
+
# Check if the attribute is marked as an abstract method
|
|
2368
2449
|
if hasattr(attr, '__isabstractmethod__') and attr.__isabstractmethod__:
|
|
2369
2450
|
return True
|
|
2451
|
+
|
|
2370
2452
|
except Exception:
|
|
2371
2453
|
pass
|
|
2372
2454
|
|
|
2455
|
+
# If none of the checks matched, it's not abstract
|
|
2373
2456
|
return False
|
|
2374
2457
|
|
|
2375
2458
|
def __isGenericType(self, type_: type) -> bool:
|
|
@@ -2403,6 +2486,7 @@ class Container(IContainer):
|
|
|
2403
2486
|
if hasattr(typing, 'TypeVar') and isinstance(type_, typing.TypeVar):
|
|
2404
2487
|
return True
|
|
2405
2488
|
|
|
2489
|
+
# If none of the checks matched, it's not a generic type
|
|
2406
2490
|
return False
|
|
2407
2491
|
|
|
2408
2492
|
def __isProtocolOrTyping(self, type_: type) -> bool:
|
|
@@ -2435,9 +2519,12 @@ class Container(IContainer):
|
|
|
2435
2519
|
|
|
2436
2520
|
# Check for common typing constructs that shouldn't be instantiated
|
|
2437
2521
|
typing_constructs = ['Union', 'Optional', 'Any', 'Callable', 'Type']
|
|
2522
|
+
|
|
2523
|
+
# If the type's name matches a known typing construct, it's not instantiable
|
|
2438
2524
|
if hasattr(type_, '__name__') and type_.__name__ in typing_constructs:
|
|
2439
2525
|
return True
|
|
2440
2526
|
|
|
2527
|
+
# If none of the checks matched, it's not a protocol or typing construct
|
|
2441
2528
|
return False
|
|
2442
2529
|
|
|
2443
2530
|
def __hasRequiredConstructorParams(self, type_: type) -> bool:
|
|
@@ -2499,6 +2586,7 @@ class Container(IContainer):
|
|
|
2499
2586
|
"""
|
|
2500
2587
|
|
|
2501
2588
|
try:
|
|
2589
|
+
|
|
2502
2590
|
# For safety, first check if the constructor signature suggests it's safe to instantiate
|
|
2503
2591
|
try:
|
|
2504
2592
|
|
|
@@ -2523,8 +2611,10 @@ class Container(IContainer):
|
|
|
2523
2611
|
# Attempt to create an instance only if it seems safe
|
|
2524
2612
|
instance = type_()
|
|
2525
2613
|
|
|
2526
|
-
# If successful, clean up
|
|
2614
|
+
# If successful, clean up
|
|
2527
2615
|
del instance
|
|
2616
|
+
|
|
2617
|
+
# Return True if instantiation succeeded
|
|
2528
2618
|
return True
|
|
2529
2619
|
|
|
2530
2620
|
except Exception:
|
|
@@ -2569,6 +2659,7 @@ class Container(IContainer):
|
|
|
2569
2659
|
)
|
|
2570
2660
|
|
|
2571
2661
|
try:
|
|
2662
|
+
|
|
2572
2663
|
# Mark this type as being resolved to prevent circular dependencies
|
|
2573
2664
|
self.__resolution_cache[type_key] = True
|
|
2574
2665
|
|
|
@@ -2594,17 +2685,21 @@ class Container(IContainer):
|
|
|
2594
2685
|
)
|
|
2595
2686
|
|
|
2596
2687
|
except Exception as e:
|
|
2688
|
+
|
|
2597
2689
|
# Remove the type from the resolution cache on error
|
|
2598
2690
|
self.__resolution_cache.pop(type_key, None)
|
|
2599
2691
|
|
|
2692
|
+
# If the exception is already an OrionisContainerException, re-raise it
|
|
2600
2693
|
if isinstance(e, OrionisContainerException):
|
|
2601
2694
|
raise
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2695
|
+
|
|
2696
|
+
# Otherwise, raise a new OrionisContainerException with additional context
|
|
2697
|
+
raise OrionisContainerException(
|
|
2698
|
+
f"Failed to auto-resolve '{type_.__name__}': {str(e)}"
|
|
2699
|
+
) from e
|
|
2606
2700
|
|
|
2607
2701
|
finally:
|
|
2702
|
+
|
|
2608
2703
|
# Always clean up the resolution cache after resolution attempt
|
|
2609
2704
|
self.__resolution_cache.pop(type_key, None)
|
|
2610
2705
|
|
|
@@ -2198,11 +2198,7 @@ class Application(Container, IApplication):
|
|
|
2198
2198
|
if not self.__booted:
|
|
2199
2199
|
|
|
2200
2200
|
# Register the application instance in the container
|
|
2201
|
-
self.instance(
|
|
2202
|
-
IApplication,
|
|
2203
|
-
self,
|
|
2204
|
-
alias="x-orionis.foundation.contracts.application.IApplication"
|
|
2205
|
-
)
|
|
2201
|
+
self.instance(IApplication, self, alias="x-orionis.foundation.contracts.application.IApplication")
|
|
2206
2202
|
|
|
2207
2203
|
# Load configuration if not already set
|
|
2208
2204
|
self.__loadConfig()
|
|
@@ -2212,8 +2208,6 @@ class Application(Container, IApplication):
|
|
|
2212
2208
|
self.__loadFrameworkProviders()
|
|
2213
2209
|
self.__registerProviders()
|
|
2214
2210
|
self.__bootProviders()
|
|
2215
|
-
|
|
2216
|
-
# Mark as booted
|
|
2217
2211
|
self.__booted = True
|
|
2218
2212
|
|
|
2219
2213
|
# Load core framework kernels with app booted
|
orionis/metadata/framework.py
CHANGED
|
@@ -67,7 +67,7 @@ orionis/console/stubs/listener.stub,sha256=DbX-ghx2-vb73kzQ6L20lyg5vSKn58jSLTwFu
|
|
|
67
67
|
orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
orionis/console/tasks/schedule.py,sha256=ZeeuQ9Tbu5KNowKC5oIk7yWeJXzlDQiQ278mWEgoCXc,87989
|
|
69
69
|
orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
orionis/container/container.py,sha256=
|
|
70
|
+
orionis/container/container.py,sha256=3s1ej-wGeylBzG4qAJ9JOra1Lvt5M3QJyAeu8q23rP8,112421
|
|
71
71
|
orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
72
|
orionis/container/context/manager.py,sha256=I08K_jKXSKmrq18Pv33qYyMKIlAovVOwIgmfiVm-J7c,2971
|
|
73
73
|
orionis/container/context/scope.py,sha256=p_oCzR7dDz-5ZAd16ab4vfLc3gBf34CaN0f4iR9D0bQ,1155
|
|
@@ -104,7 +104,7 @@ orionis/failure/contracts/handler.py,sha256=AeJfkJfD3hTkOIYAtADq6GnQfq-qWgDfUc7b
|
|
|
104
104
|
orionis/failure/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
105
105
|
orionis/failure/entities/throwable.py,sha256=1zD-awcuAyEtlR-L7V7ZIfPSF4GpXkf-neL5sXul7dc,1240
|
|
106
106
|
orionis/foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
|
-
orionis/foundation/application.py,sha256=
|
|
107
|
+
orionis/foundation/application.py,sha256=5A93XNiYJi1FEu8hIv2UStxZu--ac4KanhcWsSU25hU,94028
|
|
108
108
|
orionis/foundation/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
109
|
orionis/foundation/config/startup.py,sha256=btqvryeIf9lLNQ9fBff7bJMrfraEY8qrWi4y_5YAR0Q,9681
|
|
110
110
|
orionis/foundation/config/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -217,7 +217,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=IrPQJwvQVLRm5Qnz0Cxon4
|
|
|
217
217
|
orionis/foundation/providers/testing_provider.py,sha256=eI1p2lUlxl25b5Z487O4nmqLE31CTDb4c3Q21xFadkE,1615
|
|
218
218
|
orionis/foundation/providers/workers_provider.py,sha256=GdHENYV_yGyqmHJHn0DCyWmWId5xWjD48e6Zq2PGCWY,1674
|
|
219
219
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
220
|
-
orionis/metadata/framework.py,sha256=
|
|
220
|
+
orionis/metadata/framework.py,sha256=cxeQWRZy2fnzU53QvPzM6KYNMf4DDEQhu_iD33csm6E,4089
|
|
221
221
|
orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
|
|
222
222
|
orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
223
223
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -404,8 +404,8 @@ orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnI
|
|
|
404
404
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
405
405
|
orionis/test/view/render.py,sha256=R55ykeRs0wDKcdTf4O1YZ8GDHTFmJ0IK6VQkbJkYUvo,5571
|
|
406
406
|
orionis/test/view/report.stub,sha256=QLqqCdRoENr3ECiritRB3DO_MOjRQvgBh5jxZ3Hs1r0,28189
|
|
407
|
-
orionis-0.
|
|
408
|
-
orionis-0.
|
|
409
|
-
orionis-0.
|
|
410
|
-
orionis-0.
|
|
411
|
-
orionis-0.
|
|
407
|
+
orionis-0.654.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
408
|
+
orionis-0.654.0.dist-info/METADATA,sha256=MZG7617D7xqfB14CWjZdQ8sqkcMvxrkSucLHJlSTwsM,4772
|
|
409
|
+
orionis-0.654.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
410
|
+
orionis-0.654.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
|
|
411
|
+
orionis-0.654.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|