orionis 0.7.0__py3-none-any.whl → 0.9.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/framework.py CHANGED
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.7.0"
8
+ VERSION = "0.9.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,8 +1,10 @@
1
1
  import inspect
2
2
  from typing import Any, Callable
3
+ from orionis.luminate.container.types import Types
4
+ from orionis.luminate.contracts.container.container_interface import IContainer
3
5
  from orionis.luminate.container.exception import OrionisContainerException, OrionisContainerValueError
4
6
 
5
- class Container:
7
+ class Container(IContainer):
6
8
  """Service container and dependency injection."""
7
9
 
8
10
  _instance = None
@@ -18,6 +20,8 @@ class Container:
18
20
  cls._instance._aliases = {}
19
21
  cls._instance._scoped_instances = {}
20
22
  cls._instance._conditional_bindings = {}
23
+ # Initialize the PrimitiveTypes validator
24
+ cls._instance._primitive_types_validator = Types()
21
25
  return cls._instance
22
26
 
23
27
  def bind(self, abstract: str, concrete: Callable[..., Any]) -> None:
@@ -31,6 +35,10 @@ class Container:
31
35
  OrionisContainerException: If the service is already registered.
32
36
  TypeError: If the implementation is not a callable or instantiable class.
33
37
  """
38
+
39
+ # Validate that the abstract name is not a primitive type
40
+ self._primitiveTypeValidator(abstract)
41
+
34
42
  if self.has(abstract):
35
43
  raise OrionisContainerException(f"The service '{abstract}' is already registered in the container.")
36
44
 
@@ -50,6 +58,10 @@ class Container:
50
58
  OrionisContainerException: If the service is already registered.
51
59
  TypeError: If the implementation is not a callable or instantiable class.
52
60
  """
61
+
62
+ # Validate that the abstract name is not a primitive type
63
+ self._primitiveTypeValidator(abstract)
64
+
53
65
  if self.has(abstract):
54
66
  raise OrionisContainerException(f"The service '{abstract}' is already registered in the container.")
55
67
 
@@ -69,6 +81,10 @@ class Container:
69
81
  OrionisContainerException: If the service is already registered.
70
82
  TypeError: If the implementation is not a callable or instantiable class.
71
83
  """
84
+
85
+ # Validate that the abstract name is not a primitive type
86
+ self._primitiveTypeValidator(abstract)
87
+
72
88
  if self.has(abstract):
73
89
  raise OrionisContainerException(f"The service '{abstract}' is already registered in the container.")
74
90
 
@@ -88,6 +104,10 @@ class Container:
88
104
  OrionisContainerException: If the service is already registered.
89
105
  TypeError: If the implementation is not a callable or instantiable class.
90
106
  """
107
+
108
+ # Validate that the abstract name is not a primitive type
109
+ self._primitiveTypeValidator(abstract)
110
+
91
111
  if self.has(abstract):
92
112
  raise OrionisContainerException(f"The service '{abstract}' is already registered in the container.")
93
113
 
@@ -107,6 +127,10 @@ class Container:
107
127
  OrionisContainerException: If the instance is already registered.
108
128
  ValueError: If the provided instance is of an unexpected or invalid type.
109
129
  """
130
+
131
+ # Validate that the abstract name is not a primitive type
132
+ self._primitiveTypeValidator(abstract)
133
+
110
134
  if abstract in self._instances:
111
135
  raise OrionisContainerException(f"The instance '{abstract}' is already registered in the container.")
112
136
 
@@ -151,6 +175,10 @@ class Container:
151
175
  OrionisContainerException: If the original service is not registered.
152
176
  ValueError: If the alias is not a valid string or is already in use.
153
177
  """
178
+
179
+ # Validate that the abstract name is not a primitive type
180
+ self._primitiveTypeValidator(abstract)
181
+
154
182
  # Validate alias type
155
183
  if not isinstance(alias, str) or not alias:
156
184
  raise ValueError("The alias must be a non-empty string.")
@@ -214,6 +242,57 @@ class Container:
214
242
 
215
243
  raise OrionisContainerValueError(f"No definition found for '{abstract}'. Ensure the service is registered.")
216
244
 
