orionis 0.151.0__py3-none-any.whl → 0.153.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.
Files changed (28) hide show
  1. orionis/framework.py +1 -1
  2. orionis/luminate/application.py +159 -309
  3. orionis/luminate/container/__init__.py +0 -0
  4. orionis/luminate/container/container.py +2 -22
  5. orionis/luminate/container/container_integrity.py +2 -2
  6. orionis/luminate/container/resolve.py +74 -0
  7. orionis/luminate/contracts/application.py +41 -0
  8. orionis/luminate/contracts/foundation/providers/service_providers_bootstrapper.py +4 -3
  9. orionis/luminate/facades/environment/environment_facade.py +0 -24
  10. orionis/luminate/foundation/exceptions/exception_providers.py +54 -0
  11. orionis/luminate/foundation/providers/service_providers_bootstrapper.py +52 -44
  12. orionis/luminate/providers/commands/reactor_commands_service_provider.py +3 -3
  13. orionis/luminate/providers/commands/scheduler_provider.py +1 -10
  14. orionis/luminate/providers/config/config_service_provider.py +1 -10
  15. orionis/luminate/providers/environment/environment__service_provider.py +2 -4
  16. orionis/luminate/providers/files/paths_provider.py +2 -4
  17. orionis/luminate/providers/log/log_service_provider.py +2 -2
  18. orionis/luminate/providers/service_provider.py +1 -4
  19. orionis/luminate/services/commands/reactor_commands_service.py +5 -14
  20. orionis/luminate/services/config/config_service.py +3 -3
  21. orionis/luminate/services/environment/environment_service.py +24 -0
  22. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/METADATA +1 -1
  23. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/RECORD +28 -24
  24. /orionis/luminate/contracts/foundation/{i_bootstraper.py → bootstraper.py} +0 -0
  25. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/LICENCE +0 -0
  26. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/WHEEL +0 -0
  27. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/entry_points.txt +0 -0
  28. {orionis-0.151.0.dist-info → orionis-0.153.0.dist-info}/top_level.txt +0 -0
orionis/framework.py CHANGED
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.151.0"
8
+ VERSION = "0.153.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,404 +1,254 @@
1
- from typing import Any, Callable
1
+ import asyncio
2
+ import inspect
3
+ from typing import Dict, List, Type
2
4
  from contextlib import contextmanager
3
- from orionis.luminate.contracts.foundation.i_bootstraper import IBootstrapper
5
+ from orionis.luminate.contracts.application import IApplication
6
+ from orionis.luminate.contracts.container.container import IContainer
7
+ from orionis.luminate.contracts.foundation.bootstraper import IBootstrapper
4
8
  from orionis.luminate.container.container import Container
9
+ from orionis.luminate.contracts.providers.service_provider import IServiceProvider
5
10
  from orionis.luminate.foundation.config.config_bootstrapper import ConfigBootstrapper
6
11
  from orionis.luminate.foundation.console.command_bootstrapper import CommandsBootstrapper
7
12
  from orionis.luminate.foundation.environment.environment_bootstrapper import EnvironmentBootstrapper
13
+ from orionis.luminate.foundation.exceptions.exception_bootstrapper import BootstrapRuntimeError
8
14
  from orionis.luminate.foundation.providers.service_providers_bootstrapper import ServiceProvidersBootstrapper
9
15
  from orionis.luminate.patterns.singleton import SingletonMeta
10
- from orionis.luminate.providers.service_provider import ServiceProvider
11
16
 
12
17
  class Application(metaclass=SingletonMeta):
