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.
- orionis/__init__.py +0 -0
- orionis/cli_manager.py +48 -0
- orionis/framework.py +45 -0
- orionis/luminate/__init__.py +0 -0
- orionis/luminate/app.py +0 -0
- orionis/luminate/bootstrap/__init__.py +0 -0
- orionis/luminate/bootstrap/parser.py +49 -0
- orionis/luminate/bootstrap/register.py +95 -0
- orionis/luminate/cache/__init__.py +0 -0
- orionis/luminate/cache/app/__init__.py +0 -0
- orionis/luminate/cache/app/config.py +96 -0
- orionis/luminate/cache/console/__init__.py +0 -0
- orionis/luminate/cache/console/commands.py +98 -0
- orionis/luminate/config/__init__.py +0 -0
- orionis/luminate/config/dataclass/__init__.py +0 -0
- orionis/luminate/config/dataclass/app.py +50 -0
- orionis/luminate/config/dataclass/auth.py +17 -0
- orionis/luminate/config/dataclass/cache.py +51 -0
- orionis/luminate/config/dataclass/cors.py +58 -0
- orionis/luminate/config/dataclass/database.py +203 -0
- orionis/luminate/config/dataclass/filesystems.py +102 -0
- orionis/luminate/config/dataclass/logging.py +107 -0
- orionis/luminate/config/dataclass/mail.py +81 -0
- orionis/luminate/config/dataclass/queue.py +63 -0
- orionis/luminate/config/dataclass/session.py +59 -0
- orionis/luminate/config/environment.py +110 -0
- orionis/luminate/config/sections.py +37 -0
- orionis/luminate/console/__init__.py +0 -0
- orionis/luminate/console/base/__init__.py +0 -0
- orionis/luminate/console/base/command.py +427 -0
- orionis/luminate/console/cache.py +132 -0
- orionis/luminate/console/command.py +40 -0
- orionis/luminate/console/command_filter.py +40 -0
- orionis/luminate/console/commands/__init__.py +0 -0
- orionis/luminate/console/commands/cache_clear.py +56 -0
- orionis/luminate/console/commands/help.py +59 -0
- orionis/luminate/console/commands/schedule_work.py +50 -0
- orionis/luminate/console/commands/tests.py +40 -0
- orionis/luminate/console/commands/version.py +39 -0
- orionis/luminate/console/exceptions/__init__.py +0 -0
- orionis/luminate/console/exceptions/cli_exception.py +125 -0
- orionis/luminate/console/kernel.py +32 -0
- orionis/luminate/console/output/__init__.py +0 -0
- orionis/luminate/console/output/console.py +426 -0
- orionis/luminate/console/output/executor.py +90 -0
- orionis/luminate/console/output/progress_bar.py +100 -0
- orionis/luminate/console/output/styles.py +95 -0
- orionis/luminate/console/parser.py +159 -0
- orionis/luminate/console/register.py +98 -0
- orionis/luminate/console/runner.py +126 -0
- orionis/luminate/console/scripts/__init__.py +0 -0
- orionis/luminate/console/scripts/management.py +94 -0
- orionis/luminate/console/tasks/__init__.py +0 -0
- orionis/luminate/console/tasks/scheduler.py +616 -0
- orionis/luminate/contracts/__init__.py +0 -0
- orionis/luminate/contracts/bootstrap/parser_interface.py +46 -0
- orionis/luminate/contracts/cache/__init__.py +0 -0
- orionis/luminate/contracts/cache/cache_commands_interface.py +69 -0
- orionis/luminate/contracts/config/__init__.py +0 -0
- orionis/luminate/contracts/config/config_interface.py +27 -0
- orionis/luminate/contracts/config/environment_interface.py +64 -0
- orionis/luminate/contracts/console/__init__.py +0 -0
- orionis/luminate/contracts/console/base_command_interface.py +448 -0
- orionis/luminate/contracts/console/cli_cache_interface.py +34 -0
- orionis/luminate/contracts/console/command_filter_interface.py +32 -0
- orionis/luminate/contracts/console/command_interface.py +36 -0
- orionis/luminate/contracts/console/console_interface.py +305 -0
- orionis/luminate/contracts/console/executor_interface.py +51 -0
- orionis/luminate/contracts/console/kernel_interface.py +32 -0
- orionis/luminate/contracts/console/management_interface.py +63 -0
- orionis/luminate/contracts/console/parser_interface.py +76 -0
- orionis/luminate/contracts/console/progress_bar_interface.py +66 -0
- orionis/luminate/contracts/console/register_interface.py +32 -0
- orionis/luminate/contracts/console/runner_interface.py +50 -0
- orionis/luminate/contracts/console/schedule_interface.py +317 -0
- orionis/luminate/contracts/console/task_manager_interface.py +37 -0
- orionis/luminate/contracts/facades/__init__.py +0 -0
- orionis/luminate/contracts/facades/env_interface.py +64 -0
- orionis/luminate/contracts/facades/log_interface.py +48 -0
- orionis/luminate/contracts/facades/paths_interface.py +141 -0
- orionis/luminate/contracts/facades/tests_interface.py +33 -0
- orionis/luminate/contracts/files/__init__.py +0 -0
- orionis/luminate/contracts/files/paths_interface.py +29 -0
- orionis/luminate/contracts/installer/__init__.py +0 -0
- orionis/luminate/contracts/installer/output_interface.py +125 -0
- orionis/luminate/contracts/installer/setup_interface.py +29 -0
- orionis/luminate/contracts/installer/upgrade_interface.py +24 -0
- orionis/luminate/contracts/log/__init__.py +0 -0
- orionis/luminate/contracts/log/logger_interface.py +33 -0
- orionis/luminate/contracts/pipelines/cli_pipeline_interface.py +84 -0
- orionis/luminate/contracts/publisher/__init__.py +0 -0
- orionis/luminate/contracts/publisher/pypi_publisher_interface.py +36 -0
- orionis/luminate/contracts/test/__init__.py +0 -0
- orionis/luminate/contracts/test/unit_test_interface.py +51 -0
- orionis/luminate/contracts/tools/__init__.py +0 -0
- orionis/luminate/contracts/tools/reflection_interface.py +343 -0
- orionis/luminate/contracts/tools/std_interface.py +56 -0
- orionis/luminate/facades/__init__.py +0 -0
- orionis/luminate/facades/environment.py +81 -0
- orionis/luminate/facades/log.py +56 -0
- orionis/luminate/facades/paths.py +268 -0
- orionis/luminate/facades/tests.py +48 -0
- orionis/luminate/files/__init__.py +0 -0
- orionis/luminate/files/paths.py +56 -0
- orionis/luminate/installer/__init__.py +0 -0
- orionis/luminate/installer/icon.ascii +11 -0
- orionis/luminate/installer/info.ascii +13 -0
- orionis/luminate/installer/output.py +188 -0
- orionis/luminate/installer/setup.py +191 -0
- orionis/luminate/installer/upgrade.py +42 -0
- orionis/luminate/log/__init__.py +0 -0
- orionis/luminate/log/logger.py +116 -0
- orionis/luminate/pipelines/__init__.py +0 -0
- orionis/luminate/pipelines/cli_pipeline.py +116 -0
- orionis/luminate/publisher/__init__.py +0 -0
- orionis/luminate/publisher/pypi.py +206 -0
- orionis/luminate/static/logos/flaskavel.png +0 -0
- orionis/luminate/test/__init__.py +0 -0
- orionis/luminate/test/exception.py +48 -0
- orionis/luminate/test/unit_test.py +108 -0
- orionis/luminate/tools/__init__.py +0 -0
- orionis/luminate/tools/reflection.py +390 -0
- orionis/luminate/tools/std.py +53 -0
- orionis-0.1.0.dist-info/LICENCE +21 -0
- orionis-0.1.0.dist-info/METADATA +27 -0
- orionis-0.1.0.dist-info/RECORD +133 -0
- orionis-0.1.0.dist-info/WHEEL +5 -0
- orionis-0.1.0.dist-info/entry_points.txt +2 -0
- orionis-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/tools/__init__.py +0 -0
- tests/tools/class_example.py +50 -0
- tests/tools/test_reflection.py +128 -0
@@ -0,0 +1,426 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import getpass
|
4
|
+
import datetime
|
5
|
+
from orionis.luminate.console.output.styles import ANSIColors
|
6
|
+
from orionis.luminate.contracts.console.console_interface import IConsole
|
7
|
+
|
8
|
+
class Console(IConsole):
|
9
|
+
"""
|
10
|
+
Utility class for printing formatted messages to the console with ANSI colors.
|
11
|
+
|
12
|
+
Provides methods to print success, info, warning, and error messages with
|
13
|
+
optional timestamps, as well as general text formatting methods.
|
14
|
+
"""
|
15
|
+
|
16
|
+
@staticmethod
|
17
|
+
def _get_timestamp() -> str:
|
18
|
+
"""
|
19
|
+
Returns the current date and time formatted in a muted color.
|
20
|
+
|
21
|
+
Returns
|
22
|
+
-------
|
23
|
+
str
|
24
|
+
The formatted timestamp with muted color.
|
25
|
+
"""
|
26
|
+
return f"{ANSIColors.TEXT_MUTED.value}{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}{ANSIColors.DEFAULT.value}"
|
27
|
+
|
28
|
+
@staticmethod
|
29
|
+
def _print_with_background(label: str, bg_color: ANSIColors, message: str, timestamp: bool):
|
30
|
+
"""
|
31
|
+
Prints a formatted message with a background color.
|
32
|
+
|
33
|
+
Parameters
|
34
|
+
----------
|
35
|
+
label : str
|
36
|
+
The label to display (e.g., 'SUCCESS', 'INFO').
|
37
|
+
bg_color : ANSIColors
|
38
|
+
The background color to use.
|
39
|
+
message : str
|
40
|
+
The message to print.
|
41
|
+
timestamp : bool
|
42
|
+
Whether to include a timestamp.
|
43
|
+
"""
|
44
|
+
str_time = Console._get_timestamp() if timestamp else ''
|
45
|
+
print(f"{bg_color.value}{ANSIColors.TEXT_WHITE.value} {label} {ANSIColors.DEFAULT.value} {str_time} {message}{ANSIColors.DEFAULT.value}")
|
46
|
+
|
47
|
+
@staticmethod
|
48
|
+
def _print_colored(message: str, text_color: ANSIColors):
|
49
|
+
"""
|
50
|
+
Prints a message with a specified text color.
|
51
|
+
|
52
|
+
Parameters
|
53
|
+
----------
|
54
|
+
message : str
|
55
|
+
The message to print.
|
56
|
+
text_color : ANSIColors
|
57
|
+
The text color to use.
|
58
|
+
"""
|
59
|
+
print(f"{text_color.value}{message}{ANSIColors.DEFAULT.value}")
|
60
|
+
|
61
|
+
# ---- SUCCESS ----
|
62
|
+
|
63
|
+
@staticmethod
|
64
|
+
def success(message: str = '', timestamp: bool = True):
|
65
|
+
"""
|
66
|
+
Prints a success message with a green background.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
message : str, optional
|
71
|
+
The success message to print (default is '').
|
72
|
+
timestamp : bool, optional
|
73
|
+
Whether to include a timestamp (default is True).
|
74
|
+
"""
|
75
|
+
Console._print_with_background("SUCCESS", ANSIColors.BG_SUCCESS, message, timestamp)
|
76
|
+
|
77
|
+
@staticmethod
|
78
|
+
def textSuccess(message: str = ''):
|
79
|
+
"""Prints a success message in green."""
|
80
|
+
Console._print_colored(message, ANSIColors.TEXT_SUCCESS)
|
81
|
+
|
82
|
+
@staticmethod
|
83
|
+
def textSuccessBold(message: str = ''):
|
84
|
+
"""Prints a bold success message in green."""
|
85
|
+
Console._print_colored(message, ANSIColors.TEXT_BOLD_SUCCESS)
|
86
|
+
|
87
|
+
# ---- INFO ----
|
88
|
+
|
89
|
+
@staticmethod
|
90
|
+
def info(message: str = '', timestamp: bool = True):
|
91
|
+
"""Prints an informational message with a blue background."""
|
92
|
+
Console._print_with_background("INFO", ANSIColors.BG_INFO, message, timestamp)
|
93
|
+
|
94
|
+
@staticmethod
|
95
|
+
def textInfo(message: str = ''):
|
96
|
+
"""Prints an informational message in blue."""
|
97
|
+
Console._print_colored(message, ANSIColors.TEXT_INFO)
|
98
|
+
|
99
|
+
@staticmethod
|
100
|
+
def textInfoBold(message: str = ''):
|
101
|
+
"""Prints a bold informational message in blue."""
|
102
|
+
Console._print_colored(message, ANSIColors.TEXT_BOLD_INFO)
|
103
|
+
|
104
|
+
# ---- WARNING ----
|
105
|
+
|
106
|
+
@staticmethod
|
107
|
+
def warning(message: str = '', timestamp: bool = True):
|
108
|
+
"""Prints a warning message with a yellow background."""
|
109
|
+
Console._print_with_background("WARNING", ANSIColors.BG_WARNING, message, timestamp)
|
110
|
+
|
111
|
+
@staticmethod
|
112
|
+
def textWarning(message: str = ''):
|
113
|
+
"""Prints a warning message in yellow."""
|
114
|
+
Console._print_colored(message, ANSIColors.TEXT_WARNING)
|
115
|
+
|
116
|
+
@staticmethod
|
117
|
+
def textWarningBold(message: str = ''):
|
118
|
+
"""Prints a bold warning message in yellow."""
|
119
|
+
Console._print_colored(message, ANSIColors.TEXT_BOLD_WARNING)
|
120
|
+
|
121
|
+
# ---- FAIL ----
|
122
|
+
|
123
|
+
@staticmethod
|
124
|
+
def fail(message: str = '', timestamp: bool = True):
|
125
|
+
"""Prints an fail message with a red background."""
|
126
|
+
Console._print_with_background("FAIL", ANSIColors.BG_FAIL, message, timestamp)
|
127
|
+
|
128
|
+
# ---- ERROR ----
|
129
|
+
|
130
|
+
@staticmethod
|
131
|
+
def error(message: str = '', timestamp: bool = True):
|
132
|
+
"""Prints an error message with a red background."""
|
133
|
+
Console._print_with_background("ERROR", ANSIColors.BG_ERROR, message, timestamp)
|
134
|
+
|
135
|
+
@staticmethod
|
136
|
+
def textError(message: str = ''):
|
137
|
+
"""Prints an error message in red."""
|
138
|
+
Console._print_colored(message, ANSIColors.TEXT_ERROR)
|
139
|
+
|
140
|
+
@staticmethod
|
141
|
+
def textErrorBold(message: str = ''):
|
142
|
+
"""Prints a bold error message in red."""
|
143
|
+
Console._print_colored(message, ANSIColors.TEXT_BOLD_ERROR)
|
144
|
+
|
145
|
+
# ---- MUTED ----
|
146
|
+
|
147
|
+
@staticmethod
|
148
|
+
def textMuted(message: str = ''):
|
149
|
+
"""Prints a muted (gray) message."""
|
150
|
+
Console._print_colored(message, ANSIColors.TEXT_MUTED)
|
151
|
+
|
152
|
+
@staticmethod
|
153
|
+
def textMutedBold(message: str = ''):
|
154
|
+
"""Prints a bold muted (gray) message."""
|
155
|
+
Console._print_colored(message, ANSIColors.TEXT_BOLD_MUTED)
|
156
|
+
|
157
|
+
# ---- UNDERLINE ----
|
158
|
+
|
159
|
+
@staticmethod
|
160
|
+
def textUnderline(message: str = ''):
|
161
|
+
"""
|
162
|
+
Prints an underlined message.
|
163
|
+
|
164
|
+
Parameters
|
165
|
+
----------
|
166
|
+
message : str, optional
|
167
|
+
The message to print (default is '').
|
168
|
+
"""
|
169
|
+
print(f"{ANSIColors.TEXT_STYLE_UNDERLINE.value}{message}{ANSIColors.DEFAULT.value}")
|
170
|
+
|
171
|
+
# ---- CLEAR CONSOLE ----
|
172
|
+
|
173
|
+
@staticmethod
|
174
|
+
def clear():
|
175
|
+
"""Clears the console screen."""
|
176
|
+
os.system('cls' if os.name == 'nt' else 'clear')
|
177
|
+
|
178
|
+
@staticmethod
|
179
|
+
def clearLine():
|
180
|
+
"""Clears the current console line."""
|
181
|
+
sys.stdout.write("\r \r")
|
182
|
+
sys.stdout.flush()
|
183
|
+
|
184
|
+
# ---- EMPTY LINE CONSOLE ----
|
185
|
+
|
186
|
+
@staticmethod
|
187
|
+
def line(message: str = ''):
|
188
|
+
"""Prints a line of text."""
|
189
|
+
print(message)
|
190
|
+
|
191
|
+
@staticmethod
|
192
|
+
def newLine(count: int = 1):
|
193
|
+
"""
|
194
|
+
Prints multiple new lines.
|
195
|
+
|
196
|
+
Parameters
|
197
|
+
----------
|
198
|
+
count : int, optional
|
199
|
+
The number of new lines to print (default is 1).
|
200
|
+
|
201
|
+
Raises
|
202
|
+
------
|
203
|
+
ValueError
|
204
|
+
If count is less than or equal to 0.
|
205
|
+
"""
|
206
|
+
if count <= 0:
|
207
|
+
raise ValueError(f"Unsupported Value '{count}'")
|
208
|
+
print("\n" * count, end="")
|
209
|
+
|
210
|
+
# ---- WRITE CONSOLE ----
|
211
|
+
|
212
|
+
@staticmethod
|
213
|
+
def write(message: str = ''):
|
214
|
+
"""
|
215
|
+
Prints a message without moving to the next line.
|
216
|
+
|
217
|
+
Parameters
|
218
|
+
----------
|
219
|
+
message : str, optional
|
220
|
+
The message to print (default is '').
|
221
|
+
"""
|
222
|
+
sys.stdout.write(f"{message}")
|
223
|
+
sys.stdout.flush()
|
224
|
+
|
225
|
+
@staticmethod
|
226
|
+
def writeLine(message: str = ''):
|
227
|
+
"""
|
228
|
+
Prints a message and moves to the next line.
|
229
|
+
|
230
|
+
Parameters
|
231
|
+
----------
|
232
|
+
message : str, optional
|
233
|
+
The message to print (default is '').
|
234
|
+
"""
|
235
|
+
print(f"{message}")
|
236
|
+
|
237
|
+
@staticmethod
|
238
|
+
def ask(question: str) -> str:
|
239
|
+
"""
|
240
|
+
Prompts the user for input with a message and returns the user's response.
|
241
|
+
|
242
|
+
Parameters
|
243
|
+
----------
|
244
|
+
question : str
|
245
|
+
The question to ask the user.
|
246
|
+
|
247
|
+
Returns
|
248
|
+
-------
|
249
|
+
str
|
250
|
+
The user's input, as a string.
|
251
|
+
"""
|
252
|
+
return input(f"{ANSIColors.TEXT_INFO.value}{str(question).strip()}{ANSIColors.DEFAULT.value} ")
|
253
|
+
|
254
|
+
@staticmethod
|
255
|
+
def confirm(question: str, default: bool = False) -> bool:
|
256
|
+
"""
|
257
|
+
Asks a confirmation question and returns True or False based on the user's response.
|
258
|
+
|
259
|
+
Parameters
|
260
|
+
----------
|
261
|
+
question : str
|
262
|
+
The confirmation question to ask.
|
263
|
+
default : bool, optional
|
264
|
+
The default response if the user presses Enter without typing a response.
|
265
|
+
Default is False, which corresponds to a 'No' response.
|
266
|
+
|
267
|
+
Returns
|
268
|
+
-------
|
269
|
+
bool
|
270
|
+
The user's response, which will be True if 'Y' is entered,
|
271
|
+
or False if 'N' is entered or the default is used.
|
272
|
+
"""
|
273
|
+
response = input(f"{ANSIColors.TEXT_INFO.value}{str(question).strip()} (Y/n): {ANSIColors.DEFAULT.value} ").upper()
|
274
|
+
return default if not response else response == 'Y'
|
275
|
+
|
276
|
+
@staticmethod
|
277
|
+
def secret(question: str) -> str:
|
278
|
+
"""
|
279
|
+
Prompts the user for hidden input, typically used for password input.
|
280
|
+
|
281
|
+
Parameters
|
282
|
+
----------
|
283
|
+
question : str
|
284
|
+
The prompt to ask the user.
|
285
|
+
|
286
|
+
Returns
|
287
|
+
-------
|
288
|
+
str
|
289
|
+
The user's hidden input, returned as a string.
|
290
|
+
"""
|
291
|
+
return getpass.getpass(f"{ANSIColors.TEXT_INFO.value}{str(question).strip()}{ANSIColors.DEFAULT.value} ")
|
292
|
+
|
293
|
+
@staticmethod
|
294
|
+
def table(headers: list, rows: list):
|
295
|
+
"""
|
296
|
+
Prints a table in the console with the given headers and rows, with bold headers.
|
297
|
+
|
298
|
+
Parameters
|
299
|
+
----------
|
300
|
+
headers : list of str
|
301
|
+
The column headers for the table.
|
302
|
+
rows : list of list of str
|
303
|
+
The rows of the table, where each row is a list of strings representing the columns.
|
304
|
+
|
305
|
+
Raises
|
306
|
+
------
|
307
|
+
ValueError
|
308
|
+
If headers or rows are empty.
|
309
|
+
|
310
|
+
Notes
|
311
|
+
-----
|
312
|
+
The table adjusts column widths dynamically, includes bold headers, and uses box-drawing characters for formatting.
|
313
|
+
"""
|
314
|
+
if not headers:
|
315
|
+
raise ValueError("Headers cannot be empty.")
|
316
|
+
if not rows:
|
317
|
+
raise ValueError("Rows cannot be empty.")
|
318
|
+
|
319
|
+
# Determine the maximum width of each column
|
320
|
+
col_widths = [max(len(str(item)) for item in col) for col in zip(headers, *rows)]
|
321
|
+
|
322
|
+
# Define border characters
|
323
|
+
top_border = "┌" + "┬".join("─" * (col_width + 2) for col_width in col_widths) + "┐"
|
324
|
+
separator = "├" + "┼".join("─" * (col_width + 2) for col_width in col_widths) + "┤"
|
325
|
+
bottom_border = "└" + "┴".join("─" * (col_width + 2) for col_width in col_widths) + "┘"
|
326
|
+
|
327
|
+
# Format the header row with bold text
|
328
|
+
header_row = "│ " + " │ ".join(f"{ANSIColors.TEXT_BOLD.value}{header:<{col_width}}{ANSIColors.TEXT_RESET.value}" for header, col_width in zip(headers, col_widths)) + " │"
|
329
|
+
|
330
|
+
# Print the table
|
331
|
+
print(top_border)
|
332
|
+
print(header_row)
|
333
|
+
print(separator)
|
334
|
+
|
335
|
+
for row in rows:
|
336
|
+
row_text = "│ " + " │ ".join(f"{str(item):<{col_width}}" for item, col_width in zip(row, col_widths)) + " │"
|
337
|
+
print(row_text)
|
338
|
+
|
339
|
+
print(bottom_border)
|
340
|
+
|
341
|
+
@staticmethod
|
342
|
+
def anticipate(question: str, options: list, default=None):
|
343
|
+
"""
|
344
|
+
Provides autocomplete suggestions based on user input.
|
345
|
+
|
346
|
+
Parameters
|
347
|
+
----------
|
348
|
+
question : str
|
349
|
+
The prompt for the user.
|
350
|
+
options : list of str
|
351
|
+
The list of possible options for autocomplete.
|
352
|
+
default : str, optional
|
353
|
+
The default value if no matching option is found. Defaults to None.
|
354
|
+
|
355
|
+
Returns
|
356
|
+
-------
|
357
|
+
str
|
358
|
+
The chosen option or the default value.
|
359
|
+
|
360
|
+
Notes
|
361
|
+
-----
|
362
|
+
This method allows the user to input a string, and then attempts to provide
|
363
|
+
an autocomplete suggestion by matching the beginning of the input with the
|
364
|
+
available options. If no match is found, the method returns the default value
|
365
|
+
or the user input if no default is provided.
|
366
|
+
"""
|
367
|
+
# Prompt the user for input
|
368
|
+
input_value = input(f"{ANSIColors.TEXT_INFO.value}{str(question).strip()}{ANSIColors.DEFAULT.value} ")
|
369
|
+
|
370
|
+
# Find the first option that starts with the input value, or use the default value
|
371
|
+
return next((option for option in options if option.startswith(input_value)), default or input_value)
|
372
|
+
|
373
|
+
@staticmethod
|
374
|
+
def choice(question: str, choices: list, default_index: int = 0) -> str:
|
375
|
+
"""
|
376
|
+
Allows the user to select an option from a list.
|
377
|
+
|
378
|
+
Parameters
|
379
|
+
----------
|
380
|
+
question : str
|
381
|
+
The prompt for the user.
|
382
|
+
choices : list of str
|
383
|
+
The list of available choices.
|
384
|
+
default_index : int, optional
|
385
|
+
The index of the default choice (zero-based). Defaults to 0.
|
386
|
+
|
387
|
+
Returns
|
388
|
+
-------
|
389
|
+
str
|
390
|
+
The selected choice.
|
391
|
+
|
392
|
+
Raises
|
393
|
+
------
|
394
|
+
ValueError
|
395
|
+
If `default_index` is out of the range of choices.
|
396
|
+
|
397
|
+
Notes
|
398
|
+
-----
|
399
|
+
The user is presented with a numbered list of choices and prompted to select
|
400
|
+
one by entering the corresponding number. If an invalid input is provided,
|
401
|
+
the user will be repeatedly prompted until a valid choice is made.
|
402
|
+
"""
|
403
|
+
if not choices:
|
404
|
+
raise ValueError("The choices list cannot be empty.")
|
405
|
+
|
406
|
+
if not (0 <= default_index < len(choices)):
|
407
|
+
raise ValueError(f"Invalid default_index {default_index}. Must be between 0 and {len(choices) - 1}.")
|
408
|
+
|
409
|
+
# Display the question and the choices
|
410
|
+
print(f"{ANSIColors.TEXT_INFO.value}{question.strip()} (default: {choices[default_index]}):{ANSIColors.DEFAULT.value}")
|
411
|
+
|
412
|
+
for idx, choice in enumerate(choices, 1):
|
413
|
+
print(f"{ANSIColors.TEXT_MUTED.value}{idx}: {choice}{ANSIColors.DEFAULT.value}")
|
414
|
+
|
415
|
+
# Prompt the user for input
|
416
|
+
answer = input("Answer: ").strip()
|
417
|
+
|
418
|
+
# If the user provides no input, select the default choice
|
419
|
+
if not answer:
|
420
|
+
return choices[default_index]
|
421
|
+
|
422
|
+
# Validate input: ensure it's a number within range
|
423
|
+
while not answer.isdigit() or not (1 <= int(answer) <= len(choices)):
|
424
|
+
answer = input("Please select a valid number: ").strip()
|
425
|
+
|
426
|
+
return choices[int(answer) - 1]
|
@@ -0,0 +1,90 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from orionis.luminate.console.output.styles import ANSIColors
|
3
|
+
from orionis.luminate.contracts.console.executor_interface import IExecutor
|
4
|
+
|
5
|
+
class Executor(IExecutor):
|
6
|
+
"""
|
7
|
+
A utility class for logging program execution states with ANSI color formatting.
|
8
|
+
|
9
|
+
Methods
|
10
|
+
-------
|
11
|
+
running(program: str, time: str = ''):
|
12
|
+
Logs the execution of a program in a "RUNNING" state.
|
13
|
+
done(program: str, time: str = ''):
|
14
|
+
Logs the execution of a program in a "DONE" state.
|
15
|
+
fail(program: str, time: str = ''):
|
16
|
+
Logs the execution of a program in a "FAIL" state.
|
17
|
+
"""
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
def _ansi_output(program: str, state: str, state_color: str, time: str = ''):
|
21
|
+
"""
|
22
|
+
Logs a formatted message with timestamp, program name, and execution state.
|
23
|
+
|
24
|
+
Parameters
|
25
|
+
----------
|
26
|
+
program : str
|
27
|
+
The name of the program being executed.
|
28
|
+
state : str
|
29
|
+
The state of execution (e.g., RUNNING, DONE, FAIL).
|
30
|
+
state_color : str
|
31
|
+
The ANSI color code for the state.
|
32
|
+
time : str, optional
|
33
|
+
The time duration of execution, default is an empty string, example (30s)
|
34
|
+
"""
|
35
|
+
width = 60
|
36
|
+
len_state = len(state)
|
37
|
+
len_time = len(time)
|
38
|
+
line = '.' * (width - (len(program) + len_state + len_time))
|
39
|
+
|
40
|
+
timestamp = f"{ANSIColors.TEXT_MUTED.value}{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}{ANSIColors.DEFAULT.value}"
|
41
|
+
program_formatted = f"{program}"
|
42
|
+
time_formatted = f"{ANSIColors.TEXT_MUTED.value}{time}{ANSIColors.DEFAULT.value}" if time else ""
|
43
|
+
state_formatted = f"{state_color}{state}{ANSIColors.DEFAULT.value}"
|
44
|
+
|
45
|
+
start = "\n\r" if state == 'RUNNING' else ''
|
46
|
+
end = "\n\r" if state != 'RUNNING' else ''
|
47
|
+
|
48
|
+
print(f"{start}{timestamp} | {program_formatted} {line} {time_formatted} {state_formatted}{end}")
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def running(program: str, time: str = ''):
|
52
|
+
"""
|
53
|
+
Logs the execution of a program in a "RUNNING" state.
|
54
|
+
|
55
|
+
Parameters
|
56
|
+
----------
|
57
|
+
program : str
|
58
|
+
The name of the program being executed.
|
59
|
+
time : str, optional
|
60
|
+
The time duration of execution, default is an empty string.
|
61
|
+
"""
|
62
|
+
Executor._ansi_output(program, "RUNNING", ANSIColors.TEXT_BOLD_WARNING.value, time)
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
def done(program: str, time: str = ''):
|
66
|
+
"""
|
67
|
+
Logs the execution of a program in a "DONE" state.
|
68
|
+
|
69
|
+
Parameters
|
70
|
+
----------
|
71
|
+
program : str
|
72
|
+
The name of the program being executed.
|
73
|
+
time : str, optional
|
74
|
+
The time duration of execution, default is an empty string.
|
75
|
+
"""
|
76
|
+
Executor._ansi_output(program, "DONE", ANSIColors.TEXT_BOLD_SUCCESS.value, time)
|
77
|
+
|
78
|
+
@staticmethod
|
79
|
+
def fail(program: str, time: str = ''):
|
80
|
+
"""
|
81
|
+
Logs the execution of a program in a "FAIL" state.
|
82
|
+
|
83
|
+
Parameters
|
84
|
+
----------
|
85
|
+
program : str
|
86
|
+
The name of the program being executed.
|
87
|
+
time : str, optional
|
88
|
+
The time duration of execution, default is an empty string.
|
89
|
+
"""
|
90
|
+
Executor._ansi_output(program, "FAIL", ANSIColors.TEXT_BOLD_ERROR.value, time)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import sys
|
2
|
+
from orionis.luminate.contracts.console.progress_bar_interface import IProgressBar
|
3
|
+
|
4
|
+
class ProgressBar(IProgressBar):
|
5
|
+
"""
|
6
|
+
A console-based progress bar implementation.
|
7
|
+
|
8
|
+
This class provides a simple text-based progress bar that updates
|
9
|
+
in place without clearing the console.
|
10
|
+
|
11
|
+
Parameters
|
12
|
+
----------
|
13
|
+
total : int, optional
|
14
|
+
The total amount of progress (default is 100).
|
15
|
+
width : int, optional
|
16
|
+
The width of the progress bar in characters (default is 50).
|
17
|
+
|
18
|
+
Attributes
|
19
|
+
----------
|
20
|
+
total : int
|
21
|
+
The maximum progress value.
|
22
|
+
bar_width : int
|
23
|
+
The width of the progress bar in characters.
|
24
|
+
progress : int
|
25
|
+
The current progress value.
|
26
|
+
|
27
|
+
Methods
|
28
|
+
-------
|
29
|
+
start()
|
30
|
+
Initializes the progress bar to the starting state.
|
31
|
+
advance(increment=1)
|
32
|
+
Advances the progress bar by a given increment.
|
33
|
+
finish()
|
34
|
+
Completes the progress bar and moves to a new line.
|
35
|
+
"""
|
36
|
+
|
37
|
+
def __init__(self, total=100, width=50):
|
38
|
+
"""
|
39
|
+
Constructs all the necessary attributes for the progress bar object.
|
40
|
+
|
41
|
+
Parameters
|
42
|
+
----------
|
43
|
+
total : int, optional
|
44
|
+
The total amount of progress (default is 100).
|
45
|
+
width : int, optional
|
46
|
+
The width of the progress bar in characters (default is 50).
|
47
|
+
"""
|
48
|
+
self.total = total
|
49
|
+
self.bar_width = width
|
50
|
+
self.progress = 0
|
51
|
+
|
52
|
+
def _update_bar(self):
|
53
|
+
"""
|
54
|
+
Updates the visual representation of the progress bar.
|
55
|
+
|
56
|
+
This method calculates the percentage of progress and updates the
|
57
|
+
console output accordingly.
|
58
|
+
"""
|
59
|
+
percent = self.progress / self.total
|
60
|
+
filled_length = int(self.bar_width * percent)
|
61
|
+
bar = f"[{'█' * filled_length}{'░' * (self.bar_width - filled_length)}] {int(percent * 100)}%"
|
62
|
+
|
63
|
+
# Move the cursor to the start of the line and overwrite it
|
64
|
+
sys.stdout.write("\r" + bar)
|
65
|
+
sys.stdout.flush()
|
66
|
+
|
67
|
+
def start(self):
|
68
|
+
"""
|
69
|
+
Initializes the progress bar to the starting state.
|
70
|
+
|
71
|
+
This method resets the progress to zero and displays the initial bar.
|
72
|
+
"""
|
73
|
+
self.progress = 0
|
74
|
+
self._update_bar()
|
75
|
+
|
76
|
+
def advance(self, increment=1):
|
77
|
+
"""
|
78
|
+
Advances the progress bar by a specific increment.
|
79
|
+
|
80
|
+
Parameters
|
81
|
+
----------
|
82
|
+
increment : int, optional
|
83
|
+
The amount by which the progress should be increased (default is 1).
|
84
|
+
"""
|
85
|
+
self.progress += increment
|
86
|
+
if self.progress > self.total:
|
87
|
+
self.progress = self.total
|
88
|
+
self._update_bar()
|
89
|
+
|
90
|
+
def finish(self):
|
91
|
+
"""
|
92
|
+
Completes the progress bar.
|
93
|
+
|
94
|
+
This method sets the progress to its maximum value, updates the bar,
|
95
|
+
and moves the cursor to a new line for cleaner output.
|
96
|
+
"""
|
97
|
+
self.progress = self.total
|
98
|
+
self._update_bar()
|
99
|
+
sys.stdout.write("\n")
|
100
|
+
sys.stdout.flush()
|