argenta 1.1.1rc0__py3-none-any.whl → 1.1.2__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.
- argenta/__init__.py +6 -0
- argenta/app/__init__.py +10 -1
- argenta/app/autocompleter/entity.py +18 -19
- argenta/app/defaults.py +0 -1
- argenta/app/dividing_line/models.py +5 -5
- argenta/app/models.py +226 -140
- argenta/app/protocols.py +22 -0
- argenta/app/registered_routers/entity.py +7 -14
- argenta/command/__init__.py +11 -2
- argenta/command/exceptions.py +20 -13
- argenta/command/flag/__init__.py +5 -11
- argenta/command/flag/defaults.py +19 -24
- argenta/command/flag/flags/__init__.py +2 -8
- argenta/command/flag/flags/models.py +65 -49
- argenta/command/flag/models.py +78 -93
- argenta/command/models.py +100 -144
- argenta/di/__init__.py +2 -0
- argenta/di/integration.py +45 -0
- argenta/di/providers.py +14 -0
- argenta/metrics/main.py +2 -2
- argenta/orchestrator/__init__.py +2 -2
- argenta/orchestrator/argparser/__init__.py +6 -1
- argenta/orchestrator/argparser/arguments/__init__.py +3 -3
- argenta/orchestrator/argparser/arguments/models.py +61 -35
- argenta/orchestrator/argparser/entity.py +56 -37
- argenta/orchestrator/entity.py +20 -18
- argenta/py.typed +0 -0
- argenta/response/__init__.py +2 -2
- argenta/response/entity.py +17 -18
- argenta/response/status.py +12 -1
- argenta/router/__init__.py +2 -2
- argenta/router/command_handler/entity.py +9 -27
- argenta/router/entity.py +133 -160
- argenta/router/exceptions.py +9 -12
- {argenta-1.1.1rc0.dist-info → argenta-1.1.2.dist-info}/METADATA +12 -5
- argenta-1.1.2.dist-info/RECORD +44 -0
- argenta-1.1.1rc0.dist-info/RECORD +0 -39
- {argenta-1.1.1rc0.dist-info → argenta-1.1.2.dist-info}/WHEEL +0 -0
- {argenta-1.1.1rc0.dist-info → argenta-1.1.2.dist-info}/licenses/LICENSE +0 -0
argenta/app/models.py
CHANGED
@@ -1,89 +1,108 @@
|
|
1
|
-
from typing import Callable
|
2
|
-
from rich.console import Console
|
3
|
-
from rich.markup import escape
|
4
|
-
from art import text2art
|
5
|
-
from contextlib import redirect_stdout
|
6
1
|
import io
|
7
2
|
import re
|
3
|
+
from contextlib import redirect_stdout
|
4
|
+
from typing import Never, TypeAlias
|
5
|
+
|
6
|
+
from art import text2art # pyright: ignore[reportMissingTypeStubs, reportUnknownVariableType]
|
7
|
+
from rich.console import Console
|
8
|
+
from rich.markup import escape
|
8
9
|
|
9
|
-
from argenta.command.models import Command, InputCommand
|
10
|
-
from argenta.router import Router
|
11
|
-
from argenta.router.defaults import system_router
|
12
10
|
from argenta.app.autocompleter import AutoCompleter
|
13
|
-
from argenta.app.dividing_line.models import
|
11
|
+
from argenta.app.dividing_line.models import DynamicDividingLine, StaticDividingLine
|
12
|
+
from argenta.app.protocols import (
|
13
|
+
DescriptionMessageGenerator,
|
14
|
+
EmptyCommandHandler,
|
15
|
+
NonStandardBehaviorHandler,
|
16
|
+
Printer,
|
17
|
+
)
|
18
|
+
from argenta.app.registered_routers.entity import RegisteredRouters
|
14
19
|
from argenta.command.exceptions import (
|
15
|
-
UnprocessedInputFlagException,
|
16
|
-
RepeatedInputFlagsException,
|
17
20
|
EmptyInputCommandException,
|
18
|
-
|
21
|
+
InputCommandException,
|
22
|
+
RepeatedInputFlagsException,
|
23
|
+
UnprocessedInputFlagException,
|
19
24
|
)
|
20
|
-
from argenta.
|
25
|
+
from argenta.command.models import Command, InputCommand
|
21
26
|
from argenta.response import Response
|
27
|
+
from argenta.router import Router
|
28
|
+
from argenta.router.defaults import system_router
|
22
29
|
|
30
|
+
Matches: TypeAlias = list[str] | list[Never]
|
23
31
|
|
24
32
|
|
25
33
|
class BaseApp:
|
26
|
-
def __init__(
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
self.
|
42
|
-
self.
|
43
|
-
self.
|
44
|
-
self.
|
45
|
-
self.
|
46
|
-
|
47
|
-
self.
|
48
|
-
self.
|
49
|
-
|
50
|
-
|
51
|
-
self.
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
*,
|
37
|
+
prompt: str,
|
38
|
+
initial_message: str,
|
39
|
+
farewell_message: str,
|
40
|
+
exit_command: Command,
|
41
|
+
system_router_title: str | None,
|
42
|
+
ignore_command_register: bool,
|
43
|
+
dividing_line: StaticDividingLine | DynamicDividingLine,
|
44
|
+
repeat_command_groups: bool,
|
45
|
+
override_system_messages: bool,
|
46
|
+
autocompleter: AutoCompleter,
|
47
|
+
print_func: Printer,
|
48
|
+
) -> None:
|
49
|
+
self._prompt: str = prompt
|
50
|
+
self._print_func: Printer = print_func
|
51
|
+
self._exit_command: Command = exit_command
|
52
|
+
self._system_router_title: str | None = system_router_title
|
53
|
+
self._dividing_line: StaticDividingLine | DynamicDividingLine = dividing_line
|
54
|
+
self._ignore_command_register: bool = ignore_command_register
|
55
|
+
self._repeat_command_groups_description: bool = repeat_command_groups
|
56
|
+
self._override_system_messages: bool = override_system_messages
|
57
|
+
self._autocompleter: AutoCompleter = autocompleter
|
58
|
+
|
59
|
+
self._farewell_message: str = farewell_message
|
60
|
+
self._initial_message: str = initial_message
|
61
|
+
|
62
|
+
self._description_message_gen: DescriptionMessageGenerator = (
|
63
|
+
lambda command, description: f"{command} *=*=* {description}"
|
64
|
+
)
|
65
|
+
self.registered_routers: RegisteredRouters = RegisteredRouters()
|
52
66
|
self._messages_on_startup: list[str] = []
|
53
67
|
|
54
68
|
self._matching_lower_triggers_with_routers: dict[str, Router] = {}
|
55
69
|
self._matching_default_triggers_with_routers: dict[str, Router] = {}
|
56
70
|
|
57
|
-
|
58
|
-
self.
|
59
|
-
|
60
|
-
|
71
|
+
self._current_matching_triggers_with_routers: dict[str, Router] = (
|
72
|
+
self._matching_lower_triggers_with_routers
|
73
|
+
if self._ignore_command_register
|
74
|
+
else self._matching_default_triggers_with_routers
|
75
|
+
)
|
61
76
|
|
62
|
-
self._incorrect_input_syntax_handler:
|
63
|
-
lambda
|
77
|
+
self._incorrect_input_syntax_handler: NonStandardBehaviorHandler[str] = (
|
78
|
+
lambda _: print_func(f"Incorrect flag syntax: {_}")
|
64
79
|
)
|
65
|
-
self._repeated_input_flags_handler:
|
66
|
-
lambda
|
80
|
+
self._repeated_input_flags_handler: NonStandardBehaviorHandler[str] = (
|
81
|
+
lambda _: print_func(f"Repeated input flags: {_}")
|
67
82
|
)
|
68
|
-
self._empty_input_command_handler:
|
83
|
+
self._empty_input_command_handler: EmptyCommandHandler = lambda: print_func(
|
69
84
|
"Empty input command"
|
70
85
|
)
|
71
|
-
self._unknown_command_handler:
|
72
|
-
lambda
|
86
|
+
self._unknown_command_handler: NonStandardBehaviorHandler[InputCommand] = (
|
87
|
+
lambda _: print_func(f"Unknown command: {_.trigger}")
|
73
88
|
)
|
74
|
-
self._exit_command_handler:
|
75
|
-
lambda
|
89
|
+
self._exit_command_handler: NonStandardBehaviorHandler[Response] = (
|
90
|
+
lambda _: print_func(self._farewell_message)
|
76
91
|
)
|
77
92
|
|
78
|
-
def set_description_message_pattern(
|
93
|
+
def set_description_message_pattern(
|
94
|
+
self, _: DescriptionMessageGenerator, /
|
95
|
+
) -> None:
|
79
96
|
"""
|
80
97
|
Public. Sets the output pattern of the available commands
|
81
98
|
:param _: output pattern of the available commands
|
82
99
|
:return: None
|
83
100
|
"""
|
84
|
-
self._description_message_gen
|
101
|
+
self._description_message_gen = _
|
85
102
|
|
86
|
-
def set_incorrect_input_syntax_handler(
|
103
|
+
def set_incorrect_input_syntax_handler(
|
104
|
+
self, _: NonStandardBehaviorHandler[str], /
|
105
|
+
) -> None:
|
87
106
|
"""
|
88
107
|
Public. Sets the handler for incorrect flags when entering a command
|
89
108
|
:param _: handler for incorrect flags when entering a command
|
@@ -91,7 +110,9 @@ class BaseApp:
|
|
91
110
|
"""
|
92
111
|
self._incorrect_input_syntax_handler = _
|
93
112
|
|
94
|
-
def set_repeated_input_flags_handler(
|
113
|
+
def set_repeated_input_flags_handler(
|
114
|
+
self, _: NonStandardBehaviorHandler[str], /
|
115
|
+
) -> None:
|
95
116
|
"""
|
96
117
|
Public. Sets the handler for repeated flags when entering a command
|
97
118
|
:param _: handler for repeated flags when entering a command
|
@@ -99,7 +120,9 @@ class BaseApp:
|
|
99
120
|
"""
|
100
121
|
self._repeated_input_flags_handler = _
|
101
122
|
|
102
|
-
def set_unknown_command_handler(
|
123
|
+
def set_unknown_command_handler(
|
124
|
+
self, _: NonStandardBehaviorHandler[InputCommand], /
|
125
|
+
) -> None:
|
103
126
|
"""
|
104
127
|
Public. Sets the handler for unknown commands when entering a command
|
105
128
|
:param _: handler for unknown commands when entering a command
|
@@ -107,7 +130,7 @@ class BaseApp:
|
|
107
130
|
"""
|
108
131
|
self._unknown_command_handler = _
|
109
132
|
|
110
|
-
def set_empty_command_handler(self, _:
|
133
|
+
def set_empty_command_handler(self, _: EmptyCommandHandler, /) -> None:
|
111
134
|
"""
|
112
135
|
Public. Sets the handler for empty commands when entering a command
|
113
136
|
:param _: handler for empty commands when entering a command
|
@@ -115,7 +138,9 @@ class BaseApp:
|
|
115
138
|
"""
|
116
139
|
self._empty_input_command_handler = _
|
117
140
|
|
118
|
-
def set_exit_command_handler(
|
141
|
+
def set_exit_command_handler(
|
142
|
+
self, _: NonStandardBehaviorHandler[Response], /
|
143
|
+
) -> None:
|
119
144
|
"""
|
120
145
|
Public. Sets the handler for exit command when entering a command
|
121
146
|
:param _: handler for exit command when entering a command
|
@@ -128,14 +153,15 @@ class BaseApp:
|
|
128
153
|
Private. Prints the description of the available commands
|
129
154
|
:return: None
|
130
155
|
"""
|
131
|
-
for registered_router in self.
|
156
|
+
for registered_router in self.registered_routers:
|
132
157
|
if registered_router.title:
|
133
158
|
self._print_func(registered_router.title)
|
134
|
-
for command_handler in registered_router.
|
159
|
+
for command_handler in registered_router.command_handlers:
|
160
|
+
handled_command = command_handler.handled_command
|
135
161
|
self._print_func(
|
136
162
|
self._description_message_gen(
|
137
|
-
|
138
|
-
|
163
|
+
handled_command.trigger,
|
164
|
+
handled_command.description,
|
139
165
|
)
|
140
166
|
)
|
141
167
|
self._print_func("")
|
@@ -146,16 +172,7 @@ class BaseApp:
|
|
146
172
|
:param text: framed text
|
147
173
|
:return: None
|
148
174
|
"""
|
149
|
-
if isinstance(self._dividing_line,
|
150
|
-
self._print_func(
|
151
|
-
self._dividing_line.get_full_static_line(self._override_system_messages)
|
152
|
-
)
|
153
|
-
print(text.strip("\n"))
|
154
|
-
self._print_func(
|
155
|
-
self._dividing_line.get_full_static_line(self._override_system_messages)
|
156
|
-
)
|
157
|
-
|
158
|
-
elif isinstance(self._dividing_line, DynamicDividingLine):
|
175
|
+
if isinstance(self._dividing_line, DynamicDividingLine):
|
159
176
|
clear_text = re.sub(r"\u001b\[[0-9;]*m", "", text)
|
160
177
|
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
161
178
|
max_length_line = (
|
@@ -168,36 +185,49 @@ class BaseApp:
|
|
168
185
|
|
169
186
|
self._print_func(
|
170
187
|
self._dividing_line.get_full_dynamic_line(
|
171
|
-
max_length_line, self._override_system_messages
|
188
|
+
length=max_length_line, is_override=self._override_system_messages
|
172
189
|
)
|
173
190
|
)
|
174
191
|
print(text.strip("\n"))
|
175
192
|
self._print_func(
|
176
193
|
self._dividing_line.get_full_dynamic_line(
|
177
|
-
max_length_line, self._override_system_messages
|
194
|
+
length=max_length_line, is_override=self._override_system_messages
|
195
|
+
)
|
196
|
+
)
|
197
|
+
|
198
|
+
elif isinstance(self._dividing_line, StaticDividingLine): # pyright: ignore[reportUnnecessaryIsInstance]
|
199
|
+
self._print_func(
|
200
|
+
self._dividing_line.get_full_static_line(
|
201
|
+
is_override=self._override_system_messages
|
202
|
+
)
|
203
|
+
)
|
204
|
+
print(text.strip("\n"))
|
205
|
+
self._print_func(
|
206
|
+
self._dividing_line.get_full_static_line(
|
207
|
+
is_override=self._override_system_messages
|
178
208
|
)
|
179
209
|
)
|
180
210
|
|
211
|
+
else:
|
212
|
+
raise NotImplementedError
|
213
|
+
|
181
214
|
def _is_exit_command(self, command: InputCommand) -> bool:
|
182
215
|
"""
|
183
216
|
Private. Checks if the given command is an exit command
|
184
217
|
:param command: command to check
|
185
218
|
:return: is it an exit command or not as bool
|
186
219
|
"""
|
220
|
+
trigger = command.trigger
|
221
|
+
exit_trigger = self._exit_command.trigger
|
187
222
|
if self._ignore_command_register:
|
188
|
-
if (
|
189
|
-
command.get_trigger().lower()
|
190
|
-
== self._exit_command.get_trigger().lower()
|
191
|
-
):
|
223
|
+
if trigger.lower() == exit_trigger.lower():
|
192
224
|
return True
|
193
|
-
elif
|
194
|
-
x.lower() for x in self._exit_command.get_aliases()
|
195
|
-
]:
|
225
|
+
elif trigger.lower() in [x.lower() for x in self._exit_command.aliases]:
|
196
226
|
return True
|
197
227
|
else:
|
198
|
-
if
|
228
|
+
if trigger == exit_trigger:
|
199
229
|
return True
|
200
|
-
elif
|
230
|
+
elif trigger in self._exit_command.aliases:
|
201
231
|
return True
|
202
232
|
return False
|
203
233
|
|
@@ -207,18 +237,20 @@ class BaseApp:
|
|
207
237
|
:param command: command to check
|
208
238
|
:return: is it an unknown command or not as bool
|
209
239
|
"""
|
210
|
-
input_command_trigger = command.
|
240
|
+
input_command_trigger = command.trigger
|
211
241
|
if self._ignore_command_register:
|
212
|
-
if input_command_trigger.lower() in list(
|
242
|
+
if input_command_trigger.lower() in list(
|
243
|
+
self._current_matching_triggers_with_routers.keys()
|
244
|
+
):
|
213
245
|
return False
|
214
246
|
else:
|
215
|
-
if input_command_trigger in list(
|
247
|
+
if input_command_trigger in list(
|
248
|
+
self._current_matching_triggers_with_routers.keys()
|
249
|
+
):
|
216
250
|
return False
|
217
251
|
return True
|
218
252
|
|
219
|
-
def _error_handler(
|
220
|
-
self, error: BaseInputCommandException, raw_command: str
|
221
|
-
) -> None:
|
253
|
+
def _error_handler(self, error: InputCommandException, raw_command: str) -> None:
|
222
254
|
"""
|
223
255
|
Private. Handles parsing errors of the entered command
|
224
256
|
:param error: error being handled
|
@@ -240,23 +272,25 @@ class BaseApp:
|
|
240
272
|
system_router.title = self._system_router_title
|
241
273
|
|
242
274
|
@system_router.command(self._exit_command)
|
243
|
-
def
|
275
|
+
def _(response: Response) -> None:
|
244
276
|
self._exit_command_handler(response)
|
245
277
|
|
246
|
-
if system_router not in self.
|
247
|
-
system_router.
|
248
|
-
self.
|
278
|
+
if system_router not in self.registered_routers.registered_routers:
|
279
|
+
system_router.command_register_ignore = self._ignore_command_register
|
280
|
+
self.registered_routers.add_registered_router(system_router)
|
249
281
|
|
250
282
|
def _most_similar_command(self, unknown_command: str) -> str | None:
|
251
283
|
all_commands = list(self._current_matching_triggers_with_routers.keys())
|
252
284
|
|
253
|
-
|
285
|
+
matches_startswith_unknown_command: Matches = sorted(
|
254
286
|
cmd for cmd in all_commands if cmd.startswith(unknown_command)
|
255
287
|
)
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
288
|
+
matches_startswith_cmd: Matches = sorted(
|
289
|
+
cmd for cmd in all_commands if unknown_command.startswith(cmd)
|
290
|
+
)
|
291
|
+
|
292
|
+
matches: Matches = matches_startswith_unknown_command or matches_startswith_cmd
|
293
|
+
|
260
294
|
if len(matches) == 1:
|
261
295
|
return matches[0]
|
262
296
|
elif len(matches) > 1:
|
@@ -270,26 +304,36 @@ class BaseApp:
|
|
270
304
|
:return: None
|
271
305
|
"""
|
272
306
|
self._prompt = f"[italic dim bold]{self._prompt}"
|
273
|
-
self._initial_message = (
|
307
|
+
self._initial_message = (
|
308
|
+
"\n" + f"[bold red]{text2art(self._initial_message, font='tarty1')}" + "\n"
|
309
|
+
)
|
274
310
|
self._farewell_message = (
|
275
311
|
"[bold red]\n\n"
|
276
|
-
+ text2art(self._farewell_message, font="chanky")
|
312
|
+
+ str(text2art(self._farewell_message, font="chanky")) # pyright: ignore[reportUnknownArgumentType]
|
277
313
|
+ "\n[/bold red]\n"
|
278
|
-
"[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n"
|
314
|
+
+ "[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n"
|
279
315
|
)
|
280
316
|
self._description_message_gen = lambda command, description: (
|
281
317
|
f"[bold red]{escape('[' + command + ']')}[/bold red] "
|
282
318
|
f"[blue dim]*=*=*[/blue dim] "
|
283
319
|
f"[bold yellow italic]{escape(description)}"
|
284
320
|
)
|
285
|
-
self._incorrect_input_syntax_handler = lambda raw_command: self._print_func(
|
286
|
-
|
287
|
-
|
321
|
+
self._incorrect_input_syntax_handler = lambda raw_command: self._print_func(
|
322
|
+
f"[red bold]Incorrect flag syntax: {escape(raw_command)}"
|
323
|
+
)
|
324
|
+
self._repeated_input_flags_handler = lambda raw_command: self._print_func(
|
325
|
+
f"[red bold]Repeated input flags: {escape(raw_command)}"
|
326
|
+
)
|
327
|
+
self._empty_input_command_handler = lambda: self._print_func(
|
328
|
+
"[red bold]Empty input command"
|
329
|
+
)
|
288
330
|
|
289
331
|
def unknown_command_handler(command: InputCommand) -> None:
|
290
|
-
cmd_trg: str = command.
|
332
|
+
cmd_trg: str = command.trigger
|
291
333
|
mst_sim_cmd: str | None = self._most_similar_command(cmd_trg)
|
292
|
-
first_part_of_text =
|
334
|
+
first_part_of_text = (
|
335
|
+
f"[red]Unknown command:[/red] [blue]{escape(cmd_trg)}[/blue]"
|
336
|
+
)
|
293
337
|
second_part_of_text = (
|
294
338
|
("[red], most similar:[/red] " + ("[blue]" + mst_sim_cmd + "[/blue]"))
|
295
339
|
if mst_sim_cmd
|
@@ -299,28 +343,34 @@ class BaseApp:
|
|
299
343
|
|
300
344
|
self._unknown_command_handler = unknown_command_handler
|
301
345
|
|
302
|
-
def
|
346
|
+
def _pre_cycle_setup(self) -> None:
|
303
347
|
"""
|
304
348
|
Private. Configures various aspects of the application before the start of the cycle
|
305
349
|
:return: None
|
306
350
|
"""
|
307
351
|
self._setup_system_router()
|
308
352
|
|
309
|
-
for router_entity in self.
|
310
|
-
router_triggers = router_entity.
|
311
|
-
router_aliases = router_entity.
|
353
|
+
for router_entity in self.registered_routers:
|
354
|
+
router_triggers = router_entity.triggers
|
355
|
+
router_aliases = router_entity.aliases
|
312
356
|
combined = router_triggers + router_aliases
|
313
357
|
|
314
358
|
for trigger in combined:
|
315
359
|
self._matching_default_triggers_with_routers[trigger] = router_entity
|
316
|
-
self._matching_lower_triggers_with_routers[trigger.lower()] =
|
360
|
+
self._matching_lower_triggers_with_routers[trigger.lower()] = (
|
361
|
+
router_entity
|
362
|
+
)
|
317
363
|
|
318
|
-
self._autocompleter.initial_setup(
|
364
|
+
self._autocompleter.initial_setup(
|
365
|
+
list(self._current_matching_triggers_with_routers.keys())
|
366
|
+
)
|
319
367
|
|
320
368
|
seen = {}
|
321
369
|
for item in list(self._current_matching_triggers_with_routers.keys()):
|
322
370
|
if item in seen:
|
323
|
-
Console().print(
|
371
|
+
Console().print(
|
372
|
+
f"\n[b red]WARNING:[/b red] Overlapping trigger or alias: [b blue]{item}[/b blue]"
|
373
|
+
)
|
324
374
|
else:
|
325
375
|
seen[item] = True
|
326
376
|
|
@@ -337,20 +387,29 @@ class BaseApp:
|
|
337
387
|
self._print_command_group_description()
|
338
388
|
|
339
389
|
|
390
|
+
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine
|
391
|
+
DEFAULT_DIVIDING_LINE: StaticDividingLine = StaticDividingLine()
|
392
|
+
|
393
|
+
DEFAULT_PRINT_FUNC: Printer = Console().print
|
394
|
+
DEFAULT_AUTOCOMPLETER: AutoCompleter = AutoCompleter()
|
395
|
+
DEFAULT_EXIT_COMMAND: Command = Command("Q", description="Exit command")
|
396
|
+
|
397
|
+
|
340
398
|
class App(BaseApp):
|
341
399
|
def __init__(
|
342
400
|
self,
|
343
|
-
|
401
|
+
*,
|
402
|
+
prompt: str = "What do you want to do?\n\n",
|
344
403
|
initial_message: str = "Argenta\n",
|
345
404
|
farewell_message: str = "\nSee you\n",
|
346
|
-
exit_command: Command =
|
405
|
+
exit_command: Command = DEFAULT_EXIT_COMMAND,
|
347
406
|
system_router_title: str | None = "System points:",
|
348
407
|
ignore_command_register: bool = True,
|
349
|
-
dividing_line:
|
408
|
+
dividing_line: AVAILABLE_DIVIDING_LINES = DEFAULT_DIVIDING_LINE,
|
350
409
|
repeat_command_groups: bool = True,
|
351
410
|
override_system_messages: bool = False,
|
352
|
-
autocompleter: AutoCompleter =
|
353
|
-
print_func:
|
411
|
+
autocompleter: AutoCompleter = DEFAULT_AUTOCOMPLETER,
|
412
|
+
print_func: Printer = DEFAULT_PRINT_FUNC,
|
354
413
|
) -> None:
|
355
414
|
"""
|
356
415
|
Public. The essence of the application itself.
|
@@ -387,7 +446,7 @@ class App(BaseApp):
|
|
387
446
|
Private. Starts the user input processing cycle
|
388
447
|
:return: None
|
389
448
|
"""
|
390
|
-
self.
|
449
|
+
self._pre_cycle_setup()
|
391
450
|
while True:
|
392
451
|
if self._repeat_command_groups_description:
|
393
452
|
self._print_command_group_description()
|
@@ -395,43 +454,70 @@ class App(BaseApp):
|
|
395
454
|
raw_command: str = Console().input(self._prompt)
|
396
455
|
|
397
456
|
try:
|
398
|
-
input_command: InputCommand = InputCommand.parse(
|
399
|
-
|
400
|
-
|
457
|
+
input_command: InputCommand = InputCommand.parse(
|
458
|
+
raw_command=raw_command
|
459
|
+
)
|
460
|
+
except InputCommandException as error:
|
461
|
+
with redirect_stdout(io.StringIO()) as stderr:
|
401
462
|
self._error_handler(error, raw_command)
|
402
|
-
|
403
|
-
self._print_framed_text(
|
463
|
+
stderr_result: str = stderr.getvalue()
|
464
|
+
self._print_framed_text(stderr_result)
|
404
465
|
continue
|
405
466
|
|
406
467
|
if self._is_exit_command(input_command):
|
407
468
|
system_router.finds_appropriate_handler(input_command)
|
408
|
-
self._autocompleter.exit_setup(
|
469
|
+
self._autocompleter.exit_setup(
|
470
|
+
list(self._current_matching_triggers_with_routers.keys())
|
471
|
+
)
|
409
472
|
return
|
410
473
|
|
411
474
|
if self._is_unknown_command(input_command):
|
412
|
-
with redirect_stdout(io.StringIO()) as
|
475
|
+
with redirect_stdout(io.StringIO()) as stdout:
|
413
476
|
self._unknown_command_handler(input_command)
|
414
|
-
|
415
|
-
self._print_framed_text(
|
477
|
+
stdout_res: str = stdout.getvalue()
|
478
|
+
self._print_framed_text(stdout_res)
|
416
479
|
continue
|
417
480
|
|
418
|
-
processing_router = self._current_matching_triggers_with_routers[
|
481
|
+
processing_router = self._current_matching_triggers_with_routers[
|
482
|
+
input_command.trigger.lower()
|
483
|
+
]
|
419
484
|
|
420
485
|
if processing_router.disable_redirect_stdout:
|
421
486
|
if isinstance(self._dividing_line, StaticDividingLine):
|
422
|
-
self._print_func(
|
487
|
+
self._print_func(
|
488
|
+
self._dividing_line.get_full_static_line(
|
489
|
+
is_override=self._override_system_messages
|
490
|
+
)
|
491
|
+
)
|
423
492
|
processing_router.finds_appropriate_handler(input_command)
|
424
|
-
self._print_func(
|
493
|
+
self._print_func(
|
494
|
+
self._dividing_line.get_full_static_line(
|
495
|
+
is_override=self._override_system_messages
|
496
|
+
)
|
497
|
+
)
|
425
498
|
else:
|
426
|
-
self.
|
499
|
+
dividing_line_unit_part: str = self._dividing_line.get_unit_part()
|
500
|
+
self._print_func(
|
501
|
+
StaticDividingLine(
|
502
|
+
dividing_line_unit_part
|
503
|
+
).get_full_static_line(
|
504
|
+
is_override=self._override_system_messages
|
505
|
+
)
|
506
|
+
)
|
427
507
|
processing_router.finds_appropriate_handler(input_command)
|
428
|
-
self._print_func(
|
508
|
+
self._print_func(
|
509
|
+
StaticDividingLine(
|
510
|
+
dividing_line_unit_part
|
511
|
+
).get_full_static_line(
|
512
|
+
is_override=self._override_system_messages
|
513
|
+
)
|
514
|
+
)
|
429
515
|
else:
|
430
|
-
with redirect_stdout(io.StringIO()) as
|
516
|
+
with redirect_stdout(io.StringIO()) as stdout:
|
431
517
|
processing_router.finds_appropriate_handler(input_command)
|
432
|
-
|
433
|
-
if
|
434
|
-
self._print_framed_text(
|
518
|
+
stdout_result: str = stdout.getvalue()
|
519
|
+
if stdout_result:
|
520
|
+
self._print_framed_text(stdout_result)
|
435
521
|
|
436
522
|
def include_router(self, router: Router) -> None:
|
437
523
|
"""
|
@@ -439,8 +525,8 @@ class App(BaseApp):
|
|
439
525
|
:param router: registered router
|
440
526
|
:return: None
|
441
527
|
"""
|
442
|
-
router.
|
443
|
-
self.
|
528
|
+
router.command_register_ignore = self._ignore_command_register
|
529
|
+
self.registered_routers.add_registered_router(router)
|
444
530
|
|
445
531
|
def include_routers(self, *routers: Router) -> None:
|
446
532
|
"""
|
argenta/app/protocols.py
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
from typing import Protocol, TypeVar
|
2
|
+
|
3
|
+
T = TypeVar('T', contravariant=True) # noqa: WPS111
|
4
|
+
|
5
|
+
|
6
|
+
class NonStandardBehaviorHandler(Protocol[T]):
|
7
|
+
def __call__(self, __param: T) -> None:
|
8
|
+
raise NotImplementedError
|
9
|
+
|
10
|
+
class EmptyCommandHandler(Protocol):
|
11
|
+
def __call__(self) -> None:
|
12
|
+
raise NotImplementedError
|
13
|
+
|
14
|
+
|
15
|
+
class Printer(Protocol):
|
16
|
+
def __call__(self, __text: str) -> None:
|
17
|
+
raise NotImplementedError
|
18
|
+
|
19
|
+
|
20
|
+
class DescriptionMessageGenerator(Protocol):
|
21
|
+
def __call__(self, __first_param: str, __second_param: str) -> str:
|
22
|
+
raise NotImplementedError
|
@@ -1,34 +1,27 @@
|
|
1
|
-
from typing import Iterator
|
1
|
+
from typing import Iterator, Optional
|
2
2
|
|
3
3
|
from argenta.router import Router
|
4
4
|
|
5
5
|
|
6
6
|
class RegisteredRouters:
|
7
|
-
def __init__(self, registered_routers: list[Router]
|
7
|
+
def __init__(self, registered_routers: Optional[list[Router]] = None) -> None:
|
8
8
|
"""
|
9
9
|
Private. Combines registered routers
|
10
10
|
:param registered_routers: list of the registered routers
|
11
11
|
:return: None
|
12
12
|
"""
|
13
|
-
self.
|
13
|
+
self.registered_routers: list[Router] = registered_routers if registered_routers else []
|
14
14
|
|
15
|
-
def
|
16
|
-
"""
|
17
|
-
Private. Returns the registered routers
|
18
|
-
:return: registered routers as list[Router]
|
19
|
-
"""
|
20
|
-
return self._registered_routers
|
21
|
-
|
22
|
-
def add_registered_router(self, router: Router) -> None:
|
15
|
+
def add_registered_router(self, router: Router, /) -> None:
|
23
16
|
"""
|
24
17
|
Private. Adds a new registered router
|
25
18
|
:param router: registered router
|
26
19
|
:return: None
|
27
20
|
"""
|
28
|
-
self.
|
21
|
+
self.registered_routers.append(router)
|
29
22
|
|
30
23
|
def __iter__(self) -> Iterator[Router]:
|
31
|
-
return iter(self.
|
24
|
+
return iter(self.registered_routers)
|
32
25
|
|
33
26
|
def __next__(self) -> Router:
|
34
|
-
return next(iter(self.
|
27
|
+
return next(iter(self.registered_routers))
|