13
18
  """
14
- The core Application class responsible for bootstrapping and managing the application lifecycle.
19
+ Main application class that follows the Singleton pattern.
15
20
 
16
- This class follows the Singleton pattern to ensure a single instance throughout the application.
21
+ This class manages service providers, environment variables, configurations,
22
+ and commands for the application lifecycle.
17
23
 
18
24
  Attributes
19
25
  ----------
26
+ _booted : bool
27
+ Indicates whether the application has been booted.
28
+ _custom_providers : List[Type[ServiceProvider]]
29
+ Custom service providers defined by the developer.
30
+ _service_providers : List[Type[ServiceProvider]]
31
+ Core application service providers.
20
32
  _config : dict
21
- A dictionary to store application configuration.
33
+ Configuration settings of the application.
22
34
  _commands : dict
23
- A dictionary to store application commands.
24
- _environment_vars : dict
25
- A dictionary to store environment variables.
26
- container : Container
27
- The dependency injection container for the application.
28
-
29
- Methods
30
- -------
31
- boot()
32
- Bootstraps the application by loading environment, configuration, and core providers.
33
- _beforeBootstrapProviders()
34
- Registers and boots essential providers required before bootstrapping.
35
- _bootstraping()
36
- Loads user-defined configuration, commands, and environment variables.
37
- _afterBootstrapProviders()
38
- Registers and boots additional providers after bootstrapping.
35
+ Registered console commands.
36
+ _env : dict
37
+ Environment variables.
38
+ _container : IContainer
39
+ The service container instance.
39
40
  """
40
- booted = False
41
+
42
+ _booted: bool = False
43
+
44
+ def __init__(self):
45
+ """
46
+ Initializes the application by setting up service providers, environment variables,
47
+ configuration, and the service container.
48
+ """
49
+ self._custom_providers: List[Type[IServiceProvider]] = []
50
+ self._service_providers: List[Type[IServiceProvider]] = []
51
+ self._config: Dict = {}
52
+ self._commands: Dict = {}
53
+ self._env: Dict = {}
54
+ self._container: IContainer = Container()
55
+
56
+ # Register the application instance in the service container
57
+ self._container.instance(IApplication, self)
41
58
 
42
59
  @classmethod
43
- def started(cls):
60
+ def boot(cls) -> None:
44
61
  """
45
62
  Marks the application as booted.
46
63
  """
47
- cls.booted = True
64
+ cls._booted = True
65
+
66
+ @classmethod
67
+ def isRunning(cls) -> bool:
68
+ """
69
+ Checks if the application has been booted.
70
+
71
+ Returns
72
+ -------
73
+ bool
74
+ True if the application is running, otherwise False.
75
+ """
76
+ return cls._booted
48
77
 
49
78
  @classmethod
50
- def getCurrentInstance(cls):
79
+ def getInstance(cls) -> "Application":
51
80
  """
52
- Returns the existing application instance if available.
81
+ Retrieves the singleton instance of the Application.
53
82
 
54
83
  Returns
55
84
  -------
56
85
  Application
57
- The current singleton instance of the application.
86
+ The current application instance.
58
87
 
59
88
  Raises
60
89
  ------
61
90
  RuntimeError
62
- If no instance has been initialized yet.
91
+ If the application has not been initialized yet.
63
92
  """
64
93
  if cls not in SingletonMeta._instances:
65
94
  raise RuntimeError("Application has not been initialized yet. Please create an instance first.")
66
95
  return SingletonMeta._instances[cls]
67
96
 
68
97
  @classmethod
69
- def reset(cls):
98
+ def destroy(cls) -> None:
70
99
  """
71
- Resets the application instance if it exists.
72
-
73
- This method is used to reset the application instance and clear the singleton instances
74
- stored in the `SingletonMeta` class.
100
+ Destroys the singleton instance of the Application.
75
101
  """
76
102
  if cls in SingletonMeta._instances:
77
103
  del SingletonMeta._instances[cls]
78
104
 
79
- def __init__(self, container: Container):
105
+ def withProviders(self, providers: List[Type[IServiceProvider]] = None) -> None:
80
106
  """
81
- Initializes the Application instance.
107
+ Sets custom service providers.
82
108
 
83
109
  Parameters
84
110
  ----------
85
- container : Container
86
- The dependency injection container for the application.
111
+ providers : List[Type[IServiceProvider]], optional
112
+ List of service providers, by default None.
87
113
  """
