orionis 0.419.0__py3-none-any.whl → 0.420.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/metadata/framework.py +1 -1
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/METADATA +1 -1
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/RECORD +7 -80
- orionis/_contracts/__init__.py +0 -0
- orionis/_contracts/application.py +0 -41
- orionis/_contracts/config/__init__.py +0 -0
- orionis/_contracts/config/config.py +0 -27
- orionis/_contracts/console/__init__.py +0 -0
- orionis/_contracts/console/base/__init__.py +0 -0
- orionis/_contracts/console/base/command.py +0 -437
- orionis/_contracts/console/command_filter.py +0 -32
- orionis/_contracts/console/kernel.py +0 -32
- orionis/_contracts/console/output/__init__.py +0 -0
- orionis/_contracts/console/output/console.py +0 -421
- orionis/_contracts/console/output/executor.py +0 -51
- orionis/_contracts/console/parser.py +0 -75
- orionis/_contracts/console/task_manager.py +0 -37
- orionis/_contracts/facades/__init__.py +0 -0
- orionis/_contracts/facades/commands/__init__.py +0 -0
- orionis/_contracts/facades/commands/commands_facade.py +0 -40
- orionis/_contracts/facades/commands/scheduler_facade.py +0 -28
- orionis/_contracts/facades/config/__init__.py +0 -0
- orionis/_contracts/facades/config/config_facade.py +0 -37
- orionis/_contracts/facades/environment/__init__.py +0 -0
- orionis/_contracts/facades/environment/environment_facade.py +0 -74
- orionis/_contracts/facades/facade.py +0 -38
- orionis/_contracts/facades/files/__init__.py +0 -0
- orionis/_contracts/facades/files/path_facade.py +0 -148
- orionis/_contracts/facades/log/__init__.py +0 -0
- orionis/_contracts/facades/log/log_facade.py +0 -83
- orionis/_contracts/facades/tests/__init__.py +0 -0
- orionis/_contracts/facades/tests/tests_facade.py +0 -30
- orionis/_contracts/foundation/__init__.py +0 -0
- orionis/_contracts/foundation/bootstraper.py +0 -41
- orionis/_contracts/foundation/config/__init__.py +0 -0
- orionis/_contracts/foundation/config/config_bootstrapper.py +0 -140
- orionis/_contracts/foundation/console/__init__.py +0 -0
- orionis/_contracts/foundation/console/command_bootstrapper.py +0 -81
- orionis/_contracts/foundation/environment/__init__.py +0 -0
- orionis/_contracts/foundation/environment/environment_bootstrapper.py +0 -33
- orionis/_contracts/foundation/providers/__init__.py +0 -0
- orionis/_contracts/foundation/providers/service_providers_bootstrapper.py +0 -47
- orionis/_contracts/providers/__init__.py +0 -0
- orionis/_contracts/providers/service_provider.py +0 -14
- orionis/_contracts/services/__init__.py +0 -0
- orionis/_contracts/services/commands/__init__.py +0 -0
- orionis/_contracts/services/commands/reactor_commands_service.py +0 -23
- orionis/_contracts/services/commands/schedule_service.py +0 -317
- orionis/_contracts/services/config/__init__.py +0 -0
- orionis/_contracts/services/config/config_service.py +0 -37
- orionis/_contracts/services/environment/__init__.py +0 -0
- orionis/_contracts/services/environment/environment_service.py +0 -74
- orionis/_contracts/services/files/__init__.py +0 -0
- orionis/_contracts/services/files/path_resolver_service.py +0 -29
- orionis/_contracts/services/log/__init__.py +0 -0
- orionis/_contracts/services/log/log_service.py +0 -89
- orionis/_contracts/support/exception_parse.py +0 -26
- orionis/_contracts/support/reflection.py +0 -352
- orionis/_foundation/__init__.py +0 -0
- orionis/_foundation/console/__init__.py +0 -0
- orionis/_foundation/console/command_bootstrapper.py +0 -175
- orionis/_foundation/environment/__init__.py +0 -0
- orionis/_foundation/environment/environment_bootstrapper.py +0 -76
- orionis/_foundation/exceptions/__init__.py +0 -0
- orionis/_foundation/exceptions/exception_bootstrapper.py +0 -54
- orionis/_foundation/exceptions/exception_providers.py +0 -54
- orionis/_foundation/foundation/config/__init__.py +0 -0
- orionis/_foundation/foundation/config/config_bootstrapper.py +0 -209
- orionis/_foundation/providers/__init__.py +0 -0
- orionis/_foundation/providers/service_providers_bootstrapper.py +0 -107
- orionis/_services/__init__.py +0 -0
- orionis/_services/commands/__init__.py +0 -0
- orionis/_services/commands/reactor_commands_service.py +0 -148
- orionis/_services/commands/scheduler_service.py +0 -611
- orionis/_services/config/__init__.py +0 -0
- orionis/_services/config/config_service.py +0 -72
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/WHEEL +0 -0
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/top_level.txt +0 -0
- {orionis-0.419.0.dist-info → orionis-0.420.0.dist-info}/zip-safe +0 -0
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
class ProvidersException(Exception):
|
|
2
|
-
"""
|
|
3
|
-
Exception related to the providers module.
|
|
4
|
-
|
|
5
|
-
Parameters
|
|
6
|
-
----------
|
|
7
|
-
message : str
|
|
8
|
-
The error message describing the issue.
|
|
9
|
-
|
|
10
|
-
Attributes
|
|
11
|
-
----------
|
|
12
|
-
message : str
|
|
13
|
-
The stored error message.
|
|
14
|
-
|
|
15
|
-
Methods
|
|
16
|
-
-------
|
|
17
|
-
__str__()
|
|
18
|
-
Returns a user-friendly string representation of the exception.
|
|
19
|
-
__repr__()
|
|
20
|
-
Returns a detailed representation for debugging purposes.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, message: str):
|
|
24
|
-
"""
|
|
25
|
-
Initialize the exception with a message.
|
|
26
|
-
|
|
27
|
-
Parameters
|
|
28
|
-
----------
|
|
29
|
-
message : str
|
|
30
|
-
The error message describing the issue.
|
|
31
|
-
"""
|
|
32
|
-
super().__init__(f"[ProvidersException]: {message}")
|
|
33
|
-
|
|
34
|
-
def __str__(self) -> str:
|
|
35
|
-
"""
|
|
36
|
-
Returns a user-friendly string representation.
|
|
37
|
-
|
|
38
|
-
Returns
|
|
39
|
-
-------
|
|
40
|
-
str
|
|
41
|
-
A formatted error message.
|
|
42
|
-
"""
|
|
43
|
-
return self.args[0]
|
|
44
|
-
|
|
45
|
-
def __repr__(self) -> str:
|
|
46
|
-
"""
|
|
47
|
-
Returns a detailed representation for debugging.
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
str
|
|
52
|
-
A detailed string representation including the exception name.
|
|
53
|
-
"""
|
|
54
|
-
return f"{self.__class__.__name__}({self.args[0]!r})"
|
|
File without changes
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import importlib
|
|
2
|
-
import pathlib
|
|
3
|
-
from dataclasses import asdict
|
|
4
|
-
from typing import Any, Dict
|
|
5
|
-
from orionis._contracts.foundation.config.config_bootstrapper import IConfigBootstrapper
|
|
6
|
-
from orionis._contracts.config.config import IConfig
|
|
7
|
-
from orionis._foundation.exceptions.exception_bootstrapper import BootstrapRuntimeError
|
|
8
|
-
|
|
9
|
-
class ConfigBootstrapper(IConfigBootstrapper):
|
|
10
|
-
"""
|
|
11
|
-
A class responsible for loading and registering application configurations dynamically.
|
|
12
|
-
|
|
13
|
-
This class scans a specified directory for Python files, imports them, and registers
|
|
14
|
-
configuration classes that inherit from `IConfig`. It ensures that configurations
|
|
15
|
-
are loaded only once and provides methods to access and modify them.
|
|
16
|
-
|
|
17
|
-
Attributes
|
|
18
|
-
----------
|
|
19
|
-
_config : Dict[str, Any]
|
|
20
|
-
A dictionary to store registered configuration sections and their data.
|
|
21
|
-
|
|
22
|
-
Methods
|
|
23
|
-
-------
|
|
24
|
-
__init__()
|
|
25
|
-
Initializes the `ConfigBootstrapper` and triggers the autoload process.
|
|
26
|
-
_autoload()
|
|
27
|
-
Scans the configuration directory and loads configuration classes.
|
|
28
|
-
_set(concrete: Any, section: str)
|
|
29
|
-
Validates and registers a configuration class.
|
|
30
|
-
_parse(data: Any) -> Dict[str, Any]
|
|
31
|
-
Converts the 'config' attribute of a class into a dictionary.
|
|
32
|
-
_register(section: str, data: Dict[str, Any])
|
|
33
|
-
Registers a configuration section.
|
|
34
|
-
set(key: str, value: Any)
|
|
35
|
-
Dynamically sets a configuration value using dot notation.
|
|
36
|
-
get(key: str, default: Optional[Any] = None) -> Any
|
|
37
|
-
Retrieves a configuration value using dot notation.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
def __init__(self) -> None:
|
|
41
|
-
"""
|
|
42
|
-
Initializes the `ConfigBootstrapper` and triggers the autoload process.
|
|
43
|
-
|
|
44
|
-
The `_config` dictionary is initialized to store configuration data, and the
|
|
45
|
-
`_autoload` method is called to load configurations from the default directory.
|
|
46
|
-
"""
|
|
47
|
-
self._config: Dict[str, Any] = {}
|
|
48
|
-
self._autoload()
|
|
49
|
-
|
|
50
|
-
def _autoload(self) -> None:
|
|
51
|
-
"""
|
|
52
|
-
Scans the configuration directory and loads configuration classes.
|
|
53
|
-
|
|
54
|
-
This method searches for Python files in the specified directory, imports them,
|
|
55
|
-
and registers any class named `Config` that inherits from `IConfig`.
|
|
56
|
-
|
|
57
|
-
Raises
|
|
58
|
-
------
|
|
59
|
-
FileNotFoundError
|
|
60
|
-
If the configuration directory does not exist.
|
|
61
|
-
BootstrapRuntimeError
|
|
62
|
-
If there is an error loading a module.
|
|
63
|
-
"""
|
|
64
|
-
directory = "config"
|
|
65
|
-
base_path = pathlib.Path(directory).resolve()
|
|
66
|
-
|
|
67
|
-
if not base_path.exists():
|
|
68
|
-
raise FileNotFoundError(f"Directory {directory} does not exist.")
|
|
69
|
-
|
|
70
|
-
for file_path in base_path.rglob("*.py"):
|
|
71
|
-
if file_path.name == "__init__.py":
|
|
72
|
-
continue
|
|
73
|
-
|
|
74
|
-
module_path = ".".join(file_path.relative_to(base_path).with_suffix("").parts)
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
module = importlib.import_module(f"{directory}.{module_path}")
|
|
78
|
-
if hasattr(module, "Config"):
|
|
79
|
-
self._set(
|
|
80
|
-
concrete=getattr(module, "Config"),
|
|
81
|
-
section=module_path
|
|
82
|
-
)
|
|
83
|
-
except Exception as e:
|
|
84
|
-
raise BootstrapRuntimeError(f"Error loading module {module_path}") from e
|
|
85
|
-
|
|
86
|
-
def _set(self, concrete: Any, section: str) -> None:
|
|
87
|
-
"""
|
|
88
|
-
Validates and registers a configuration class.
|
|
89
|
-
|
|
90
|
-
This method ensures that the provided class is valid (inherits from `IConfig`
|
|
91
|
-
and has a `config` attribute) and registers it in the `_config` dictionary.
|
|
92
|
-
|
|
93
|
-
Parameters
|
|
94
|
-
----------
|
|
95
|
-
concrete : Any
|
|
96
|
-
The configuration class to register.
|
|
97
|
-
section : str
|
|
98
|
-
The section name under which the configuration will be registered.
|
|
99
|
-
|
|
100
|
-
Raises
|
|
101
|
-
------
|
|
102
|
-
TypeError
|
|
103
|
-
If the input is not a class or does not inherit from `IConfig`.
|
|
104
|
-
ValueError
|
|
105
|
-
If the class does not have a `config` attribute.
|
|
106
|
-
"""
|
|
107
|
-
if not isinstance(concrete, type):
|
|
108
|
-
raise TypeError(f"Expected a class, but got {type(concrete).__name__}.")
|
|
109
|
-
|
|
110
|
-
if not hasattr(concrete, "config"):
|
|
111
|
-
raise ValueError(f"Class {concrete.__name__} must have a 'config' attribute.")
|
|
112
|
-
|
|
113
|
-
if not issubclass(concrete, IConfig):
|
|
114
|
-
raise TypeError(f"Class {concrete.__name__} must inherit from 'IConfig'.")
|
|
115
|
-
|
|
116
|
-
self._register(
|
|
117
|
-
section=section,
|
|
118
|
-
data=self._parse(concrete.config)
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
def _parse(self, data: Any) -> Dict[str, Any]:
|
|
122
|
-
"""
|
|
123
|
-
Converts the 'config' attribute of a class into a dictionary.
|
|
124
|
-
|
|
125
|
-
If the input is already a dictionary, it is returned as-is. If the input is a
|
|
126
|
-
dataclass, it is converted to a dictionary using `asdict`.
|
|
127
|
-
|
|
128
|
-
Parameters
|
|
129
|
-
----------
|
|
130
|
-
data : Any
|
|
131
|
-
The data to convert into a dictionary.
|
|
132
|
-
|
|
133
|
-
Returns
|
|
134
|
-
-------
|
|
135
|
-
Dict[str, Any]
|
|
136
|
-
The converted dictionary.
|
|
137
|
-
|
|
138
|
-
Raises
|
|
139
|
-
------
|
|
140
|
-
TypeError
|
|
141
|
-
If the data cannot be converted to a dictionary.
|
|
142
|
-
"""
|
|
143
|
-
if isinstance(data, dict):
|
|
144
|
-
return data
|
|
145
|
-
try:
|
|
146
|
-
return asdict(data)
|
|
147
|
-
except TypeError as e:
|
|
148
|
-
raise TypeError(f"Error: The 'config' attribute could not be converted to a dictionary. {str(e)}")
|
|
149
|
-
|
|
150
|
-
def _register(self, section: str, data: Dict[str, Any]) -> None:
|
|
151
|
-
"""
|
|
152
|
-
Registers a configuration section.
|
|
153
|
-
|
|
154
|
-
Parameters
|
|
155
|
-
----------
|
|
156
|
-
section : str
|
|
157
|
-
The name of the configuration section.
|
|
158
|
-
data : Dict[str, Any]
|
|
159
|
-
The configuration data to register.
|
|
160
|
-
|
|
161
|
-
Raises
|
|
162
|
-
------
|
|
163
|
-
ValueError
|
|
164
|
-
If the section is already registered.
|
|
165
|
-
"""
|
|
166
|
-
if section in self._config:
|
|
167
|
-
raise ValueError(f"Configuration section '{section}' is already registered.")
|
|
168
|
-
self._config[section] = data
|
|
169
|
-
|
|
170
|
-
def get(self, key: str = None, default: Any = None) -> Any:
|
|
171
|
-
"""
|
|
172
|
-
Retrieves configuration data.
|
|
173
|
-
|
|
174
|
-
If a key is provided, it retrieves the value associated with the key using dot notation.
|
|
175
|
-
If no key is provided, it returns the entire configuration dictionary.
|
|
176
|
-
|
|
177
|
-
Parameters
|
|
178
|
-
----------
|
|
179
|
-
key : str, optional
|
|
180
|
-
The key to retrieve the value for, using dot notation (default is None).
|
|
181
|
-
default : Any, optional
|
|
182
|
-
The default value to return if the key is not found (default is None).
|
|
183
|
-
|
|
184
|
-
Returns
|
|
185
|
-
-------
|
|
186
|
-
Any
|
|
187
|
-
The configuration value associated with the key, or the entire configuration dictionary
|
|
188
|
-
if no key is provided. If the key is not found, returns the default value.
|
|
189
|
-
|
|
190
|
-
Raises
|
|
191
|
-
------
|
|
192
|
-
KeyError
|
|
193
|
-
If the key is not found and no default value is provided.
|
|
194
|
-
"""
|
|
195
|
-
if key is None:
|
|
196
|
-
return self._config
|
|
197
|
-
|
|
198
|
-
keys = key.split('.')
|
|
199
|
-
value = self._config
|
|
200
|
-
|
|
201
|
-
try:
|
|
202
|
-
for k in keys:
|
|
203
|
-
value = value[k]
|
|
204
|
-
except KeyError:
|
|
205
|
-
if default is not None:
|
|
206
|
-
return default
|
|
207
|
-
raise KeyError(f"Key '{key}' not found in configuration.")
|
|
208
|
-
|
|
209
|
-
return value
|
|
File without changes
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import importlib
|
|
2
|
-
import inspect
|
|
3
|
-
import pathlib
|
|
4
|
-
from typing import List, Type
|
|
5
|
-
from orionis._contracts.foundation.providers.service_providers_bootstrapper import IServiceProvidersBootstrapper
|
|
6
|
-
from orionis._contracts.providers.service_provider import IServiceProvider
|
|
7
|
-
from orionis._foundation.exceptions.exception_bootstrapper import BootstrapRuntimeError
|
|
8
|
-
from orionis._providers.service_provider import ServiceProvider
|
|
9
|
-
|
|
10
|
-
class ServiceProvidersBootstrapper(IServiceProvidersBootstrapper):
|
|
11
|
-
"""
|
|
12
|
-
Bootstrapper for loading and managing service providers.
|
|
13
|
-
|
|
14
|
-
This class is responsible for scanning directories, loading service provider classes,
|
|
15
|
-
and registering them in the container.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
def __init__(self, custom_providers: List[Type[IServiceProvider]] = None) -> None:
|
|
19
|
-
"""
|
|
20
|
-
Initializes the ServiceProvidersBootstrapper.
|
|
21
|
-
|
|
22
|
-
Args:
|
|
23
|
-
providers (List[Type[IServiceProvider]]): A list of service provider classes to register manually.
|
|
24
|
-
"""
|
|
25
|
-
self._service_providers: List[Type[IServiceProvider]] = []
|
|
26
|
-
self._custom_providers = custom_providers or []
|
|
27
|
-
self._autoload()
|
|
28
|
-
|
|
29
|
-
def _autoload(self) -> None:
|
|
30
|
-
"""
|
|
31
|
-
Scans the provider directories and loads provider classes.
|
|
32
|
-
|
|
33
|
-
This method searches for Python files in the specified directories, imports them,
|
|
34
|
-
and registers any class that inherits from `IServiceProvider`.
|
|
35
|
-
|
|
36
|
-
Raises:
|
|
37
|
-
BootstrapRuntimeError: If there is an error loading a module.
|
|
38
|
-
"""
|
|
39
|
-
# Base path for the project
|
|
40
|
-
base_path = pathlib.Path.cwd()
|
|
41
|
-
|
|
42
|
-
# Directories to scan for provider classes (Core Providers)
|
|
43
|
-
provider_dirs = [
|
|
44
|
-
pathlib.Path(__file__).resolve().parent.parent.parent / "providers"
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
# Scan directories for provider classes
|
|
48
|
-
for provider_dir in provider_dirs:
|
|
49
|
-
if not provider_dir.is_dir():
|
|
50
|
-
continue
|
|
51
|
-
|
|
52
|
-
for file_path in provider_dir.rglob("*.py"):
|
|
53
|
-
if file_path.name == "__init__.py":
|
|
54
|
-
continue
|
|
55
|
-
|
|
56
|
-
# Convert file path to module path
|
|
57
|
-
module_path = ".".join(file_path.relative_to(base_path).with_suffix("").parts)
|
|
58
|
-
|
|
59
|
-
# Remove 'site-packages.' prefix if present
|
|
60
|
-
if 'site-packages.' in module_path:
|
|
61
|
-
module_path = module_path.split('site-packages.')[1]
|
|
62
|
-
|
|
63
|
-
try:
|
|
64
|
-
# Import the module
|
|
65
|
-
module = importlib.import_module(module_path.strip())
|
|
66
|
-
|
|
67
|
-
# Find and register provider classes
|
|
68
|
-
for _, concrete in inspect.getmembers(module, inspect.isclass):
|
|
69
|
-
if issubclass(concrete, ServiceProvider) and concrete is not ServiceProvider:
|
|
70
|
-
self._register(concrete)
|
|
71
|
-
except Exception as e:
|
|
72
|
-
raise BootstrapRuntimeError(f"Error loading module {module_path}: {str(e)}") from e
|
|
73
|
-
|
|
74
|
-
# Register manually provided service providers
|
|
75
|
-
try:
|
|
76
|
-
for concrete in self._custom_providers:
|
|
77
|
-
if issubclass(concrete, ServiceProvider) and concrete is not ServiceProvider:
|
|
78
|
-
self._register(concrete)
|
|
79
|
-
except Exception as e:
|
|
80
|
-
raise BootstrapRuntimeError(f"Error loading provider classes: {str(e)}") from e
|
|
81
|
-
|
|
82
|
-
def _register(self, concrete: Type[IServiceProvider]) -> None:
|
|
83
|
-
"""
|
|
84
|
-
Validates and registers a service provider class.
|
|
85
|
-
|
|
86
|
-
This method ensures that the provided class is valid (inherits from `IServiceProvider`,
|
|
87
|
-
has a `register` and `boot` method) and registers it in the appropriate list.
|
|
88
|
-
|
|
89
|
-
Args:
|
|
90
|
-
concrete (Type[IServiceProvider]): The service provider class to register.
|
|
91
|
-
|
|
92
|
-
Raises:
|
|
93
|
-
BootstrapRuntimeError: If the provider class is invalid.
|
|
94
|
-
"""
|
|
95
|
-
if not hasattr(concrete, "register") or not callable(concrete.register):
|
|
96
|
-
raise BootstrapRuntimeError(f"Service provider {concrete.__name__} must implement a 'register' method.")
|
|
97
|
-
|
|
98
|
-
self._service_providers.append(concrete)
|
|
99
|
-
|
|
100
|
-
def get(self) -> List[Type[IServiceProvider]]:
|
|
101
|
-
"""
|
|
102
|
-
Retrieve the registered service providers that should run before bootstrapping.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
List[Type[IServiceProvider]]: A list of service providers to run before bootstrapping.
|
|
106
|
-
"""
|
|
107
|
-
return self._service_providers
|
orionis/_services/__init__.py
DELETED
|
File without changes
|
|
File without changes
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from typing import Any, Dict, Optional
|
|
3
|
-
from orionis._console.base.command import BaseCommand
|
|
4
|
-
from orionis._console.command_filter import CommandFilter
|
|
5
|
-
from orionis._console.exceptions.cli_exception import CLIOrionisException
|
|
6
|
-
from orionis._console.output.console import Console
|
|
7
|
-
from orionis._console.output.executor import Executor
|
|
8
|
-
from orionis._console.parser import Parser
|
|
9
|
-
from orionis._contracts.application import IApplication
|
|
10
|
-
from orionis._contracts.services.log.log_service import ILogguerService
|
|
11
|
-
from orionis._facades.app_facade import app
|
|
12
|
-
|
|
13
|
-
class ReactorCommandsService:
|
|
14
|
-
"""
|
|
15
|
-
Service responsible for executing and managing CLI commands in Orionis.
|
|
16
|
-
|
|
17
|
-
This service handles:
|
|
18
|
-
- Parsing command arguments.
|
|
19
|
-
- Executing commands and logging their output.
|
|
20
|
-
- Managing execution timing and error handling.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, command_filter: CommandFilter, log: ILogguerService, executor: Executor, console: Console, app : IApplication) -> None:
|
|
24
|
-
"""
|
|
25
|
-
Initializes the ReactorCommandsService instance.
|
|
26
|
-
|
|
27
|
-
Assigns provided services to internal attributes for later use in command
|
|
28
|
-
execution, filtering, and logging.
|
|
29
|
-
"""
|
|
30
|
-
self.commands = app._commands if hasattr(app, '_commands') else {}
|
|
31
|
-
self.command_filter = command_filter
|
|
32
|
-
self.log = log
|
|
33
|
-
self.console_executor = executor
|
|
34
|
-
self.console_output = console
|
|
35
|
-
|
|
36
|
-
def _parse_arguments(self, arguments, vars: Optional[Dict[str, Any]] = None, *args, **kwargs):
|
|
37
|
-
"""
|
|
38
|
-
Parses command-line arguments using the Orionis argument parser.
|
|
39
|
-
|
|
40
|
-
Utilizes an internal parser to convert raw arguments into structured data.
|
|
41
|
-
Handles exceptions to ensure errors are properly raised and managed.
|
|
42
|
-
"""
|
|
43
|
-
try:
|
|
44
|
-
arg_parser = Parser(vars=vars or {}, args=args, kwargs=kwargs)
|
|
45
|
-
arg_parser.setArguments(arguments=arguments)
|
|
46
|
-
arg_parser.recognize()
|
|
47
|
-
return arg_parser.get()
|
|
48
|
-
except Exception as e:
|
|
49
|
-
raise ValueError(f"Error parsing arguments: {e}")
|
|
50
|
-
|
|
51
|
-
def _extract_arguments(self, args_dict:Any):
|
|
52
|
-
"""
|
|
53
|
-
Extracts the arguments from the provided dictionary.
|
|
54
|
-
|
|
55
|
-
Parameters
|
|
56
|
-
----------
|
|
57
|
-
args_dict : Any
|
|
58
|
-
A dictionary containing the arguments to extract.
|
|
59
|
-
"""
|
|
60
|
-
try:
|
|
61
|
-
return vars(args_dict)
|
|
62
|
-
except Exception as e:
|
|
63
|
-
raise ValueError(f"Error parsing arguments: {e}")
|
|
64
|
-
|
|
65
|
-
def _call(self, signature: str, args_dict: Any) -> Any:
|
|
66
|
-
"""
|
|
67
|
-
Executes the specified command with the provided arguments.
|
|
68
|
-
|
|
69
|
-
Parameters
|
|
70
|
-
----------
|
|
71
|
-
signature : str
|
|
72
|
-
The command signature (name) to execute.
|
|
73
|
-
args_dict : Any
|
|
74
|
-
A dictionary containing named arguments for the command.
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
command_instance: BaseCommand = app(signature)
|
|
78
|
-
command_instance.setArgs(args_dict)
|
|
79
|
-
return command_instance.handle(**self._extract_arguments(args_dict))
|
|
80
|
-
|
|
81
|
-
def execute(self, signature: Optional[str] = None, vars: dict = {}, *args, **kwargs):
|
|
82
|
-
"""
|
|
83
|
-
Processes and executes a CLI command.
|
|
84
|
-
|
|
85
|
-
Determines if the command originates from `sys.argv` or is explicitly called,
|
|
86
|
-
then executes the appropriate command pipeline, handling success and errors.
|
|
87
|
-
"""
|
|
88
|
-
try:
|
|
89
|
-
|
|
90
|
-
# Determine if command is excluded from running
|
|
91
|
-
exclude_running = self.command_filter.isExcluded(signature)
|
|
92
|
-
sys_argv = signature is None
|
|
93
|
-
|
|
94
|
-
# Start timing execution
|
|
95
|
-
start_time = time.perf_counter()
|
|
96
|
-
|
|
97
|
-
# Extract signature and arguments from command-line input
|
|
98
|
-
if sys_argv:
|
|
99
|
-
if not args or len(args[0]) <= 1:
|
|
100
|
-
raise CLIOrionisException("No command signature specified. Please provide a valid command to execute.")
|
|
101
|
-
args_list = args[0]
|
|
102
|
-
signature, *args = args_list[1:]
|
|
103
|
-
|
|
104
|
-
# Log command execution
|
|
105
|
-
self.log.info(f"Running command: {signature}")
|
|
106
|
-
|
|
107
|
-
# Notify console
|
|
108
|
-
if not exclude_running:
|
|
109
|
-
self.console_executor.running(program=signature)
|
|
110
|
-
|
|
111
|
-
# Retrieve command from bootstrapper
|
|
112
|
-
command = self.commands.get(signature)
|
|
113
|
-
|
|
114
|
-
# Parse command arguments dynamically based on execution context
|
|
115
|
-
args_dict = self._parse_arguments(command.get('arguments', []), vars, *args, **kwargs)
|
|
116
|
-
|
|
117
|
-
# Exception handling for command execution
|
|
118
|
-
output = self._call(signature, args_dict)
|
|
119
|
-
|
|
120
|
-
# Log successful command execution
|
|
121
|
-
self.log.success(f"Command executed successfully: {signature}")
|
|
122
|
-
|
|
123
|
-
# Finalize execution and report elapsed time
|
|
124
|
-
if not exclude_running:
|
|
125
|
-
elapsed_time = round(time.perf_counter() - start_time, 2)
|
|
126
|
-
self.console_executor.done(program=signature, time=f"{elapsed_time}s")
|
|
127
|
-
|
|
128
|
-
# Return command output
|
|
129
|
-
return output
|
|
130
|
-
|
|
131
|
-
except ValueError as e:
|
|
132
|
-
# Handle parsing errors
|
|
133
|
-
self.log.error(f"Command failed: {signature or 'Unknown'}, Value Error: {e}")
|
|
134
|
-
if not exclude_running:
|
|
135
|
-
self.console_output.error(message=f"Value Error: {e}")
|
|
136
|
-
elapsed_time = round(time.perf_counter() - start_time, 2)
|
|
137
|
-
self.console_executor.fail(program=signature or "Unknown", time=f"{elapsed_time}s")
|
|
138
|
-
self.console_output.exception(e)
|
|
139
|
-
|
|
140
|
-
except Exception as e:
|
|
141
|
-
# Handle unexpected execution errors
|
|
142
|
-
self.log.error(f"Command failed: {signature or 'Unknown'}, Execution Error: {e}")
|
|
143
|
-
if not exclude_running:
|
|
144
|
-
self.console_output.error(message=f"Execution Error: {e}")
|
|
145
|
-
elapsed_time = round(time.perf_counter() - start_time, 2)
|
|
146
|
-
self.console_executor.fail(program=signature or "Unknown", time=f"{elapsed_time}s")
|
|
147
|
-
self.console_output.exception(e)
|
|
148
|
-
|