orionis 0.316.0__py3-none-any.whl → 0.318.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 +407 -53
- orionis/container/entities/binding.py +124 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/introspection/callables/__init__.py +0 -0
- orionis/services/introspection/callables/reflection_callable.py +146 -0
- orionis/services/introspection/dependencies/entities/callable_dependencies.py +55 -0
- orionis/services/introspection/dependencies/reflect_dependencies.py +58 -6
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/METADATA +1 -1
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/RECORD +15 -10
- tests/services/inspection/dependencies/test_reflect_dependencies.py +35 -1
- tests/services/inspection/reflection/test_reflection_callable.py +156 -0
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/WHEEL +0 -0
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/top_level.txt +0 -0
- {orionis-0.316.0.dist-info → orionis-0.318.0.dist-info}/zip-safe +0 -0
orionis/container/container.py
CHANGED
@@ -1,21 +1,146 @@
|
|
1
1
|
from typing import Any, Callable
|
2
|
+
from orionis.container.entities.binding import Binding
|
2
3
|
from orionis.container.enums.lifetimes import Lifetime
|
3
4
|
from orionis.container.exceptions.container_exception import OrionisContainerException
|
4
5
|
from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
|
5
6
|
from orionis.services.introspection.abstract.reflection_abstract import ReflectionAbstract
|
7
|
+
from orionis.services.introspection.callables.reflection_callable import ReflectionCallable
|
6
8
|
from orionis.services.introspection.concretes.reflection_concrete import ReflectionConcrete
|
7
9
|
from orionis.services.introspection.instances.reflection_instance import ReflectionInstance
|
8
10
|
from orionis.services.introspection.reflection import Reflection
|
11
|
+
import threading
|
9
12
|
|
10
13
|
class Container:
|
11
14
|
|
15
|
+
# Singleton instance of the container.
|
16
|
+
# This is a class variable that holds the single instance of the Container class.
|
17
|
+
_instance = None
|
18
|
+
|
19
|
+
# Lock for thread-safe singleton instantiation.
|
20
|
+
# This lock ensures that only one thread can create the instance at a time,
|
21
|
+
# preventing
|
22
|
+
_lock = threading.Lock()
|
23
|
+
|
24
|
+
# Class variable to track if the container has been initialized.
|
25
|
+
# This is used to ensure that the initialization logic runs only once,
|
26
|
+
# regardless of how many times the class is instantiated.
|
27
|
+
_initialized = False
|
28
|
+
|
29
|
+
def __new__(cls, *args, **kwargs):
|
30
|
+
"""
|
31
|
+
Creates and returns a singleton instance of the class.
|
32
|
+
|
33
|
+
This method implements the singleton pattern, ensuring that only one instance
|
34
|
+
of the class exists. If an instance does not exist, it acquires a lock to
|
35
|
+
ensure thread safety and creates the instance. Subsequent calls return the
|
36
|
+
existing instance.
|
37
|
+
Parameters
|
38
|
+
----------
|
39
|
+
*args : tuple
|
40
|
+
Variable length argument list.
|
41
|
+
**kwargs : dict
|
42
|
+
Arbitrary keyword arguments.
|
43
|
+
Returns
|
44
|
+
-------
|
45
|
+
Container
|
46
|
+
The singleton instance of the class.
|
47
|
+
"""
|
48
|
+
if cls._instance is None:
|
49
|
+
with cls._lock:
|
50
|
+
if cls._instance is None:
|
51
|
+
cls._instance = super(Container, cls).__new__(cls)
|
52
|
+
return cls._instance
|
53
|
+
|
12
54
|
def __init__(self):
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
55
|
+
"""
|
56
|
+
Initializes a new instance of the container.
|
57
|
+
|
58
|
+
This constructor sets up the internal dictionaries for bindings and aliases,
|
59
|
+
ensuring that these are only initialized once per class. The initialization
|
60
|
+
is guarded by the `_initialized` class attribute to prevent redundant setup.
|
61
|
+
|
62
|
+
Notes
|
63
|
+
-----
|
64
|
+
- The `__bindings` dictionary is used to store service bindings.
|
65
|
+
- The `__aliasses` dictionary is used to store service aliases.
|
66
|
+
- Initialization occurs only once per class, regardless of the number of instances.
|
67
|
+
"""
|
68
|
+
if not self.__class__._initialized:
|
69
|
+
self.__bindings = {}
|
70
|
+
self.__aliasses = {}
|
71
|
+
self.__class__._initialized = True
|
72
|
+
|
73
|
+
def __dropService(
|
74
|
+
self,
|
75
|
+
abstract: Callable[..., Any] = None,
|
76
|
+
alias: str = None
|
77
|
+
) -> None:
|
78
|
+
"""
|
79
|
+
Drops a service from the container.
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
abstract : Callable[..., Any]
|
84
|
+
The abstract type or interface to be removed.
|
85
|
+
alias : str, optional
|
86
|
+
The alias of the service to be removed. If not provided, the service will be removed by its abstract type.
|
87
|
+
|
88
|
+
Raises
|
89
|
+
------
|
90
|
+
OrionisContainerException
|
91
|
+
If the service does not exist in the container.
|
92
|
+
"""
|
93
|
+
|
94
|
+
# If abstract is provided
|
95
|
+
if abstract:
|
96
|
+
|
97
|
+
# Remove the abstract service from the bindings if it exists
|
98
|
+
if abstract in self.__bindings:
|
99
|
+
del self.__bindings[abstract]
|
100
|
+
|
101
|
+
# Remove the default alias (module + class name) from aliases if it exists
|
102
|
+
abs_alias = ReflectionAbstract(abstract).getModuleWithClassName()
|
103
|
+
if abs_alias in self.__aliasses:
|
104
|
+
del self.__aliasses[abs_alias]
|
17
105
|
|
18
|
-
|
106
|
+
# If a custom alias is provided
|
107
|
+
if alias:
|
108
|
+
|
109
|
+
# Remove it from the aliases dictionary if it exists
|
110
|
+
if alias in self.__aliasses:
|
111
|
+
del self.__aliasses[alias]
|
112
|
+
|
113
|
+
# Remove the binding associated with the alias
|
114
|
+
if alias in self.__bindings:
|
115
|
+
del self.__bindings[alias]
|
116
|
+
|
117
|
+
def __ensureIsCallable(
|
118
|
+
self,
|
119
|
+
value: Any
|
120
|
+
) -> None:
|
121
|
+
"""
|
122
|
+
Ensures that the provided value is callable.
|
123
|
+
|
124
|
+
Parameters
|
125
|
+
----------
|
126
|
+
value : Any
|
127
|
+
The value to check.
|
128
|
+
|
129
|
+
Raises
|
130
|
+
------
|
131
|
+
OrionisContainerTypeError
|
132
|
+
If the value is not callable.
|
133
|
+
"""
|
134
|
+
|
135
|
+
if not callable(value):
|
136
|
+
raise OrionisContainerTypeError(
|
137
|
+
f"Expected a callable type, but got {type(value).__name__} instead."
|
138
|
+
)
|
139
|
+
|
140
|
+
def __ensureAliasType(
|
141
|
+
self,
|
142
|
+
value: Any
|
143
|
+
) -> None:
|
19
144
|
"""
|
20
145
|
Ensures that the provided value is a valid alias of type str and does not contain invalid characters.
|
21
146
|
|
@@ -49,7 +174,11 @@ class Container:
|
|
49
174
|
"Aliases must not contain whitespace or special symbols."
|
50
175
|
)
|
51
176
|
|
52
|
-
def __ensureAbstractClass(
|
177
|
+
def __ensureAbstractClass(
|
178
|
+
self,
|
179
|
+
abstract: Callable[..., Any],
|
180
|
+
lifetime: str
|
181
|
+
) -> None:
|
53
182
|
"""
|
54
183
|
Ensures that the provided abstract is an abstract class.
|
55
184
|
|
@@ -72,7 +201,11 @@ class Container:
|
|
72
201
|
f"Unexpected error registering {lifetime} service: {e}"
|
73
202
|
) from e
|
74
203
|
|
75
|
-
def __ensureConcreteClass(
|
204
|
+
def __ensureConcreteClass(
|
205
|
+
self,
|
206
|
+
concrete: Callable[..., Any],
|
207
|
+
lifetime: str
|
208
|
+
) -> None:
|
76
209
|
"""
|
77
210
|
Ensures that the provided concrete is a concrete (non-abstract) class.
|
78
211
|
|
@@ -95,7 +228,11 @@ class Container:
|
|
95
228
|
f"Unexpected error registering {lifetime} service: {e}"
|
96
229
|
) from e
|
97
230
|
|
98
|
-
def __ensureIsSubclass(
|
231
|
+
def __ensureIsSubclass(
|
232
|
+
self,
|
233
|
+
abstract: Callable[..., Any],
|
234
|
+
concrete: Callable[..., Any]
|
235
|
+
) -> None:
|
99
236
|
"""
|
100
237
|
Validates that the concrete class is a subclass of the provided abstract class.
|
101
238
|
|
@@ -122,7 +259,11 @@ class Container:
|
|
122
259
|
"Please ensure that the concrete class is a subclass of the specified abstract class."
|
123
260
|
)
|
124
261
|
|
125
|
-
def __ensureIsNotSubclass(
|
262
|
+
def __ensureIsNotSubclass(
|
263
|
+
self,
|
264
|
+
abstract: Callable[..., Any],
|
265
|
+
concrete: Callable[..., Any]
|
266
|
+
) -> None:
|
126
267
|
"""
|
127
268
|
Validates that the concrete class is NOT a subclass of the provided abstract class.
|
128
269
|
|
@@ -148,7 +289,10 @@ class Container:
|
|
148
289
|
"Please ensure that the concrete class is not a subclass of the specified abstract class."
|
149
290
|
)
|
150
291
|
|
151
|
-
def __ensureInstance(
|
292
|
+
def __ensureInstance(
|
293
|
+
self,
|
294
|
+
instance: Any
|
295
|
+
) -> None:
|
152
296
|
"""
|
153
297
|
Ensures that the provided object is a valid instance.
|
154
298
|
|
@@ -175,7 +319,13 @@ class Container:
|
|
175
319
|
f"Error registering instance: {e}"
|
176
320
|
) from e
|
177
321
|
|
178
|
-
def __ensureImplementation(
|
322
|
+
def __ensureImplementation(
|
323
|
+
self,
|
324
|
+
*,
|
325
|
+
abstract: Callable[..., Any] = None,
|
326
|
+
concrete: Callable[..., Any] = None,
|
327
|
+
instance: Any = None
|
328
|
+
) -> None:
|
179
329
|
"""
|
180
330
|
Ensures that a concrete class or instance implements all abstract methods defined in an abstract class.
|
181
331
|
|
@@ -229,7 +379,14 @@ class Container:
|
|
229
379
|
"Please ensure that all abstract methods are implemented."
|
230
380
|
)
|
231
381
|
|
232
|
-
def transient(
|
382
|
+
def transient(
|
383
|
+
self,
|
384
|
+
abstract: Callable[..., Any],
|
385
|
+
concrete: Callable[..., Any],
|
386
|
+
*,
|
387
|
+
alias: str = None,
|
388
|
+
enforce_decoupling: bool = False
|
389
|
+
) -> bool:
|
233
390
|
"""
|
234
391
|
Registers a service with a transient lifetime.
|
235
392
|
|
@@ -267,11 +424,12 @@ class Container:
|
|
267
424
|
# Ensure that concrete is a concrete class
|
268
425
|
self.__ensureConcreteClass(concrete, Lifetime.TRANSIENT)
|
269
426
|
|
427
|
+
# Ensure that concrete is NOT a subclass of abstract
|
270
428
|
if enforce_decoupling:
|
271
|
-
# Ensure that concrete is NOT a subclass of abstract
|
272
429
|
self.__ensureIsNotSubclass(abstract, concrete)
|
430
|
+
|
431
|
+
# Validate that concrete is a subclass of abstract
|
273
432
|
else:
|
274
|
-
# Validate that concrete is a subclass of abstract
|
275
433
|
self.__ensureIsSubclass(abstract, concrete)
|
276
434
|
|
277
435
|
# Ensure implementation
|
@@ -284,20 +442,37 @@ class Container:
|
|
284
442
|
if alias:
|
285
443
|
self.__ensureAliasType(alias)
|
286
444
|
|
445
|
+
# Extract the module and class name for the alias
|
446
|
+
else:
|
447
|
+
rf_asbtract = ReflectionAbstract(abstract)
|
448
|
+
alias = rf_asbtract.getModuleWithClassName()
|
449
|
+
|
450
|
+
# If the service is already registered, drop it
|
451
|
+
self.__dropService(abstract, alias)
|
452
|
+
|
287
453
|
# Register the service with transient lifetime
|
288
|
-
self.
|
454
|
+
self.__bindings[abstract] = Binding(
|
455
|
+
contract = abstract,
|
456
|
+
concrete = concrete,
|
457
|
+
lifetime = Lifetime.TRANSIENT,
|
458
|
+
enforce_decoupling = enforce_decoupling,
|
459
|
+
alias = alias
|
460
|
+
)
|
289
461
|
|
290
|
-
#
|
291
|
-
|
292
|
-
self.__transient[alias] = concrete
|
293
|
-
elif hasattr(abstract, '__name__'):
|
294
|
-
alias = abstract.__name__
|
295
|
-
self.__transient[alias] = concrete
|
462
|
+
# Register the alias
|
463
|
+
self.__aliasses[alias] = self.__bindings[abstract]
|
296
464
|
|
297
465
|
# Return True to indicate successful registration
|
298
466
|
return True
|
299
467
|
|
300
|
-
def singleton(
|
468
|
+
def singleton(
|
469
|
+
self,
|
470
|
+
abstract: Callable[..., Any],
|
471
|
+
concrete: Callable[..., Any],
|
472
|
+
*,
|
473
|
+
alias: str = None,
|
474
|
+
enforce_decoupling: bool = False
|
475
|
+
) -> bool:
|
301
476
|
"""
|
302
477
|
Registers a service with a singleton lifetime.
|
303
478
|
|
@@ -334,11 +509,12 @@ class Container:
|
|
334
509
|
# Ensure that concrete is a concrete class
|
335
510
|
self.__ensureConcreteClass(concrete, Lifetime.SINGLETON)
|
336
511
|
|
512
|
+
# Ensure that concrete is NOT a subclass of abstract
|
337
513
|
if enforce_decoupling:
|
338
|
-
# Ensure that concrete is NOT a subclass of abstract
|
339
514
|
self.__ensureIsNotSubclass(abstract, concrete)
|
515
|
+
|
516
|
+
# Validate that concrete is a subclass of abstract
|
340
517
|
else:
|
341
|
-
# Validate that concrete is a subclass of abstract
|
342
518
|
self.__ensureIsSubclass(abstract, concrete)
|
343
519
|
|
344
520
|
# Ensure implementation
|
@@ -350,21 +526,36 @@ class Container:
|
|
350
526
|
# Ensure that the alias is a valid string if provided
|
351
527
|
if alias:
|
352
528
|
self.__ensureAliasType(alias)
|
529
|
+
else:
|
530
|
+
rf_asbtract = ReflectionAbstract(abstract)
|
531
|
+
alias = rf_asbtract.getModuleWithClassName()
|
532
|
+
|
533
|
+
# If the service is already registered, drop it
|
534
|
+
self.__dropService(abstract, alias)
|
353
535
|
|
354
536
|
# Register the service with singleton lifetime
|
355
|
-
self.
|
537
|
+
self.__bindings[abstract] = Binding(
|
538
|
+
contract = abstract,
|
539
|
+
concrete = concrete,
|
540
|
+
lifetime = Lifetime.SINGLETON,
|
541
|
+
enforce_decoupling = enforce_decoupling,
|
542
|
+
alias = alias
|
543
|
+
)
|
356
544
|
|
357
|
-
#
|
358
|
-
|
359
|
-
self.__singleton[alias] = concrete
|
360
|
-
elif hasattr(abstract, '__name__'):
|
361
|
-
alias = abstract.__name__
|
362
|
-
self.__singleton[alias] = concrete
|
545
|
+
# Register the alias
|
546
|
+
self.__aliasses[alias] = self.__bindings[abstract]
|
363
547
|
|
364
548
|
# Return True to indicate successful registration
|
365
549
|
return True
|
366
550
|
|
367
|
-
def scoped(
|
551
|
+
def scoped(
|
552
|
+
self,
|
553
|
+
abstract: Callable[..., Any],
|
554
|
+
concrete: Callable[..., Any],
|
555
|
+
*,
|
556
|
+
alias: str = None,
|
557
|
+
enforce_decoupling: bool = False
|
558
|
+
) -> bool:
|
368
559
|
"""
|
369
560
|
Registers a service with a scoped lifetime.
|
370
561
|
|
@@ -401,11 +592,12 @@ class Container:
|
|
401
592
|
# Ensure that concrete is a concrete class
|
402
593
|
self.__ensureConcreteClass(concrete, Lifetime.SCOPED)
|
403
594
|
|
595
|
+
# Ensure that concrete is NOT a subclass of abstract
|
404
596
|
if enforce_decoupling:
|
405
|
-
# Ensure that concrete is NOT a subclass of abstract
|
406
597
|
self.__ensureIsNotSubclass(abstract, concrete)
|
598
|
+
|
599
|
+
# Validate that concrete is a subclass of abstract
|
407
600
|
else:
|
408
|
-
# Validate that concrete is a subclass of abstract
|
409
601
|
self.__ensureIsSubclass(abstract, concrete)
|
410
602
|
|
411
603
|
# Ensure implementation
|
@@ -417,21 +609,36 @@ class Container:
|
|
417
609
|
# Ensure that the alias is a valid string if provided
|
418
610
|
if alias:
|
419
611
|
self.__ensureAliasType(alias)
|
612
|
+
else:
|
613
|
+
rf_asbtract = ReflectionAbstract(abstract)
|
614
|
+
alias = rf_asbtract.getModuleWithClassName()
|
615
|
+
|
616
|
+
# If the service is already registered, drop it
|
617
|
+
self.__dropService(abstract, alias)
|
420
618
|
|
421
619
|
# Register the service with scoped lifetime
|
422
|
-
self.
|
620
|
+
self.__bindings[abstract] = Binding(
|
621
|
+
contract = abstract,
|
622
|
+
concrete = concrete,
|
623
|
+
lifetime = Lifetime.SCOPED,
|
624
|
+
enforce_decoupling = enforce_decoupling,
|
625
|
+
alias = alias
|
626
|
+
)
|
423
627
|
|
424
|
-
#
|
425
|
-
|
426
|
-
self.__scoped[alias] = concrete
|
427
|
-
elif hasattr(abstract, '__name__'):
|
428
|
-
alias = abstract.__name__
|
429
|
-
self.__scoped[alias] = concrete
|
628
|
+
# Register the alias
|
629
|
+
self.__aliasses[alias] = self.__bindings[abstract]
|
430
630
|
|
431
631
|
# Return True to indicate successful registration
|
432
632
|
return True
|
433
633
|
|
434
|
-
def instance(
|
634
|
+
def instance(
|
635
|
+
self,
|
636
|
+
abstract: Callable[..., Any],
|
637
|
+
instance: Any,
|
638
|
+
*,
|
639
|
+
alias: str = None,
|
640
|
+
enforce_decoupling: bool = False
|
641
|
+
) -> bool:
|
435
642
|
"""
|
436
643
|
Registers an instance of a class or interface in the container.
|
437
644
|
Parameters
|
@@ -466,11 +673,12 @@ class Container:
|
|
466
673
|
# Ensure that the instance is a valid instance
|
467
674
|
self.__ensureInstance(instance)
|
468
675
|
|
676
|
+
# Ensure that instance is NOT a subclass of abstract
|
469
677
|
if enforce_decoupling:
|
470
|
-
# Ensure that instance is NOT a subclass of abstract
|
471
678
|
self.__ensureIsNotSubclass(abstract, instance.__class__)
|
679
|
+
|
680
|
+
# Validate that instance is a subclass of abstract
|
472
681
|
else:
|
473
|
-
# Validate that instance is a subclass of abstract
|
474
682
|
self.__ensureIsSubclass(abstract, instance.__class__)
|
475
683
|
|
476
684
|
# Ensure implementation
|
@@ -482,19 +690,165 @@ class Container:
|
|
482
690
|
# Ensure that the alias is a valid string if provided
|
483
691
|
if alias:
|
484
692
|
self.__ensureAliasType(alias)
|
693
|
+
else:
|
694
|
+
rf_asbtract = ReflectionAbstract(abstract)
|
695
|
+
alias = rf_asbtract.getModuleWithClassName()
|
696
|
+
|
697
|
+
# If the service is already registered, drop it
|
698
|
+
self.__dropService(abstract, alias)
|
485
699
|
|
486
700
|
# Register the instance with the abstract type
|
487
|
-
self.
|
701
|
+
self.__bindings[abstract] = Binding(
|
702
|
+
contract = abstract,
|
703
|
+
instance = instance,
|
704
|
+
lifetime = Lifetime.SINGLETON,
|
705
|
+
enforce_decoupling = enforce_decoupling,
|
706
|
+
alias = alias
|
707
|
+
)
|
488
708
|
|
489
|
-
#
|
490
|
-
|
491
|
-
self.__instance[alias] = instance
|
492
|
-
elif hasattr(abstract, '__name__'):
|
493
|
-
alias = abstract.__name__
|
494
|
-
self.__instance[alias] = instance
|
709
|
+
# Register the alias
|
710
|
+
self.__aliasses[alias] = self.__bindings[abstract]
|
495
711
|
|
496
712
|
# Return True to indicate successful registration
|
497
713
|
return True
|
498
714
|
|
499
|
-
def
|
500
|
-
|
715
|
+
def function(
|
716
|
+
self,
|
717
|
+
alias: str,
|
718
|
+
function: Callable[..., Any],
|
719
|
+
*,
|
720
|
+
lifetime: Lifetime = Lifetime.TRANSIENT
|
721
|
+
) -> bool:
|
722
|
+
"""
|
723
|
+
Registers a function or factory under a given alias.
|
724
|
+
|
725
|
+
Parameters
|
726
|
+
----------
|
727
|
+
alias : str
|
728
|
+
The alias to register the function under.
|
729
|
+
function : Callable[..., Any]
|
730
|
+
The function or factory to register.
|
731
|
+
lifetime : Lifetime, optional
|
732
|
+
The lifetime of the function registration (default is TRANSIENT).
|
733
|
+
|
734
|
+
Returns
|
735
|
+
-------
|
736
|
+
bool
|
737
|
+
True if the function was registered successfully.
|
738
|
+
|
739
|
+
Raises
|
740
|
+
------
|
741
|
+
OrionisContainerTypeError
|
742
|
+
If the alias is invalid or the function is not callable.
|
743
|
+
OrionisContainerException
|
744
|
+
If the lifetime is not allowed for the function signature.
|
745
|
+
"""
|
746
|
+
# Normalize and validate the lifetime parameter
|
747
|
+
if not isinstance(lifetime, Lifetime):
|
748
|
+
if isinstance(lifetime, str):
|
749
|
+
lifetime_key = lifetime.strip().upper()
|
750
|
+
if lifetime_key in Lifetime.__members__:
|
751
|
+
lifetime = Lifetime[lifetime_key]
|
752
|
+
else:
|
753
|
+
valid = ', '.join(Lifetime.__members__.keys())
|
754
|
+
raise OrionisContainerTypeError(
|
755
|
+
f"Invalid lifetime '{lifetime}'. Valid options are: {valid}."
|
756
|
+
)
|
757
|
+
else:
|
758
|
+
raise OrionisContainerTypeError(
|
759
|
+
f"Lifetime must be of type str or Lifetime enum, got {type(lifetime).__name__}."
|
760
|
+
)
|
761
|
+
|
762
|
+
# Ensure that the alias is a valid string
|
763
|
+
self.__ensureAliasType(alias)
|
764
|
+
|
765
|
+
# Validate that the function is callable
|
766
|
+
self.__ensureIsCallable(function)
|
767
|
+
|
768
|
+
# Inspect the function signature
|
769
|
+
params = ReflectionCallable(function).getDependencies()
|
770
|
+
|
771
|
+
# If the function requires arguments, only allow TRANSIENT
|
772
|
+
if (len(params.resolved) + len(params.unresolved)) > 0 and lifetime != Lifetime.TRANSIENT:
|
773
|
+
raise OrionisContainerException(
|
774
|
+
"Functions that require arguments can only be registered with a TRANSIENT lifetime."
|
775
|
+
)
|
776
|
+
|
777
|
+
# If the service is already registered, drop it
|
778
|
+
self.__dropService(None, alias)
|
779
|
+
|
780
|
+
# Register the function with the specified alias and lifetime
|
781
|
+
self.__bindings[alias] = Binding(
|
782
|
+
function=function,
|
783
|
+
lifetime=lifetime,
|
784
|
+
alias=alias
|
785
|
+
)
|
786
|
+
|
787
|
+
# Register the function as a binding
|
788
|
+
self.__aliasses[alias] = self.__bindings[alias]
|
789
|
+
|
790
|
+
return True
|
791
|
+
|
792
|
+
def bound(
|
793
|
+
self,
|
794
|
+
abstract_or_alias: Any,
|
795
|
+
) -> bool:
|
796
|
+
"""
|
797
|
+
Checks if a service (by abstract type or alias) is registered in the container.
|
798
|
+
|
799
|
+
Parameters
|
800
|
+
----------
|
801
|
+
abstract_or_alias : Any
|
802
|
+
The abstract class, interface, or alias (str) to check for registration.
|
803
|
+
|
804
|
+
Returns
|
805
|
+
-------
|
806
|
+
bool
|
807
|
+
True if the service is registered (either as an abstract type or alias), False otherwise.
|
808
|
+
|
809
|
+
Notes
|
810
|
+
-----
|
811
|
+
This method allows you to verify whether a service has been registered in the container,
|
812
|
+
either by its abstract type or by its alias. It supports both class-based and string-based lookups.
|
813
|
+
"""
|
814
|
+
return (
|
815
|
+
abstract_or_alias in self.__bindings
|
816
|
+
or abstract_or_alias in self.__aliasses
|
817
|
+
)
|
818
|
+
|
819
|
+
def make(
|
820
|
+
self,
|
821
|
+
abstract_or_alias: Any,
|
822
|
+
*args,
|
823
|
+
**kwargs
|
824
|
+
) -> Any:
|
825
|
+
"""
|
826
|
+
Resolves and returns an instance of the requested service.
|
827
|
+
|
828
|
+
Parameters
|
829
|
+
----------
|
830
|
+
abstract_or_alias : Any
|
831
|
+
The abstract class, interface, or alias (str) to resolve.
|
832
|
+
*args : tuple
|
833
|
+
Positional arguments to pass to the constructor of the resolved service.
|
834
|
+
**kwargs : dict
|
835
|
+
Keyword arguments to pass to the constructor of the resolved service.
|
836
|
+
|
837
|
+
Returns
|
838
|
+
-------
|
839
|
+
Any
|
840
|
+
An instance of the requested service.
|
841
|
+
|
842
|
+
Raises
|
843
|
+
------
|
844
|
+
OrionisContainerException
|
845
|
+
If the requested service is not registered in the container.
|
846
|
+
"""
|
847
|
+
if not self.bound(abstract_or_alias):
|
848
|
+
raise OrionisContainerException(
|
849
|
+
f"The requested service '{abstract_or_alias}' is not registered in the container."
|
850
|
+
)
|
851
|
+
|
852
|
+
binding = self.__bindings.get(abstract_or_alias) or self.__aliasses.get(abstract_or_alias)
|
853
|
+
|
854
|
+
print(binding)
|