orionis 0.319.0__py3-none-any.whl → 0.320.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.
@@ -5,6 +5,14 @@ from orionis.container.entities.binding import Binding
5
5
  from orionis.container.enums.lifetimes import Lifetime
6
6
  from orionis.container.exceptions.container_exception import OrionisContainerException
7
7
  from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
8
+ from orionis.container.validators.implements import ImplementsAbstractMethods
9
+ from orionis.container.validators.is_abstract_class import IsAbstractClass
10
+ from orionis.container.validators.is_callable import IsCallable
11
+ from orionis.container.validators.is_concrete_class import IsConcreteClass
12
+ from orionis.container.validators.is_instance import IsInstance
13
+ from orionis.container.validators.is_not_subclass import IsNotSubclass
14
+ from orionis.container.validators.is_subclass import IsSubclass
15
+ from orionis.container.validators.is_valid_alias import IsValidAlias
8
16
  from orionis.services.introspection.abstract.reflection_abstract import ReflectionAbstract
9
17
  from orionis.services.introspection.callables.reflection_callable import ReflectionCallable
10
18
  from orionis.services.introspection.concretes.reflection_concrete import ReflectionConcrete
@@ -51,10 +59,20 @@ class Container(IContainer):
51
59
  Container
52
60
  The singleton instance of the class.
53
61
  """
62
+
63
+ # Check if the class has an existing instance
54
64
  if cls._instance is None:
65
+
66
+ # Acquire the lock to ensure thread safety during instance creation
55
67
  with cls._lock:
68
+
69
+ # If the instance is still None, create a new instance
56
70
  if cls._instance is None:
71
+
72
+ # Call the superclass's __new__ method to create a new instance
57
73
  cls._instance = super(Container, cls).__new__(cls)
74
+
75
+ # Return the existing instance of the class
58
76
  return cls._instance
59
77
 
60
78
  def __init__(
@@ -75,362 +93,19 @@ class Container(IContainer):
75
93
  - Initialization occurs only once per class, regardless of the number of instances.
76
94
  - The container registers itself under the IContainer interface to allow for dependency injection.
77
95
  """
96
+
97
+ # Check if the class has been initialized
78
98
  if not self.__class__._initialized:
99
+
100
+ # Initialize the container's internal state
79
101
  self.__bindings = {}
80
102
  self.__aliasses = {}