245
+ def call(self, instance: Any, method_name: str, **overrides):
246
+ """Llama a un método del objeto resolviendo automáticamente las dependencias registradas.
247
+
248
+ Args:
249
+ instance (Any): Instancia del objeto en el cual se ejecutará el método.
250
+ method_name (str): Nombre del método a llamar.
251
+ **overrides: Argumentos que se deben pasar manualmente en lugar de resolverlos automáticamente.
252
+
253
+ Returns:
254
+ Any: El resultado de ejecutar el método con las dependencias resueltas.
255
+
256
+ Raises:
257
+ AttributeError: Si el método no existe en la instancia.
258
+ """
259
+ if not hasattr(instance, method_name):
260
+ raise AttributeError(f"'{instance.__class__.__name__}' has no method '{method_name}'")
261
+
262
+ method = getattr(instance, method_name)
263
+ signature = inspect.signature(method)
264
+ dependencies = {}
265
+
266
+ for name, param in signature.parameters.items():
267
+ if name in overrides:
268
+ dependencies[name] = overrides[name]
269
+ elif param.annotation != inspect.Parameter.empty:
270
+ # Check if the type is primitive
271
+ if isinstance(param.annotation, type):
272
+ # It is a primitive type like str, int, etc.
273
+ dependencies[name] = param.default if param.default != inspect.Parameter.empty else param.annotation()
274
+ else:
275
+ dependencies[name] = self.make(param.annotation.__name__)
276
+ elif param.default != inspect.Parameter.empty:
277
+ dependencies[name] = param.default
278
+ else:
279
+ raise OrionisContainerValueError(f"Cannot resolve parameter '{name}' in method '{method_name}'")
280
+
281
+ return method(**dependencies)
282
+
283
+
284
+ def _primitiveTypeValidator(self, abstract: str) -> None:
285
+ """Validates that the abstract name is not a primitive type.
286
+
287
+ Args:
288
+ abstract (str): Name of the service to validate.
289
+
290
+ Raises:
291
+ OrionisContainerException: If the service name matches a primitive type.
292
+ """
293
+ if self._primitive_types_validator.isPrimitive(abstract):
294
+ raise OrionisContainerException(f"Cannot register a service with a name equal to a primitive type: '{abstract}'.")
295
+
217
296
  def _resolve(self, concrete: Callable[..., Any]):