88
- # Class attributes
89
- self._before_boot_service_providers: list = []
90
- self._after_boot_service_providers: list = []
91
- self._config: dict = {}
92
- self._commands: dict = {}
93
- self._environment_vars: dict = {}
94
- self._booted: bool = False
95
-
96
- # Initialize the application container
97
- self.container = container
98
- self.container.instance(container)
99
-
100
- def isBooted(self) -> bool:
101
- """
102
- Check if the application has been booted.
114
+ self._custom_providers = providers or []
103
115
 
104
- Returns
105
- -------
106
- bool
107
- True if the application has been booted, False otherwise.
116
+ def container(self) -> IContainer:
108
117
  """
109
- return self._booted
110
-
111
- def bind(self, concrete: Callable[..., Any]) -> str:
112
- """
113
- Bind a callable to the container.
114
- This method ensures that the provided callable is not the main function,
115
- is unique within the container, and is indeed callable. It then creates
116
- a unique key for the callable based on its module and name, and stores
117
- the callable in the container's bindings.
118
- Args:
119
- concrete (Callable[..., Any]): The callable to be bound to the container.
120
- Returns:
121
- str: The unique key generated for the callable.
122
- """
123
- return self.container.bind(concrete)
124
-
125
- def transient(self, concrete: Callable[..., Any]) -> str:
126
- """
127
- Registers a transient service in the container.
128
- A transient service is created each time it is requested.
129
- Args:
130
- concrete (Callable[..., Any]): The callable that defines the service.
131
- Returns:
132
- str: The unique key generated for the callable.
133
- """
134
- return self.container.transient(concrete)
135
-
136
- def singleton(self, concrete: Callable[..., Any]) -> str:
137
- """
138
- Registers a callable as a singleton in the container.
139
- This method ensures that the provided callable is not the main module,
140
- is unique within the container, and is indeed callable. It then registers
141
- the callable as a singleton, storing it in the container's singleton registry.
142
- Args:
143
- concrete (Callable[..., Any]): The callable to be registered as a singleton.
144
- Returns:
145
- str: The key under which the singleton is registered in the container.
146
- """
147
- return self.container.singleton(concrete)
148
-
149
- def scoped(self, concrete: Callable[..., Any]) -> str:
150
- """
151
- Registers a callable as a scoped service.
152
- This method ensures that the provided callable is not the main service,
153
- is unique, and is indeed callable. It then registers the callable in the
154
- scoped services dictionary with relevant metadata.
155
- Args:
156
- concrete (Callable[..., Any]): The callable to be registered as a scoped service.
157
- Returns:
158
- str: The key under which the callable is registered in the scoped services dictionary.
159
- """
160
- return self.container.scoped(concrete)
161
-
162
- def instance(self, instance: Any) -> str:
163
- """
164
- Registers an instance as a singleton in the container.
165
- Args:
166
- instance (Any): The instance to be registered as a singleton.
167
- Returns:
168
- str: The key under which the instance is registered in the container.
169
- """
170
- return self.container.instance(instance)
171
-
172
- def alias(self, alias: str, concrete: Any) -> None:
173
- """
174
- Creates an alias for a registered service.
175
- Args:
176
- alias (str): The alias name to be used for the service.
177
- concrete (Any): The actual service instance or callable to be aliased.
178
- Raises:
179
- OrionisContainerException: If the concrete instance is not a valid object or if the alias is a primitive type.
180
- """
181
- return self.container.alias(alias, concrete)
182
-
183
- def has(self, obj: Any) -> bool:
184
- """
185
- Checks if a service is registered in the container.
186
-
187
- Parameters
188
- ----------
189
- obj : Any
190
- The service class, instance, or alias to check.
118
+ Returns the service container instance.
191
119
 
192
120
  Returns
193
121
  -------
194
- bool
195
- True if the service is registered, False otherwise.
122
+ IContainer
123
+ The service container.
196
124
  """
197
- return self.container.has(obj)
125
+ return self._container
198
126
 
199
- def make(self, abstract: Any) -> Any:
127
+ def create(self) -> None:
128
+ """
129
+ Initializes and boots the application, including loading commands
130
+ and service providers.
200
131
  """