81
- self.__class__._initialized = True
82
- self.instance(IContainer, self)
83
-
84
- def __dropService(
85
- self,
86
- abstract: Callable[..., Any] = None,
87
- alias: str = None
88
- ) -> None:
89
- """
90
- Drops a service from the container.
91
-
92
- Parameters
93
- ----------
94
- abstract : Callable[..., Any]
95
- The abstract type or interface to be removed.
96
- alias : str, optional
97
- The alias of the service to be removed. If not provided, the service will be removed by its abstract type.
98
-
99
- Raises
100
- ------
101
- OrionisContainerException
102
- If the service does not exist in the container.
103
- """
104
-
105
- # If abstract is provided
106
- if abstract:
107
-
108
- # Remove the abstract service from the bindings if it exists
109
- if abstract in self.__bindings:
110
- del self.__bindings[abstract]
111
-
112
- # Remove the default alias (module + class name) from aliases if it exists
113
- abs_alias = ReflectionAbstract(abstract).getModuleWithClassName()
114
- if abs_alias in self.__aliasses:
115
- del self.__aliasses[abs_alias]
116
-
117
- # If a custom alias is provided
118
- if alias:
119
-
120
- # Remove it from the aliases dictionary if it exists
121
- if alias in self.__aliasses:
122
- del self.__aliasses[alias]
123
-
124
- # Remove the binding associated with the alias
125
- if alias in self.__bindings:
126
- del self.__bindings[alias]
127
-
128
- def __ensureIsCallable(
129
- self,
130
- value: Any
131
- ) -> None:
132
- """
133
- Ensures that the provided value is callable.
134
-
135
- Parameters
136
- ----------
137
- value : Any
138
- The value to check.
139
-
140
- Raises
141
- ------
142
- OrionisContainerTypeError
143
- If the value is not callable.
144
- """
145
-
146
- if not callable(value):
147
- raise OrionisContainerTypeError(
148
- f"Expected a callable type, but got {type(value).__name__} instead."
149
- )
150
-
151
- def __ensureAliasType(
152
- self,
153
- value: Any
154
- ) -> None:
155
- """
156
- Ensures that the provided value is a valid alias of type str and does not contain invalid characters.
157
-
158
- Parameters
159
- ----------
160
- value : Any
161
- The value to check.
162
-
163
- Raises
164
- ------
165
- OrionisContainerTypeError
166
- If the value is not of type str or contains invalid characters.
167
-
168
- Notes
169
- -----
170
- This method validates that a given value is a string and does not contain characters
171
- that could cause errors when resolving dependencies (e.g., whitespace, special symbols).
172
- """
173
-
174
- # Check if the value is a string
175
- if not isinstance(value, str):
176
- raise OrionisContainerTypeError(
177
- f"Expected a string type for alias, but got {type(value).__name__} instead."
178
- )
179
-
180
- # Define a set of invalid characters for aliases
181
- invalid_chars = set(' \t\n\r\x0b\x0c!@#$%^&*()[]{};:,/<>?\\|`~"\'')
182
- if any(char in invalid_chars for char in value):
183
- raise OrionisContainerTypeError(
184
- f"Alias '{value}' contains invalid characters. "
185
- "Aliases must not contain whitespace or special symbols."
186
- )
187
-
188
- def __ensureAbstractClass(
189
- self,
190
- abstract: Callable[..., Any],
191
- lifetime: str
192
- ) -> None:
193
- """
194
- Ensures that the provided abstract is an abstract class.
195
-
196
- Parameters
197
- ----------
198
- abstract : Callable[..., Any]
199
- The class intended to represent the abstract type.
200
- lifetime : str
201
- The service lifetime descriptor, used for error messages.
202
-
203
- Raises
204
- ------
205
- OrionisContainerTypeError
206
- If the abstract class check fails.
207
- """
208
- try:
209
- ReflectionAbstract.ensureIsAbstractClass(abstract)
210
- except Exception as e:
211
- raise OrionisContainerTypeError(
212
- f"Unexpected error registering {lifetime} service: {e}"
213
- ) from e
214
-
215
- def __ensureConcreteClass(
216
- self,
217
- concrete: Callable[..., Any],
218
- lifetime: str
219
- ) -> None:
220
- """
221
- Ensures that the provided concrete is a concrete (non-abstract) class.
222
-
223
- Parameters
224
- ----------
225
- concrete : Callable[..., Any]
226
- The class intended to represent the concrete implementation.
227
- lifetime : str
228
- The service lifetime descriptor, used for error messages.
229
-
230
- Raises
231
- ------
232
- OrionisContainerTypeError
233
- If the concrete class check fails.
234
- """
235
- try:
236
- ReflectionConcrete.ensureIsConcreteClass(concrete)
237
- except Exception as e:
238
- raise OrionisContainerTypeError(
239
- f"Unexpected error registering {lifetime} service: {e}"
240
- ) from e
241
-
242
- def __ensureIsSubclass(
243
- self,
244
- abstract: Callable[..., Any],
245
- concrete: Callable[..., Any]
246
- ) -> None:
247
- """
248
- Validates that the concrete class is a subclass of the provided abstract class.
249
-
250
- Parameters
251
- ----------
252
- abstract : Callable[..., Any]
253
- The abstract base class or interface.
254
- concrete : Callable[..., Any]
255
- The concrete implementation class to check.
256
-
257
- Raises
258
- ------
259
- OrionisContainerException
260
- If the concrete class is NOT a subclass of the abstract class.
261
-
262
- Notes
263
- -----
264
- This method ensures that the concrete implementation inherits from the abstract class,
265
- which is required for proper dependency injection and interface enforcement.
266
- """
267
- if not issubclass(concrete, abstract):
268
- raise OrionisContainerException(
269
- "The concrete class must inherit from the provided abstract class. "
270
- "Please ensure that the concrete class is a subclass of the specified abstract class."
271
- )
272
-
273
- def __ensureIsNotSubclass(
274
- self,
275
- abstract: Callable[..., Any],
276
- concrete: Callable[..., Any]
277
- ) -> None:
278
- """
279
- Validates that the concrete class is NOT a subclass of the provided abstract class.
280
-
281
- Parameters
282
- ----------
283
- abstract : Callable[..., Any]
284
- The abstract base class or interface.
285
- concrete : Callable[..., Any]
286
- The concrete implementation class to check.
287
-
288
- Raises
289
- ------
290
- OrionisContainerException
291
- If the concrete class IS a subclass of the abstract class.
292
-
293
- Notes
294
- -----
295
- This method ensures that the concrete implementation does NOT inherit from the abstract class.
296
- """
297
- if issubclass(concrete, abstract):
298
- raise OrionisContainerException(
299
- "The concrete class must NOT inherit from the provided abstract class. "
300
- "Please ensure that the concrete class is not a subclass of the specified abstract class."
301
- )
302
-
303
- def __ensureInstance(
304
- self,
305
- instance: Any
306
- ) -> None:
307
- """
308
- Ensures that the provided object is a valid instance.
309
-
310
- Parameters
311
- ----------
312
- instance : Any
313
- The object to be validated as an instance.
314
-
315
- Raises
316
- ------
317
- OrionisContainerTypeError
318
- If the provided object is not a valid instance.
319
-
320
- Notes
321
- -----
322
- This method uses ReflectionInstance to verify that the given object
323
- is a proper instance (not a class or abstract type). If the check fails,
324
- an OrionisContainerTypeError is raised with a descriptive message.
325
- """
326
- try:
327
- ReflectionInstance.ensureIsInstance(instance)
328
- except Exception as e:
329
- raise OrionisContainerTypeError(
330
- f"Error registering instance: {e}"
331
- ) from e
332
-
333
- def __ensureImplementation(
334
- self,
335
- *,
336
- abstract: Callable[..., Any] = None,
337
- concrete: Callable[..., Any] = None,
338
- instance: Any = None
339
- ) -> None:
340
- """
341
- Ensures that a concrete class or instance implements all abstract methods defined in an abstract class.
342
-
343
- Parameters
344
- ----------
345
- abstract : Callable[..., Any]
346
- The abstract class containing abstract methods.
347
- concrete : Callable[..., Any], optional
348
- The concrete class that should implement the abstract methods.
349
- instance : Any, optional
350
- The instance that should implement the abstract methods.
351
-
352
- Raises
353
- ------
354
- OrionisContainerException
355
- If the concrete class or instance does not implement all abstract methods defined in the abstract class.
356
-
357
- Notes
358
- -----
359
- This method checks that all abstract methods in the given abstract class are implemented
360
- in the provided concrete class or instance. If any methods are missing, an exception is raised with
361
- details about the missing implementations.
362
- """
363
- if abstract is None:
364
- raise OrionisContainerException("Abstract class must be provided for implementation check.")
365
-
366
- abstract_methods = getattr(abstract, '__abstractmethods__', set())
367
- if not abstract_methods:
368
- raise OrionisContainerException(
369
- f"The abstract class '{abstract.__name__}' does not define any abstract methods. "
370
- "An abstract class must have at least one abstract method."
371
- )
372
-
373
- target = concrete if concrete is not None else instance
374
- if target is None:
375
- raise OrionisContainerException("Either concrete class or instance must be provided for implementation check.")
376
-
377
- target_class = target if Reflection.isClass(target) else target.__class__
378
- target_name = target_class.__name__
379
- abstract_name = abstract.__name__
380
-
381
- not_implemented = []
382
- for method in abstract_methods:
383
- if not hasattr(target, str(method).replace(f"_{abstract_name}", f"_{target_name}")):
384
- not_implemented.append(method)
385
-
386
- if not_implemented:
387
- formatted_methods = "\n • " + "\n • ".join(not_implemented)
388
- raise OrionisContainerException(
389
- f"'{target_name}' does not implement the following abstract methods defined in '{abstract_name}':{formatted_methods}\n"
390
- "Please ensure that all abstract methods are implemented."
391
- )
392
-
393
- def __getService(
394
- self,
395
- abstract_or_alias: Any
396
- ) -> Binding:
397
- """
398
- Retrieves the binding for the requested abstract type or alias.
399
-
400
- Parameters
401
- ----------
402
- abstract_or_alias : Any
403
- The abstract class, interface, or alias (str) to retrieve.
404
-
405
- Returns
406
- -------
407
- Binding
408
- The binding associated with the requested abstract type or alias.
409
- """
410
- return self.__bindings.get(abstract_or_alias) or self.__aliasses.get(abstract_or_alias)
411
103
 
