argenta 1.0.0a5__py3-none-any.whl → 1.0.0b2__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/app/models.py +41 -20
- argenta/command/exceptions.py +1 -1
- argenta/command/flag/__init__.py +2 -2
- argenta/command/flag/models.py +24 -124
- argenta/command/flags/__init__.py +10 -0
- argenta/command/flags/models.py +87 -0
- argenta/command/models.py +18 -10
- argenta/response/__init__.py +5 -0
- argenta/response/entity.py +27 -0
- argenta/response/status.py +9 -0
- argenta/router/command_handler/entity.py +7 -11
- argenta/router/entity.py +87 -53
- {argenta-1.0.0a5.dist-info → argenta-1.0.0b2.dist-info}/METADATA +4 -4
- {argenta-1.0.0a5.dist-info → argenta-1.0.0b2.dist-info}/RECORD +16 -11
- {argenta-1.0.0a5.dist-info → argenta-1.0.0b2.dist-info}/WHEEL +0 -0
- {argenta-1.0.0a5.dist-info → argenta-1.0.0b2.dist-info}/licenses/LICENSE +0 -0
argenta/app/models.py
CHANGED
@@ -16,6 +16,7 @@ from argenta.command.exceptions import (UnprocessedInputFlagException,
|
|
16
16
|
EmptyInputCommandException,
|
17
17
|
BaseInputCommandException)
|
18
18
|
from argenta.app.registered_routers.entity import RegisteredRouters
|
19
|
+
from argenta.response import Response
|
19
20
|
|
20
21
|
|
21
22
|
|
@@ -58,7 +59,7 @@ class BaseApp:
|
|
58
59
|
self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Repeated input flags: {raw_command}')
|
59
60
|
self._empty_input_command_handler: Callable[[], None] = lambda: print_func('Empty input command')
|
60
61
|
self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"Unknown command: {command.get_trigger()}")
|
61
|
-
self._exit_command_handler: Callable[[], None] = lambda: print_func(self._farewell_message)
|
62
|
+
self._exit_command_handler: Callable[[Response], None] = lambda response: print_func(self._farewell_message)
|
62
63
|
|
63
64
|
|
64
65
|
def set_description_message_pattern(self, _: Callable[[str, str], str]) -> None:
|
@@ -210,30 +211,51 @@ class BaseApp:
|
|
210
211
|
system_router.set_title(self._system_router_title)
|
211
212
|
|
212
213
|
@system_router.command(self._exit_command)
|
213
|
-
def exit_command():
|
214
|
-
self._exit_command_handler()
|
214
|
+
def exit_command(response: Response) -> None:
|
215
|
+
self._exit_command_handler(response)
|
215
216
|
|
216
217
|
if system_router not in self._registered_routers.get_registered_routers():
|
217
218
|
system_router.set_command_register_ignore(self._ignore_command_register)
|
218
219
|
self._registered_routers.add_registered_router(system_router)
|
219
220
|
|
220
221
|
|
222
|
+
def _most_similar_command(self, unknown_command: str) -> str | None:
|
223
|
+
all_commands = self._all_registered_triggers_in_lower if self._ignore_command_register else self._all_registered_triggers_in_default_case
|
224
|
+
matches: list[str] | list = sorted(cmd for cmd in all_commands if cmd.startswith(unknown_command))
|
225
|
+
if not matches:
|
226
|
+
matches: list[str] | list = sorted(cmd for cmd in all_commands if unknown_command.startswith(cmd))
|
227
|
+
if len(matches) == 1:
|
228
|
+
return matches[0]
|
229
|
+
elif len(matches) > 1:
|
230
|
+
return sorted(matches, key=lambda cmd: len(cmd))[0]
|
231
|
+
else:
|
232
|
+
return None
|
233
|
+
|
234
|
+
|
221
235
|
def _setup_default_view(self) -> None:
|
222
236
|
"""
|
223
237
|
Private. Sets up default app view
|
224
238
|
:return: None
|
225
239
|
"""
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
240
|
+
self._prompt = '[italic dim bold]What do you want to do?\n'
|
241
|
+
self._initial_message = f'\n[bold red]{text2art(self._initial_message, font="tarty1")}\n'
|
242
|
+
self._farewell_message = (f'[bold red]\n{text2art(f"\n{self._farewell_message}\n", font="chanky")}[/bold red]\n'
|
243
|
+
f'[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n')
|
244
|
+
self._description_message_gen = lambda command, description: (f'[bold red]{escape("[" + command + "]")}[/bold red] '
|
245
|
+
f'[blue dim]*=*=*[/blue dim] '
|
246
|
+
f'[bold yellow italic]{escape(description)}')
|
247
|
+
self._invalid_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}')
|
248
|
+
self._repeated_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Repeated input flags: {escape(raw_command)}')
|
249
|
+
self._empty_input_command_handler = lambda: self._print_func('[red bold]Empty input command')
|
250
|
+
|
251
|
+
def unknown_command_handler(command: InputCommand) -> None:
|
252
|
+
cmd_trg: str = command.get_trigger()
|
253
|
+
mst_sim_cmd: str | None = self._most_similar_command(cmd_trg)
|
254
|
+
first_part_of_text = f"[red]Unknown command:[/red] [blue]{escape(cmd_trg)}[/blue]"
|
255
|
+
second_part_of_text = ('[red], most similar:[/red] ' + ('[blue]' + mst_sim_cmd + '[/blue]')) if mst_sim_cmd else ''
|
256
|
+
self._print_func(first_part_of_text + second_part_of_text)
|
257
|
+
|
258
|
+
self._unknown_command_handler = unknown_command_handler
|
237
259
|
|
238
260
|
|
239
261
|
def _pre_cycle_setup(self) -> None:
|
@@ -241,7 +263,6 @@ class BaseApp:
|
|
241
263
|
Private. Configures various aspects of the application before the start of the cycle
|
242
264
|
:return: None
|
243
265
|
"""
|
244
|
-
self._setup_default_view()
|
245
266
|
self._setup_system_router()
|
246
267
|
|
247
268
|
for router_entity in self._registered_routers:
|
@@ -253,12 +274,15 @@ class BaseApp:
|
|
253
274
|
|
254
275
|
self._autocompleter.initial_setup(self._all_registered_triggers_in_lower)
|
255
276
|
|
277
|
+
if not self._override_system_messages:
|
278
|
+
self._setup_default_view()
|
279
|
+
|
256
280
|
self._print_func(self._initial_message)
|
257
281
|
|
258
282
|
for message in self._messages_on_startup:
|
259
283
|
self._print_func(message)
|
260
284
|
if self._messages_on_startup:
|
261
|
-
print('\n
|
285
|
+
print('\n')
|
262
286
|
|
263
287
|
if not self._repeat_command_groups_description:
|
264
288
|
self._print_command_group_description()
|
@@ -267,7 +291,7 @@ class BaseApp:
|
|
267
291
|
|
268
292
|
class App(BaseApp):
|
269
293
|
def __init__(self,
|
270
|
-
prompt: str = '
|
294
|
+
prompt: str = 'What do you want to do?\n',
|
271
295
|
initial_message: str = '\nArgenta\n',
|
272
296
|
farewell_message: str = '\nSee you\n',
|
273
297
|
exit_command: Command = Command('Q', 'Exit command'),
|
@@ -346,9 +370,6 @@ class App(BaseApp):
|
|
346
370
|
res: str = f.getvalue()
|
347
371
|
self._print_framed_text(res)
|
348
372
|
|
349
|
-
if not self._repeat_command_groups_description:
|
350
|
-
self._print_func(self._prompt)
|
351
|
-
|
352
373
|
|
353
374
|
def include_router(self, router: Router) -> None:
|
354
375
|
"""
|
argenta/command/exceptions.py
CHANGED
argenta/command/flag/__init__.py
CHANGED
argenta/command/flag/models.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import Literal, Pattern
|
2
|
-
from abc import ABC, abstractmethod
|
3
2
|
|
4
3
|
|
5
|
-
|
4
|
+
|
5
|
+
class BaseFlag:
|
6
6
|
def __init__(self, name: str,
|
7
7
|
prefix: Literal['-', '--', '---'] = '--') -> None:
|
8
8
|
"""
|
@@ -36,37 +36,8 @@ class BaseFlag(ABC):
|
|
36
36
|
"""
|
37
37
|
return self._prefix
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
class InputFlag(BaseFlag):
|
42
|
-
def __init__(self, name: str,
|
43
|
-
prefix: Literal['-', '--', '---'] = '--',
|
44
|
-
value: str = None):
|
45
|
-
"""
|
46
|
-
Public. The entity of the flag of the entered command
|
47
|
-
:param name: the name of the input flag
|
48
|
-
:param prefix: the prefix of the input flag
|
49
|
-
:param value: the value of the input flag
|
50
|
-
:return: None
|
51
|
-
"""
|
52
|
-
super().__init__(name, prefix)
|
53
|
-
self._flag_value = value
|
54
|
-
|
55
|
-
def get_value(self) -> str | None:
|
56
|
-
"""
|
57
|
-
Public. Returns the value of the flag
|
58
|
-
:return: the value of the flag as str
|
59
|
-
"""
|
60
|
-
return self._flag_value
|
61
|
-
|
62
|
-
def set_value(self, value):
|
63
|
-
"""
|
64
|
-
Private. Sets the value of the flag
|
65
|
-
:param value: the fag value to set
|
66
|
-
:return: None
|
67
|
-
"""
|
68
|
-
self._flag_value = value
|
69
|
-
|
39
|
+
def __eq__(self, other) -> bool:
|
40
|
+
return self.get_string_entity() == other.get_string_entity()
|
70
41
|
|
71
42
|
|
72
43
|
class Flag(BaseFlag):
|
@@ -113,106 +84,35 @@ class Flag(BaseFlag):
|
|
113
84
|
return True
|
114
85
|
|
115
86
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
"""
|
121
|
-
__slots__ = ('_flags',)
|
122
|
-
|
123
|
-
@abstractmethod
|
124
|
-
def get_flags(self):
|
125
|
-
"""
|
126
|
-
Public. Returns a list of flags
|
127
|
-
:return: list of flags
|
128
|
-
"""
|
129
|
-
pass
|
130
|
-
|
131
|
-
@abstractmethod
|
132
|
-
def add_flag(self, flag: Flag | InputFlag):
|
133
|
-
"""
|
134
|
-
Public. Adds a flag to the list of flags
|
135
|
-
:param flag: flag to add
|
136
|
-
:return: None
|
137
|
-
"""
|
138
|
-
pass
|
139
|
-
|
140
|
-
@abstractmethod
|
141
|
-
def add_flags(self, flags: list[Flag] | list[InputFlag]):
|
87
|
+
class InputFlag(BaseFlag):
|
88
|
+
def __init__(self, name: str,
|
89
|
+
prefix: Literal['-', '--', '---'] = '--',
|
90
|
+
value: str = None):
|
142
91
|
"""
|
143
|
-
Public.
|
144
|
-
:param
|
92
|
+
Public. The entity of the flag of the entered command
|
93
|
+
:param name: the name of the input flag
|
94
|
+
:param prefix: the prefix of the input flag
|
95
|
+
:param value: the value of the input flag
|
145
96
|
:return: None
|
146
97
|
"""
|
147
|
-
|
148
|
-
|
149
|
-
@abstractmethod
|
150
|
-
def get_flag(self, name: str):
|
151
|
-
"""
|
152
|
-
Public. Returns the flag entity by its name or None if not found
|
153
|
-
:param name: the name of the flag to get
|
154
|
-
:return: entity of the flag or None
|
155
|
-
"""
|
156
|
-
pass
|
157
|
-
|
158
|
-
def __iter__(self):
|
159
|
-
return iter(self._flags)
|
160
|
-
|
161
|
-
def __next__(self):
|
162
|
-
return next(iter(self))
|
163
|
-
|
164
|
-
def __getitem__(self, item):
|
165
|
-
return self._flags[item]
|
166
|
-
|
167
|
-
|
98
|
+
super().__init__(name, prefix)
|
99
|
+
self._flag_value = value
|
168
100
|
|
169
|
-
|
170
|
-
def __init__(self, *flags: Flag):
|
101
|
+
def get_value(self) -> str | None:
|
171
102
|
"""
|
172
|
-
Public.
|
173
|
-
:
|
174
|
-
:return: None
|
103
|
+
Public. Returns the value of the flag
|
104
|
+
:return: the value of the flag as str
|
175
105
|
"""
|
176
|
-
self.
|
177
|
-
|
178
|
-
def get_flags(self) -> list[Flag]:
|
179
|
-
return self._flags
|
180
|
-
|
181
|
-
def add_flag(self, flag: Flag):
|
182
|
-
self._flags.append(flag)
|
183
|
-
|
184
|
-
def add_flags(self, flags: list[Flag]):
|
185
|
-
self._flags.extend(flags)
|
186
|
-
|
187
|
-
def get_flag(self, name: str) -> Flag | None:
|
188
|
-
if name in [flag.get_name() for flag in self._flags]:
|
189
|
-
return list(filter(lambda flag: flag.get_name() == name, self._flags))[0]
|
190
|
-
else:
|
191
|
-
return None
|
192
|
-
|
193
|
-
|
106
|
+
return self._flag_value
|
194
107
|
|
195
|
-
|
196
|
-
def __init__(self, *flags: InputFlag):
|
108
|
+
def set_value(self, value):
|
197
109
|
"""
|
198
|
-
|
199
|
-
:param
|
110
|
+
Private. Sets the value of the flag
|
111
|
+
:param value: the fag value to set
|
200
112
|
:return: None
|
201
113
|
"""
|
202
|
-
self.
|
203
|
-
|
204
|
-
def get_flags(self) -> list[InputFlag]:
|
205
|
-
return self._flags
|
206
|
-
|
207
|
-
def add_flag(self, flag: InputFlag):
|
208
|
-
self._flags.append(flag)
|
209
|
-
|
210
|
-
def add_flags(self, flags: list[InputFlag]):
|
211
|
-
self._flags.extend(flags)
|
114
|
+
self._flag_value = value
|
212
115
|
|
213
|
-
def
|
214
|
-
|
215
|
-
return list(filter(lambda flag: flag.get_name() == name, self._flags))[0]
|
216
|
-
else:
|
217
|
-
return None
|
116
|
+
def __eq__(self, other) -> bool:
|
117
|
+
return self.get_string_entity() == other.get_string_entity() and self.get_value() == other.get_value()
|
218
118
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from argenta.command.flag.models import InputFlag, Flag
|
2
|
+
from typing import Generic, TypeVar
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
FlagType = TypeVar('FlagType')
|
7
|
+
|
8
|
+
|
9
|
+
class BaseFlags(Generic[FlagType]):
|
10
|
+
def __init__(self, *flags: FlagType):
|
11
|
+
"""
|
12
|
+
Public. A model that combines the registered flags
|
13
|
+
:param flags: the flags that will be registered
|
14
|
+
:return: None
|
15
|
+
"""
|
16
|
+
self._flags = flags if flags else []
|
17
|
+
|
18
|
+
def get_flags(self) -> list[FlagType]:
|
19
|
+
"""
|
20
|
+
Public. Returns a list of flags
|
21
|
+
:return: list of flags as list[FlagType]
|
22
|
+
"""
|
23
|
+
return self._flags
|
24
|
+
|
25
|
+
def add_flag(self, flag: FlagType):
|
26
|
+
"""
|
27
|
+
Public. Adds a flag to the list of flags
|
28
|
+
:param flag: flag to add
|
29
|
+
:return: None
|
30
|
+
"""
|
31
|
+
self._flags.append(flag)
|
32
|
+
|
33
|
+
def add_flags(self, flags: list[FlagType]):
|
34
|
+
"""
|
35
|
+
Public. Adds a list of flags to the list of flags
|
36
|
+
:param flags: list of flags to add
|
37
|
+
:return: None
|
38
|
+
"""
|
39
|
+
self._flags.extend(flags)
|
40
|
+
|
41
|
+
def get_flag(self, name: str) -> FlagType | None:
|
42
|
+
"""
|
43
|
+
Public. Returns the flag entity by its name or None if not found
|
44
|
+
:param name: the name of the flag to get
|
45
|
+
:return: entity of the flag or None
|
46
|
+
"""
|
47
|
+
if name in [flag.get_name() for flag in self._flags]:
|
48
|
+
return list(filter(lambda flag: flag.get_name() == name, self._flags))[0]
|
49
|
+
else:
|
50
|
+
return None
|
51
|
+
|
52
|
+
def __iter__(self):
|
53
|
+
return iter(self._flags)
|
54
|
+
|
55
|
+
def __next__(self):
|
56
|
+
return next(iter(self))
|
57
|
+
|
58
|
+
def __getitem__(self, item):
|
59
|
+
return self._flags[item]
|
60
|
+
|
61
|
+
def __bool__(self):
|
62
|
+
return bool(self._flags)
|
63
|
+
|
64
|
+
def __eq__(self, other):
|
65
|
+
if len(self.get_flags()) != len(other.get_flags()):
|
66
|
+
return False
|
67
|
+
else:
|
68
|
+
for flag, other_flag in zip(self.get_flags(), other.get_flags()):
|
69
|
+
if not flag == other_flag:
|
70
|
+
return False
|
71
|
+
return True
|
72
|
+
|
73
|
+
|
74
|
+
class Flags(BaseFlags[Flag]): pass
|
75
|
+
|
76
|
+
|
77
|
+
class InputFlags(BaseFlags[InputFlag]): pass
|
78
|
+
|
79
|
+
|
80
|
+
class ValidInputFlags(InputFlags): pass
|
81
|
+
|
82
|
+
|
83
|
+
class UndefinedInputFlags(InputFlags): pass
|
84
|
+
|
85
|
+
|
86
|
+
class InvalidValueInputFlags(InputFlags): pass
|
87
|
+
|
argenta/command/models.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from argenta.command.flag.models import Flag, InputFlag
|
1
|
+
from argenta.command.flag.models import Flag, InputFlag
|
2
|
+
from argenta.command.flags.models import InputFlags, Flags
|
2
3
|
from argenta.command.exceptions import (UnprocessedInputFlagException,
|
3
4
|
RepeatedInputFlagsException,
|
4
5
|
EmptyInputCommandException)
|
@@ -38,7 +39,7 @@ class Command(BaseCommand):
|
|
38
39
|
"""
|
39
40
|
super().__init__(trigger)
|
40
41
|
self._registered_flags: Flags = flags if isinstance(flags, Flags) else Flags(flags) if isinstance(flags, Flag) else Flags()
|
41
|
-
self._description = f'
|
42
|
+
self._description = f'Very useful command' if not description else description
|
42
43
|
self._aliases = aliases if isinstance(aliases, list) else []
|
43
44
|
|
44
45
|
def get_registered_flags(self) -> Flags:
|
@@ -55,7 +56,7 @@ class Command(BaseCommand):
|
|
55
56
|
"""
|
56
57
|
return self._aliases
|
57
58
|
|
58
|
-
def validate_input_flag(self, flag: InputFlag) ->
|
59
|
+
def validate_input_flag(self, flag: InputFlag) -> Literal['Undefined', 'Valid', 'Invalid']:
|
59
60
|
"""
|
60
61
|
Private. Validates the input flag
|
61
62
|
:param flag: input flag for validation
|
@@ -67,14 +68,21 @@ class Command(BaseCommand):
|
|
67
68
|
if registered_flags.get_string_entity() == flag.get_string_entity():
|
68
69
|
is_valid = registered_flags.validate_input_flag_value(flag.get_value())
|
69
70
|
if is_valid:
|
70
|
-
return
|
71
|
+
return 'Valid'
|
72
|
+
else:
|
73
|
+
return 'Invalid'
|
74
|
+
else:
|
75
|
+
return 'Undefined'
|
71
76
|
else:
|
72
77
|
for registered_flag in registered_flags:
|
73
78
|
if registered_flag.get_string_entity() == flag.get_string_entity():
|
74
79
|
is_valid = registered_flag.validate_input_flag_value(flag.get_value())
|
75
80
|
if is_valid:
|
76
|
-
return
|
77
|
-
|
81
|
+
return 'Valid'
|
82
|
+
else:
|
83
|
+
return 'Invalid'
|
84
|
+
return 'Undefined'
|
85
|
+
return 'Undefined'
|
78
86
|
|
79
87
|
def get_description(self) -> str:
|
80
88
|
"""
|
@@ -131,11 +139,11 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
|
|
131
139
|
|
132
140
|
for k, _ in enumerate(list_of_tokens):
|
133
141
|
if _.startswith('-'):
|
134
|
-
if
|
142
|
+
if len(_) < 2 or len(_[:_.rfind('-')]) > 3:
|
135
143
|
raise UnprocessedInputFlagException()
|
136
144
|
current_flag_name = _
|
137
145
|
else:
|
138
|
-
if not current_flag_name:
|
146
|
+
if not current_flag_name or current_flag_value:
|
139
147
|
raise UnprocessedInputFlagException()
|
140
148
|
current_flag_value = _
|
141
149
|
|
@@ -144,9 +152,9 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
|
|
144
152
|
if not list_of_tokens[k+1].startswith('-'):
|
145
153
|
continue
|
146
154
|
|
147
|
-
input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-')+1:],
|
155
|
+
input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-') + 1:],
|
148
156
|
prefix=cast(Literal['-', '--', '---'],
|
149
|
-
|
157
|
+
current_flag_name[:current_flag_name.rfind('-')+1]),
|
150
158
|
value=current_flag_value)
|
151
159
|
|
152
160
|
all_flags = [flag.get_string_entity() for flag in input_flags.get_flags()]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from argenta.response.status import Status
|
2
|
+
from argenta.command.flags import (ValidInputFlags,
|
3
|
+
UndefinedInputFlags,
|
4
|
+
InvalidValueInputFlags)
|
5
|
+
|
6
|
+
|
7
|
+
class Response:
|
8
|
+
__slots__ = ('status',
|
9
|
+
'valid_flags',
|
10
|
+
'undefined_flags',
|
11
|
+
'invalid_value_flags')
|
12
|
+
|
13
|
+
def __init__(self, status: Status = None,
|
14
|
+
valid_flags: ValidInputFlags = ValidInputFlags(),
|
15
|
+
undefined_flags: UndefinedInputFlags = UndefinedInputFlags(),
|
16
|
+
invalid_value_flags: InvalidValueInputFlags = InvalidValueInputFlags()):
|
17
|
+
"""
|
18
|
+
Public. The entity of the user input sent to the handler
|
19
|
+
:param status: the status of the response
|
20
|
+
:param valid_flags: valid input flags
|
21
|
+
:param undefined_flags: undefined input flags
|
22
|
+
:param invalid_value_flags: input flags with invalid values
|
23
|
+
"""
|
24
|
+
self.status = status
|
25
|
+
self.valid_flags = valid_flags
|
26
|
+
self.undefined_flags = undefined_flags
|
27
|
+
self.invalid_value_flags = invalid_value_flags
|
@@ -1,12 +1,11 @@
|
|
1
1
|
from typing import Callable, Iterator
|
2
2
|
|
3
3
|
from argenta.command import Command
|
4
|
-
from argenta.
|
5
|
-
|
4
|
+
from argenta.response import Response
|
6
5
|
|
7
6
|
|
8
7
|
class CommandHandler:
|
9
|
-
def __init__(self, handler: Callable[[], None]
|
8
|
+
def __init__(self, handler: Callable[[Response], None], handled_command: Command):
|
10
9
|
"""
|
11
10
|
Private. Entity of the model linking the handler and the command being processed
|
12
11
|
:param handler: the handler being called
|
@@ -15,21 +14,18 @@ class CommandHandler:
|
|
15
14
|
self._handler = handler
|
16
15
|
self._handled_command = handled_command
|
17
16
|
|
18
|
-
def handling(self,
|
17
|
+
def handling(self, response: Response) -> None:
|
19
18
|
"""
|
20
19
|
Private. Direct processing of an input command
|
21
|
-
:param
|
20
|
+
:param response: the entity of response: various groups of flags and status of response
|
22
21
|
:return: None
|
23
22
|
"""
|
24
|
-
|
25
|
-
self._handler(input_flags)
|
26
|
-
else:
|
27
|
-
self._handler()
|
23
|
+
self._handler(response)
|
28
24
|
|
29
|
-
def get_handler(self) -> Callable[[], None]
|
25
|
+
def get_handler(self) -> Callable[[Response], None]:
|
30
26
|
"""
|
31
27
|
Private. Returns the handler being called
|
32
|
-
:return: the handler being called as Callable[[], None]
|
28
|
+
:return: the handler being called as Callable[[Response], None]
|
33
29
|
"""
|
34
30
|
return self._handler
|
35
31
|
|
argenta/router/entity.py
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
from typing import Callable
|
2
|
-
from inspect import getfullargspec
|
1
|
+
from typing import Callable, Literal, Type
|
2
|
+
from inspect import getfullargspec, get_annotations, getsourcefile, getsourcelines
|
3
|
+
from rich.console import Console
|
4
|
+
|
3
5
|
from argenta.command import Command
|
4
6
|
from argenta.command.models import InputCommand
|
7
|
+
from argenta.response import Response, Status
|
5
8
|
from argenta.router.command_handler.entity import CommandHandlers, CommandHandler
|
6
|
-
from argenta.command.
|
9
|
+
from argenta.command.flags.models import (Flags, InputFlags,
|
10
|
+
UndefinedInputFlags,
|
11
|
+
ValidInputFlags,
|
12
|
+
InvalidValueInputFlags)
|
7
13
|
from argenta.router.exceptions import (RepeatedFlagNameException,
|
8
14
|
TooManyTransferredArgsException,
|
9
15
|
RequiredArgumentNotPassedException,
|
@@ -11,8 +17,7 @@ from argenta.router.exceptions import (RepeatedFlagNameException,
|
|
11
17
|
|
12
18
|
|
13
19
|
class Router:
|
14
|
-
def __init__(self,
|
15
|
-
title: str = None):
|
20
|
+
def __init__(self, title: str = None):
|
16
21
|
"""
|
17
22
|
Public. Directly configures and manages handlers
|
18
23
|
:param title: the title of the router, displayed when displaying the available commands
|
@@ -22,19 +27,20 @@ class Router:
|
|
22
27
|
|
23
28
|
self._command_handlers: CommandHandlers = CommandHandlers()
|
24
29
|
self._ignore_command_register: bool = False
|
25
|
-
self._not_valid_flag_handler: Callable[[Flag], None] = lambda flag: print(f"Undefined or incorrect input flag: {flag.get_string_entity()}{(' '+flag.get_value()) if flag.get_value() else ''}")
|
26
30
|
|
27
31
|
|
28
|
-
def command(self, command: Command) -> Callable:
|
32
|
+
def command(self, command: Command | str) -> Callable:
|
29
33
|
"""
|
30
34
|
Public. Registers handler
|
31
35
|
:param command: Registered command
|
32
|
-
:return: decorated handler as Callable
|
36
|
+
:return: decorated handler as Callable
|
33
37
|
"""
|
34
38
|
self._validate_command(command)
|
39
|
+
if isinstance(command, str):
|
40
|
+
command = Command(command)
|
35
41
|
|
36
42
|
def command_decorator(func):
|
37
|
-
Router._validate_func_args(
|
43
|
+
Router._validate_func_args(func)
|
38
44
|
self._command_handlers.add_handler(CommandHandler(func, command))
|
39
45
|
|
40
46
|
def wrapper(*args, **kwargs):
|
@@ -44,15 +50,6 @@ class Router:
|
|
44
50
|
return command_decorator
|
45
51
|
|
46
52
|
|
47
|
-
def set_invalid_input_flag_handler(self, func: Callable[[Flag], None]) -> None:
|
48
|
-
"""
|
49
|
-
Public. Registers handler for invalid input flag
|
50
|
-
:param func: registered handler
|
51
|
-
:return: None
|
52
|
-
"""
|
53
|
-
self._not_valid_flag_handler = func
|
54
|
-
|
55
|
-
|
56
53
|
def finds_appropriate_handler(self, input_command: InputCommand) -> None:
|
57
54
|
"""
|
58
55
|
Private. Finds the appropriate handler for given input command and passes control to it
|
@@ -78,73 +75,110 @@ class Router:
|
|
78
75
|
:return: None
|
79
76
|
"""
|
80
77
|
handle_command = command_handler.get_handled_command()
|
78
|
+
response: Response = Response()
|
81
79
|
if handle_command.get_registered_flags().get_flags():
|
82
80
|
if input_command_flags.get_flags():
|
83
|
-
|
84
|
-
|
85
|
-
return
|
81
|
+
response: Response = self._structuring_input_flags(handle_command, input_command_flags)
|
82
|
+
command_handler.handling(response)
|
86
83
|
else:
|
87
|
-
|
88
|
-
|
84
|
+
response.status = Status.ALL_FLAGS_VALID
|
85
|
+
command_handler.handling(response)
|
89
86
|
else:
|
90
87
|
if input_command_flags.get_flags():
|
91
|
-
|
92
|
-
|
88
|
+
response.status = Status.UNDEFINED_FLAGS
|
89
|
+
response.undefined_flags = UndefinedInputFlags()
|
90
|
+
response.undefined_flags.add_flags(input_command_flags.get_flags())
|
91
|
+
command_handler.handling(response)
|
93
92
|
else:
|
94
|
-
|
95
|
-
|
93
|
+
response.status = Status.ALL_FLAGS_VALID
|
94
|
+
command_handler.handling(response)
|
96
95
|
|
97
96
|
|
98
|
-
|
97
|
+
@staticmethod
|
98
|
+
def _structuring_input_flags(handled_command: Command, input_flags: InputFlags) -> Response:
|
99
99
|
"""
|
100
100
|
Private. Validates flags of input command
|
101
101
|
:param handled_command: entity of the handled command
|
102
102
|
:param input_flags:
|
103
|
-
:return:
|
103
|
+
:return: entity of response as Response
|
104
104
|
"""
|
105
|
+
valid_input_flags: ValidInputFlags = ValidInputFlags()
|
106
|
+
invalid_value_input_flags: InvalidValueInputFlags = InvalidValueInputFlags()
|
107
|
+
undefined_input_flags: UndefinedInputFlags = UndefinedInputFlags()
|
105
108
|
for flag in input_flags:
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
flag_status: Literal['Undefined', 'Valid', 'Invalid'] = handled_command.validate_input_flag(flag)
|
110
|
+
match flag_status:
|
111
|
+
case 'Valid':
|
112
|
+
valid_input_flags.add_flag(flag)
|
113
|
+
case 'Undefined':
|
114
|
+
undefined_input_flags.add_flag(flag)
|
115
|
+
case 'Invalid':
|
116
|
+
invalid_value_input_flags.add_flag(flag)
|
117
|
+
|
118
|
+
if not invalid_value_input_flags.get_flags() and not undefined_input_flags.get_flags():
|
119
|
+
status = Status.ALL_FLAGS_VALID
|
120
|
+
elif invalid_value_input_flags.get_flags() and not undefined_input_flags.get_flags():
|
121
|
+
status = Status.INVALID_VALUE_FLAGS
|
122
|
+
elif not invalid_value_input_flags.get_flags() and undefined_input_flags.get_flags():
|
123
|
+
status = Status.UNDEFINED_FLAGS
|
124
|
+
else:
|
125
|
+
status = Status.UNDEFINED_AND_INVALID_FLAGS
|
126
|
+
|
127
|
+
return Response(invalid_value_flags=invalid_value_input_flags,
|
128
|
+
valid_flags=valid_input_flags,
|
129
|
+
status=status,
|
130
|
+
undefined_flags=undefined_input_flags)
|
111
131
|
|
112
132
|
|
113
133
|
@staticmethod
|
114
|
-
def _validate_command(command: Command) -> None:
|
134
|
+
def _validate_command(command: Command | str) -> None:
|
115
135
|
"""
|
116
136
|
Private. Validates the command registered in handler
|
117
137
|
:param command: validated command
|
118
138
|
:return: None if command is valid else raise exception
|
119
139
|
"""
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
140
|
+
match type(command).__name__:
|
141
|
+
case 'Command':
|
142
|
+
command_name: str = command.get_trigger()
|
143
|
+
if command_name.find(' ') != -1:
|
144
|
+
raise TriggerContainSpacesException()
|
145
|
+
flags: Flags = command.get_registered_flags()
|
146
|
+
if flags:
|
147
|
+
flags_name: list = [x.get_string_entity().lower() for x in flags]
|
148
|
+
if len(set(flags_name)) < len(flags_name):
|
149
|
+
raise RepeatedFlagNameException()
|
150
|
+
case 'str':
|
151
|
+
if command.find(' ') != -1:
|
152
|
+
raise TriggerContainSpacesException()
|
129
153
|
|
130
154
|
|
131
155
|
@staticmethod
|
132
|
-
def _validate_func_args(
|
156
|
+
def _validate_func_args(func: Callable) -> None:
|
133
157
|
"""
|
134
158
|
Private. Validates the arguments of the handler
|
135
|
-
:param command: registered command in handler
|
136
159
|
:param func: entity of the handler func
|
137
160
|
:return: None if func is valid else raise exception
|
138
161
|
"""
|
139
|
-
registered_args = command.get_registered_flags()
|
140
162
|
transferred_args = getfullargspec(func).args
|
141
|
-
if
|
142
|
-
if len(transferred_args) != 1:
|
143
|
-
raise TooManyTransferredArgsException()
|
144
|
-
elif registered_args.get_flags() and not transferred_args:
|
145
|
-
raise RequiredArgumentNotPassedException()
|
146
|
-
elif not registered_args.get_flags() and transferred_args:
|
163
|
+
if len(transferred_args) > 1:
|
147
164
|
raise TooManyTransferredArgsException()
|
165
|
+
elif len(transferred_args) == 0:
|
166
|
+
raise RequiredArgumentNotPassedException()
|
167
|
+
|
168
|
+
transferred_arg: str = transferred_args[0]
|
169
|
+
func_annotations: dict[str, Type] = get_annotations(func)
|
170
|
+
|
171
|
+
if arg_annotation := func_annotations.get(transferred_arg):
|
172
|
+
if arg_annotation is Response:
|
173
|
+
pass
|
174
|
+
else:
|
175
|
+
file_path: str = getsourcefile(func)
|
176
|
+
source_line: int = getsourcelines(func)[1]+1
|
177
|
+
fprint = Console().print
|
178
|
+
fprint(f'\nFile "{file_path}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
|
179
|
+
f'of argument([green]{transferred_arg}[/green]) passed to the handler is [/i][bold blue]{Response}[/bold blue],'
|
180
|
+
f' [i]but[/i] [bold blue]{arg_annotation}[/bold blue] [i]is specified[/i]\n', highlight=False)
|
181
|
+
|
148
182
|
|
149
183
|
|
150
184
|
def set_command_register_ignore(self, _: bool) -> None:
|
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: argenta
|
3
|
-
Version: 1.0.
|
4
|
-
Summary: Python library for
|
3
|
+
Version: 1.0.0b2
|
4
|
+
Summary: Python library for building modular CLI applications
|
5
5
|
Author-email: kolo <kolo.is.main@gmail.com>
|
6
6
|
License: MIT
|
7
7
|
License-File: LICENSE
|
8
8
|
Requires-Python: <4.0,>=3.11
|
9
9
|
Requires-Dist: art<7.0,>=6.4
|
10
|
-
Requires-Dist: pyreadline3
|
10
|
+
Requires-Dist: pyreadline3>=3.5.4
|
11
11
|
Requires-Dist: rich<15.0.0,>=14.0.0
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
|
@@ -87,7 +87,7 @@ Description-Content-Type: text/markdown
|
|
87
87
|
|
88
88
|
---
|
89
89
|
|
90
|
-

|
91
91
|
An example of the TUI appearance
|
92
92
|
|
93
93
|
---
|
@@ -1,7 +1,7 @@
|
|
1
1
|
argenta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
argenta/app/__init__.py,sha256=I8FTXU17ajDI-hbC6Rw0LxLmvDYipdQaos3v1pmu14E,57
|
3
3
|
argenta/app/defaults.py,sha256=GE4UzsJ7PD7654weNzTFGcBroc_0Zy5H9VL5P8ZbFek,393
|
4
|
-
argenta/app/models.py,sha256=
|
4
|
+
argenta/app/models.py,sha256=52iXVPQ7ekL5T60ErDR1X-qCmIt8YjzRerd_L8Jkwxo,18246
|
5
5
|
argenta/app/autocompleter/__init__.py,sha256=VT_p3QA78UnczV7pYR2NnwQ0Atd8mnDUnLazvUQNqJk,93
|
6
6
|
argenta/app/autocompleter/entity.py,sha256=6IurcSTLfiEYrh-yYsCYjrKsJ8_9xds3fxs5sr0FoqE,2901
|
7
7
|
argenta/app/dividing_line/__init__.py,sha256=jJZDDZix8XYCAUWW4FzGJH0JmJlchYcx0FPWifjgv1I,147
|
@@ -9,24 +9,29 @@ argenta/app/dividing_line/models.py,sha256=pDHZsUhgMJOGusMigS93a-4KXM-zqdQkahCdg
|
|
9
9
|
argenta/app/registered_routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
argenta/app/registered_routers/entity.py,sha256=hNaY3YfCp62Dk3U1XGvqTjt8mYDzgXcMsgNJMAqIU4w,1076
|
11
11
|
argenta/command/__init__.py,sha256=Plo2Da0fhq8H1eo2mg7nA1-OBLuGjK2BYpDGRvGGMIU,67
|
12
|
-
argenta/command/exceptions.py,sha256=
|
13
|
-
argenta/command/models.py,sha256
|
14
|
-
argenta/command/flag/__init__.py,sha256=
|
12
|
+
argenta/command/exceptions.py,sha256=QvJl3fY3MxDZscQQKSQ__lRuP9Jd2XVdQOo27TvmVnw,1030
|
13
|
+
argenta/command/models.py,sha256=t_NTLc5CIhV210R-GGb9sQyAb3n51XHx9VIQ9KOq2GI,6914
|
14
|
+
argenta/command/flag/__init__.py,sha256=4MOxfv8f2SkBzIfVo5LAZUTu4iH1jcs5WzPq60PhFMs,94
|
15
15
|
argenta/command/flag/defaults.py,sha256=0wCvh2l3eNU3vTuxuARVaUwhEzG3v9FID0rBbXHyK-k,982
|
16
|
-
argenta/command/flag/models.py,sha256=
|
16
|
+
argenta/command/flag/models.py,sha256=SUXDZPEcy7HTboociW6FFQ7bk0gTfwdt39HRx3AxTCo,3870
|
17
|
+
argenta/command/flags/__init__.py,sha256=Hpw8RO2_RxdRhS8EqWPGuLwAlmRLA-XkbO7q1iNxrvQ,396
|
18
|
+
argenta/command/flags/models.py,sha256=nkrM9dwrS--_pbpt7n2UEuOPX0QLwJ263_UK0QA85AA,2311
|
17
19
|
argenta/orchestrator/__init__.py,sha256=vFtJEJTjFfoYP3DZx0gNlhoa0Tk8u-yzkGIUN3SiABA,86
|
18
20
|
argenta/orchestrator/entity.py,sha256=HUKhoEQtiWvxeA3QhSkvTcIgwgXDLjmcB2cBFHlCGhw,1101
|
19
21
|
argenta/orchestrator/argparser/__init__.py,sha256=twfb-FQqW4QUo2XkmMASi654KGiimIbrkEzb1ZkMGzU,88
|
20
22
|
argenta/orchestrator/argparser/entity.py,sha256=nmwp7dFHTIqLvR9v0n_4j9wvtTowvLK7_SeoyaYL_RM,2145
|
21
23
|
argenta/orchestrator/argparser/arguments/__init__.py,sha256=4T55Tl_4WKOYp9HtVDmzQZylYVKA_cb3XiGoBvAyjNo,318
|
22
24
|
argenta/orchestrator/argparser/arguments/models.py,sha256=hSUXBjTsyzNKvyPgWhiNCa4SSQdmixIQnne2A9iuPMc,1546
|
25
|
+
argenta/response/__init__.py,sha256=u4NuwUQkWa55aX67hTQs_B_gIaZ9Dn4Fe7xhSFQ_Rpw,128
|
26
|
+
argenta/response/entity.py,sha256=Wz-plcx0lDx_VbFQs2I98uxxthZaZ1Gg5YSKfmiwGOQ,1150
|
27
|
+
argenta/response/status.py,sha256=owDBpCrJ0Xb6U5RtvYt9HTdM8ouVgJLFdzVD8h-Ho4w,246
|
23
28
|
argenta/router/__init__.py,sha256=ldrIWTXNLXUAMAGQ8ex4e8nMso_fhi01nZi2DVzHnnk,66
|
24
29
|
argenta/router/defaults.py,sha256=RX3DMbZk7XUbj6uR4uADhZOPqEDoeCz9X-n26YTCCPM,87
|
25
|
-
argenta/router/entity.py,sha256=
|
30
|
+
argenta/router/entity.py,sha256=D7wnWSJ1c5hJzfKp3hdTf5AZMMQZ3z82II5lQn6aie4,10005
|
26
31
|
argenta/router/exceptions.py,sha256=q6y-4gmbgkX-0U4-qXHDP5HTtUQ_c4svaqVILn-ZzRw,852
|
27
32
|
argenta/router/command_handler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
|
-
argenta/router/command_handler/entity.py,sha256=
|
29
|
-
argenta-1.0.
|
30
|
-
argenta-1.0.
|
31
|
-
argenta-1.0.
|
32
|
-
argenta-1.0.
|
33
|
+
argenta/router/command_handler/entity.py,sha256=z7X70yD66hAVug0Q-YKPxTLvYOZrLI6qZnPdFLCNmIQ,2385
|
34
|
+
argenta-1.0.0b2.dist-info/METADATA,sha256=tAv_oL7bAlFnbqNHx-EU7TKukqloade0HsGDkQnAlgg,25737
|
35
|
+
argenta-1.0.0b2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
36
|
+
argenta-1.0.0b2.dist-info/licenses/LICENSE,sha256=zmqoGh2n5rReBv4s8wPxF_gZEZDgauJYSPMuPczgOiU,1082
|
37
|
+
argenta-1.0.0b2.dist-info/RECORD,,
|
File without changes
|
File without changes
|