218
297
  """Automatically resolves the dependencies of a service, handling its constructor dependencies.
219
298
 
@@ -236,22 +315,37 @@ class Container:
236
315
  if len(parameters) == 0 or (len(parameters) == 1 and "self" in parameters):
237
316
  return concrete()
238
317
 
318
+ # Resolve the dependencies of the class constructor
239
319
  dependencies = {}
240
320
  for name, param in parameters.items():
241
321
  if name == "self" or param.kind in (param.VAR_POSITIONAL, param.VAR_KEYWORD):
242
322
  continue
243
323
 
244
324
  param_type = param.annotation
245
- if param_type == param.empty:
246
- raise OrionisContainerValueError(f"Parameter type {name} not specified in {concrete.__name__}")
247
-
248
- dep_name = param_type.__name__
249
325
 
250
- # Conditional resolution of dependencies, if registered
251
- if concrete in self._conditional_bindings and dep_name in self._conditional_bindings[concrete]:
252
- dependencies[name] = self.make(self._conditional_bindings[concrete][dep_name])
326
+ # If the parameter has a default value, use it directly
327
+ if param_type == param.empty:
328
+ if param.default != param.empty:
329
+ # Use the default value if available
330
+ dependencies[name] = param.default
331
+ continue
332
+ else:
333
+ raise OrionisContainerValueError(f"Parameter type {name} not specified in {concrete.__name__}")
334
+
335
+ # If the parameter type is a primitive (str, int, etc.), pass it as is
336
+ if isinstance(param_type, type):
337
+ if param.default != param.empty:
338
+ dependencies[name] = param.default if param.default != param.empty else param_type()
339
+ else:
340
+ dependencies[name] = param_type() # Provide default value for primitive types if not specified
253
341
  else:
254
- dependencies[name] = self.make(dep_name)
342
+ dep_name = param_type.__name__
343
+
344
+ # Conditional resolution of dependencies, if registered
345
+ if concrete in self._conditional_bindings and dep_name in self._conditional_bindings[concrete]:
346
+ dependencies[name] = self.make(self._conditional_bindings[concrete][dep_name])
347
+ else:
348
+ dependencies[name] = self.make(dep_name)
255
349
 
256
350
  return concrete(**dependencies)
257
351
 
@@ -0,0 +1,25 @@
1
+ from orionis.luminate.contracts.container.types_interface import ITypes
2
+
3
+ class Types(ITypes):
4
+ """A class that handles validation of primitive types to prevent registering services with primitive-type names."""
5
+
6
+ # A set of common primitive types in Python
7
+ _primitive_types = {
8
+ int, float, str, bool, bytes, type(None), complex,
9
+ list, tuple, dict, set, frozenset,
10
+ "int", "float", "str", "bool", "bytes", "None", "complex",
11
+ "list", "tuple", "dict", "set", "frozenset"
12
+ }
13
+
14
+ def isPrimitive(self, name: str) -> None:
15
+ """Checks if the provided name corresponds to a primitive type.
16
+
17
+ Args:
18
+ name (str): The name of the service or alias to check.
19
+
20
+ Raises:
21
+ OrionisContainerException: If the name matches a primitive type.
22
+ """
23
+ if name in self._primitive_types:
24
+ return True
25
+ return False
@@ -0,0 +1,152 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Callable
3
+
4
+ class IContainer(ABC):
5
+ """Service container and dependency injection."""
6
+
7
+ @abstractmethod
8
+ def bind(self, abstract: str, concrete: Callable[..., Any]) -> None:
9
+ """Registers a service with a specific implementation.
10
+
11
+ Args:
12
+ abstract (str): Name or key of the service to register.
13
+ concrete (Callable[..., Any]): Concrete implementation of the service.
14
+
15
+ Raises:
16
+ OrionisContainerException: If the service is already registered.
17
+ TypeError: If the implementation is not a callable or instantiable class.
18
+ """
19
+ pass
20
+
21
+ @abstractmethod
22
+ def transient(self, abstract: str, concrete: Callable[..., Any]) -> None:
23
+ """Registers a service as Transient, creating a new instance on each request.
24
+
25
+ Args:
26
+ abstract (str): Name or key of the service to register.
27
+ concrete (Callable[..., Any]): Concrete implementation of the service.
28
+
29
+ Raises:
30
+ OrionisContainerException: If the service is already registered.
31
+ TypeError: If the implementation is not a callable or instantiable class.
32
+ """
33
+ pass
34
+
35
+ @abstractmethod
36
+ def singleton(self, abstract: str, concrete: Callable[..., Any]) -> None:
37
+ """Registers a service as Singleton, ensuring a single shared instance.
38
+
39
+ Args:
40
+ abstract (str): Name or key of the service to register.
41
+ concrete (Callable[..., Any]): Concrete implementation of the service.
42
+
43
+ Raises:
44
+ OrionisContainerException: If the service is already registered.
45
+ TypeError: If the implementation is not a callable or instantiable class.
46
+ """
47
+ pass
48
+
49
+ @abstractmethod
50
+ def scoped(self, abstract: str, concrete: Callable[..., Any]) -> None:
51
+ """Registers a service as Scoped, shared within the same request.
52
+
53
+ Args:
54
+ abstract (str): Name or key of the service to register.
55
+ concrete (Callable[..., Any]): Concrete implementation of the service.
56
+
57
+ Raises:
58
+ OrionisContainerException: If the service is already registered.
59
+ TypeError: If the implementation is not a callable or instantiable class.
60
+ """
61
+ pass
62
+
63
+ @abstractmethod
64
+ def instance(self, abstract: str, instance: Any) -> None:
65
+ """Registers a specific instance in the container, allowing it to be reused.
66
+
67
+ Args:
68
+ abstract (str): Name or key of the service to register.
69
+ instance (Any): Specific instance of the service to register.
70
+
71
+ Raises:
72
+ OrionisContainerException: If the instance is already registered.
73
+ ValueError: If the provided instance is of an unexpected or invalid type.
74
+ """
75
+ pass
76
+
77
+ @abstractmethod
78
+ def has(self, abstract: str) -> bool:
79
+ """Checks if a service is registered in the container.
80
+
81
+ Args:
82
+ abstract (str): Name or key of the service to check.
83
+
84
+ Returns:
85
+ bool: True if the service is registered, False otherwise.
86
+
87
+ Raises:
88
+ ValueError: If the service name (abstract) is not a valid string.
89
+ """
90
+ pass
91
+
92
+ @abstractmethod
93
+ def alias(self, abstract: str, alias: str) -> None:
94
+ """Creates an alias for a registered service, allowing access to the service using an alternative name.
95
+
96
+ Args:
97
+ abstract (str): Name or key of the original service.
98
+ alias (str): The alias to assign to the service.
99
+
100
+ Raises:
101
+ OrionisContainerException: If the original service is not registered.
102
+ ValueError: If the alias is not a valid string or is already in use.
103
+ """
104
+ pass
105
+
106
+ @abstractmethod
107
+ def make(self, abstract: str):
108
+ """Automatically resolves a dependency, handling instances, singletons, scoped, transients, and aliases.
109
+
110
+ This method resolves the dependencies of a service and handles the following service types:
111
+ 1. **Instances**: Returns a specific instance.
112
+ 2. **Singletons**: Returns the same unique instance each time.
113
+ 3. **Scoped**: Returns a shared instance within the same request.
114
+ 4. **Transients**: Creates a new instance each time.
115
+ 5. **Aliases**: Resolves an alias to the original service.
116
+
117
+ Args:
118
+ abstract (str): Name or key of the service to resolve.
119
+
120
+ Returns:
121
+ Any: The resolved instance or service.
122
+
123
+ Raises:
124
+ OrionisContainerException: If the service is not found.
125
+ """
126
+ pass
127
+
128
+ @abstractmethod
129
+ def call(self, instance: Any, method_name: str, **overrides):
130
+ """Llama a un método del objeto resolviendo automáticamente las dependencias registradas.
131
+
132
+ Args:
133
+ instance (Any): Instancia del objeto en el cual se ejecutará el método.
134
+ method_name (str): Nombre del método a llamar.
135
+ **overrides: Argumentos que se deben pasar manualmente en lugar de resolverlos automáticamente.
136
+
137
+ Returns:
138
+ Any: El resultado de ejecutar el método con las dependencias resueltas.
139
+
140
+ Raises:
141
+ AttributeError: Si el método no existe en la instancia.
142
+ """
143
+ pass
144
+
145
+ @abstractmethod
146
+ def startRequest(self):
147
+ """Starts a new request and clears the Scoped instances.
148
+
149
+ This method should be called at the beginning of each request to ensure that
150
+ scoped services do not persist between requests.
151
+ """
152
+ pass
@@ -0,0 +1,16 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class ITypes(ABC):
4
+ """A class that handles validation of primitive types to prevent registering services with primitive-type names."""
5
+
6
+ @abstractmethod
7
+ def isPrimitive(self, name: str) -> None:
8
+ """Checks if the provided name corresponds to a primitive type.
9
+
10
+ Args:
11
+ name (str): The name of the service or alias to check.
12
+
13
+ Raises:
14
+ OrionisContainerException: If the name matches a primitive type.
15
+ """
16
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: orionis
3
- Version: 0.7.0
3
+ Version: 0.9.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
@@ -1,6 +1,6 @@
1
1
  orionis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  orionis/cli_manager.py,sha256=9wNVJxB0HyqUbNesUvkwlsqTyUbZwK6R46iVLE5WVBQ,1715
3
- orionis/framework.py,sha256=ZiVoL5HQ9nx6oZijIDIPxNNieVtsLT7l2r2Q9zeeBA0,1385
3
+ orionis/framework.py,sha256=BDQNBEtNeZ5JZqepVCR2lQaQu7J3yGdOPT4QZR1RIJU,1385
4
4
  orionis/luminate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  orionis/luminate/app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  orionis/luminate/bootstrap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -52,8 +52,9 @@ orionis/luminate/console/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
52
52
  orionis/luminate/console/scripts/management.py,sha256=KT6Bg8kyuUw63SNAtZo6tLH6syOEkxM9J70tCpKgrUw,2860
53
53
  orionis/luminate/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  orionis/luminate/console/tasks/scheduler.py,sha256=h3fRVTx6TuZVcY7zZ6oOzGDnlDAWaRwkj92pFTGUm6E,22686
55
- orionis/luminate/container/container.py,sha256=Tw_Kibld2dKSomXKQCH-_jn_vAHLXWkbBHRjeSgdwC4,11445
55
+ orionis/luminate/container/container.py,sha256=NB7WpK1-7V-Vhd4ykYH1mU4pqvICZi5U_W7Sdmg1dqc,15652
56
56
  orionis/luminate/container/exception.py,sha256=Tf7KdfbEtr0YldhZ1WrKfkBlI5W_KvZO61xWAGFdF0A,1156
57
+ orionis/luminate/container/types.py,sha256=PbPNOJ8e4SGzCmu-zOmCQmDzt1b9I73v3fw_xzLq9RU,932
57
58
  orionis/luminate/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
59
  orionis/luminate/contracts/bootstrap/parser_interface.py,sha256=7DLnp7yB7edayVkSm-piTi8JSf0QKaYYI82qDZudgM0,1641
59
60
  orionis/luminate/contracts/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -76,6 +77,8 @@ orionis/luminate/contracts/console/register_interface.py,sha256=rhHI_as_3yNWtdgQ
76
77
  orionis/luminate/contracts/console/runner_interface.py,sha256=vWLtMhl0m1T6rfCUHZbxGQJl9ZWTXlp3HjcTfCAztGk,1644
77
78
  orionis/luminate/contracts/console/schedule_interface.py,sha256=_dsR0gCvJ7_67lwPUAzBwQFHNvWM6jVjcg1EdPqDIIo,10117
78
79
  orionis/luminate/contracts/console/task_manager_interface.py,sha256=sOmeifoncpWCG2WYh4q3QZ7M7w7P9Onb3Jxw9X2lpXE,1197
80
+ orionis/luminate/contracts/container/container_interface.py,sha256=Pzvyu5guJkHCxqzHf0Z6JGSLVMwekhrLvccDkPXgC-0,5764
81
+ orionis/luminate/contracts/container/types_interface.py,sha256=GCH7x3PjpXKPET3l84GcXbcM8cpne8AGrmTw-uFaT24,526
79
82
  orionis/luminate/contracts/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
83
  orionis/luminate/contracts/facades/env_interface.py,sha256=aN9dZdsuCpy3meZqMxyxLCYlKEIF7XkRNXmP7aS7eCw,1664
81
84
  orionis/luminate/contracts/facades/log_interface.py,sha256=EF1sYbjxWdu7-MJMVVG_xxHDbC3JfiMVr1E6DA5WMOk,1294
@@ -133,9 +136,9 @@ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
136
  tests/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
137
  tests/tools/class_example.py,sha256=dIPD997Y15n6WmKhWoOFSwEldRm9MdOHTZZ49eF1p3c,1056
135
138
  tests/tools/test_reflection.py,sha256=dNN5p_xAosyEf0ddAElmmmTfhcTtBd4zBNl7qzgnsc0,5242
136
- orionis-0.7.0.dist-info/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
137
- orionis-0.7.0.dist-info/METADATA,sha256=-wJ-IuY4pOizRCsgyAqcGYLO_fMqeWzuQJkixy4lI1o,2977
138
- orionis-0.7.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
139
- orionis-0.7.0.dist-info/entry_points.txt,sha256=eef1_CVewfokKjrGBynXa06KabSJYo7LlDKKIKvs1cM,53
140
- orionis-0.7.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
141
- orionis-0.7.0.dist-info/RECORD,,
139
+ orionis-0.9.0.dist-info/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
140
+ orionis-0.9.0.dist-info/METADATA,sha256=m0yzNERPFenFK381JNLuGbah-nCXAvlgAkX04lYd_Vg,2977
141
+ orionis-0.9.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
142
+ orionis-0.9.0.dist-info/entry_points.txt,sha256=eef1_CVewfokKjrGBynXa06KabSJYo7LlDKKIKvs1cM,53
143
+ orionis-0.9.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
144
+ orionis-0.9.0.dist-info/RECORD,,