201
- Create and return an instance of a registered service.
202
132
 
203
- Parameters
204
- ----------
205
- abstract : Any
206
- The service class or alias to instantiate.
133
+ # Boot the application
134
+ self._bootstrapping()
207
135
 
208
- Returns
209
- -------
210
- Any
211
- An instance of the requested service.
136
+ # Load commands and service providers
137
+ self._loadCommands()
212
138
 
213
- Raises
214
- ------
215
- OrionisContainerException
216
- If the service is not found in the container.
217
- """
218
- return self.container.make(abstract)
139
+ # Boot service providers
140
+ asyncio.run(self._bootServiceProviders())
219
141
 
220
- def forgetScopedInstances(self) -> None:
221
- """
222
- Reset scoped instances at the beginning of a new request.
223
- """
224
- return self.container.forgetScopedInstances()
142
+ # Change the application status to booted
143
+ Application.boot()
225
144
 
226
- def boot(self):
145
+ async def _bootServiceProviders(self) -> None:
227
146
  """
228
- Bootstraps the application by loading environment configuration and core providers.
229
- Notes
230
- -----
231
- The bootstrapping process involves several steps:
232
- 1. Loading essential services.
233
- 2. Executing pre-bootstrap provider hooks.
234
- 3. Initializing core components.
235
- 4. Executing post-bootstrap provider hooks.
236
- 5. Loading command-line interface commands.
237
- After these steps, the application is marked as booted.
147
+ Boots all registered service providers.
238
148
  """
239
- # Mark the application as booted
240
- Application.started()
149
+ for service in self._service_providers:
150
+ provider: IServiceProvider = service(app=self._container)
151
+ provider.register()
241
152
 
242
- # Bootstrapping process
243
- self._bootServices()
244
- self._beforeBootstrapProviders()
245
- self._bootstrapping()
246
- self._afterBootstrapProviders()
247
- self._loadCommands()
153
+ # If the provider has a boot method, execute it (sync or async)
154
+ if hasattr(provider, 'boot') and callable(provider.boot):
155
+ if inspect.iscoroutinefunction(provider.boot):
156
+ await provider.boot()
157
+ else:
158
+ provider.boot()
248
159
 
249
- def _bootServices(self):
160
+ def _bootstrapping(self) -> None:
250
161
  """
251
- Bootstraps the application services.
252
-
253
- This method is responsible for loading the application's services. It reads all the
254
- ServiceProviders from the Core and those defined by the developer. Then, it stores
255
- in class dictionaries the services that need to be loaded before and after the Bootstrap.
256
-
257
- Parameters
258
- ----------
259
- None
260
-
261
- Returns
262
- -------
263
- None
162
+ Loads essential components such as environment variables,
163
+ configurations, commands, and service providers.
264
164
  """
265
- services_bootstrapper_key = self.singleton(ServiceProvidersBootstrapper)
266
- services_bootstrapper: ServiceProvidersBootstrapper = self.make(services_bootstrapper_key)
267
- self._before_boot_service_providers = services_bootstrapper.getBeforeServiceProviders()
268
- self._after_boot_service_providers = services_bootstrapper.getAfterServiceProviders()
165
+ bootstrappers = [
166
+ {'property': self._env, 'instance': EnvironmentBootstrapper()},
167
+ {'property': self._config, 'instance': ConfigBootstrapper()},
168
+ {'property': self._commands, 'instance': CommandsBootstrapper()},
169
+ {'property': self._service_providers, 'instance': ServiceProvidersBootstrapper(self._custom_providers)},
170
+ ]
269
171
 
270
- def _beforeBootstrapProviders(self):
271
- """
272
- Loads and registers essential services before bootstrapping.
172
+ for bootstrapper in bootstrappers:
173
+ try:
174
+ property_ref: Dict = bootstrapper["property"]
175
+ bootstrapper_instance: IBootstrapper = bootstrapper["instance"]
176
+ property_ref.update(bootstrapper_instance.get())
177
+ except Exception as e:
178
+ raise BootstrapRuntimeError(f"Error bootstrapping {type(bootstrapper_instance).__name__}: {str(e)}") from e
273
179
 
