orionis 0.321.0__py3-none-any.whl → 0.322.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.
@@ -1,5 +1,6 @@
1
1
  import threading
2
2
  from typing import Any, Callable
3
+ from orionis.container.context.manager import ScopeManager
3
4
  from orionis.container.contracts.container import IContainer
4
5
  from orionis.container.entities.binding import Binding
5
6
  from orionis.container.enums.lifetimes import Lifetime
@@ -430,7 +431,7 @@ class Container(IContainer):
430
431
  # Return True to indicate successful registration
431
432
  return True
432
433
 
433
- def function(
434
+ def callable(
434
435
  self,
435
436
  alias: str,
436
437
  fn: Callable[..., Any],
@@ -633,4 +634,26 @@ class Container(IContainer):
633
634
  binding,
634
635
  *args,
635
636
  **kwargs
636
- )
637
+ )
638
+
639
+ def createContext(self) -> ScopeManager:
640
+ """
641
+ Creates a new context for managing scoped services.
642
+
643
+ This method returns a context manager that can be used with a 'with' statement
644
+ to control the lifecycle of scoped services.
645
+
646
+ Returns
647
+ -------
648
+ ScopeManager
649
+ A context manager for scoped services.
650
+
651
+ Usage
652
+ -------
653
+ with container.createContext():
654
+ # Scoped services created here will be disposed when exiting this block
655
+ service = container.make(IScopedService)
656
+ ...
657
+ # Scoped services are automatically disposed here
658
+ """
659
+ return ScopeManager()
@@ -0,0 +1,94 @@
1
+ from orionis.container.context.scope import ScopedContext
2
+
3
+ class ScopeManager:
4
+ """
5
+ A context manager to manage scoped lifetimes in the container.
6
+ """
7
+ def __init__(self):
8
+ """
9
+ Initialize a new ScopeManager with an empty instances dictionary.
10
+ """
11
+ self._instances = {}
12
+
13
+ def __getitem__(self, key):
14
+ """
15
+ Get an instance by key.
16
+
17
+ Parameters
18
+ ----------
19
+ key : hashable
20
+ The key of the instance to retrieve.
21
+
22
+ Returns
23
+ -------
24
+ object or None
25
+ The instance associated with the key or None if not found.
26
+ """
27
+ return self._instances.get(key)
28
+
29
+ def __setitem__(self, key, value):
30
+ """
31
+ Store an instance by key.
32
+
33
+ Parameters
34
+ ----------
35
+ key : hashable
36
+ The key to associate with the instance.
37
+ value : object
38
+ The instance to store.
39
+ """
40
+ self._instances[key] = value
41
+
42
+ def __contains__(self, key):
43
+ """
44
+ Check if a key exists in this scope.
45
+
46
+ Parameters
47
+ ----------
48
+ key : hashable
49
+ The key to check.
50
+
51
+ Returns
52
+ -------
53
+ bool
54
+ True if the key exists in the scope, False otherwise.
55
+ """
56
+ return key in self._instances
57
+
58
+ def clear(self):
59
+ """
60
+ Clear all instances from this scope.
61
+ """
62
+ self._instances.clear()
63
+
64
+ def __enter__(self):
65
+ """
66
+ Enter the scope context.
67
+
68
+ Sets this scope as the current active scope.
69
+
70
+ Returns
71
+ -------
72
+ ScopeManager
73
+ This scope manager instance.
74
+ """
75
+ ScopedContext.setCurrentScope(self)
76
+ return self
77
+
78
+ def __exit__(self, exc_type, exc_val, exc_tb):
79
+ """
80
+ Exit the scope context.
81
+
82
+ Clears this scope and the active scope reference.
83
+
84
+ Parameters
85
+ ----------
86
+ exc_type : type or None
87
+ The exception type if an exception was raised, None otherwise.
88
+ exc_val : Exception or None
89
+ The exception instance if an exception was raised, None otherwise.
90
+ exc_tb : traceback or None
91
+ The exception traceback if an exception was raised, None otherwise.
92
+ """
93
+ self.clear()
94
+ ScopedContext.clear()
@@ -0,0 +1,40 @@
1
+ import contextvars
2
+
3
+ class ScopedContext:
4
+ """
5
+ Holds scoped instances for the current context.
6
+ """
7
+ _active_scope = contextvars.ContextVar("orionis_scope", default=None)
8
+
9
+ @classmethod
10
+ def getCurrentScope(cls):
11
+ """
12
+ Get the currently active scope.
13
+
14
+ Returns
15
+ -------
16
+ object or None
17
+ The current active scope or None if no scope is active.
18
+ """
19
+ return cls._active_scope.get()
20
+
21
+ @classmethod
22
+ def setCurrentScope(cls, scope):
23
+ """
24
+ Set the current active scope.
25
+
26
+ Parameters
27
+ ----------
28
+ scope : object
29
+ The scope object to set as active.
30
+ """
31
+ cls._active_scope.set(scope)
32
+
33
+ @classmethod
34
+ def clear(cls):
35
+ """
36
+ Clear the current active scope.
37
+
38
+ Sets the active scope to None.
39
+ """
40
+ cls._active_scope.set(None)
@@ -131,7 +131,7 @@ class IContainer(ABC):
131
131
  pass
132
132
 
133
133
  @abstractmethod
