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 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
- if not self._override_system_messages:
227
- self._initial_message = f'\n[bold red]{text2art(self._initial_message, font="tarty1")}\n\n'
228
- self._farewell_message = (f'[bold red]\n{text2art(f"\n{self._farewell_message}\n", font="chanky")}[/bold red]\n'
229
- f'[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n')
230
- self._description_message_gen = lambda command, description: (f'[bold red]{escape("[" + command + "]")}[/bold red] '
231
- f'[blue dim]*=*=*[/blue dim] '
232
- f'[bold yellow italic]{escape(description)}')
233
- self._invalid_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}')
234
- self._repeated_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Repeated input flags: {escape(raw_command)}')
235
- self._empty_input_command_handler = lambda: self._print_func('[red bold]Empty input command')
236
- self._unknown_command_handler = lambda command: self._print_func(f"[red bold]Unknown command: {escape(command.get_trigger())}")
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\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 = '[italic dim bold]What do you want to do?\n',
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
  """
@@ -1,4 +1,4 @@
1
- from argenta.command.flag.models import InputFlag, Flag
1
+ from argenta.command.flag.models import Flag, InputFlag
2
2
 
3
3
 
4
4
  class BaseInputCommandException(Exception):
@@ -1,4 +1,4 @@
1
- __all__ = ('InputFlags', 'InputFlag', 'Flag', 'Flags')
1
+ __all__ = ["Flag", "InputFlag"]
2
2
 
3
3
 
4
- from argenta.command.flag.models import InputFlags, InputFlag, Flags, Flag
4
+ from argenta.command.flag.models import Flag, InputFlag
@@ -1,8 +1,8 @@
1
1
  from typing import Literal, Pattern
2
- from abc import ABC, abstractmethod
3
2
 
4
3
 
5
- class BaseFlag(ABC):
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
- class BaseFlags(ABC):
118
- """
119
- Private. Base class for groups of flags
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. Adds a list of flags to the list of flags
144
- :param flags: list of flags to add
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
- pass
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
- class Flags(BaseFlags, ABC):
170
- def __init__(self, *flags: Flag):
101
+ def get_value(self) -> str | None:
171
102
  """
172
- Public. A model that combines the registered flags
173
- :param flags: the flags that will be registered
174
- :return: None
103
+ Public. Returns the value of the flag
104
+ :return: the value of the flag as str
175
105
  """
176
- self._flags = flags if flags else []
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
- class InputFlags(BaseFlags, ABC):
196
- def __init__(self, *flags: InputFlag):
108
+ def set_value(self, value):
197
109
  """
198
- Public. A model that combines the input flags of the input command
199
- :param flags: all input flags
110
+ Private. Sets the value of the flag
111
+ :param value: the fag value to set
200
112
  :return: None
201
113
  """
202
- self._flags = flags if flags else []
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 get_flag(self, name: str) -> InputFlag | None:
214
- if name in [flag.get_name() for flag in self._flags]:
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,10 @@
1
+ __all__ = ["Flags", "InputFlags",
2
+ "UndefinedInputFlags",
3
+ "InvalidValueInputFlags",
4
+ "ValidInputFlags"]
5
+
6
+
7
+ from argenta.command.flags.models import (Flags, InputFlags,
8
+ UndefinedInputFlags,
9
+ InvalidValueInputFlags,
10
+ ValidInputFlags)
@@ -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, Flags, InputFlags
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'Description for "{self._trigger}" command' if not description else description
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) -> bool:
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 True
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 True
77
- return False
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 current_flag_name or len(_) < 2 or len(_[:_.rfind('-')]) > 3:
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
- current_flag_name[:current_flag_name.rfind('-')+1]),
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,5 @@
1
+ __all__ = ["Response", "Status"]
2
+
3
+
4
+ from argenta.response.entity import Response
5
+ from argenta.response.status import Status
@@ -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
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Status(Enum):
5
+ ALL_FLAGS_VALID = 'ALL_FLAGS_VALID'
6
+ UNDEFINED_FLAGS = 'UNDEFINED_FLAGS'
7
+ INVALID_VALUE_FLAGS = 'INVALID_VALUE_FLAGS'
8
+ UNDEFINED_AND_INVALID_FLAGS = 'UNDEFINED_AND_INVALID_FLAGS'
9
+
@@ -1,12 +1,11 @@
1
1
  from typing import Callable, Iterator