274
- This method is responsible for loading and registering the services that are
275
- required before the main bootstrapping process. It iterates through the list
276
- of service providers that need to be initialized early, registers them, and
277
- then boots them to make sure they are ready for use.
180
+ def _loadCommands(self) -> None:
278
181
  """
279
- for service in self._before_boot_service_providers:
280
- _environment_provider : ServiceProvider = service(app=self.container)
281
- _environment_provider.register()
282
- _environment_provider.boot()
283
-
284
- def _bootstrapping(self):
182
+ Registers application commands in the service container.
285
183
  """
286
- Loads configuration, commands, environment variables, and other bootstrappers.
184
+ for command, data_command in self._commands.items():
185
+ self._container.transient(data_command.get('signature'), data_command.get('concrete'))
287
186
 
288
- This method initializes and updates the class dictionaries with the results
289
- from various bootstrappers. It ensures that the application has the necessary
290
- configuration, commands, and environment variables loaded before proceeding
291
- with the rest of the bootstrapping process.
292
- """
293
- singletons_bootstrappers = [
294
- (self._config, ConfigBootstrapper),
295
- (self._commands, CommandsBootstrapper),
296
- (self._environment_vars, EnvironmentBootstrapper)
297
- ]
298
- for bootstrapper in singletons_bootstrappers:
299
- property_cls, bootstrapper_class = bootstrapper
300
- bootstrapper_key = self.singleton(bootstrapper_class)
301
- bootstrapper_instance : IBootstrapper = self.make(bootstrapper_key)
302
- property_cls.update(bootstrapper_instance.get())
303
187
 
304
- def _loadCommands(self):
305
- """
306
- Loads CLI commands, including both core system commands and those defined by the developer.
307
188
 
308
- This method iterates over the commands stored in the `_commands` attribute, binds each command
309
- to its corresponding concrete implementation, and registers the command alias.
310
189
 
311
- Parameters
312
- ----------
313
- None
314
190
 
315
- Returns
316
- -------
317
- None
318
- """
319
- for command in self._commands.keys():
320
- data_command:dict = self._commands[command]
321
- id_container_concrete = self.bind(data_command.get('concrete'))
322
- self.alias(alias=command, concrete=id_container_concrete)
323
191
 
324
- def _afterBootstrapProviders(self):
325
- """
326
- Loads services into the container that depend on the Bootstrap process being completed.
327
192
 
328
- This method iterates over the list of service providers that need to be loaded after the
329
- Bootstrap process. For each service provider, it creates an instance, registers it, and
330
- then boots it.
331
193
 
332
- Parameters
333
- ----------
334
- None
335
194
 
336
- Returns
337
- -------
338
- None
339
- """
340
- for service in self._after_boot_service_providers:
341
- _environment_provider : ServiceProvider = service(app=self.container)
342
- _environment_provider.register()
343
- _environment_provider.boot()
344
195
 
345
- @contextmanager
346
- def app_context():
347
- """
348
- Context manager for creating an instance of the Orionis application.
196
+ # @contextmanager
197
+ # def app_context():
198
+ # """
199
+ # Context manager for creating an instance of the Orionis application.
349
200
 
350
- This function initializes the Orionis application with a new container,
351
- ensuring that the application is properly set up before use.
201
+ # This function initializes the Orionis application with a new container,
202
+ # ensuring that the application is properly set up before use.
352
203
 
353
- Yields
354
- ------
355
- Application
356
- The initialized Orionis application instance.
204
+ # Yields
205
+ # ------
206
+ # Application
207
+ # The initialized Orionis application instance.
357
208
 
358
- Raises
359
- ------
360
- RuntimeError
361
- If the application has not been properly initialized.
362
- """
363
- try:
209
+ # Raises
210
+ # ------
211
+ # RuntimeError
212
+ # If the application has not been properly initialized.
213
+ # """
214
+ # try:
364
215
 