412
- def __getFirstService(
413
- self,
414
- abstract_or_aliasses: list
415
- ) -> Binding:
416
- """
417
- Retrieves the first binding from a list of abstract types or aliases.
418
-
419
- Parameters
420
- ----------
421
- abstract_or_aliasses : list
422
- A list of abstract classes, interfaces, or aliases (str) to retrieve.
104
+ # Set the initialized flag to True to prevent re-initialization
105
+ self.__class__._initialized = True
423
106
 
424
- Returns
425
- -------
426
- Binding
427
- The first binding found in the container for the provided abstract types or aliases.
428
- """
429
- for item in abstract_or_aliasses:
430
- binding = self.__getService(item)
431
- if binding:
432
- return binding
433
- return None
107
+ # Register the container itself as a service
108
+ self.instance(IContainer, self)
434
109
 
435
110
  def transient(
436
111
  self,
@@ -472,28 +147,28 @@ class Container(IContainer):
472
147
  """
473
148
 
474
149
  # Ensure that abstract is an abstract class
475
- self.__ensureAbstractClass(abstract, Lifetime.TRANSIENT)
150
+ IsAbstractClass(abstract, Lifetime.TRANSIENT)
476
151
 
477
152
  # Ensure that concrete is a concrete class
478
- self.__ensureConcreteClass(concrete, Lifetime.TRANSIENT)
153
+ IsConcreteClass(concrete, Lifetime.TRANSIENT)
479
154
 
480
155
  # Ensure that concrete is NOT a subclass of abstract
481
156
  if enforce_decoupling:
482
- self.__ensureIsNotSubclass(abstract, concrete)
157
+ IsNotSubclass(abstract, concrete)
483
158
 
484
159
  # Validate that concrete is a subclass of abstract
485
160
  else:
486
- self.__ensureIsSubclass(abstract, concrete)
161
+ IsSubclass(abstract, concrete)
487
162
 
488
163
  # Ensure implementation
489
- self.__ensureImplementation(
164
+ ImplementsAbstractMethods(
490
165
  abstract=abstract,
491
166
  concrete=concrete
492
167
  )
493
168
 
494
169
  # Ensure that the alias is a valid string if provided
495
170
  if alias:
496
- self.__ensureAliasType(alias)
171
+ IsValidAlias(alias)
497
172
 
498
173
  # Extract the module and class name for the alias
499
174
  else:
@@ -501,7 +176,7 @@ class Container(IContainer):
501
176
  alias = rf_asbtract.getModuleWithClassName()
502
177
 
503
178
  # If the service is already registered, drop it
504
- self.__dropService(abstract, alias)
179
+ self.drop(abstract, alias)
505
180
 
506
181
  # Register the service with transient lifetime
507
182
  self.__bindings[abstract] = Binding(
@@ -557,34 +232,34 @@ class Container(IContainer):
557
232
  """
558
233
 
559
234
  # Ensure that abstract is an abstract class
560
- self.__ensureAbstractClass(abstract, Lifetime.SINGLETON)
235
+ IsAbstractClass(abstract, Lifetime.SINGLETON)
561
236
 
562
237
  # Ensure that concrete is a concrete class
563
- self.__ensureConcreteClass(concrete, Lifetime.SINGLETON)
238
+ IsConcreteClass(concrete, Lifetime.SINGLETON)
564
239
 
565
240
  # Ensure that concrete is NOT a subclass of abstract
566
241
  if enforce_decoupling:
567
- self.__ensureIsNotSubclass(abstract, concrete)
242
+ IsNotSubclass(abstract, concrete)
568
243
 
569
244
  # Validate that concrete is a subclass of abstract
570
245
  else:
571
- self.__ensureIsSubclass(abstract, concrete)
246
+ IsSubclass(abstract, concrete)
572
247
 
573
248
  # Ensure implementation
574
- self.__ensureImplementation(
249
+ ImplementsAbstractMethods(
575
250
  abstract=abstract,
576
251
  concrete=concrete
577
252
  )
578
253
 
579
254
  # Ensure that the alias is a valid string if provided
580
255
  if alias:
581
- self.__ensureAliasType(alias)
256
+ IsValidAlias(alias)
582
257
  else:
583
258
  rf_asbtract = ReflectionAbstract(abstract)
584
259
  alias = rf_asbtract.getModuleWithClassName()
585
260
 
586
261
  # If the service is already registered, drop it
587
- self.__dropService(abstract, alias)
262
+ self.drop(abstract, alias)
588
263
 
589
264
  # Register the service with singleton lifetime
590
265
  self.__bindings[abstract] = Binding(
@@ -640,34 +315,34 @@ class Container(IContainer):
640
315
  """
641
316
 
642
317
  # Ensure that abstract is an abstract class
643
- self.__ensureAbstractClass(abstract, Lifetime.SCOPED)
318
+ IsAbstractClass(abstract, Lifetime.SCOPED)
644
319
 
645
320
  # Ensure that concrete is a concrete class
646
- self.__ensureConcreteClass(concrete, Lifetime.SCOPED)
321
+ IsConcreteClass(concrete, Lifetime.SCOPED)
647
322
 
648
323
  # Ensure that concrete is NOT a subclass of abstract
649
324
  if enforce_decoupling:
650
- self.__ensureIsNotSubclass(abstract, concrete)
325
+ IsNotSubclass(abstract, concrete)
651
326
 
652
327
  # Validate that concrete is a subclass of abstract
653
328
  else:
654
- self.__ensureIsSubclass(abstract, concrete)
329
+ IsSubclass(abstract, concrete)
655
330
 
656
331
  # Ensure implementation
657
- self.__ensureImplementation(
332
+ ImplementsAbstractMethods(
658
333
  abstract=abstract,
659
334
  concrete=concrete
660
335
  )
661
336
 
662
337
  # Ensure that the alias is a valid string if provided
663
338
  if alias:
664
- self.__ensureAliasType(alias)
339
+ IsValidAlias(alias)
665
340
  else:
666
341
  rf_asbtract = ReflectionAbstract(abstract)
667
342
  alias = rf_asbtract.getModuleWithClassName()
668
343
 
669
344
  # If the service is already registered, drop it
670
- self.__dropService(abstract, alias)
345
+ self.drop(abstract, alias)
671
346
 
672
347
  # Register the service with scoped lifetime
673
348
  self.__bindings[abstract] = Binding(
@@ -721,34 +396,34 @@ class Container(IContainer):
721
396
  """
722
397
 
723
398
  # Ensure that the abstract is an abstract class
724
- self.__ensureAbstractClass(abstract, f"Instance {Lifetime.SINGLETON}")
399
+ IsAbstractClass(abstract, f"Instance {Lifetime.SINGLETON}")
725
400
 
726
401
  # Ensure that the instance is a valid instance
727
- self.__ensureInstance(instance)
402
+ IsInstance(instance)
728
403
 
729
404
  # Ensure that instance is NOT a subclass of abstract
730
405
  if enforce_decoupling:
731
- self.__ensureIsNotSubclass(abstract, instance.__class__)
406
+ IsNotSubclass(abstract, instance.__class__)
732
407
 
733
408
  # Validate that instance is a subclass of abstract
734
409
  else:
735
- self.__ensureIsSubclass(abstract, instance.__class__)
410
+ IsSubclass(abstract, instance.__class__)
736
411
 
737
412
  # Ensure implementation
738
- self.__ensureImplementation(
413
+ ImplementsAbstractMethods(
739
414
  abstract=abstract,
740
415
  instance=instance
741
416
  )
742
417
 
743
418
  # Ensure that the alias is a valid string if provided
744
419
  if alias:
745
- self.__ensureAliasType(alias)
420
+ IsValidAlias(alias)
746
421
  else:
747
422
  rf_asbtract = ReflectionAbstract(abstract)
748
423
  alias = rf_asbtract.getModuleWithClassName()
749
424
 
750
425
  # If the service is already registered, drop it
751
- self.__dropService(abstract, alias)
426
+ self.drop(abstract, alias)
752
427
 
753
428
  # Register the instance with the abstract type
754
429
  self.__bindings[abstract] = Binding(
@@ -813,10 +488,10 @@ class Container(IContainer):
813
488
  )
814
489
 
815
490
  # Ensure that the alias is a valid string
816
- self.__ensureAliasType(alias)
491
+ IsValidAlias(alias)
817
492
 
818
493
  # Validate that the function is callable
819
- self.__ensureIsCallable(fn)
494
+ IsCallable(fn)
820
495
 
821
496
  # Inspect the function signature
822
497
  params = ReflectionCallable(fn).getDependencies()
@@ -828,7 +503,7 @@ class Container(IContainer):
828
503
  )
829
504
 
830
505
  # If the service is already registered, drop it
831
- self.__dropService(None, alias)
506
+ self.drop(None, alias)
832
507
 
833
508
  # Register the function with the specified alias and lifetime
834
509
  self.__bindings[alias] = Binding(
@@ -869,6 +544,99 @@ class Container(IContainer):
869
544
  or abstract_or_alias in self.__aliasses
870
545
  )
871
546
 
547
+ def __getService(
548
+ self,
549
+ abstract_or_alias: Any
550
+ ) -> Binding:
551
+ """
552
+ Retrieves the binding for the requested abstract type or alias.
553
+
554
+ Parameters
555
+ ----------
556
+ abstract_or_alias : Any
557
+ The abstract class, interface, or alias (str) to retrieve.
558
+
559
+ Returns
560
+ -------
561
+ Binding
562
+ The binding associated with the requested abstract type or alias.
563
+ """
564
+ return self.__bindings.get(abstract_or_alias) or self.__aliasses.get(abstract_or_alias)
565
+
566
+ def __getFirstService(
567
+ self,
568
+ abstract_or_aliasses: list
569
+ ) -> Binding:
570
+ """
571
+ Retrieves the first binding from a list of abstract types or aliases.
572
+
573
+ Parameters
574
+ ----------
575
+ abstract_or_aliasses : list
576
+ A list of abstract classes, interfaces, or aliases (str) to retrieve.
577
+
578
+ Returns
579
+ -------
580
+ Binding
581
+ The first binding found in the container for the provided abstract types or aliases.
582
+ """
583
+ for item in abstract_or_aliasses:
584
+ binding = self.__getService(item)
585
+ if binding:
586
+ return binding
587
+ return None
588
+
589
+ def drop(
590
+ self,
591
+ abstract: Callable[..., Any] = None,
592
+ alias: str = None
593
+ ) -> None:
594
+ """
595
+ Drops a service from the container by removing its bindings and aliases.
596
+ This method allows removing registered services from the dependency injection container,
597
+ either by their abstract type or by their alias. When a service is dropped,
598
+ all its bindings and aliases are removed from the container.
599
+
600
+ Warning
601
+ -------
602
+ Using this method irresponsibly can severely damage the system's logic.
603
+ Only use it when you are certain about the consequences, as removing
604
+ critical services may lead to system failures and unexpected behavior.
605
+ abstract : Callable[..., Any], optional
606
+ The abstract type or interface to be removed from the container.
607
+ If provided, both the binding and the default alias for this type will be removed.
608
+ The alias of the service to be removed. If provided, both the alias entry
609
+ and any associated binding will be removed.
610
+
611
+ Notes
612
+ -----
613
+ At least one parameter (abstract or alias) must be provided for the method to take effect.
614
+ If both are provided, both will be processed independently.
615
+ """
616
+
617
+ # If abstract is provided
618
+ if abstract:
619
+
620
+ # Remove the abstract service from the bindings if it exists
621
+ if abstract in self.__bindings:
622
+ del self.__bindings[abstract]
623
+
624
+ # Remove the default alias (module + class name) from aliases if it exists
625
+ abs_alias = ReflectionAbstract(abstract).getModuleWithClassName()
626
+ if abs_alias in self.__aliasses:
627
+ del self.__aliasses[abs_alias]
628
+
629
+ # If a custom alias is provided
630
+ if alias:
631
+
632
+ # Remove it from the aliases dictionary if it exists
633
+ if alias in self.__aliasses:
634
+ del self.__aliasses[alias]
635
+
636
+ # Remove the binding associated with the alias
637
+ if alias in self.__bindings:
638
+ del self.__bindings[alias]
639
+
872
640
  def make(
873
641
  self,
874
642
  abstract_or_alias: Any,
@@ -0,0 +1,28 @@
1
+ from orionis.container.contracts.container import IContainer
2
+ from orionis.container.entities.binding import Binding
3
+ from orionis.container.enums.lifetimes import Lifetime
4
+
5
+
6
+ class Resolver:
7
+ """
8
+ Resolver class for handling dependency resolution in the container.
9
+ """
10
+
11
+ def __init__(
12
+ self,
13
+ container:IContainer,
14
+ lifetime:Lifetime
15
+ ):
16
+ self.container = container
17
+ self.lifetime = lifetime
18
+
19
+ def transient(
20
+ self,
21
+ binding:Binding,
22
+ *args,
23
+ **kwargs
24
+ ):
25
+ """
26
+ Register a transient service.
27
+ """
28
+ return self.container.transient(service, implementation, **kwargs)
File without changes
@@ -0,0 +1,67 @@
1
+ from typing import Callable, Any
2
+ from orionis.services.introspection.reflection import Reflection
3
+ from orionis.container.exceptions.container_exception import OrionisContainerException
4
+
5
+ class _ImplementsAbstractMethods:
6
+ """
7
+ Validator that ensures a concrete class or instance implements all abstract methods of an abstract class.
8
+ """
9
+
10
+ def __call__(
11
+ self,
12
+ *,
13
+ abstract: Callable[..., Any] = None,
14
+ concrete: Callable[..., Any] = None,
15
+ instance: Any = None
16
+ ) -> None:
17
+ """
18
+ Validates that a concrete class or instance implements all abstract methods defined in an abstract class.
19
+
20
+ Parameters
21
+ ----------
22
+ abstract : Callable[..., Any]
23
+ The abstract base class.
24
+ concrete : Callable[..., Any], optional
25
+ The class expected to implement the abstract methods.
26
+ instance : Any, optional
27
+ The instance expected to implement the abstract methods.
28
+
29
+ Raises
30
+ ------
31
+ OrionisContainerException
32
+ If any abstract method is not implemented.
33
+ """
34
+ if abstract is None:
35
+ raise OrionisContainerException("Abstract class must be provided for implementation check.")
36
+
37
+ abstract_methods = getattr(abstract, '__abstractmethods__', set())
38
+ if not abstract_methods:
39
+ raise OrionisContainerException(
40
+ f"The abstract class '{abstract.__name__}' does not define any abstract methods. "
41
+ "An abstract class must have at least one abstract method."
42
+ )
43
+
44
+ target = concrete if concrete is not None else instance
45
+ if target is None:
46
+ raise OrionisContainerException("Either concrete class or instance must be provided for implementation check.")
47
+
48
+ target_class = target if Reflection.isClass(target) else target.__class__
49
+ target_name = target_class.__name__
50
+ abstract_name = abstract.__name__
51
+
52
+ not_implemented = []
53
+ for method in abstract_methods:
54
+ # Considera métodos renombrados en clases concretas (_Abstract.m → _Concrete.m)
55
+ expected_method = str(method).replace(f"_{abstract_name}", f"_{target_name}")
56
+ if not hasattr(target, expected_method):
57
+ not_implemented.append(method)
58
+
59
+ if not_implemented:
60
+ formatted = "\n • " + "\n • ".join(not_implemented)
61
+ raise OrionisContainerException(
62
+ f"'{target_name}' does not implement the following abstract methods defined in '{abstract_name}':{formatted}\n"
63
+ "Please ensure that all abstract methods are implemented."
64
+ )
65
+
66
+ # Exported singleton instance
67
+ ImplementsAbstractMethods = _ImplementsAbstractMethods()
@@ -0,0 +1,34 @@
1
+ from typing import Callable, Any
2
+ from orionis.services.introspection.abstract.reflection_abstract import ReflectionAbstract
3
+ from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
4
+
5
+ class _IsAbstractClass:
6
+ """
7
+ Validator that ensures a class is an abstract class.
8
+ """
9
+
10
+ def __call__(self, abstract: Callable[..., Any], lifetime: str) -> None:
11
+ """
12
+ Ensures that the provided class is an abstract class.
13
+
14
+ Parameters
15
+ ----------
16
+ abstract : Callable[..., Any]
17
+ The class intended to represent the abstract type.
18
+ lifetime : str
19
+ A string indicating the service lifetime, used in error messages.
20
+
21
+ Raises
22
+ ------
23
+ OrionisContainerTypeError
24
+ If the class is not abstract.
25
+ """
26
+ try:
27
+ ReflectionAbstract.ensureIsAbstractClass(abstract)
28
+ except Exception as e:
29
+ raise OrionisContainerTypeError(
30
+ f"Unexpected error registering {lifetime} service: {e}"
31
+ ) from e
32
+
33
+ # Exported singleton instance
34
+ IsAbstractClass = _IsAbstractClass()
@@ -0,0 +1,30 @@
1
+ from typing import Any
2
+ from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
3
+
4
+ class _IsCallable:
5
+ """
6
+ Validator that checks if a value is callable.
7
+ Can be used directly like a function: `IsCallable(value)`
8
+ """
9
+
10
+ def __call__(self, value: Any) -> None:
11
+ """
12
+ Ensures that the provided value is callable.
13
+
14
+ Parameters
15
+ ----------
16
+ value : Any
17
+ The value to check.
18
+
19
+ Raises
20
+ ------
21
+ OrionisContainerTypeError
22
+ If the value is not callable.
23
+ """
24
+ if not callable(value):
25
+ raise OrionisContainerTypeError(
26
+ f"Expected a callable type, but got {type(value).__name__} instead."
27
+ )
28
+
29
+ # Exported singleton instance
30
+ IsCallable = _IsCallable()
@@ -0,0 +1,34 @@
1
+ from typing import Callable, Any
2
+ from orionis.services.introspection.concretes.reflection_concrete import ReflectionConcrete
3
+ from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
4
+
5
+ class _IsConcreteClass:
6
+ """
7
+ Validator that ensures a class is a concrete (non-abstract) class.
8
+ """
9
+
10
+ def __call__(self, concrete: Callable[..., Any], lifetime: str) -> None:
11
+ """
12
+ Ensures that the provided class is a concrete (non-abstract) class.
13
+
14
+ Parameters
15
+ ----------
16
+ concrete : Callable[..., Any]
17
+ The class intended to represent the concrete implementation.
18
+ lifetime : str
19
+ A string indicating the service lifetime, used in error messages.
20
+
21
+ Raises
22
+ ------
23
+ OrionisContainerTypeError
24
+ If the class is abstract or invalid.
25
+ """
26
+ try:
27
+ ReflectionConcrete.ensureIsConcreteClass(concrete)
28
+ except Exception as e:
29
+ raise OrionisContainerTypeError(
30
+ f"Unexpected error registering {lifetime} service: {e}"
31
+ ) from e
32
+
33
+ # Exported singleton instance
34
+ IsConcreteClass = _IsConcreteClass()
@@ -0,0 +1,32 @@
1
+ from typing import Any
2
+ from orionis.services.introspection.instances.reflection_instance import ReflectionInstance
3
+ from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
4
+
5
+ class _IsInstance:
6
+ """
7
+ Validator that ensures the provided object is a valid instance (not a class or abstract type).
8
+ """
9
+
10
+ def __call__(self, instance: Any) -> None:
11
+ """
12
+ Ensures that the provided object is a valid instance.
13
+
14
+ Parameters
15
+ ----------
16
+ instance : Any
17
+ The object to be validated.
18
+
19
+ Raises
20
+ ------
21
+ OrionisContainerTypeError
22
+ If the object is not a valid instance.
23
+ """
24
+ try:
25
+ ReflectionInstance.ensureIsInstance(instance)
26
+ except Exception as e:
27
+ raise OrionisContainerTypeError(
28
+ f"Error registering instance: {e}"
29
+ ) from e
30
+
31
+ # Exported singleton instance
32
+ IsInstance = _IsInstance()
@@ -0,0 +1,32 @@
1
+ from typing import Callable
2
+ from orionis.container.exceptions.container_exception import OrionisContainerException
3
+
4
+ class _IsNotSubclass:
5
+ """
6
+ Validator that ensures a class is NOT a subclass of another class.
7
+ """
8
+
9
+ def __call__(self, abstract: Callable[..., any], concrete: Callable[..., any]) -> None:
10
+ """
11
+ Validates that the concrete class is NOT a subclass of the abstract class.
12
+
13
+ Parameters
14
+ ----------
15
+ abstract : Callable[..., Any]
16
+ The supposed base class or interface.
17
+ concrete : Callable[..., Any]
18
+ The implementation class to check.
19
+
20
+ Raises
21
+ ------
22
+ OrionisContainerException
23
+ If the concrete class IS a subclass of the abstract class.
24
+ """
25
+ if issubclass(concrete, abstract):
26
+ raise OrionisContainerException(
27
+ "The concrete class must NOT inherit from the provided abstract class. "
28
+ "Please ensure that the concrete class is not a subclass of the specified abstract class."
29
+ )
30
+
31
+ # Exported singleton instance
32
+ IsNotSubclass = _IsNotSubclass()
@@ -0,0 +1,32 @@
1
+ from typing import Callable
2
+ from orionis.container.exceptions.container_exception import OrionisContainerException
3
+
4
+ class _IsSubclass:
5
+ """
6
+ Validator that ensures a class is a subclass of a given abstract class.
7
+ """
8
+
9
+ def __call__(self, abstract: Callable[..., any], concrete: Callable[..., any]) -> None:
10
+ """
11
+ Validates that the concrete class is a subclass of the abstract class.
12
+
13
+ Parameters
14
+ ----------
15
+ abstract : Callable[..., Any]
16
+ The base or abstract class.
17
+ concrete : Callable[..., Any]
18
+ The class to verify.
19
+
20
+ Raises
21
+ ------
22
+ OrionisContainerException
23
+ If the concrete class is NOT a subclass of the abstract class.
24
+ """
25
+ if not issubclass(concrete, abstract):
26
+ raise OrionisContainerException(
27
+ "The concrete class must inherit from the provided abstract class. "
28
+ "Please ensure that the concrete class is a subclass of the specified abstract class."
29
+ )
30
+
31
+ # Exported singleton instance
32
+ IsSubclass = _IsSubclass()
@@ -0,0 +1,37 @@
1
+ from typing import Any
2
+ from orionis.container.exceptions.type_error_exception import OrionisContainerTypeError
3
+
4
+ class _IsValidAlias:
5
+ """
6
+ Validator that checks if a value is a valid alias string.
7
+ """
8
+
9
+ _INVALID_CHARS = set(' \t\n\r\x0b\x0c!@#$%^&*()[]{};:,/<>?\\|`~"\'')
10
+
11
+ def __call__(self, value: Any) -> None:
12
+ """
13
+ Ensures that the provided value is a valid alias of type str and does not contain invalid characters.
14
+
15
+ Parameters
16
+ ----------
17
+ value : Any
18
+ The value to check.
19
+
20
+ Raises
21
+ ------
22
+ OrionisContainerTypeError
23
+ If the value is not of type str or contains invalid characters.
24
+ """
25
+ if not isinstance(value, str):
26
+ raise OrionisContainerTypeError(
27
+ f"Expected a string type for alias, but got {type(value).__name__} instead."
28
+ )
29
+
30
+ if any(char in self._INVALID_CHARS for char in value):
31
+ raise OrionisContainerTypeError(
32
+ f"Alias '{value}' contains invalid characters. "
33
+ "Aliases must not contain whitespace or special symbols."
34
+ )
35
+
36
+ # Exported singleton instance
37
+ IsValidAlias = _IsValidAlias()
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.319.0"
8
+ VERSION = "0.320.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.319.0
3
+ Version: 0.320.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
@@ -135,13 +135,23 @@ orionis/console/output/console.py,sha256=TE_Hl720ADd82dbERFSWhkoQRukDQZmETSw4nkw
135
135
  orionis/console/output/executor.py,sha256=bdvkzW2-buy0BPpy2r5qUGrRFW2Ay6k-5rSeHb0gQ3o,3352
136
136
  orionis/console/output/progress_bar.py,sha256=vFy582z6VJS46LV6tuyrmr9qvdVeTEtw3hyNcEHezeg,3088
137
137
  orionis/console/output/styles.py,sha256=6a4oQCOBOKMh2ARdeq5GlIskJ3wjiylYmh66tUKKmpQ,4053
138
- orionis/container/container.py,sha256=ZL3S0HyAt8Hm58dPjltNMCSMNNP30VR61ByslzmCGgs,45066
138
+ orionis/container/container.py,sha256=HHEXnObv1Q_022dfGpTOx6cwyRPa7ooD8FfqJ_cDCro,37291
139
+ orionis/container/resolver.py,sha256=9nojqjrYYXw2kQUzyuLkHs-os5dDxq6ntZ8e8IbYIu0,704
139
140
  orionis/container/contracts/container.py,sha256=LkZ5til_3Um8ctCVTwuO36HkysL59saKwUzXR5cWUBs,5750
140
141
  orionis/container/entities/binding.py,sha256=Qp6Lf4XUDp2NjqXDAC2lzvhOFQWiBDKiGFcKfwb4axw,4342
141
142
  orionis/container/enums/lifetimes.py,sha256=RqQmugMIB1Ev_j_vFLcWorndm-to7xg4stQ7yKFDdDw,190
142
143
  orionis/container/exceptions/container_exception.py,sha256=goTDEwC70xTMD2qppN8KV-xyR0Nps218OD4D1LZ2-3s,470
143
144
  orionis/container/exceptions/type_error_exception.py,sha256=cYuvoXVOgRYj3tZPfK341aUERkf33-buOiI2eXxcrAw,470
144
145
  orionis/container/exceptions/value_exception.py,sha256=hjY0YEusoL3DurME1ornxvIv1wyGaf6tBggLFlGHblo,472
146
+ orionis/container/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
+ orionis/container/validators/implements.py,sha256=iSoDxxTalQKhyKjvsojFlkROhBFvAjvJxRvPJlmGrSg,2843
148
+ orionis/container/validators/is_abstract_class.py,sha256=Q-Lqyrrps6oj2XWI0KFRp-hDZf4_sgbZlEbfBXj5XT4,1169
149
+ orionis/container/validators/is_callable.py,sha256=8Bi5AflNmXhpgtk1ieirE3xgCKzq3mcgyqokCU3GHN8,843
150
+ orionis/container/validators/is_concrete_class.py,sha256=BMhJ7vCQ2ccBA3qrRJPlsYDTSqBpqLZFfrdEGO5mlr4,1215
151
+ orionis/container/validators/is_instance.py,sha256=vUwWIMeG1zLMsGX9GyoOU-LZtCgqBDZ9hUNDj_KyuYo,999
152
+ orionis/container/validators/is_not_subclass.py,sha256=-iZw5ZCYnQtlU-xPO-o7lUj5DxPkN0G67-bLbLVhwtw,1167
153
+ orionis/container/validators/is_subclass.py,sha256=O2aF0KLg5ZnDutKQ1xDvet34kentftlqgEkRNvumCoM,1135
154
+ orionis/container/validators/is_valid_alias.py,sha256=avm6uz-huVi_kRov4BksSToslIHQfz-MLynjkzhdSRM,1246
145
155
  orionis/foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
156
  orionis/foundation/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
157
  orionis/foundation/config/startup.py,sha256=JKAH2ZRhlAZgkD2w11LR1-TVktfjSH9cHo3PsZXOLrg,8275
@@ -233,7 +243,7 @@ orionis/foundation/contracts/config.py,sha256=Rpz6U6t8OXHO9JJKSTnCimytXE-tfCB-1i
233
243
  orionis/foundation/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
234
244
  orionis/foundation/exceptions/integrity.py,sha256=mc4pL1UMoYRHEmphnpW2oGk5URhu7DJRREyzHaV-cs8,472
235
245
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
236
- orionis/metadata/framework.py,sha256=MyXQ31_zvD5irlN_XvuSicVccDNBPb64XCKc8qujCEc,4960
246
+ orionis/metadata/framework.py,sha256=sBQIEDehFdisleRXQSFyOhHx2bVTGjprHNNBI_Famsw,4960
237
247
  orionis/metadata/package.py,sha256=tqLfBRo-w1j_GN4xvzUNFyweWYFS-qhSgAEc-AmCH1M,5452
238
248
  orionis/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
249
  orionis/patterns/singleton/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -345,7 +355,7 @@ orionis/test/suite/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
345
355
  orionis/test/suite/test_unit.py,sha256=MWgW8dRCRyT1XZ5LsbXQ7-KVPReasoXwzEEL1EWWfE4,52190
346
356
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
347
357
  orionis/test/view/render.py,sha256=jXZkbITBknbUwm_mD8bcTiwLDvsFkrO9qrf0ZgPwqxc,4903
348
- orionis-0.319.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
358
+ orionis-0.320.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
349
359
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
350
360
  tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
351
361
  tests/example/test_example.py,sha256=kvWgiW3ADEZf718dGsMPtDh_rmOSx1ypEInKm7_6ZPQ,601
@@ -446,8 +456,8 @@ tests/support/wrapper/test_services_wrapper_docdict.py,sha256=yeVwl-VcwkWSQYyxZu
446
456
  tests/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
447
457
  tests/testing/test_testing_result.py,sha256=MrGK3ZimedL0b5Ydu69Dg8Iul017AzLTm7VPxpXlpfU,4315
448
458
  tests/testing/test_testing_unit.py,sha256=DjLBtvVn8B1KlVJNNkstBT8_csA1yeaMqnGrbanN_J4,7438
449
- orionis-0.319.0.dist-info/METADATA,sha256=426gql1AFezl4n3-_ORGM8wdkUYcEsZr8n3ykl6ruOI,4772
450
- orionis-0.319.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
451
- orionis-0.319.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
452
- orionis-0.319.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
453
- orionis-0.319.0.dist-info/RECORD,,
459
+ orionis-0.320.0.dist-info/METADATA,sha256=J4HkjZk_1Wa2wuK0UZboolNPepT3CA4uflTNQrXlGk0,4772
460
+ orionis-0.320.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
461
+ orionis-0.320.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
462
+ orionis-0.320.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
463
+ orionis-0.320.0.dist-info/RECORD,,