orionis 0.1.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 (133) hide show
  1. orionis/__init__.py +0 -0
  2. orionis/cli_manager.py +48 -0
  3. orionis/framework.py +45 -0
  4. orionis/luminate/__init__.py +0 -0
  5. orionis/luminate/app.py +0 -0
  6. orionis/luminate/bootstrap/__init__.py +0 -0
  7. orionis/luminate/bootstrap/parser.py +49 -0
  8. orionis/luminate/bootstrap/register.py +95 -0
  9. orionis/luminate/cache/__init__.py +0 -0
  10. orionis/luminate/cache/app/__init__.py +0 -0
  11. orionis/luminate/cache/app/config.py +96 -0
  12. orionis/luminate/cache/console/__init__.py +0 -0
  13. orionis/luminate/cache/console/commands.py +98 -0
  14. orionis/luminate/config/__init__.py +0 -0
  15. orionis/luminate/config/dataclass/__init__.py +0 -0
  16. orionis/luminate/config/dataclass/app.py +50 -0
  17. orionis/luminate/config/dataclass/auth.py +17 -0
  18. orionis/luminate/config/dataclass/cache.py +51 -0
  19. orionis/luminate/config/dataclass/cors.py +58 -0
  20. orionis/luminate/config/dataclass/database.py +203 -0
  21. orionis/luminate/config/dataclass/filesystems.py +102 -0
  22. orionis/luminate/config/dataclass/logging.py +107 -0
  23. orionis/luminate/config/dataclass/mail.py +81 -0
  24. orionis/luminate/config/dataclass/queue.py +63 -0
  25. orionis/luminate/config/dataclass/session.py +59 -0
  26. orionis/luminate/config/environment.py +110 -0
  27. orionis/luminate/config/sections.py +37 -0
  28. orionis/luminate/console/__init__.py +0 -0
  29. orionis/luminate/console/base/__init__.py +0 -0
  30. orionis/luminate/console/base/command.py +427 -0
  31. orionis/luminate/console/cache.py +132 -0
  32. orionis/luminate/console/command.py +40 -0
  33. orionis/luminate/console/command_filter.py +40 -0
  34. orionis/luminate/console/commands/__init__.py +0 -0
  35. orionis/luminate/console/commands/cache_clear.py +56 -0
  36. orionis/luminate/console/commands/help.py +59 -0
  37. orionis/luminate/console/commands/schedule_work.py +50 -0
  38. orionis/luminate/console/commands/tests.py +40 -0
  39. orionis/luminate/console/commands/version.py +39 -0
  40. orionis/luminate/console/exceptions/__init__.py +0 -0
  41. orionis/luminate/console/exceptions/cli_exception.py +125 -0
  42. orionis/luminate/console/kernel.py +32 -0
  43. orionis/luminate/console/output/__init__.py +0 -0
  44. orionis/luminate/console/output/console.py +426 -0
  45. orionis/luminate/console/output/executor.py +90 -0
  46. orionis/luminate/console/output/progress_bar.py +100 -0
  47. orionis/luminate/console/output/styles.py +95 -0
  48. orionis/luminate/console/parser.py +159 -0
  49. orionis/luminate/console/register.py +98 -0
  50. orionis/luminate/console/runner.py +126 -0
  51. orionis/luminate/console/scripts/__init__.py +0 -0
  52. orionis/luminate/console/scripts/management.py +94 -0
  53. orionis/luminate/console/tasks/__init__.py +0 -0
  54. orionis/luminate/console/tasks/scheduler.py +616 -0
  55. orionis/luminate/contracts/__init__.py +0 -0
  56. orionis/luminate/contracts/bootstrap/parser_interface.py +46 -0
  57. orionis/luminate/contracts/cache/__init__.py +0 -0
  58. orionis/luminate/contracts/cache/cache_commands_interface.py +69 -0
  59. orionis/luminate/contracts/config/__init__.py +0 -0
  60. orionis/luminate/contracts/config/config_interface.py +27 -0
  61. orionis/luminate/contracts/config/environment_interface.py +64 -0
  62. orionis/luminate/contracts/console/__init__.py +0 -0
  63. orionis/luminate/contracts/console/base_command_interface.py +448 -0
  64. orionis/luminate/contracts/console/cli_cache_interface.py +34 -0
  65. orionis/luminate/contracts/console/command_filter_interface.py +32 -0
  66. orionis/luminate/contracts/console/command_interface.py +36 -0
  67. orionis/luminate/contracts/console/console_interface.py +305 -0
  68. orionis/luminate/contracts/console/executor_interface.py +51 -0
  69. orionis/luminate/contracts/console/kernel_interface.py +32 -0
  70. orionis/luminate/contracts/console/management_interface.py +63 -0
  71. orionis/luminate/contracts/console/parser_interface.py +76 -0
  72. orionis/luminate/contracts/console/progress_bar_interface.py +66 -0
  73. orionis/luminate/contracts/console/register_interface.py +32 -0
  74. orionis/luminate/contracts/console/runner_interface.py +50 -0
  75. orionis/luminate/contracts/console/schedule_interface.py +317 -0
  76. orionis/luminate/contracts/console/task_manager_interface.py +37 -0
  77. orionis/luminate/contracts/facades/__init__.py +0 -0
  78. orionis/luminate/contracts/facades/env_interface.py +64 -0
  79. orionis/luminate/contracts/facades/log_interface.py +48 -0
  80. orionis/luminate/contracts/facades/paths_interface.py +141 -0
  81. orionis/luminate/contracts/facades/tests_interface.py +33 -0
  82. orionis/luminate/contracts/files/__init__.py +0 -0
  83. orionis/luminate/contracts/files/paths_interface.py +29 -0
  84. orionis/luminate/contracts/installer/__init__.py +0 -0
  85. orionis/luminate/contracts/installer/output_interface.py +125 -0
  86. orionis/luminate/contracts/installer/setup_interface.py +29 -0
  87. orionis/luminate/contracts/installer/upgrade_interface.py +24 -0
  88. orionis/luminate/contracts/log/__init__.py +0 -0
  89. orionis/luminate/contracts/log/logger_interface.py +33 -0
  90. orionis/luminate/contracts/pipelines/cli_pipeline_interface.py +84 -0
  91. orionis/luminate/contracts/publisher/__init__.py +0 -0
  92. orionis/luminate/contracts/publisher/pypi_publisher_interface.py +36 -0
  93. orionis/luminate/contracts/test/__init__.py +0 -0
  94. orionis/luminate/contracts/test/unit_test_interface.py +51 -0
  95. orionis/luminate/contracts/tools/__init__.py +0 -0
  96. orionis/luminate/contracts/tools/reflection_interface.py +343 -0
  97. orionis/luminate/contracts/tools/std_interface.py +56 -0
  98. orionis/luminate/facades/__init__.py +0 -0
  99. orionis/luminate/facades/environment.py +81 -0
  100. orionis/luminate/facades/log.py +56 -0
  101. orionis/luminate/facades/paths.py +268 -0
  102. orionis/luminate/facades/tests.py +48 -0
  103. orionis/luminate/files/__init__.py +0 -0
  104. orionis/luminate/files/paths.py +56 -0
  105. orionis/luminate/installer/__init__.py +0 -0
  106. orionis/luminate/installer/icon.ascii +11 -0
  107. orionis/luminate/installer/info.ascii +13 -0
  108. orionis/luminate/installer/output.py +188 -0
  109. orionis/luminate/installer/setup.py +191 -0
  110. orionis/luminate/installer/upgrade.py +42 -0
  111. orionis/luminate/log/__init__.py +0 -0
  112. orionis/luminate/log/logger.py +116 -0
  113. orionis/luminate/pipelines/__init__.py +0 -0
  114. orionis/luminate/pipelines/cli_pipeline.py +116 -0
  115. orionis/luminate/publisher/__init__.py +0 -0
  116. orionis/luminate/publisher/pypi.py +206 -0
  117. orionis/luminate/static/logos/flaskavel.png +0 -0
  118. orionis/luminate/test/__init__.py +0 -0
  119. orionis/luminate/test/exception.py +48 -0
  120. orionis/luminate/test/unit_test.py +108 -0
  121. orionis/luminate/tools/__init__.py +0 -0
  122. orionis/luminate/tools/reflection.py +390 -0
  123. orionis/luminate/tools/std.py +53 -0
  124. orionis-0.1.0.dist-info/LICENCE +21 -0
  125. orionis-0.1.0.dist-info/METADATA +27 -0
  126. orionis-0.1.0.dist-info/RECORD +133 -0
  127. orionis-0.1.0.dist-info/WHEEL +5 -0
  128. orionis-0.1.0.dist-info/entry_points.txt +2 -0
  129. orionis-0.1.0.dist-info/top_level.txt +2 -0
  130. tests/__init__.py +0 -0
  131. tests/tools/__init__.py +0 -0
  132. tests/tools/class_example.py +50 -0
  133. tests/tools/test_reflection.py +128 -0