2
2
 
3
3
  from argenta.command import Command
4
- from argenta.command.flag import InputFlags
5
-
4
+ from argenta.response import Response
6
5
 
7
6
 
8
7
  class CommandHandler:
9
- def __init__(self, handler: Callable[[], None] | Callable[[InputFlags], None], handled_command: Command):
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, input_flags: InputFlags = None) -> None:
17
+ def handling(self, response: Response) -> None:
19
18
  """
20
19
  Private. Direct processing of an input command
21
- :param input_flags: the flags of the input command
20
+ :param response: the entity of response: various groups of flags and status of response
22
21
  :return: None
23
22
  """
24
- if input_flags is not None:
25
- self._handler(input_flags)
26
- else:
27
- self._handler()
23
+ self._handler(response)
28
24
 
29
- def get_handler(self) -> Callable[[], None] | Callable[[InputFlags], 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] or Callable[[InputFlags], 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.flag.models import Flag, Flags, InputFlags
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[[Any], Any]
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(command, func)
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
- if self._validate_input_flags(handle_command, input_command_flags):
84
- command_handler.handling(input_command_flags)
85
- return
81
+ response: Response = self._structuring_input_flags(handle_command, input_command_flags)
82
+ command_handler.handling(response)
86
83
  else:
87
- command_handler.handling(input_command_flags)
88
- return
84
+ response.status = Status.ALL_FLAGS_VALID
85
+ command_handler.handling(response)
89
86
  else:
90
87
  if input_command_flags.get_flags():
91
- self._not_valid_flag_handler(input_command_flags[0])
92
- return
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
- command_handler.handling()
95
- return
93
+ response.status = Status.ALL_FLAGS_VALID
94
+ command_handler.handling(response)
96
95
 
97
96
 
98
- def _validate_input_flags(self, handled_command: Command, input_flags: InputFlags) -> bool:
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: is flags of input command valid as bool
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
- is_valid: bool = handled_command.validate_input_flag(flag)
107
- if not is_valid:
108
- self._not_valid_flag_handler(flag)
109
- return False
110
- return True
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
- command_name: str = command.get_trigger()
121
- if command_name.find(' ') != -1:
122
- raise TriggerContainSpacesException()
123
-
124
- flags: Flags = command.get_registered_flags()
125
- if flags:
126
- flags_name: list = [x.get_string_entity().lower() for x in flags]
127
- if len(set(flags_name)) < len(flags_name):
128
- raise RepeatedFlagNameException()
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(command: Command, func: Callable) -> None:
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 registered_args.get_flags() and transferred_args:
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.0a5
4
- Summary: Python library for creating TUI
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<4.0.0,>=3.5.4
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
- ![preview](https://github.com/koloideal/Argenta/blob/kolo/imgs/mock_app_preview3.png?raw=True)
90
+ ![preview](https://github.com/koloideal/Argenta/blob/kolo/imgs/mock_app_preview4.png?raw=True)
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=g_HGYzqfhZ_GqJEclF99vqkPLSRARQXmZNZjFIludE8,17161
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=FLX4z7-mvCTRKO7_2_FfJVUbfNLf_Z-vwyZYDy6cnnY,1030
13
- argenta/command/models.py,sha256=-CTHYhiBYOUz-XmkNPIxC8-Ma0rb7e1uYwLodQlW4D4,6604
14
- argenta/command/flag/__init__.py,sha256=PaZAaqU3DgyO1o5do-xKhWV6TyEuOSaQTmE4VbPY6JA,136
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=OYC4yfym1XPvGdtWtRFKJF48SuwZpVU3dalOIplm-zQ,6403
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=kW_mdL15V9jpRW72Z21sDMvsV3gVO6Bub0hKthYo8ao,7957
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=VjSh5tpU-nGKkf8FUn5H_35DN7ZnwVaoVXOVqkoracE,2526
29
- argenta-1.0.0a5.dist-info/METADATA,sha256=414GSoqTVYYUecTot71XRaCCtED99xura_PENlKYhJw,25723
30
- argenta-1.0.0a5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- argenta-1.0.0a5.dist-info/licenses/LICENSE,sha256=zmqoGh2n5rReBv4s8wPxF_gZEZDgauJYSPMuPczgOiU,1082
32
- argenta-1.0.0a5.dist-info/RECORD,,
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,,