134
- def function(
134
+ def callable(
135
135
  self,
136
136
  alias: str,
137
137
  fn: Callable[..., Any],
@@ -1,4 +1,5 @@
1
1
  from typing import Any, Callable
2
+ from orionis.container.context.scope import ScopedContext
2
3
  from orionis.container.contracts.container import IContainer
3
4
  from orionis.container.entities.binding import Binding
4
5
  from orionis.container.enums.lifetimes import Lifetime
@@ -61,10 +62,7 @@ class Resolver:
61
62
  elif binding.lifetime == Lifetime.SINGLETON:
62
63
  return self.__resolveSingleton(binding, *args, **kwargs)
63
64
  elif binding.lifetime == Lifetime.SCOPED:
64
- # TODO: Implement scoped lifetime resolution
65
- raise OrionisContainerException(
66
- "Scoped lifetime resolution is not yet implemented."
67
- )
65
+ return self.__resolveScoped(binding, *args, **kwargs)
68
66
 
69
67
  def __resolveTransient(self, binding: Binding, *args, **kwargs) -> Any:
70
68
  """
@@ -153,6 +151,58 @@ class Resolver:
153
151
  "Cannot resolve singleton binding: neither a concrete class, instance, nor function is defined."
154
152
  )
155
153
 
154
+ def __resolveScoped(self, binding: Binding, *args, **kwargs) -> Any:
155
+ """
156
+ Resolves a service with scoped lifetime.
157
+
158
+ Parameters
159
+ ----------
160
+ binding : Binding
161
+ The binding to resolve.
162
+ *args : tuple
163
+ Positional arguments to pass to the constructor.
164
+ **kwargs : dict
165
+ Keyword arguments to pass to the constructor.
166
+
167
+ Returns
168
+ -------
169
+ Any
170
+ The scoped instance of the requested service.
171
+
172
+ Raises
173
+ ------
174
+ OrionisContainerException
175
+ If no scope is active or service can't be resolved.
176
+ """
177
+ scope = ScopedContext.getCurrentScope()
178
+ if scope is None:
179
+ raise OrionisContainerException(
180
+ f"No active scope found while resolving scoped service '{binding.alias}'. "
181
+ f"Use 'with container.createContext():' to create a scope context."
182
+ )
183
+
184
+ if binding.alias in scope:
185
+ return scope[binding.alias]
186
+
187
+ # Create a new instance
188
+ if binding.concrete:
189
+ if args or kwargs:
190
+ instance = self.__instantiateConcreteWithArgs(binding.concrete, *args, **kwargs)
191
+ else:
192
+ instance = self.__instantiateConcreteReflective(binding.concrete)
193
+ elif binding.function:
194
+ if args or kwargs:
195
+ instance = self.__instantiateCallableWithArgs(binding.function, *args, **kwargs)
196
+ else:
197
+ instance = self.__instantiateCallableReflective(binding.function)
198
+ else:
199
+ raise OrionisContainerException(
200
+ "Cannot resolve scoped binding: neither a concrete class nor a function is defined."
201
+ )
202
+
203
+ scope[binding.alias] = instance
204
+ return instance
205
+
156
206
  def __instantiateConcreteWithArgs(self, concrete: Callable[..., Any], *args, **kwargs) -> Any:
157
207
  """
158
208
  Instantiates a concrete class with the provided arguments.
@@ -401,4 +451,3 @@ class Resolver:
401
451
 
402
452
  # Raise a more informative exception
403
453
  raise OrionisContainerException(error_msg) from e
404
-
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.321.0"
8
+ VERSION = "0.322.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.321.0
3
+ Version: 0.322.0
4
4
  Summary: Orionis Framework – Elegant, Fast, and Powerful.
5
5
  Home-page: https://github.com/orionis-framework/framework
6
6
  Author: Raul Mauricio Uñate Castro
@@ -2,12 +2,6 @@ orionis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  orionis/_application.py,sha256=dMjJ0nFcIIOBGb5zr-tHNzcgTOZ1vJ7iMdFAlqSQph0,9405
3
3
  orionis/application.py,sha256=Off5uOUj-IYvvR8DcqLUoBW_98opWa7MQrtqTr0SZGc,292
4
4
  orionis/unittesting.py,sha256=_NU3_sm3R6bUUH_Y-KSPgNVBajUGCtKo_CGgjB1YD5k,2094
5
- orionis/_container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- orionis/_container/container.py,sha256=0AOqTNwpN_OtWbq9mBI99qfJ7LMkN71y0lP0JWKzut0,18289
7
- orionis/_container/container_integrity.py,sha256=vrqZrkJaP6ghbiAzr-nEul9f_lEWVa2nMUSugQXDfWk,10095
8
- orionis/_container/exception.py,sha256=ap1SqYEjQEEHXJJTNmL7V1jrmRjgT5_7geZ95MYkhMA,1691
9
- orionis/_container/lifetimes.py,sha256=2lbdiV7R2WlJf1cLD6eBxLnJud_lZvX1IhQH2Djy3Ww,375
10
- orionis/_container/resolve.py,sha256=5qVE--fBpbVFiTYM_jXKbjHNssm28aM4cwd49AhiLkY,2231
11
5
  orionis/_contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
6
  orionis/_contracts/application.py,sha256=ltuDA1mN5P73l89jJto_A96ePJWE02OZ_B2NOPpfeWs,1061
13
7
  orionis/_contracts/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -135,9 +129,12 @@ orionis/console/output/console.py,sha256=TE_Hl720ADd82dbERFSWhkoQRukDQZmETSw4nkw
135
129
  orionis/console/output/executor.py,sha256=bdvkzW2-buy0BPpy2r5qUGrRFW2Ay6k-5rSeHb0gQ3o,3352
136
130
  orionis/console/output/progress_bar.py,sha256=vFy582z6VJS46LV6tuyrmr9qvdVeTEtw3hyNcEHezeg,3088
137
131
  orionis/console/output/styles.py,sha256=6a4oQCOBOKMh2ARdeq5GlIskJ3wjiylYmh66tUKKmpQ,4053
138
- orionis/container/container.py,sha256=eBVQMzfSvXcxrdm-0hq0gmXZzxf3uabIcxbGVvGZmIo,22342
139
- orionis/container/resolver.py,sha256=iuyTWCnCqWXQCtWvFXPdS9cR_g3Q58_wjHVn0Yg0YNM,16209
140
- orionis/container/contracts/container.py,sha256=ksMn6ZLnFkIxd9_hbUGz3OpHzaYTA5izcDtH959kOow,7603
132
+ orionis/container/container.py,sha256=dIfHPCC28_Eho7kgp0AUFS1S5iaCD4ws7udCy_jQ6sE,23112
133
+ orionis/container/resolver.py,sha256=bR26v1bAtg9FgDtfs6zP30-g75aWrSO43UJPweJ7jfo,18014
134
+ orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
+ orionis/container/context/manager.py,sha256=9yODWkHBoJ2kgJZ5ONLqcEcex50vaWuMcxsvmDgnQo4,2437
136
+ orionis/container/context/scope.py,sha256=CWFiLLTAC_IdmeFKWX-jrphdxB0_TMEVBlz6lQVMPC8,937
137
+ orionis/container/contracts/container.py,sha256=hOO3w2yqVhp2nPTeS1uJEYgXSTbM3xwezDCOSNMC_a0,7603
141
138
  orionis/container/entities/binding.py,sha256=Qp6Lf4XUDp2NjqXDAC2lzvhOFQWiBDKiGFcKfwb4axw,4342
142
139
  orionis/container/enums/lifetimes.py,sha256=RqQmugMIB1Ev_j_vFLcWorndm-to7xg4stQ7yKFDdDw,190
143
140
  orionis/container/exceptions/container_exception.py,sha256=goTDEwC70xTMD2qppN8KV-xyR0Nps218OD4D1LZ2-3s,470
@@ -244,7 +241,7 @@ orionis/foundation/contracts/config.py,sha256=Rpz6U6t8OXHO9JJKSTnCimytXE-tfCB-1i
244
241
  orionis/foundation/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
245
242
  orionis/foundation/exceptions/integrity.py,sha256=mc4pL1UMoYRHEmphnpW2oGk5URhu7DJRREyzHaV-cs8,472
246
243
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
247
- orionis/metadata/framework.py,sha256=gv-aVbvyQwRvOTPPCJTIwJffZOEd9Ak6L9jdwT46oOE,4960
244
+ orionis/metadata/framework.py,sha256=-G5Ox-3m6R7JXyXZxf3c-6gmJ37J674tYlWjc8-Ar6k,4960
248
245
  orionis/metadata/package.py,sha256=tqLfBRo-w1j_GN4xvzUNFyweWYFS-qhSgAEc-AmCH1M,5452
249
246
  orionis/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
250
247
  orionis/patterns/singleton/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -356,7 +353,7 @@ orionis/test/suite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
356
353
  orionis/test/suite/test_unit.py,sha256=MWgW8dRCRyT1XZ5LsbXQ7-KVPReasoXwzEEL1EWWfE4,52190
357
354
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
358
355
  orionis/test/view/render.py,sha256=jXZkbITBknbUwm_mD8bcTiwLDvsFkrO9qrf0ZgPwqxc,4903
359
- orionis-0.321.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
356
+ orionis-0.322.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
360
357
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
361
358
  tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
362
359
  tests/example/test_example.py,sha256=kvWgiW3ADEZf718dGsMPtDh_rmOSx1ypEInKm7_6ZPQ,601
@@ -457,8 +454,8 @@ tests/support/wrapper/test_services_wrapper_docdict.py,sha256=yeVwl-VcwkWSQYyxZu
457
454
  tests/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
458
455
  tests/testing/test_testing_result.py,sha256=MrGK3ZimedL0b5Ydu69Dg8Iul017AzLTm7VPxpXlpfU,4315
459
456
  tests/testing/test_testing_unit.py,sha256=DjLBtvVn8B1KlVJNNkstBT8_csA1yeaMqnGrbanN_J4,7438
460
- orionis-0.321.0.dist-info/METADATA,sha256=kQ_DamwqrnAqkqPJQZd6mR4u-U_ERbRLwEw8FqTgTwE,4772
461
- orionis-0.321.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
462
- orionis-0.321.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
463
- orionis-0.321.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
464
- orionis-0.321.0.dist-info/RECORD,,
457
+ orionis-0.322.0.dist-info/METADATA,sha256=AU8sCGe16NBNt6PHdMNm_gcUrv3R8mwDPArdt-WH0qU,4772
458
+ orionis-0.322.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
459
+ orionis-0.322.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
460
+ orionis-0.322.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
461
+ orionis-0.322.0.dist-info/RECORD,,
@@ -1,543 +0,0 @@
1
- import inspect
2
- from threading import Lock
3
- from typing import Callable, Any, Dict, Deque, Optional, Type, get_origin, get_args
4
- from collections import deque
5
- from orionis._container.container_integrity import ContainerIntegrity
6
- from orionis._container.lifetimes import Lifetime
7
- from orionis._container.exception import OrionisContainerException, OrionisContainerValueError, OrionisContainerTypeError
8
- from orionis._contracts.container.container import IContainer
9
-
10
- class Container(IContainer):
11
- """
12
- Service container and dependency injection manager.
13
-
14
- This class follows the singleton pattern to manage service bindings, instances,
15
- and different lifecycle types such as transient, singleton, and scoped.
16
- """
17
-
18
- _instance = None
19
- _lock = Lock()
20
-
21
- @classmethod
22
- def destroy(cls):
23
- """
24
- Destroys the container instance.
25
- """
26
- cls._instance = None
27
-
28
- def __new__(cls):
29
- """
30
- Create a new instance of the container.
31
- """
32
- if cls._instance is None:
33
- with cls._lock:
34
- if cls._instance is None:
35
- cls._instance = super().__new__(cls)
36
- cls._instance._scoped_instances = {}
37
- cls._instance._singleton_instances = {}
38
- cls._instance._instances_services = {}
39
- cls._instance._transient_services = {}
40
- cls._instance._scoped_services = {}
41
- cls._instance._singleton_services = {}
42
- cls._instance._aliases_services = {}
43
- cls._instance.instance(IContainer, cls._instance)
44
- return cls._instance
45
-
46
- def bind(self, abstract: Callable[..., Any], concrete: Callable[..., Any], lifetime: str = Lifetime.TRANSIENT.value) -> None:
47
- """
48
- Binds an abstract type to a concrete implementation with a specified lifetime.
49
-
50
- Parameters
51
- ----------
52
- abstract : Callable[..., Any]
53
- The abstract base type or alias to be bound.
54
- concrete : Callable[..., Any]
55
- The concrete implementation to associate with the abstract type.
56
- lifetime : str
57
- The lifecycle of the binding. Must be one of 'transient', 'scoped', or 'singleton'.
58
-
59
- Raises
60
- ------
61
- OrionisContainerValueError
62
- If an invalid lifetime is provided or the concrete implementation is None.
63
-
64
- Examples
65
- --------
66
- >>> container.bind(MyService, MyServiceImplementation, "singleton")
67
- """
68
- if lifetime not in [member.value for member in Lifetime]:
69
- raise OrionisContainerValueError(f"Invalid lifetime type '{lifetime}'.")
70
-
71
- if concrete is None:
72
- raise OrionisContainerValueError("Concrete implementation cannot be None when binding a service.")
73
-
74
- abstract = abstract or concrete
75
- ContainerIntegrity.ensureIsCallable(concrete)
76
- ContainerIntegrity.ensureNotMain(concrete)
77
-
78
- service_entry = {
79
- "concrete": concrete,
80
- "async": inspect.iscoroutinefunction(concrete)
81
- }
82
-
83
- service_registry = {
84
- Lifetime.TRANSIENT.value: self._transient_services,
85
- Lifetime.SCOPED.value: self._scoped_services,
86
- Lifetime.SINGLETON.value: self._singleton_services
87
- }
88
-
89
- if ContainerIntegrity.isAbstract(abstract):
90
- ContainerIntegrity.ensureImplementation(abstract, concrete)
91
- service_registry[lifetime][abstract] = service_entry
92
- return
93
-
94
- if ContainerIntegrity.isAlias(abstract):
95
- service_registry[lifetime][abstract] = service_entry
96
- return
97
-
98
- raise OrionisContainerValueError(f"Invalid abstract type '{abstract}'. It must be a valid alias or an abstract class.")
99
-
100
- def transient(self, abstract: Callable[..., Any], concrete: Callable[..., Any]) -> None:
101
- """
102
- Registers a service with a transient lifetime.
103
-
104
- Parameters
105
- ----------
106
- abstract : Callable[..., Any]
107
- The abstract base type or alias to be bound.
108
- concrete : Callable[..., Any]
109
- The concrete implementation to associate with the abstract type.
110
-
111
- Examples
112
- --------
113
- >>> container.transient(MyService, MyServiceImplementation)
114
- """
115
-
116
- self.bind(abstract, concrete, Lifetime.TRANSIENT.value)
117
-
118
- def scoped(self, abstract: Callable[..., Any], concrete: Callable[..., Any]) -> None:
119
- """
120
- Registers a service with a scoped lifetime.
121
-
122
- Parameters
123
- ----------
124
- abstract : Callable[..., Any]
125
- The abstract base type or alias to be bound.
126
- concrete : Callable[..., Any]
127
- The concrete implementation to associate with the abstract type.
128
-
129
- Examples
130
- --------
131
- >>> container.scoped(MyService, MyServiceImplementation)
132
- """
133
-
134
- self.bind(abstract, concrete, Lifetime.SCOPED.value)
135
-
136
- def singleton(self, abstract: Callable[..., Any], concrete: Callable[..., Any]) -> None:
137
- """
138
- Registers a service with a singleton lifetime.
139
-
140
- Parameters
141
- ----------
142
- abstract : Callable[..., Any]
143
- The abstract base type or alias to be bound.
144
- concrete : Callable[..., Any]
145
- The concrete implementation to associate with the abstract type.
146
-
147
- Examples
148
- --------
149
- >>> container.singleton(MyService, MyServiceImplementation)
150
- """
151
-
152
- self.bind(abstract, concrete, Lifetime.SINGLETON.value)
153
-
154
- def instance(self, abstract: Callable[..., Any], instance: Any) -> None:
155
- """
156
- Registers an already instantiated object in the container.
157
-
158
- Parameters
159
- ----------
160
- abstract : Callable[..., Any]
161
- The abstract base type or alias to be bound.
162
- instance : Any
163
- The instance to be stored.
164
-
165
- Raises
166
- ------
167
- OrionisContainerValueError
168
- If the instance is None.
169
-
170
- Examples
171
- --------
172
- >>> container.instance(MyService, my_service_instance)
173
- """
174
-
175
- if instance is None:
176
- raise OrionisContainerValueError("The provided instance cannot be None.")
177
-
178
- ContainerIntegrity.ensureIsInstance(instance)
179
-
180
- if ContainerIntegrity.isAbstract(abstract):
181
- ContainerIntegrity.ensureImplementation(abstract, instance.__class__)
182
- self._instances_services[abstract] = instance
183
- return
184
-
185
- if ContainerIntegrity.isAlias(abstract):
186
- self._instances_services[abstract] = instance
187
- return
188
-
189
- raise OrionisContainerValueError(f"Invalid abstract type '{abstract}'. It must be a valid alias or an abstract class.")
190
-
191
- def bound(self, abstract_or_alias: Callable[..., Any]) -> bool:
192
- """
193
- Checks if a service or alias is bound in the container.
194
-
195
- Parameters
196
- ----------
197
- abstract_or_alias : Callable[..., Any]
198
- The abstract type or alias to check.
199
-
200
- Returns
201
- -------
202
- bool
203
- True if the service is bound, False otherwise.
204
-
205
- Examples
206
- --------
207
- >>> container.bound(MyService)
208
- True
209
- """
210
-
211
- service_dicts = [
212
- self._instances_services,
213
- self._transient_services,
214
- self._scoped_services,
215
- self._singleton_services,
216
- self._aliases_services
217
- ]
218
- return any(abstract_or_alias in service_dict for service_dict in service_dicts)
219
-
220
- def has(self, abstract_or_alias: Callable[..., Any]) -> bool:
221
- """
222
- Alias for `bound()` method.
223
-
224
- Parameters
225
- ----------
226
- abstract_or_alias : Callable[..., Any]
227
- The abstract type or alias to check.
228
-
229
- Returns
230
- -------
231
- bool
232
- True if the service is bound, False otherwise.
233
-
234
- Examples
235
- --------
236
- >>> container.has(MyService)
237
- True
238
- """
239
-
240
- return self.bound(abstract_or_alias)
241
-
242
- def alias(self, alias: Callable[..., Any], abstract: Callable[..., Any]) -> None:
243
- """
244
- Creates an alias for an existing abstract binding.
245
-
246
- Parameters
247
- ----------
248
- alias : Callable[..., Any]
249
- The alias name.
250
- abstract : Callable[..., Any]
251
- The existing abstract type to alias.
252
-
253
- Raises
254
- ------
255
- OrionisContainerValueError
256
- If the abstract type is not registered or the alias is already in use.
257
-
258
- Examples
259
- --------
260
- >>> container.alias("DatabaseService", MyDatabaseService)
261
- """
262
-
263
- if not self.has(abstract):
264
- raise OrionisContainerValueError(f"Abstract '{abstract}' is not registered in the container.")
265
-
266
- if alias in self._aliases_services:
267
- raise OrionisContainerValueError(f"Alias '{alias}' is already in use.")
268
-
269
- if not ContainerIntegrity.isAlias(abstract):
270
- raise OrionisContainerValueError(f"Invalid target abstract type: {abstract}. It must be an alias.")
271
-
272
- self._aliases_services[alias] = abstract
273
-
274
- def isAlias(self, name: str) -> bool:
275
- """
276
- Checks if a given name is an alias.
277
-
278
- Parameters
279
- ----------
280
- name : str
281
- The name to check.
282
-
283
- Returns
284
- -------
285
- bool
286
- True if the name is an alias, False otherwise.
287
-
288
- Raises
289
- ------
290
- OrionisContainerTypeError
291
- If the name is not a string.
292
-
293
- Examples
294
- --------
295
- >>> container.isAlias("DatabaseService")
296
- True
297
- """
298
-
299
- if not isinstance(name, str):
300
- raise OrionisContainerTypeError("The name must be a valid string.")
301
- return name in self._aliases_services
302
-
303
- def getBindings(self) -> Dict[str, Any]:
304
- """
305
- Retrieves all registered service bindings.
306
-
307
- Returns
308
- -------
309
- dict
310
- A dictionary containing all instances, transient, scoped, singleton, and alias services.
311
-
312
- Examples
313
- --------
314
- >>> container.getBindings()
315
- """
316
-
317
- return {
318
- "instances": self._instances_services,
319
- "transient": self._transient_services,
320
- "scoped": self._scoped_services,
321
- "singleton": self._singleton_services,
322
- "aliases": self._aliases_services
323
- }
324
-
325
- def getAlias(self, name: str) -> Callable[..., Any]:
326
- """
327
- Retrieves the abstract type associated with an alias.
328
-
329
- Parameters
330
- ----------
331
- name : str
332
- The alias name.
333
-
334
- Returns
335
- -------
336
- Callable[..., Any]
337
- The abstract type associated with the alias.
338
-
339
- Raises
340
- ------
341
- OrionisContainerValueError
342
- If the alias is not registered.
343
-
344
- Examples
345
- --------
346
- >>> container.getAlias("DatabaseService")
347
- <class 'MyDatabaseService'>
348
- """
349
-
350
- if not isinstance(name, str):
351
- raise OrionisContainerValueError("The name must be a valid string.")
352
-
353
- if name not in self._aliases_services:
354
- raise OrionisContainerValueError(f"Alias '{name}' is not registered in the container.")
355
-
356
- return self._aliases_services[name]
357
-
358
- def forgetScopedInstances(self) -> None:
359
- """
360
- Clears all scoped instances.
361
-
362
- Examples
363
- --------
364
- >>> container.forgetScopedInstances()
365
- """
366
-
367
- self._scoped_instances = {}
368
-
369
- def newRequest(self) -> None:
370
- """
371
- Resets scoped instances to handle a new request.
372
-
373
- Examples
374
- --------
375
- >>> container.newRequest()
376
- """
377
-
378
- self.forgetScopedInstances()
379
-
380
- async def make(self, abstract_or_alias: Callable[..., Any]) -> Any:
381
- """
382
- Resolves and instantiates a service from the container.
383
-
384
- Parameters
385
- ----------
386
- abstract_or_alias : Callable[..., Any]
387
- The abstract type or alias to resolve.
388
-
389
- Returns
390
- -------
391
- Any
392
- The instantiated service.
393
-
394
- Raises
395
- ------
396
- OrionisContainerException
397
- If the service is not found.
398
-
399
- Examples
400
- --------
401
- >>> service = await container.make(MyService)
402
- """
403
- if abstract_or_alias in self._aliases_services:
404
- abstract_or_alias = self._aliases_services[abstract_or_alias]
405
-
406
- if abstract_or_alias in self._instances_services:
407
- return self._instances_services[abstract_or_alias]
408
-
409
- if abstract_or_alias in self._singleton_services:
410
- if abstract_or_alias not in self._singleton_instances:
411
- service = self._singleton_services[abstract_or_alias]
412
- self._singleton_instances[abstract_or_alias] = await self._resolve(service['concrete'])
413
- return self._singleton_instances[abstract_or_alias]
414
-
415
- if abstract_or_alias in self._scoped_services:
416
- if abstract_or_alias not in self._scoped_instances:
417
- service = self._scoped_services[abstract_or_alias]
418
- self._scoped_instances[abstract_or_alias] = await self._resolve(service['concrete'])
419
- return self._scoped_instances[abstract_or_alias]
420
-
421
- if abstract_or_alias in self._transient_services:
422
- service = self._transient_services[abstract_or_alias]
423
- return await self._resolve(service['concrete'])
424
-
425
- raise OrionisContainerException(f"No binding found for '{abstract_or_alias}' in the container.")
426
-
427
- async def _resolve(self, concrete: Callable[..., Any], resolving: Optional[Deque[Type]] = None) -> Any:
428
- """
429
- Asynchronous method to resolve dependencies recursively and instantiate a class.
430
-
431
- Parameters
432
- ----------
433
- concrete : Callable[..., Any]
434
- The concrete implementation to instantiate.
435
- resolving : Optional[Deque[Type]], optional
436
- A queue to track resolving dependencies and prevent circular dependencies.
437
-
438
- Returns
439
- -------
440
- Any
441
- The instantiated object.
442
-
443
- Raises
444
- ------
445
- OrionisContainerException
446
- If circular dependencies are detected or instantiation fails.
447
-
448
- Examples
449
- --------
450
- >>> instance = await container._resolve(MyClass)
451
- """
452
- if resolving is None:
453
- resolving = deque()
454
-
455
- if concrete in resolving:
456
- raise OrionisContainerException(f"Circular dependency detected for {concrete}.")
457
-
458
- resolving.append(concrete)
459
-
460
- try:
461
- signature = inspect.signature(concrete)
462
- except ValueError as e:
463
- raise OrionisContainerException(f"Unable to inspect signature of {concrete}: {str(e)}")
464
-
465
- resolved_dependencies: Dict[str, Any] = {}
466
- unresolved_dependencies = deque()
467
-
468
- for param_name, param in signature.parameters.items():
469
- if param_name == 'self':
470
- continue
471
-
472
- if param.kind in (param.VAR_POSITIONAL, param.VAR_KEYWORD):
473
- continue
474
-
475
- if param.annotation is param.empty and param.default is param.empty:
476
- unresolved_dependencies.append(param_name)
477
- continue
478
-
479
- if param.default is not param.empty:
480
- resolved_dependencies[param_name] = param.default
481
- continue
482
-
483
- if param.annotation is not param.empty:
484
- param_type = param.annotation
485
-
486
- if get_origin(param_type) is not None:
487
- param_type = get_args(param_type)[0]
488
-
489
- if isinstance(param_type, type) and not issubclass(param_type, (int, str, bool, float)):
490
- if self.has(param_type):
491
- resolved_dependencies[param_name] = await self.make(param_type)
492
- else:
493
- resolved_dependencies[param_name] = await self._resolve_dependency(param_type, resolving)
494
- else:
495
- resolved_dependencies[param_name] = param_type
496
-
497
- while unresolved_dependencies:
498
- dep_name = unresolved_dependencies.popleft()
499
- if dep_name not in resolved_dependencies:
500
- resolved_dependencies[dep_name] = await self._resolve_dependency(dep_name, resolving)
501
-
502
- try:
503
- instance = concrete(**resolved_dependencies)
504
- resolving.pop()
505
- return instance
506
- except Exception as e:
507
- raise OrionisContainerException(f"Failed to instantiate {concrete}: {str(e)}")
508
-
509
- async def _resolve_dependency(self, dep_type: Any, resolving: Optional[Deque[Type]] = None) -> Any:
510
- """
511
- Asynchronously resolves a dependency by instantiating or retrieving it from the container.
512
-
513
- Parameters
514
- ----------
515
- dep_type : Any
516
- The dependency type to resolve.
517
- resolving : Optional[Deque[Type]], optional
518
- A queue to track resolving dependencies.
519
-
520
- Returns
521
- -------
522
- Any
523
- The resolved dependency.
524
-
525
- Raises
526
- ------
527
- OrionisContainerException
528
- If the dependency cannot be resolved.
529
-
530
- Examples
531
- --------
532
- >>> dependency = await container._resolve_dependency(MyDependency)
533
- """
534
- if resolving is None:
535
- resolving = deque()
536
-
537
- if isinstance(dep_type, type):
538
- if self.has(dep_type):
539
- return await self.make(dep_type)
540
- else:
541
- return await self._resolve(dep_type, resolving)
542
-
543
- raise OrionisContainerException(f"Cannot resolve dependency of type {dep_type}")
@@ -1,292 +0,0 @@
1
- import re
2
- import inspect
3
- from abc import ABC
4
- from typing import Any, Callable, Set, Type
5
- from orionis._container.exception import OrionisContainerValueError, OrionisContainerTypeError
6
- from orionis._contracts.container.container_integrity import IContainerIntegrity
7
-
8
- class ContainerIntegrity(IContainerIntegrity):
9
-
10
- @staticmethod
11
- def ensureImplementation(abstract: Type, concrete: Type, raise_exception: bool = True) -> bool:
12
- """
13
- Strictly verify that 'concrete' implements all abstract methods of 'abstract'.
14
-
15
- Args:
16
- abstract: Abstract class or interface to verify against
17
- concrete: Concrete class that should implement the abstract class
18
-
19
- Raises:
20
- OrionisContainerTypeError: If concrete doesn't properly implement abstract
21
- """
22
-
23
- # Check if abstract is a class
24
- if not inspect.isclass(abstract):
25
- if raise_exception:
26
- raise OrionisContainerTypeError(
27
- f"Abstract must be a class, got {type(abstract).__name__}"
28
- )
29
- return False
30
-
31
- # Check if concrete is a class
32
- if not inspect.isclass(concrete):
33
- if raise_exception:
34
- raise OrionisContainerTypeError(
35
- f"Concrete must be a class, got {type(concrete).__name__}"
36
- )
37
- return False
38
-
39
- # Check if concrete inherits from abstract
40
- if not issubclass(concrete, abstract):
41
- if raise_exception:
42
- raise OrionisContainerTypeError(
43
- f"{concrete.__name__} must inherit from {abstract.__name__}"
44
- )
45
- return False
46
-
47
- abstract_methods: Set[str] = set()
48
- for base in abstract.__mro__:
49
- if hasattr(base, '__abstractmethods__'):
50
- abstract_methods.update(base.__abstractmethods__)
51
-
52
- if not abstract_methods:
53
- return # No abstract methods to implement
54
-
55
- class_methods = {
56
- name for name, member in inspect.getmembers(concrete)
57
- if not name.startswith("_") and inspect.isfunction(member)
58
- }
59
-
60
- missing_methods = abstract_methods - class_methods
61
- if missing_methods:
62
- raise OrionisContainerTypeError(
63
- f"{concrete.__name__} must implement: {sorted(missing_methods)}"
64
- )
65
-
66
- def ensureImplementation(abstract: Type, concrete: Type) -> None:
67
- """
68
- Verify at runtime if `concrete` implements all methods of `abstract`.
69
-
70
- :param abstract: Abstract class or interface.
71
- :param concrete: Concrete class that should implement the abstract class.
72
- :raises TypeError: If `concrete` does not implement all methods of `abstract`.
73
- """
74
- # Get public methods of the interface (excluding magic methods)
75
- interface_methods = {
76
- name for name, func in inspect.getmembers(abstract, predicate=inspect.isfunction)
77
- if not name.startswith("_")
78
- }
79
-
80
- # Get public methods of the concrete class
81
- class_methods = {
82
- name for name, func in inspect.getmembers(concrete, predicate=inspect.isfunction)
83
- if not name.startswith("_")
84
- }
85
-
86
- # Verify that all interface methods are in the concrete class
87
- if not interface_methods.issubset(class_methods):
88
- missing_methods = interface_methods - class_methods
89
- raise OrionisContainerTypeError(f"{concrete.__name__} does not implement the required methods of {abstract.__name__}: {missing_methods}")
90
-
91
-
92
- @staticmethod
93
- def ensureIsAbstract(abstract: Callable[..., Any]) -> None:
94
- """
95
- Ensure that the given abstract is a valid abstract class.
96
-
97
- :param abstract: Class to check
98
- :raises OrionisContainerValueError: If the class is not a valid abstract interface
99
- """
100
- if not isinstance(abstract, type) or not issubclass(abstract, ABC) or abstract is ABC:
101
- raise OrionisContainerValueError("The provided class must inherit from ABC and not be ABC itself.")
102
-
103
- if not any(getattr(attr, "__isabstractmethod__", False) for attr in abstract.__dict__.values()):
104
- raise OrionisContainerValueError("The provided class must define at least one abstract method.")
105
-
106
- @staticmethod
107
- def ensureIsCallable(concrete: Callable[..., Any]) -> None:
108
- """
109
- Ensure that the given implementation is callable or instantiable.
110
-
111
- Parameters
112
- ----------
113
- concrete : Callable[..., Any]
114
- The implementation to check.
115
-
116
- Raises
117
- ------
118
- OrionisContainerTypeError
119
- If the implementation is not callable.
120
- """
121
- if not callable(concrete):
122
- raise OrionisContainerTypeError(f"The implementation '{str(concrete)}' must be callable or an instantiable class.")
123
-
124
- @staticmethod
125
- def ensureIsInstance(instance: Any) -> None:
126
- """
127
- Ensure that the given instance is a valid object.
128
-
129
- Parameters
130
- ----------
131
- instance : Any
132
- The instance to check.
133
-
134
- Raises
135
- ------
136
- OrionisContainerValueError
137
- If the instance is not a valid object.
138
- """
139
- if not isinstance(instance, object):
140
- raise OrionisContainerValueError(f"The instance '{str(instance)}' must be a valid object.")
141
-
142
- module = type(instance).__module__
143
- if module in ['builtins', 'abc']:
144
- raise OrionisContainerValueError(f"The instance '{str(instance)}' is not a valid user-defined object. It belongs to the '{module}' module.")
145
-
146
- @staticmethod
147
- def ensureNotMain(concrete: Callable[..., Any]) -> str:
148
- """
149
- Ensure that a class is not defined in the main script.
150
-
151
- Parameters
152
- ----------
153
- concrete : Callable[..., Any]
154
- The class or function to check.
155
-
156
- Returns
157
- -------
158
- str
159
- The fully qualified name of the class.
160
-
161
- Raises
162
- ------
163
- OrionisContainerValueError
164
- If the class is defined in the main module.
165
- """
166
- if concrete.__module__ == "__main__":
167
- raise OrionisContainerValueError("Cannot register a class from the (__main__) module in the container.")
168
-
169
- @staticmethod
170
- def ensureIsAlias(name: str) -> bool:
171
- """
172
- Ensure that the given alias name is a valid string, with no special characters or spaces,
173
- and it is not a primitive type.
174
-
175
- Parameters
176
- ----------
177
- name : str
178
- The alias name to check.
179
-
180
- Raises
181
- ------
182
- OrionisContainerValueError
183
- If the alias is invalid.
184
- """
185
- if not isinstance(name, str):
186
- raise OrionisContainerValueError(f"The alias '{name}' must be a string.")
187
-
188
- if not re.match(r'^[a-zA-Z0-9_:]+$', name):
189
- raise OrionisContainerValueError(
190
- f"The alias '{name}' can only contain letters, numbers, underscores, and colons, without spaces or other special characters."
191
- )
192
-
193
- if name in {
194
- int, "int",
195
- float, "float",
196
- str, "str",
197
- bool, "bool",
198
- bytes, "bytes",
199
- type(None), "None",
200
- complex, "complex",
201
- list, "list",
202
- tuple, "tuple",
203
- dict, "dict",
204
- set, "set",
205
- frozenset, "frozenset"
206
- }:
207
- raise OrionisContainerValueError(f"The alias '{name}' cannot be a primitive type.")
208
-
209
- @staticmethod
210
- def isAlias(name: str) -> bool:
211
- """
212
- Check if the given alias name is a valid string, with no special characters or spaces,
213
- and it is not a primitive type.
214
-
215
- Parameters
216
- ----------
217
- name : str
218
- The alias name to check.
219
-
220
- Returns
221
- -------
222
- bool
223
- True if the alias is valid, False otherwise.
224
- """
225
- try:
226
- ContainerIntegrity.ensureIsAlias(name)
227
- return True
228
- except OrionisContainerValueError:
229
- return False
230
-
231
- @staticmethod
232
- def isCallable(concrete: Callable[..., Any]) -> bool:
233
- """
234
- Check if the given implementation is callable or instantiable.
235
-
236
- Parameters
237
- ----------
238
- concrete : Callable[..., Any]
239
- The implementation to check.
240
-
241
- Returns
242
- -------
243
- bool
244
- True if the implementation is callable, False otherwise.
245
- """
246
- try:
247
- ContainerIntegrity.ensureIsCallable(concrete)
248
- return True
249
- except OrionisContainerTypeError:
250
- return False
251
-
252
- @staticmethod
253
- def isInstance(instance: Any) -> bool:
254
- """
255
- Check if the given instance is a valid object.
256
-
257
- Parameters
258
- ----------
259
- instance : Any
260
- The instance to check.
261
-
262
- Returns
263
- -------
264
- bool
265
- True if the instance is valid, False otherwise.
266
- """
267
- try:
268
- ContainerIntegrity.ensureIsInstance(instance)
269
- return True
270
- except OrionisContainerValueError:
271
- return False
272
-
273
- @staticmethod
274
- def isAbstract(abstract: Callable[..., Any]) -> bool:
275
- """
276
- Check if the given abstract is a valid abstract class.
277
-
278
- Parameters
279
- ----------
280
- abstract : Callable[..., Any]
281
- The class to check.
282
-
283
- Returns
284
- -------
285
- bool
286
- True if the class is a valid abstract interface, False otherwise.
287
- """
288
- try:
289
- ContainerIntegrity.ensureIsAbstract(abstract)
290
- return True
291
- except OrionisContainerValueError:
292
- return False
@@ -1,54 +0,0 @@
1
- class OrionisContainerException(Exception):
2
- """
3
- Excepción personalizada para errores relacionados con el contenedor de inyección de dependencias Orionis.
4
- """
5
-
6
- def __init__(self, message: str) -> None:
7
- """
8
- Inicializa la excepción con un mensaje de error.
9
-
10
- Args:
11
- message (str): Mensaje descriptivo del error.
12
- """
13
- super().__init__(message)
14
-
15
- def __str__(self) -> str:
16
- """Retorna una representación en cadena de la excepción."""
17
- return f"[OrionisContainerException] {self.args[0]}"
18
-
19
-
20
- class OrionisContainerValueError(ValueError):
21
- """
22
- Excepción personalizada para errores de tipo ValueError en el contenedor Orionis.
23
- """
24
-
25
- def __init__(self, message: str) -> None:
26
- """
27
- Inicializa la excepción con un mensaje de error.
28
-
29
- Args:
30
- message (str): Mensaje descriptivo del error.
31
- """
32
- super().__init__(message)
33
-
34
- def __str__(self) -> str:
35
- """Retorna una representación en cadena de la excepción."""
36
- return f"[OrionisContainerValueError] {self.args[0]}"
37
-
38
- class OrionisContainerTypeError(TypeError):
39
- """
40
- Custom exception for TypeError related to the Orionis container.
41
- """
42
-
43
- def __init__(self, message: str) -> None:
44
- """
45
- Initializes the exception with an error message.
46
-
47
- Args:
48
- message (str): Descriptive error message.
49
- """
50
- super().__init__(message)
51
-
52
- def __str__(self) -> str:
53
- """Returns a string representation of the exception."""
54
- return f"[OrionisContainerTypeError] {self.args[0]}"
@@ -1,13 +0,0 @@
1
- from enum import Enum
2
-
3
- class Lifetime(Enum):
4
- """Defines the lifecycle types for dependency injection."""
5
-
6
- # Creates a new instance every time it is requested
7
- TRANSIENT = "transient"
8
-
9
- # A single instance is shared throughout the application
10
- SINGLETON = "singleton"
11
-
12
- # A new instance is created per request or context
13
- SCOPED = "scoped"
@@ -1,64 +0,0 @@
1
- from typing import Any, Callable
2
- from orionis._container.container import Container
3
- from orionis._container.exception import OrionisContainerValueError
4
-
5
- class Resolve:
6
- """
7
- A class to resolve dependencies from the dependency injection container.
8
-
9
- This class ensures that a given abstract class or alias exists in the container
10
- and resolves the associated service when an instance is created.
11
-
12
- Parameters
13
- ----------
14
- abstract_or_alias : Callable[..., Any] or str
15
- The abstract class, alias, or callable to resolve from the container.
16
-
17
- Returns
18
- -------
19
- Any
20
- The service associated with the abstract class or alias.
21
-
22
- Raises
23
- ------
24
- OrionisContainerValueError
25
- If the abstract class or alias is not found in the container.
26
-
27
- Examples
28
- --------
29
- >>> container = Container()
30
- >>> container.bind("my_service", MyService)
31
- >>> container.alias("my_alias", "my_service")
32
- >>> service = Resolve("my_alias") # Returns the service associated with "my_alias"
33
- >>> service = Resolve(MyService) # Returns the service associated with MyService
34
- """
35
-
36
- def __new__(cls, abstract_or_alias: Callable[..., Any] | str):
37
- """
38
- Create an instance of Resolve and return the resolved service.
39
-
40
- Parameters
41
- ----------
42
- abstract_or_alias : Callable[..., Any] or str
43
- The abstract class, alias, or callable to resolve from the container.
44
-
45
- Returns
46
- -------
47
- Any
48
- The service associated with the abstract class or alias.
49
-
50
- Raises
51
- ------
52
- OrionisContainerValueError
53
- If the abstract class or alias is not found in the container.
54
- """
55
-
56
- # Validate that the abstract or alias exists in the container
57
- container = Container()
58
- if not container.bound(abstract_or_alias):
59
- raise OrionisContainerValueError(
60
- f"Service or alias '{abstract_or_alias}' not found in the container."
61
- )
62
-
63
- # Resolve and return the service associated with the abstract or alias
64
- # return AsyncExecutor.run(container.make(abstract_or_alias))
File without changes