argenta 1.0.7__py3-none-any.whl → 1.1.1__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 +10 -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 +129 -118
- 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/metrics/main.py +2 -2
- argenta/orchestrator/__init__.py +5 -1
- argenta/orchestrator/argparser/__init__.py +9 -1
- argenta/orchestrator/argparser/arguments/models.py +18 -12
- argenta/orchestrator/argparser/entity.py +15 -35
- argenta/orchestrator/entity.py +4 -7
- argenta/py.typed +0 -0
- argenta/response/__init__.py +2 -2
- argenta/response/entity.py +12 -18
- argenta/response/status.py +12 -1
- argenta/router/__init__.py +2 -2
- argenta/router/command_handler/entity.py +7 -27
- argenta/router/entity.py +127 -155
- argenta/router/exceptions.py +11 -8
- {argenta-1.0.7.dist-info → argenta-1.1.1.dist-info}/METADATA +10 -4
- argenta-1.1.1.dist-info/RECORD +41 -0
- argenta-1.0.7.dist-info/RECORD +0 -39
- {argenta-1.0.7.dist-info → argenta-1.1.1.dist-info}/WHEEL +0 -0
- {argenta-1.0.7.dist-info → argenta-1.1.1.dist-info}/licenses/LICENSE +0 -0
argenta/__init__.py
CHANGED
argenta/app/__init__.py
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
-
__all__ = [
|
1
|
+
__all__ = [
|
2
|
+
"App",
|
3
|
+
"PredefinedMessages",
|
4
|
+
"DynamicDividingLine",
|
5
|
+
"StaticDividingLine",
|
6
|
+
"AutoCompleter"
|
7
|
+
]
|
2
8
|
|
3
9
|
from argenta.app.models import App
|
10
|
+
from argenta.app.defaults import PredefinedMessages
|
11
|
+
from argenta.app.dividing_line.models import DynamicDividingLine, StaticDividingLine
|
12
|
+
from argenta.app.autocompleter.entity import AutoCompleter
|
@@ -13,10 +13,10 @@ class AutoCompleter:
|
|
13
13
|
:param autocomplete_button: the button for auto-completion
|
14
14
|
:return: None
|
15
15
|
"""
|
16
|
-
self.history_filename = history_filename
|
17
|
-
self.autocomplete_button = autocomplete_button
|
16
|
+
self.history_filename: str | None = history_filename
|
17
|
+
self.autocomplete_button: str = autocomplete_button
|
18
18
|
|
19
|
-
def _complete(self, text, state) -> str | None:
|
19
|
+
def _complete(self, text: str, state: int) -> str | None:
|
20
20
|
"""
|
21
21
|
Private. Auto-completion function
|
22
22
|
:param text: part of the command being entered
|
@@ -24,7 +24,7 @@ class AutoCompleter:
|
|
24
24
|
:return: the desired candidate as str or None
|
25
25
|
"""
|
26
26
|
matches: list[str] = sorted(
|
27
|
-
cmd for cmd in
|
27
|
+
cmd for cmd in _get_history_items() if cmd.startswith(text)
|
28
28
|
)
|
29
29
|
if len(matches) > 1:
|
30
30
|
common_prefix = matches[0]
|
@@ -38,7 +38,7 @@ class AutoCompleter:
|
|
38
38
|
i += 1
|
39
39
|
common_prefix = common_prefix[:i]
|
40
40
|
if state == 0:
|
41
|
-
readline.insert_text(common_prefix[len(text) :])
|
41
|
+
readline.insert_text(common_prefix[len(text) :])
|
42
42
|
readline.redisplay()
|
43
43
|
return None
|
44
44
|
elif len(matches) == 1:
|
@@ -54,10 +54,10 @@ class AutoCompleter:
|
|
54
54
|
"""
|
55
55
|
if self.history_filename:
|
56
56
|
if os.path.exists(self.history_filename):
|
57
|
-
readline.read_history_file(self.history_filename)
|
57
|
+
readline.read_history_file(self.history_filename)
|
58
58
|
else:
|
59
59
|
for line in all_commands:
|
60
|
-
readline.add_history(line)
|
60
|
+
readline.add_history(line)
|
61
61
|
|
62
62
|
readline.set_completer(self._complete)
|
63
63
|
readline.set_completer_delims(readline.get_completer_delims().replace(" ", ""))
|
@@ -69,7 +69,7 @@ class AutoCompleter:
|
|
69
69
|
:return: None
|
70
70
|
"""
|
71
71
|
if self.history_filename:
|
72
|
-
readline.write_history_file(self.history_filename)
|
72
|
+
readline.write_history_file(self.history_filename)
|
73
73
|
with open(self.history_filename, "r") as history_file:
|
74
74
|
raw_history = history_file.read()
|
75
75
|
pretty_history: list[str] = []
|
@@ -77,15 +77,14 @@ class AutoCompleter:
|
|
77
77
|
if line.split()[0] in all_commands:
|
78
78
|
pretty_history.append(line)
|
79
79
|
with open(self.history_filename, "w") as history_file:
|
80
|
-
history_file.write("\n".join(pretty_history))
|
80
|
+
_ = history_file.write("\n".join(pretty_history))
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
]
|
82
|
+
def _get_history_items() -> list[str] | list[Never]:
|
83
|
+
"""
|
84
|
+
Private. Returns a list of all commands entered by the user
|
85
|
+
:return: all commands entered by the user as list[str] | list[Never]
|
86
|
+
"""
|
87
|
+
return [
|
88
|
+
readline.get_history_item(i)
|
89
|
+
for i in range(1, readline.get_current_history_length() + 1)
|
90
|
+
]
|
argenta/app/defaults.py
CHANGED
@@ -5,7 +5,6 @@ class PredefinedMessages(StrEnum):
|
|
5
5
|
"""
|
6
6
|
Public. A dataclass with predetermined messages for quick use
|
7
7
|
"""
|
8
|
-
|
9
8
|
USAGE = "[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]"
|
10
9
|
HELP = "[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]"
|
11
10
|
AUTOCOMPLETE = "[b dim]Autocomplete[/b dim]: [i]<part>[/i] [bold]<tab>"
|
@@ -8,7 +8,7 @@ class BaseDividingLine(ABC):
|
|
8
8
|
:param unit_part: the single part of the dividing line
|
9
9
|
:return: None
|
10
10
|
"""
|
11
|
-
self._unit_part = unit_part
|
11
|
+
self._unit_part: str = unit_part
|
12
12
|
|
13
13
|
def get_unit_part(self) -> str:
|
14
14
|
"""
|
@@ -22,7 +22,7 @@ class BaseDividingLine(ABC):
|
|
22
22
|
|
23
23
|
|
24
24
|
class StaticDividingLine(BaseDividingLine):
|
25
|
-
def __init__(self, unit_part: str = "-", length: int = 25) -> None:
|
25
|
+
def __init__(self, unit_part: str = "-", *, length: int = 25) -> None:
|
26
26
|
"""
|
27
27
|
Public. The static dividing line
|
28
28
|
:param unit_part: the single part of the dividing line
|
@@ -30,9 +30,9 @@ class StaticDividingLine(BaseDividingLine):
|
|
30
30
|
:return: None
|
31
31
|
"""
|
32
32
|
super().__init__(unit_part)
|
33
|
-
self.length = length
|
33
|
+
self.length: int = length
|
34
34
|
|
35
|
-
def get_full_static_line(self, is_override: bool) -> str:
|
35
|
+
def get_full_static_line(self, *, is_override: bool) -> str:
|
36
36
|
"""
|
37
37
|
Private. Returns the full line of the dividing line
|
38
38
|
:param is_override: has the default text layout been redefined
|
@@ -53,7 +53,7 @@ class DynamicDividingLine(BaseDividingLine):
|
|
53
53
|
"""
|
54
54
|
super().__init__(unit_part)
|
55
55
|
|
56
|
-
def get_full_dynamic_line(self, length: int, is_override: bool) -> str:
|
56
|
+
def get_full_dynamic_line(self, *, length: int, is_override: bool) -> str:
|
57
57
|
"""
|
58
58
|
Private. Returns the full line of the dividing line
|
59
59
|
:param length: the length of the dividing line
|
argenta/app/models.py
CHANGED
@@ -1,29 +1,37 @@
|
|
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__(self, prompt: str,
|
34
|
+
def __init__(self, *, prompt: str,
|
27
35
|
initial_message: str,
|
28
36
|
farewell_message: str,
|
29
37
|
exit_command: Command,
|
@@ -33,57 +41,44 @@ class BaseApp:
|
|
33
41
|
repeat_command_groups: bool,
|
34
42
|
override_system_messages: bool,
|
35
43
|
autocompleter: AutoCompleter,
|
36
|
-
print_func:
|
37
|
-
self._prompt = prompt
|
38
|
-
self._print_func = print_func
|
39
|
-
self._exit_command = exit_command
|
40
|
-
self._system_router_title = system_router_title
|
41
|
-
self._dividing_line = dividing_line
|
42
|
-
self._ignore_command_register = ignore_command_register
|
43
|
-
self._repeat_command_groups_description = repeat_command_groups
|
44
|
-
self._override_system_messages = override_system_messages
|
45
|
-
self._autocompleter = autocompleter
|
46
|
-
|
47
|
-
self._farewell_message = farewell_message
|
48
|
-
self._initial_message = initial_message
|
49
|
-
|
50
|
-
self._description_message_gen:
|
44
|
+
print_func: Printer) -> None:
|
45
|
+
self._prompt: str = prompt
|
46
|
+
self._print_func: Printer = print_func
|
47
|
+
self._exit_command: Command = exit_command
|
48
|
+
self._system_router_title: str | None = system_router_title
|
49
|
+
self._dividing_line: StaticDividingLine | DynamicDividingLine = dividing_line
|
50
|
+
self._ignore_command_register: bool = ignore_command_register
|
51
|
+
self._repeat_command_groups_description: bool = repeat_command_groups
|
52
|
+
self._override_system_messages: bool = override_system_messages
|
53
|
+
self._autocompleter: AutoCompleter = autocompleter
|
54
|
+
|
55
|
+
self._farewell_message: str = farewell_message
|
56
|
+
self._initial_message: str = initial_message
|
57
|
+
|
58
|
+
self._description_message_gen: DescriptionMessageGenerator = lambda command, description: f"{command} *=*=* {description}"
|
51
59
|
self._registered_routers: RegisteredRouters = RegisteredRouters()
|
52
60
|
self._messages_on_startup: list[str] = []
|
53
61
|
|
54
62
|
self._matching_lower_triggers_with_routers: dict[str, Router] = {}
|
55
63
|
self._matching_default_triggers_with_routers: dict[str, Router] = {}
|
56
64
|
|
57
|
-
if self._ignore_command_register
|
58
|
-
self._current_matching_triggers_with_routers: dict[str, Router] = self._matching_lower_triggers_with_routers
|
59
|
-
else:
|
60
|
-
self._current_matching_triggers_with_routers: dict[str, Router] = self._matching_default_triggers_with_routers
|
65
|
+
self._current_matching_triggers_with_routers: dict[str, Router] = self._matching_lower_triggers_with_routers if self._ignore_command_register else self._matching_default_triggers_with_routers
|
61
66
|
|
62
|
-
self._incorrect_input_syntax_handler:
|
63
|
-
|
64
|
-
)
|
65
|
-
self.
|
66
|
-
|
67
|
-
)
|
68
|
-
self._empty_input_command_handler: Callable[[], None] = lambda: print_func(
|
69
|
-
"Empty input command"
|
70
|
-
)
|
71
|
-
self._unknown_command_handler: Callable[[InputCommand], None] = (
|
72
|
-
lambda command: print_func(f"Unknown command: {command.get_trigger()}")
|
73
|
-
)
|
74
|
-
self._exit_command_handler: Callable[[Response], None] = (
|
75
|
-
lambda response: print_func(self._farewell_message)
|
76
|
-
)
|
67
|
+
self._incorrect_input_syntax_handler: NonStandardBehaviorHandler[str] = lambda _: print_func(f"Incorrect flag syntax: {_}")
|
68
|
+
self._repeated_input_flags_handler: NonStandardBehaviorHandler[str] = lambda _: print_func(f"Repeated input flags: {_}")
|
69
|
+
self._empty_input_command_handler: EmptyCommandHandler = lambda: print_func("Empty input command")
|
70
|
+
self._unknown_command_handler: NonStandardBehaviorHandler[InputCommand] = lambda _: print_func(f"Unknown command: {_.trigger}")
|
71
|
+
self._exit_command_handler: NonStandardBehaviorHandler[Response] = lambda _: print_func(self._farewell_message)
|
77
72
|
|
78
|
-
def set_description_message_pattern(self, _:
|
73
|
+
def set_description_message_pattern(self, _: DescriptionMessageGenerator, /) -> None:
|
79
74
|
"""
|
80
75
|
Public. Sets the output pattern of the available commands
|
81
76
|
:param _: output pattern of the available commands
|
82
77
|
:return: None
|
83
78
|
"""
|
84
|
-
self._description_message_gen
|
79
|
+
self._description_message_gen = _
|
85
80
|
|
86
|
-
def set_incorrect_input_syntax_handler(self, _:
|
81
|
+
def set_incorrect_input_syntax_handler(self, _: NonStandardBehaviorHandler[str], /) -> None:
|
87
82
|
"""
|
88
83
|
Public. Sets the handler for incorrect flags when entering a command
|
89
84
|
:param _: handler for incorrect flags when entering a command
|
@@ -91,7 +86,7 @@ class BaseApp:
|
|
91
86
|
"""
|
92
87
|
self._incorrect_input_syntax_handler = _
|
93
88
|
|
94
|
-
def set_repeated_input_flags_handler(self, _:
|
89
|
+
def set_repeated_input_flags_handler(self, _: NonStandardBehaviorHandler[str], /) -> None:
|
95
90
|
"""
|
96
91
|
Public. Sets the handler for repeated flags when entering a command
|
97
92
|
:param _: handler for repeated flags when entering a command
|
@@ -99,7 +94,7 @@ class BaseApp:
|
|
99
94
|
"""
|
100
95
|
self._repeated_input_flags_handler = _
|
101
96
|
|
102
|
-
def set_unknown_command_handler(self, _:
|
97
|
+
def set_unknown_command_handler(self, _: NonStandardBehaviorHandler[InputCommand], /) -> None:
|
103
98
|
"""
|
104
99
|
Public. Sets the handler for unknown commands when entering a command
|
105
100
|
:param _: handler for unknown commands when entering a command
|
@@ -107,7 +102,7 @@ class BaseApp:
|
|
107
102
|
"""
|
108
103
|
self._unknown_command_handler = _
|
109
104
|
|
110
|
-
def set_empty_command_handler(self, _:
|
105
|
+
def set_empty_command_handler(self, _: EmptyCommandHandler, /) -> None:
|
111
106
|
"""
|
112
107
|
Public. Sets the handler for empty commands when entering a command
|
113
108
|
:param _: handler for empty commands when entering a command
|
@@ -115,7 +110,7 @@ class BaseApp:
|
|
115
110
|
"""
|
116
111
|
self._empty_input_command_handler = _
|
117
112
|
|
118
|
-
def set_exit_command_handler(self, _:
|
113
|
+
def set_exit_command_handler(self, _: NonStandardBehaviorHandler[Response], /) -> None:
|
119
114
|
"""
|
120
115
|
Public. Sets the handler for exit command when entering a command
|
121
116
|
:param _: handler for exit command when entering a command
|
@@ -131,11 +126,12 @@ class BaseApp:
|
|
131
126
|
for registered_router in self._registered_routers:
|
132
127
|
if registered_router.title:
|
133
128
|
self._print_func(registered_router.title)
|
134
|
-
for command_handler in registered_router.
|
129
|
+
for command_handler in registered_router.command_handlers:
|
130
|
+
handled_command = command_handler.handled_command
|
135
131
|
self._print_func(
|
136
132
|
self._description_message_gen(
|
137
|
-
|
138
|
-
|
133
|
+
handled_command.trigger,
|
134
|
+
handled_command.description,
|
139
135
|
)
|
140
136
|
)
|
141
137
|
self._print_func("")
|
@@ -146,16 +142,7 @@ class BaseApp:
|
|
146
142
|
:param text: framed text
|
147
143
|
:return: None
|
148
144
|
"""
|
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):
|
145
|
+
if isinstance(self._dividing_line, DynamicDividingLine):
|
159
146
|
clear_text = re.sub(r"\u001b\[[0-9;]*m", "", text)
|
160
147
|
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
161
148
|
max_length_line = (
|
@@ -168,15 +155,27 @@ class BaseApp:
|
|
168
155
|
|
169
156
|
self._print_func(
|
170
157
|
self._dividing_line.get_full_dynamic_line(
|
171
|
-
max_length_line, self._override_system_messages
|
158
|
+
length=max_length_line, is_override=self._override_system_messages
|
172
159
|
)
|
173
160
|
)
|
174
161
|
print(text.strip("\n"))
|
175
162
|
self._print_func(
|
176
163
|
self._dividing_line.get_full_dynamic_line(
|
177
|
-
max_length_line, self._override_system_messages
|
164
|
+
length=max_length_line, is_override=self._override_system_messages
|
178
165
|
)
|
179
166
|
)
|
167
|
+
|
168
|
+
elif isinstance(self._dividing_line, StaticDividingLine): # pyright: ignore[reportUnnecessaryIsInstance]
|
169
|
+
self._print_func(
|
170
|
+
self._dividing_line.get_full_static_line(is_override=self._override_system_messages)
|
171
|
+
)
|
172
|
+
print(text.strip("\n"))
|
173
|
+
self._print_func(
|
174
|
+
self._dividing_line.get_full_static_line(is_override=self._override_system_messages)
|
175
|
+
)
|
176
|
+
|
177
|
+
else:
|
178
|
+
raise NotImplementedError
|
180
179
|
|
181
180
|
def _is_exit_command(self, command: InputCommand) -> bool:
|
182
181
|
"""
|
@@ -184,20 +183,21 @@ class BaseApp:
|
|
184
183
|
:param command: command to check
|
185
184
|
:return: is it an exit command or not as bool
|
186
185
|
"""
|
186
|
+
trigger = command.trigger
|
187
|
+
exit_trigger = self._exit_command.trigger
|
187
188
|
if self._ignore_command_register:
|
188
189
|
if (
|
189
|
-
|
190
|
-
== self._exit_command.get_trigger().lower()
|
190
|
+
trigger.lower() == exit_trigger.lower()
|
191
191
|
):
|
192
192
|
return True
|
193
|
-
elif
|
194
|
-
x.lower() for x in self._exit_command.
|
193
|
+
elif trigger.lower() in [
|
194
|
+
x.lower() for x in self._exit_command.aliases
|
195
195
|
]:
|
196
196
|
return True
|
197
197
|
else:
|
198
|
-
if
|
198
|
+
if trigger == exit_trigger:
|
199
199
|
return True
|
200
|
-
elif
|
200
|
+
elif trigger in self._exit_command.aliases:
|
201
201
|
return True
|
202
202
|
return False
|
203
203
|
|
@@ -207,7 +207,7 @@ class BaseApp:
|
|
207
207
|
:param command: command to check
|
208
208
|
:return: is it an unknown command or not as bool
|
209
209
|
"""
|
210
|
-
input_command_trigger = command.
|
210
|
+
input_command_trigger = command.trigger
|
211
211
|
if self._ignore_command_register:
|
212
212
|
if input_command_trigger.lower() in list(self._current_matching_triggers_with_routers.keys()):
|
213
213
|
return False
|
@@ -217,7 +217,7 @@ class BaseApp:
|
|
217
217
|
return True
|
218
218
|
|
219
219
|
def _error_handler(
|
220
|
-
self, error:
|
220
|
+
self, error: InputCommandException, raw_command: str
|
221
221
|
) -> None:
|
222
222
|
"""
|
223
223
|
Private. Handles parsing errors of the entered command
|
@@ -240,23 +240,25 @@ class BaseApp:
|
|
240
240
|
system_router.title = self._system_router_title
|
241
241
|
|
242
242
|
@system_router.command(self._exit_command)
|
243
|
-
def
|
243
|
+
def _(response: Response) -> None:
|
244
244
|
self._exit_command_handler(response)
|
245
245
|
|
246
|
-
if system_router not in self._registered_routers.
|
247
|
-
system_router.
|
246
|
+
if system_router not in self._registered_routers.registered_routers:
|
247
|
+
system_router.command_register_ignore = self._ignore_command_register
|
248
248
|
self._registered_routers.add_registered_router(system_router)
|
249
249
|
|
250
250
|
def _most_similar_command(self, unknown_command: str) -> str | None:
|
251
251
|
all_commands = list(self._current_matching_triggers_with_routers.keys())
|
252
|
-
|
253
|
-
|
252
|
+
|
253
|
+
matches_startswith_unknown_command: Matches = sorted(
|
254
254
|
cmd for cmd in all_commands if cmd.startswith(unknown_command)
|
255
255
|
)
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
256
|
+
matches_startswith_cmd: Matches = sorted(
|
257
|
+
cmd for cmd in all_commands if unknown_command.startswith(cmd)
|
258
|
+
)
|
259
|
+
|
260
|
+
matches: Matches = matches_startswith_unknown_command or matches_startswith_cmd
|
261
|
+
|
260
262
|
if len(matches) == 1:
|
261
263
|
return matches[0]
|
262
264
|
elif len(matches) > 1:
|
@@ -272,9 +274,9 @@ class BaseApp:
|
|
272
274
|
self._prompt = f"[italic dim bold]{self._prompt}"
|
273
275
|
self._initial_message = ("\n" + f"[bold red]{text2art(self._initial_message, font='tarty1')}" + "\n")
|
274
276
|
self._farewell_message = (
|
275
|
-
"[bold red]\n\n"
|
276
|
-
|
277
|
-
|
277
|
+
"[bold red]\n\n" +
|
278
|
+
str(text2art(self._farewell_message, font="chanky")) + # pyright: ignore[reportUnknownArgumentType]
|
279
|
+
"\n[/bold red]\n" +
|
278
280
|
"[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n"
|
279
281
|
)
|
280
282
|
self._description_message_gen = lambda command, description: (
|
@@ -287,7 +289,7 @@ class BaseApp:
|
|
287
289
|
self._empty_input_command_handler = lambda: self._print_func("[red bold]Empty input command")
|
288
290
|
|
289
291
|
def unknown_command_handler(command: InputCommand) -> None:
|
290
|
-
cmd_trg: str = command.
|
292
|
+
cmd_trg: str = command.trigger
|
291
293
|
mst_sim_cmd: str | None = self._most_similar_command(cmd_trg)
|
292
294
|
first_part_of_text = f"[red]Unknown command:[/red] [blue]{escape(cmd_trg)}[/blue]"
|
293
295
|
second_part_of_text = (
|
@@ -299,7 +301,7 @@ class BaseApp:
|
|
299
301
|
|
300
302
|
self._unknown_command_handler = unknown_command_handler
|
301
303
|
|
302
|
-
def
|
304
|
+
def _pre_cycle_setup(self) -> None:
|
303
305
|
"""
|
304
306
|
Private. Configures various aspects of the application before the start of the cycle
|
305
307
|
:return: None
|
@@ -307,8 +309,8 @@ class BaseApp:
|
|
307
309
|
self._setup_system_router()
|
308
310
|
|
309
311
|
for router_entity in self._registered_routers:
|
310
|
-
router_triggers = router_entity.
|
311
|
-
router_aliases = router_entity.
|
312
|
+
router_triggers = router_entity.triggers
|
313
|
+
router_aliases = router_entity.aliases
|
312
314
|
combined = router_triggers + router_aliases
|
313
315
|
|
314
316
|
for trigger in combined:
|
@@ -337,20 +339,28 @@ class BaseApp:
|
|
337
339
|
self._print_command_group_description()
|
338
340
|
|
339
341
|
|
342
|
+
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine
|
343
|
+
DEFAULT_DIVIDING_LINE: StaticDividingLine = StaticDividingLine()
|
344
|
+
|
345
|
+
DEFAULT_PRINT_FUNC: Printer = Console().print
|
346
|
+
DEFAULT_AUTOCOMPLETER: AutoCompleter = AutoCompleter()
|
347
|
+
DEFAULT_EXIT_COMMAND: Command = Command("Q", description="Exit command")
|
348
|
+
|
349
|
+
|
340
350
|
class App(BaseApp):
|
341
351
|
def __init__(
|
342
|
-
self,
|
343
|
-
prompt: str = "What do you want to do?\n",
|
352
|
+
self, *,
|
353
|
+
prompt: str = "What do you want to do?\n\n",
|
344
354
|
initial_message: str = "Argenta\n",
|
345
355
|
farewell_message: str = "\nSee you\n",
|
346
|
-
exit_command: Command =
|
356
|
+
exit_command: Command = DEFAULT_EXIT_COMMAND,
|
347
357
|
system_router_title: str | None = "System points:",
|
348
358
|
ignore_command_register: bool = True,
|
349
|
-
dividing_line:
|
359
|
+
dividing_line: AVAILABLE_DIVIDING_LINES = DEFAULT_DIVIDING_LINE,
|
350
360
|
repeat_command_groups: bool = True,
|
351
361
|
override_system_messages: bool = False,
|
352
|
-
autocompleter: AutoCompleter =
|
353
|
-
print_func:
|
362
|
+
autocompleter: AutoCompleter = DEFAULT_AUTOCOMPLETER,
|
363
|
+
print_func: Printer = DEFAULT_PRINT_FUNC,
|
354
364
|
) -> None:
|
355
365
|
"""
|
356
366
|
Public. The essence of the application itself.
|
@@ -387,7 +397,7 @@ class App(BaseApp):
|
|
387
397
|
Private. Starts the user input processing cycle
|
388
398
|
:return: None
|
389
399
|
"""
|
390
|
-
self.
|
400
|
+
self._pre_cycle_setup()
|
391
401
|
while True:
|
392
402
|
if self._repeat_command_groups_description:
|
393
403
|
self._print_command_group_description()
|
@@ -396,11 +406,11 @@ class App(BaseApp):
|
|
396
406
|
|
397
407
|
try:
|
398
408
|
input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
|
399
|
-
except
|
400
|
-
with redirect_stdout(io.StringIO()) as
|
409
|
+
except InputCommandException as error:
|
410
|
+
with redirect_stdout(io.StringIO()) as stderr:
|
401
411
|
self._error_handler(error, raw_command)
|
402
|
-
|
403
|
-
self._print_framed_text(
|
412
|
+
stderr_result: str = stderr.getvalue()
|
413
|
+
self._print_framed_text(stderr_result)
|
404
414
|
continue
|
405
415
|
|
406
416
|
if self._is_exit_command(input_command):
|
@@ -409,29 +419,30 @@ class App(BaseApp):
|
|
409
419
|
return
|
410
420
|
|
411
421
|
if self._is_unknown_command(input_command):
|
412
|
-
with redirect_stdout(io.StringIO()) as
|
422
|
+
with redirect_stdout(io.StringIO()) as stdout:
|
413
423
|
self._unknown_command_handler(input_command)
|
414
|
-
|
415
|
-
self._print_framed_text(
|
424
|
+
stdout_res: str = stdout.getvalue()
|
425
|
+
self._print_framed_text(stdout_res)
|
416
426
|
continue
|
417
427
|
|
418
|
-
processing_router = self._current_matching_triggers_with_routers[input_command.
|
428
|
+
processing_router = self._current_matching_triggers_with_routers[input_command.trigger.lower()]
|
419
429
|
|
420
430
|
if processing_router.disable_redirect_stdout:
|
421
431
|
if isinstance(self._dividing_line, StaticDividingLine):
|
422
|
-
self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
|
432
|
+
self._print_func(self._dividing_line.get_full_static_line(is_override=self._override_system_messages))
|
423
433
|
processing_router.finds_appropriate_handler(input_command)
|
424
|
-
self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
|
434
|
+
self._print_func(self._dividing_line.get_full_static_line(is_override=self._override_system_messages))
|
425
435
|
else:
|
426
|
-
self.
|
436
|
+
dividing_line_unit_part: str = self._dividing_line.get_unit_part()
|
437
|
+
self._print_func(StaticDividingLine(dividing_line_unit_part).get_full_static_line(is_override=self._override_system_messages))
|
427
438
|
processing_router.finds_appropriate_handler(input_command)
|
428
|
-
self._print_func(StaticDividingLine(
|
439
|
+
self._print_func(StaticDividingLine(dividing_line_unit_part).get_full_static_line(is_override=self._override_system_messages))
|
429
440
|
else:
|
430
|
-
with redirect_stdout(io.StringIO()) as
|
441
|
+
with redirect_stdout(io.StringIO()) as stdout:
|
431
442
|
processing_router.finds_appropriate_handler(input_command)
|
432
|
-
|
433
|
-
if
|
434
|
-
self._print_framed_text(
|
443
|
+
stdout_result: str = stdout.getvalue()
|
444
|
+
if stdout_result:
|
445
|
+
self._print_framed_text(stdout_result)
|
435
446
|
|
436
447
|
def include_router(self, router: Router) -> None:
|
437
448
|
"""
|
@@ -439,7 +450,7 @@ class App(BaseApp):
|
|
439
450
|
:param router: registered router
|
440
451
|
:return: None
|
441
452
|
"""
|
442
|
-
router.
|
453
|
+
router.command_register_ignore = self._ignore_command_register
|
443
454
|
self._registered_routers.add_registered_router(router)
|
444
455
|
|
445
456
|
def include_routers(self, *routers: Router) -> None:
|
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
|