365
- # Check if the application has been booted
366
- if not Application.booted:
367
- app = Application(Container()).boot()
368
- else:
369
- app = Application.getCurrentInstance()
216
+ # # Check if the application has been booted
217
+ # if not Application.booted:
218
+ # app = Application(Container()).boot()
219
+ # else:
220
+ # app = Application.getCurrentInstance()
370
221
 
371
- # Yield the application instance
372
- yield app
222
+ # # Yield the application instance
223
+ # yield app
373
224
 
374
- finally:
225
+ # finally:
375
226
 
376
- # Close Context Manager
377
- pass
227
+ # # Close Context Manager
228
+ # pass
378
229
 
379
- def app_booted():
380
- """
381
- Check if the application has been booted.
230
+ # def app_booted():
231
+ # """
232
+ # Check if the application has been booted.
382
233
 
383
- Returns:
384
- bool: True if the application has been booted, False otherwise.
385
- """
386
- return Application.booted
234
+ # Returns:
235
+ # bool: True if the application has been booted, False otherwise.
236
+ # """
237
+ # return Application.booted
387
238
 
388
- def orionis():
389
- """
390
- Creates a new instance of the Orionis application.
239
+ # def orionis():
240
+ # """
241
+ # Creates a new instance of the Orionis application.
391
242
 
392
- Ensures that any existing singleton instance of `Application` is removed before
393
- creating a fresh instance. It resets the singleton instances stored in `SingletonMeta`
394
- and `Container`.
243
+ # Ensures that any existing singleton instance of `Application` is removed before
244
+ # creating a fresh instance. It resets the singleton instances stored in `SingletonMeta`
245
+ # and `Container`.
395
246
 
396
- Returns
397
- -------
398
- Application
399
- A new instance of the Orionis application.
400
- """
401
- Container.reset()
402
- Application.reset()
247
+ # Returns
248
+ # -------
249
+ # Application
250
+ # A new instance of the Orionis application.
251
+ # """
252
+ # Application.reset()
403
253
 
404
- return Application(Container())
254
+ # return Application()
File without changes
@@ -21,30 +21,9 @@ class Container(IContainer):
21
21
  @classmethod
22
22
  def destroy(cls):
23
23
  """
24
- Destroys the current instance of the container.
25
-
26
- This method resets the singleton instance, effectively clearing all registered
27
- services and instances.
28
-
29
- Examples
30
- --------
31
- >>> Container.destroy()
32
- """
33
- cls._instance = None
34
-
35
- @classmethod
36
- def reset(cls):
37
- """
38
- Resets the container to its initial state.
39
-
40
- This method destroys the current instance and immediately creates a new one.
41
-
42
- Examples
43
- --------
44
- >>> Container.reset()
24
+ Destroys the container instance.
45
25
  """
46
26
  cls._instance = None
47
- super().__new__(cls)
48
27
 
49
28
  def __new__(cls):
50
29
  """
@@ -61,6 +40,7 @@ class Container(IContainer):
61
40
  cls._instance._scoped_services = {}
62
41
  cls._instance._singleton_services = {}
63
42
  cls._instance._aliases_services = {}
43
+ cls._instance.instance(IContainer, cls._instance)
64
44
  return cls._instance
65
45
 
66
46
  def bind(self, abstract: Callable[..., Any], concrete: Callable[..., Any], lifetime: str = Lifetime.TRANSIENT.value) -> None:
@@ -130,8 +130,8 @@ class ContainerIntegrity(IContainerIntegrity):
130
130
  if not isinstance(name, str):
131
131
  raise OrionisContainerValueError(f"The alias '{name}' must be a string.")
132
132
 
133
- if not re.match(r'^[a-zA-Z0-9]+$', name):
134
- raise OrionisContainerValueError(f"The alias '{name}' can only contain letters and numbers, without spaces or special characters.")
133
+ if not re.match(r'^[a-zA-Z0-9_]+$', name):
134
+ raise OrionisContainerValueError(f"The alias '{name}' can only contain letters, numbers, and underscores, without spaces or other special characters.")
135
135
 
136
136
  if name in {
137
137
  int, "int",