@@ -0,0 +1,110 @@
1
+ import os
2
+ import threading
3
+ from pathlib import Path
4
+ from dotenv import set_key, unset_key, dotenv_values
5
+ from orionis.luminate.contracts.config.environment_interface import IEnvironment
6
+
7
+ class Environment(IEnvironment):
8
+ """
9
+ Singleton class to manage environment variables from a .env file.
10
+ Ensures a single instance handles environment variable access,
11
+ modification, and deletion.
12
+ """
13
+
14
+ # Singleton instance
15
+ _instance = None
16
+
17
+ # Thread lock to control instance creation
18
+ _lock = threading.Lock()
19
+
20
+ def __new__(cls, path: str = None):
21
+ """
22
+ Creates or returns the singleton instance.
23
+ Ensures thread-safe initialization using a lock.
24
+
25
+ Parameters
26
+ ----------
27
+ path : str, optional
28
+ Path to the .env file. Defaults to None.
29
+
30
+ Returns
31
+ -------
32
+ _Environment
33
+ The singleton instance of _Environment.
34
+ """
35
+ with cls._lock:
36
+ if cls._instance is None:
37
+ cls._instance = super().__new__(cls)
38
+ cls._instance._initialize(path)
39
+ return cls._instance
40
+
41
+ def _initialize(self, path: str = None):
42
+ """
43
+ Initializes the instance by setting the path to the .env file.
44
+ If no path is provided, defaults to a `.env` file in the current directory.
45
+
46
+ Parameters
47
+ ----------
48
+ path : str, optional
49
+ Path to the .env file. Defaults to None.
50
+ """
51
+ self.path = Path(path) if path else Path(os.getcwd()) / ".env"
52
+
53
+ # Ensure the .env file exists
54
+ if not self.path.exists():
55
+ self.path.touch()
56
+
57
+ def get(self, key: str, default=None) -> str:
58
+ """
59
+ Retrieves the value of an environment variable from the .env file
60
+ or from system environment variables if not found.
61
+
62
+ Parameters
63
+ ----------
64
+ key : str
65
+ The key of the environment variable.
66
+ default : optional
67
+ Default value if the key does not exist. Defaults to None.
68
+
69
+ Returns
70
+ -------
71
+ str
72
+ The value of the environment variable or the default value.
73
+ """
74
+ value = dotenv_values(self.path).get(key)
75
+ return value if value is not None else os.getenv(key, default)
76
+
77
+ def set(self, key: str, value: str) -> None:
78
+ """
79
+ Sets the value of an environment variable in the .env file.
80
+
81
+ Parameters
82
+ ----------
83
+ key : str
84
+ The key of the environment variable.
85
+ value : str
86
+ The value to set.
87
+ """
88
+ set_key(str(self.path), key, value)
89
+
90
+ def unset(self, key: str) -> None:
91
+ """
92
+ Removes an environment variable from the .env file.
93
+
94
+ Parameters
95
+ ----------
96
+ key : str
97
+ The key of the environment variable to remove.
98
+ """
99
+ unset_key(str(self.path), key)
100
+
101
+ def all(self) -> dict:
102
+ """
103
+ Retrieves all environment variable values from the .env file.
104
+
105
+ Returns
106
+ -------
107
+ dict
108
+ A dictionary of all environment variables and their values.
109
+ """
110
+ return dotenv_values(self.path)
@@ -0,0 +1,37 @@
1
+ # ------------------------------------------------------------------------------
2
+ # Authorized Configuration Sections for Bootstrapping
3
+ # ------------------------------------------------------------------------------
4
+ # This tuple defines the only allowed configuration sections that can be used
5
+ # during the application's bootstrapping process.
6
+ #
7
+ # Each section represents a core component of the framework, ensuring that only
8
+ # predefined and necessary configurations are loaded at startup. This prevents
9
+ # unauthorized modifications or unintended settings from being injected.
10
+ #
11
+ # Sections:
12
+ # - app : General application settings.
13
+ # - auth : Authentication and authorization settings.
14
+ # - cache : Configuration for caching mechanisms.
15
+ # - cors : Cross-Origin Resource Sharing (CORS) policies.
16
+ # - database : Database connection and ORM settings.
17
+ # - filesystems: File storage configurations.
18
+ # - logging : Logging and monitoring settings.
19
+ # - mail : Email sending and SMTP configurations.
20
+ # - queue : Queue system settings for background tasks.
21
+ # - session : Session management configurations.
22
+ #
23
+ # Any configuration outside these sections will be ignored or rejected.
24
+ # ------------------------------------------------------------------------------
25
+
26
+ SECTIONS = (
27
+ 'app',
28
+ 'auth',
29
+ 'cache',
30
+ 'cors',
31
+ 'database',
32
+ 'filesystems',
33
+ 'logging',
34
+ 'mail',
35
+ 'queue',
36
+ 'session'
37
+ )
File without changes
File without changes
@@ -0,0 +1,427 @@
1
+ from orionis.luminate.console.output.console import Console
2
+ from orionis.luminate.console.output.progress_bar import ProgressBar
3
+ from orionis.luminate.contracts.console.base_command_interface import IBaseCommand
4
+
5
+ class BaseCommand(IBaseCommand):
6
+ """
7
+ A base class for handling common console output functionalities. This class provides methods to print messages of
8
+ various types (success, info, warning, etc.) in different styles (e.g., text, bold, colored).
9
+
10
+ This class acts as a foundation for command classes, offering utility methods to interact with the console.
11
+ """
12
+
13
+ # Command arguments
14
+ args = {}
15
+
16
+ def success(self, message: str = '', timestamp: bool = True):
17
+ """
18
+ Prints a success message with a green background.
19
+
20
+ Parameters
21
+ ----------
22
+ message : str, optional
23
+ The message to display (default is an empty string).
24
+ timestamp : bool, optional
25
+ Whether to include a timestamp (default is True).
26
+ """
27
+ Console.success(message, timestamp)
28
+
29
+ def textSuccess(self, message: str = ''):
30
+ """
31
+ Prints a success message in green.
32
+
33
+ Parameters
34
+ ----------
35
+ message : str, optional
36
+ The message to display (default is an empty string).
37
+ """
38
+ Console.textSuccess(message)
39
+
40
+ def textSuccessBold(self, message: str = ''):
41
+ """
42
+ Prints a bold success message in green.
43
+
44
+ Parameters
45
+ ----------
46
+ message : str, optional
47
+ The message to display (default is an empty string).
48
+ """
49
+ Console.textSuccessBold(message)
50
+
51
+ def info(self, message: str = '', timestamp: bool = True):
52
+ """
53
+ Prints an informational message with a blue background.
54
+
55
+ Parameters
56
+ ----------
57
+ message : str, optional
58
+ The message to display (default is an empty string).
59
+ timestamp : bool, optional
60
+ Whether to include a timestamp (default is True).
61
+ """
62
+ Console.info(message, timestamp)
63
+
64
+ def textInfo(self, message: str = ''):
65
+ """
66
+ Prints an informational message in blue.
67
+
68
+ Parameters
69
+ ----------
70
+ message : str, optional
71
+ The message to display (default is an empty string).
72
+ """
73
+ Console.textInfo(message)
74
+
75
+ def textInfoBold(self, message: str = ''):
76
+ """
77
+ Prints a bold informational message in blue.
78
+
79
+ Parameters
80
+ ----------
81
+ message : str, optional
82
+ The message to display (default is an empty string).
83
+ """
84
+ Console.textInfoBold(message)
85
+
86
+ def warning(self, message: str = '', timestamp: bool = True):
87
+ """
88
+ Prints a warning message with a yellow background.
89
+
90
+ Parameters
91
+ ----------
92
+ message : str, optional
93
+ The message to display (default is an empty string).
94
+ timestamp : bool, optional
95
+ Whether to include a timestamp (default is True).
96
+ """
97
+ Console.warning(message, timestamp)
98
+
99
+ def textWarning(self, message: str = ''):
100
+ """
101
+ Prints a warning message in yellow.
102
+
103
+ Parameters
104
+ ----------
105
+ message : str, optional
106
+ The message to display (default is an empty string).
107
+ """
108
+ Console.textWarning(message)
109
+
110
+ def textWarningBold(self, message: str = ''):
111
+ """
112
+ Prints a bold warning message in yellow.
113
+
114
+ Parameters
115
+ ----------
116
+ message : str, optional
117
+ The message to display (default is an empty string).
118
+ """
119
+ Console.textWarningBold(message)
120
+
121
+ def fail(self, message: str = '', timestamp: bool = True):
122
+ """
123
+ Prints a failure message with a red background.
124
+
125
+ Parameters
126
+ ----------
127
+ message : str, optional
128
+ The message to display (default is an empty string).
129
+ timestamp : bool, optional
130
+ Whether to include a timestamp (default is True).
131
+ """
132
+ Console.fail(message, timestamp)
133
+
134
+ def error(self, message: str = '', timestamp: bool = True):
135
+ """
136
+ Prints an error message with a red background.
137
+
138
+ Parameters
139
+ ----------
140
+ message : str, optional
141
+ The message to display (default is an empty string).
142
+ timestamp : bool, optional
143
+ Whether to include a timestamp (default is True).
144
+ """
145
+ Console.error(message, timestamp)
146
+
147
+ def textError(self, message: str = ''):
148
+ """
149
+ Prints an error message in red.
150
+
151
+ Parameters
152
+ ----------
153
+ message : str, optional
154
+ The message to display (default is an empty string).
155
+ """
156
+ Console.textError(message)
157
+
158
+ def textErrorBold(self, message: str = ''):
159
+ """
160
+ Prints a bold error message in red.
161
+
162
+ Parameters
163
+ ----------
164
+ message : str, optional
165
+ The message to display (default is an empty string).
166
+ """
167
+ Console.textErrorBold(message)
168
+
169
+ def textMuted(self, message: str = ''):
170
+ """
171
+ Prints a muted (gray) message.
172
+
173
+ Parameters
174
+ ----------
175
+ message : str, optional
176
+ The message to display (default is an empty string).
177
+ """
178
+ Console.textMuted(message)
179
+
180
+ def textMutedBold(self, message: str = ''):
181
+ """
182
+ Prints a bold muted (gray) message.
183
+
184
+ Parameters
185
+ ----------
186
+ message : str, optional
187
+ The message to display (default is an empty string).
188
+ """
189
+ Console.textMutedBold(message)
190
+
191
+ def textUnderline(self, message: str = ''):
192
+ """
193
+ Prints an underlined message.
194
+
195
+ Parameters
196
+ ----------
197
+ message : str, optional
198
+ The message to display (default is an empty string).
199
+ """
200
+ Console.textUnderline(message)
201
+
202
+ def clear(self):
203
+ """
204
+ Clears the console screen.
205
+ """
206
+ Console.clear()
207
+
208
+ def clearLine(self):
209
+ """
210
+ Clears the current console line.
211
+ """
212
+ Console.clearLine()
213
+
214
+ def line(self, message: str = ''):
215
+ """
216
+ Prints a line of text.
217
+
218
+ Parameters
219
+ ----------
220
+ message : str, optional
221
+ The message to display (default is an empty string).
222
+ """
223
+ Console.line(message)
224
+
225
+ def newLine(self, count: int = 1):
226
+ """
227
+ Prints multiple new lines.
228
+
229
+ Parameters
230
+ ----------
231
+ count : int, optional
232
+ The number of new lines to print (default is 1).
233
+ """
234
+ Console.newLine(count)
235
+
236
+ def write(self, message: str = ''):
237
+ """
238
+ Prints a message without moving to the next line.
239
+
240
+ Parameters
241
+ ----------
242
+ message : str, optional
243
+ The message to display (default is an empty string).
244
+ """
245
+ Console.write(message)
246
+
247
+ def writeLine(self, message: str = ''):
248
+ """
249
+ Prints a message and moves to the next line.
250
+
251
+ Parameters
252
+ ----------
253
+ message : str, optional
254
+ The message to display (default is an empty string).
255
+ """
256
+ Console.writeLine(message)
257
+
258
+ def ask(self, question: str) -> str:
259
+ """
260
+ Prompts the user for input and returns the response.
261
+
262
+ Parameters
263
+ ----------
264
+ question : str
265
+ The question to ask the user.
266
+
267
+ Returns
268
+ -------
269
+ str
270
+ The user's input.
271
+ """
272
+ return Console.ask(question)
273
+
274
+ def confirm(self, question: str, default: bool = False) -> bool:
275
+ """
276
+ Asks a confirmation question and returns True/False based on the user's response.
277
+
278
+ Parameters
279
+ ----------
280
+ question : str
281
+ The confirmation question to ask.
282
+ default : bool, optional
283
+ The default response if the user presses Enter without typing a response (default is False).
284
+
285
+ Returns
286
+ -------
287
+ bool
288
+ The user's response.
289
+ """
290
+ return Console.ask(question, default)
291
+
292
+ def secret(self, question: str) -> str:
293
+ """
294
+ Prompts for hidden input (e.g., password).
295
+
296
+ Parameters
297
+ ----------
298
+ question : str
299
+ The prompt to ask the user.
300
+
301
+ Returns
302
+ -------
303
+ str
304
+ The user's hidden input.
305
+ """
306
+ return Console.secret(question)
307
+
308
+ def table(self, headers: list, rows: list):
309
+ """
310
+ Prints a formatted table in the console.
311
+
312
+ Parameters
313
+ ----------
314
+ headers : list of str
315
+ The column headers for the table.
316
+ rows : list of list of str
317
+ The rows of the table.
318
+
319
+ Raises
320
+ ------
321
+ ValueError
322
+ If headers or rows are empty.
323
+ """
324
+ Console.table(headers, rows)
325
+
326
+ def anticipate(self, question: str, options: list, default=None):
327
+ """
328
+ Provides autocomplete suggestions for user input.
329
+
330
+ Parameters
331
+ ----------
332
+ question : str
333
+ The prompt for the user.
334
+ options : list of str
335
+ The list of possible options for autocomplete.
336
+ default : str, optional
337
+ The default value if no matching option is found (default is None).
338
+
339
+ Returns
340
+ -------
341
+ str
342
+ The chosen option or the default value.
343
+ """
344
+ Console.anticipate(question, options, default)
345
+
346
+ def choice(self, question: str, choices: list, default_index: int = 0) -> str:
347
+ """
348
+ Prompts the user to select a choice from a list.
349
+
350
+ Parameters
351
+ ----------
352
+ question : str
353
+ The prompt for the user.
354
+ choices : list of str
355
+ The list of available choices.
356
+ default_index : int, optional
357
+ The index of the default choice (default is 0).
358
+
359
+ Returns
360
+ -------
361
+ str
362
+ The selected choice.
363
+
364
+ Raises
365
+ ------
366
+ ValueError
367
+ If `default_index` is out of the range of choices.
368
+ """
369
+ Console.choice(question, choices, default_index)
370
+
371
+ def createProgressBar(self, total: int = 100, width: int = 50) -> ProgressBar:
372
+ """
373
+ Creates and returns a new progress bar.
374
+
375
+ This method initializes a `ProgressBar` object with the specified total and width.
376
+
377
+ Parameters
378
+ ----------
379
+ total : int, optional
380
+ The total number of steps for the progress bar. Default is 100.
381
+ width : int, optional
382
+ The width (in characters) of the progress bar. Default is 50.
383
+
384
+ Returns
385
+ -------
386
+ ProgressBar
387
+ A new instance of the `ProgressBar` class, initialized with the specified `total` and `width`.
388
+
389
+ Notes
390
+ -----
391
+ The progress bar can be used to visually track the progress of a task.
392
+ The `total` parameter represents the number of steps to complete the task,
393
+ and the `width` parameter controls the number of characters used to represent the progress bar in the console.
394
+ """
395
+ return ProgressBar(total=total, width=width)
396
+
397
+ def setArgs(self, args):
398
+ """
399
+ Define the logic of setting command arguments.
400
+
401
+ Parameters
402
+ ----------
403
+ args : argparse.Namespace
404
+ Contain the arguments to be set for the command.
405
+ """
406
+ try:
407
+ # Convert arguments to a dictionary using vars(), if possible
408
+ self.args = vars(args)
409
+ except TypeError:
410
+ # Fallback to an empty dictionary if args is not compatible with vars()
411
+ self.args = {}
412
+
413
+
414
+ def handle(self, **kwargs):
415
+ """
416
+ Abstract method to define the logic of the command.
417
+
418
+ This method must be overridden in subclasses.
419
+
420
+ Arguments:
421
+ **kwargs: Arbitrary keyword arguments.
422
+
423
+ Raises:
424
+ NotImplementedError: If the method is not implemented in a subclass. This ensures that all command classes
425
+ adhere to the expected structure.
426
+ """
427
+ raise NotImplementedError("The 'handle' method must be implemented in the child class.")
@@ -0,0 +1,132 @@
1
+ import os
2
+ from threading import Lock
3
+ from orionis.luminate.tools.reflection import Reflection
4
+ from orionis.luminate.cache.console.commands import CacheCommands
5
+ from orionis.luminate.contracts.console.cli_cache_interface import ICLICache
6
+
7
+ class CLICache(ICLICache):
8
+ """
9
+ Singleton class responsible for managing the loading and execution of commands within the framework.
10
+
11
+ This class ensures that commands are loaded only once and are accessible for execution. It is designed to follow
12
+ the Singleton pattern, meaning only one instance of this class will exist in the application lifecycle.
13
+
14
+ Attributes
15
+ ----------
16
+ _instance : CLICache
17
+ The singleton instance of the CLICache class.
18
+ _lock : threading.Lock
19
+ A lock used to ensure thread-safety during instance creation.
20
+ _initialized : bool
21
+ A flag indicating whether the class has been initialized.
22
+ paths : list
23
+ List of directories where commands are located.
24
+
25
+ Methods
26
+ -------
27
+ __new__ :
28
+ Creates and returns the singleton instance of the CLICache class.
29
+ __init__ :
30
+ Initializes the CLICache instance, loading commands if not already initialized.
31
+ _load_commands :
32
+ Loads command modules from predefined directories and imports them dynamically.
33
+ getCommands :
34
+ Returns the instance of CacheCommands containing the command cache.
35
+ """
36
+
37
+ _instance = None
38
+ _lock = Lock()
39
+
40
+ def __new__(cls):
41
+ """
42
+ Ensures only one instance of the CLICache class exists (Singleton pattern).
43
+
44
+ This method is responsible for controlling the instance creation process, ensuring that no more than one
45
+ CLICache instance is created in the system, even in multi-threaded environments.
46
+
47
+ Returns
48
+ -------
49
+ CLICache
50
+ The singleton instance of the CLICache class.
51
+ """
52
+ with cls._lock:
53
+ if cls._instance is None:
54
+ cls._instance = super(CLICache, cls).__new__(cls)
55
+ cls._instance._initialized = False
56
+ return cls._instance
57
+
58
+ def __init__(self) -> None:
59
+ """
60
+ Initializes the CLICache instance by loading commands if not already initialized.
61
+
62
+ This method will load command modules only once, ensuring that the commands are available for execution
63
+ across the application. It should not be called directly multiple times.
64
+
65
+ Attributes
66
+ ----------
67
+ paths : list
68
+ List of directories containing command files to be loaded.
69
+ """
70
+ if self._initialized:
71
+ return
72
+
73
+ self.paths = []
74
+ self._load_commands()
75
+ self._initialized = True
76
+
77
+ def _load_commands(self):
78
+ """
79
+ Dynamically loads command modules from predefined directories.
80
+
81
+ This method traverses the specified directories, locates Python files, and imports them as modules.
82
+ It ensures that only the main directories are iterated over, avoiding subdirectories.
83
+
84
+ Directories searched:
85
+ ---------------------
86
+ - app/console/commands (relative to the base path)
87
+ - Current directory of the module (this file's directory)
88
+ """
89
+ paths = []
90
+
91
+ # Define the base path of the application
92
+ base_path = os.getcwd()
93
+
94
+ # Define command directories to be searched
95
+ command_dirs = [
96
+ os.path.join(base_path, 'app', 'console', 'commands'),
97
+ os.path.join(os.path.dirname(__file__), 'commands')
98
+ ]
99
+
100
+ # Add valid directories to paths list
101
+ for command_dir in command_dirs:
102
+ if os.path.isdir(command_dir):
103
+ paths.append(command_dir)
104
+
105
+ # Iterate over each valid directory
106
+ for path in paths:
107
+ for current_directory, _, files in os.walk(path):
108
+ # Ensure to only iterate through the top-level directories
109
+ if current_directory == path:
110
+ pre_module = current_directory.replace(base_path, '').replace(os.sep, '.').lstrip('.')
111
+ for file in files:
112
+ if file.endswith('.py'):
113
+ # Construct the module name and path
114
+ module_name = file[:-3] # Remove the '.py' extension
115
+ module_path = f"{pre_module}.{module_name}".replace('venv.Lib.site-packages.', '')
116
+
117
+ # Use Reflection to load the module dynamically
118
+ Reflection(module=module_path)
119
+
120
+ def getCommands(self):
121
+ """
122
+ Returns the instance of the CacheCommands containing the command cache.
123
+
124
+ This method provides access to the CacheCommands instance, which holds the loaded commands cache
125
+ and makes it available for use.
126
+
127
+ Returns
128
+ -------
129
+ CacheCommands
130
+ The instance of CacheCommands that holds the cached commands.
131
+ """
132
+ return CacheCommands()