argenta 0.2.1__py3-none-any.whl → 0.3.0a0__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/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from .entity import App
2
- from .exceptions import (HandlerForUnknownCommandsCanOnlyBeDeclaredForMainRouterException,
2
+ from .exceptions import (HandlerForUnknownCommandsOnNonMainRouterException,
3
3
  InvalidDescriptionMessagePatternException,
4
4
  InvalidRouterInstanceException,
5
5
  OnlyOneMainRouterIsAllowedException,
6
6
  MissingMainRouterException,
7
- MissingHandlersForUnknownCommandsOnMainRouterException)
7
+ MissingHandlerForUnknownCommandsException)
argenta/app/entity.py CHANGED
@@ -1,11 +1,14 @@
1
1
  from typing import Callable
2
+ from ..command.entity import Command
3
+ from argenta.command.input_comand.entity import InputCommand
4
+ from argenta.command.input_comand.exceptions import InvalidInputFlagException
2
5
  from ..router.entity import Router
3
6
  from .exceptions import (InvalidRouterInstanceException,
4
7
  InvalidDescriptionMessagePatternException,
5
8
  OnlyOneMainRouterIsAllowedException,
6
9
  MissingMainRouterException,
7
- MissingHandlersForUnknownCommandsOnMainRouterException,
8
- HandlerForUnknownCommandsCanOnlyBeDeclaredForMainRouterException,
10
+ MissingHandlerForUnknownCommandsException,
11
+ HandlerForUnknownCommandsOnNonMainRouterException,
9
12
  NoRegisteredRoutersException,
10
13
  NoRegisteredHandlersException,
11
14
  RepeatedCommandInDifferentRoutersException)
@@ -14,8 +17,9 @@ from .exceptions import (InvalidRouterInstanceException,
14
17
  class App:
15
18
  def __init__(self,
16
19
  prompt: str = 'Enter a command',
17
- initial_greeting: str = '\nHello, I am Argenta\n',
20
+ initial_message: str = '\nHello, I am Argenta\n',
18
21
  farewell_message: str = '\nGoodBye\n',
22
+ invalid_input_flags_message: str = 'Invalid input flags',
19
23
  exit_command: str = 'Q',
20
24
  exit_command_description: str = 'Exit command',
21
25
  exit_command_title: str = 'System points:',
@@ -32,14 +36,15 @@ class App:
32
36
  self.exit_command_title = exit_command_title
33
37
  self.ignore_exit_command_register = ignore_exit_command_register
34
38
  self.farewell_message = farewell_message
35
- self.initial_greeting = initial_greeting
39
+ self.initial_message = initial_message
40
+ self.invalid_input_flags_message = invalid_input_flags_message
36
41
  self.line_separate = line_separate
37
42
  self.command_group_description_separate = command_group_description_separate
38
43
  self.ignore_command_register = ignore_command_register
39
44
  self.repeat_command_groups = repeat_command_groups
40
45
 
41
46
  self._routers: list[Router] = []
42
- self._registered_router_entities: list[dict[str, str | list[dict[str, Callable[[], None] | str]] | Router]] = []
47
+ self._registered_router_entities: list[dict[str, str | list[dict[str, Callable[[], None] | Command]] | Router]] = []
43
48
  self._app_main_router: Router | None = None
44
49
  self._description_message_pattern: str = '[{command}] *=*=* {description}'
45
50
 
@@ -50,36 +55,47 @@ class App:
50
55
  self._validate_main_router()
51
56
  self._validate_all_router_commands()
52
57
 
53
- self.print_func(self.initial_greeting)
58
+ self.print_func(self.initial_message)
54
59
 
55
60
  if not self.repeat_command_groups:
56
61
  self._print_command_group_description()
57
- if self.repeat_command_groups:
58
62
  self.print_func(self.prompt)
59
63
 
60
64
  while True:
61
65
  if self.repeat_command_groups:
62
66
  self._print_command_group_description()
63
- self.print_func(self.prompt)
64
-
65
- command: str = input()
67
+ self.print_func(self.prompt)
68
+
69
+ raw_command: str = input()
70
+ try:
71
+ input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
72
+ except InvalidInputFlagException:
73
+ self.print_func(self.line_separate)
74
+ self.print_func(self.command_group_description_separate)
75
+ if not self.repeat_command_groups:
76
+ self.print_func(self.prompt)
77
+ continue
66
78
 
67
- self._checking_command_for_exit_command(command)
79
+ self._checking_command_for_exit_command(input_command.get_string_entity())
68
80
  self.print_func(self.line_separate)
69
81
 
70
- is_unknown_command: bool = self._check_is_command_unknown(command)
82
+ is_unknown_command: bool = self._check_is_command_unknown(input_command.get_string_entity())
71
83
  if is_unknown_command:
84
+ if not self.repeat_command_groups:
85
+ self.print_func(self.prompt)
72
86
  continue
73
87
 
74
88
  for router in self._routers:
75
- router.input_command_handler(command)
89
+ router.input_command_handler(input_command)
76
90
 
77
91
  self.print_func(self.line_separate)
78
92
  self.print_func(self.command_group_description_separate)
93
+ if not self.repeat_command_groups:
94
+ self.print_func(self.prompt)
79
95
 
80
96
 
81
- def set_initial_greeting(self, greeting: str) -> None:
82
- self.initial_greeting: str = greeting
97
+ def set_initial_message(self, message: str) -> None:
98
+ self.initial_message: str = message
83
99
 
84
100
 
85
101
  def set_farewell_message(self, message: str) -> None:
@@ -107,6 +123,27 @@ class App:
107
123
  return all_commands
108
124
 
109
125
 
126
+ def include_router(self, router: Router, is_main: True | False = False) -> None:
127
+ if not isinstance(router, Router):
128
+ raise InvalidRouterInstanceException()
129
+
130
+ if is_main:
131
+ if not self._app_main_router:
132
+ self._app_main_router = router
133
+ router.set_router_as_main()
134
+ else:
135
+ raise OnlyOneMainRouterIsAllowedException(self._app_main_router.get_name())
136
+
137
+ router.set_ignore_command_register(self.ignore_command_register)
138
+ self._routers.append(router)
139
+
140
+ command_entities: list[dict[str, Callable[[], None] | Command]] = router.get_command_entities()
141
+ self._registered_router_entities.append({'name': router.get_name(),
142
+ 'title': router.get_title(),
143
+ 'entity': router,
144
+ 'commands': command_entities})
145
+
146
+
110
147
  def _validate_number_of_routers(self) -> None:
111
148
  if not self._routers:
112
149
  raise NoRegisteredRoutersException()
@@ -128,11 +165,11 @@ class App:
128
165
  self._app_main_router = router
129
166
 
130
167
  if not self._app_main_router.unknown_command_func:
131
- raise MissingHandlersForUnknownCommandsOnMainRouterException()
168
+ raise MissingHandlerForUnknownCommandsException()
132
169
 
133
170
  for router in self._routers:
134
171
  if router.unknown_command_func and self._app_main_router is not router:
135
- raise HandlerForUnknownCommandsCanOnlyBeDeclaredForMainRouterException()
172
+ raise HandlerForUnknownCommandsOnNonMainRouterException()
136
173
 
137
174
 
138
175
  def _validate_all_router_commands(self) -> None:
@@ -163,14 +200,14 @@ class App:
163
200
 
164
201
 
165
202
  def _check_is_command_unknown(self, command: str):
166
- registered_router_entities: list[dict[str, str | list[dict[str, Callable[[], None] | str]] | Router]] = self._registered_router_entities
203
+ registered_router_entities: list[dict[str, str | list[dict[str, Callable[[], None] | Command]] | Router]] = self._registered_router_entities
167
204
  for router_entity in registered_router_entities:
168
205
  for command_entity in router_entity['commands']:
169
- if command_entity['command'].lower() == command.lower():
206
+ if command_entity['command'].get_string_entity().lower() == command.lower():
170
207
  if self.ignore_command_register:
171
208
  return False
172
209
  else:
173
- if command_entity['command'] == command:
210
+ if command_entity['command'].get_string_entity() == command:
174
211
  return False
175
212
  self._app_main_router.unknown_command_handler(command)
176
213
  self.print_func(self.line_separate)
@@ -183,8 +220,8 @@ class App:
183
220
  self.print_func(router_entity['title'])
184
221
  for command_entity in router_entity['commands']:
185
222
  self.print_func(self._description_message_pattern.format(
186
- command=command_entity['command'],
187
- description=command_entity['description']
223
+ command=command_entity['command'].get_string_entity(),
224
+ description=command_entity['command'].get_description()
188
225
  )
189
226
  )
190
227
  self.print_func(self.command_group_description_separate)
@@ -197,24 +234,3 @@ class App:
197
234
  )
198
235
  self.print_func(self.command_group_description_separate)
199
236
 
200
-
201
- def include_router(self, router: Router, is_main: True | False = False) -> None:
202
- if not isinstance(router, Router):
203
- raise InvalidRouterInstanceException()
204
-
205
- if is_main:
206
- if not self._app_main_router:
207
- self._app_main_router = router
208
- router.set_router_as_main()
209
- else:
210
- raise OnlyOneMainRouterIsAllowedException(self._app_main_router.get_name())
211
-
212
- router.set_ignore_command_register(self.ignore_command_register)
213
- self._routers.append(router)
214
-
215
- command_entities: list[dict[str, Callable[[], None] | str]] = router.get_command_entities()
216
- self._registered_router_entities.append({'name': router.get_name(),
217
- 'title': router.get_title(),
218
- 'entity': router,
219
- 'commands': command_entities})
220
-
argenta/app/exceptions.py CHANGED
@@ -28,13 +28,13 @@ class MissingMainRouterException(Exception):
28
28
  "One of the registered routers must be the main one")
29
29
 
30
30
 
31
- class MissingHandlersForUnknownCommandsOnMainRouterException(Exception):
31
+ class MissingHandlerForUnknownCommandsException(Exception):
32
32
  def __str__(self):
33
33
  return ("Missing Handlers For Unknown Commands On The Main Router\n"
34
34
  "The main router must have a declared handler for unknown commands")
35
35
 
36
36
 
37
- class HandlerForUnknownCommandsCanOnlyBeDeclaredForMainRouterException(Exception):
37
+ class HandlerForUnknownCommandsOnNonMainRouterException(Exception):
38
38
  def __str__(self):
39
39
  return '\nThe handler for unknown commands can only be declared for the main router'
40
40
 
File without changes
@@ -0,0 +1,60 @@
1
+ from .params.flag.entity import Flag
2
+ from .params.flag.flags_group.entity import FlagsGroup
3
+ from .exceptions import (InvalidCommandInstanceException,
4
+ InvalidDescriptionInstanceException,
5
+ InvalidFlagsInstanceException)
6
+ from .params.flag.input_flag.entity import InputFlag
7
+
8
+
9
+ class Command:
10
+ def __init__(self, command: str,
11
+ description: str | None = None,
12
+ flags: Flag | FlagsGroup | None = None):
13
+ self._command = command
14
+ self._description = description
15
+ self._flags: FlagsGroup | None = flags if isinstance(flags, FlagsGroup) else FlagsGroup([flags]) if isinstance(flags, Flag) else flags
16
+
17
+ self._input_flags: InputFlag | FlagsGroup | None = None
18
+
19
+ def get_string_entity(self):
20
+ return self._command
21
+
22
+ def get_description(self):
23
+ if not self._description:
24
+ description = f'description for "{self._command}" command'
25
+ return description
26
+ else:
27
+ return self._description
28
+
29
+ def get_flags(self):
30
+ return self._flags
31
+
32
+ def set_command(self, command: str):
33
+ self._command = command
34
+
35
+ def validate_commands_params(self):
36
+ if not isinstance(self._command, str):
37
+ raise InvalidCommandInstanceException(self._command)
38
+ if not isinstance(self._description, str):
39
+ raise InvalidDescriptionInstanceException()
40
+ if not any([(isinstance(self._flags, Flag), isinstance(self._flags, FlagsGroup)), not self._flags]):
41
+ raise InvalidFlagsInstanceException
42
+
43
+ def validate_input_flag(self, flag: InputFlag):
44
+ registered_flags: FlagsGroup | Flag | None = self._flags
45
+ if registered_flags:
46
+ if isinstance(registered_flags, Flag):
47
+ if registered_flags.get_string_entity() == flag.get_string_entity():
48
+ is_valid = registered_flags.validate_input_flag_value(flag.get_value())
49
+ if is_valid:
50
+ return True
51
+ else:
52
+ for registered_flag in registered_flags:
53
+ if registered_flag.get_string_entity() == flag.get_string_entity():
54
+ is_valid = registered_flag.validate_input_flag_value(flag.get_value())
55
+ if is_valid:
56
+ return True
57
+ return False
58
+
59
+
60
+
@@ -0,0 +1,13 @@
1
+ class InvalidCommandInstanceException(Exception):
2
+ def __str__(self):
3
+ return "Invalid Command Instance"
4
+
5
+
6
+ class InvalidDescriptionInstanceException(Exception):
7
+ def __str__(self):
8
+ return "Invalid Description Instance"
9
+
10
+
11
+ class InvalidFlagsInstanceException(Exception):
12
+ def __str__(self):
13
+ return "Invalid Flags Instance"
File without changes
@@ -0,0 +1,66 @@
1
+ from ..input_comand.exceptions import IncorrectInputFlagException, RepeatedInputFlagsException
2
+ from ..entity import Command
3
+ from ..params.flag.flags_group.entity import FlagsGroup
4
+ from ..params.flag.input_flag.entity import InputFlag
5
+
6
+ from typing import Generic, TypeVar
7
+
8
+
9
+ T = TypeVar('T')
10
+
11
+
12
+ class InputCommand(Command, Generic[T]):
13
+ def set_input_flags(self, input_flags: FlagsGroup):
14
+ self._input_flags = input_flags
15
+
16
+ def get_input_flags(self) -> FlagsGroup:
17
+ return self._input_flags
18
+
19
+ @staticmethod
20
+ def parse(raw_command: str) -> 'InputCommand[T]':
21
+ list_of_tokens = raw_command.split()
22
+ command = list_of_tokens[0]
23
+ list_of_tokens.pop(0)
24
+
25
+ flags: FlagsGroup = FlagsGroup()
26
+ current_flag_name = None
27
+ current_flag_value = None
28
+ for _ in list_of_tokens:
29
+ if _.startswith('-'):
30
+ flag_prefix_last_symbol_index = _.rfind('-')
31
+ if current_flag_name or len(_) < 2 or len(_[:flag_prefix_last_symbol_index]) > 3:
32
+ raise IncorrectInputFlagException()
33
+ else:
34
+ current_flag_name = _
35
+ else:
36
+ if not current_flag_name:
37
+ raise IncorrectInputFlagException()
38
+ else:
39
+ current_flag_value = _
40
+ if current_flag_name and current_flag_value:
41
+ flag_prefix_last_symbol_index = current_flag_name.rfind('-')
42
+ flag_prefix = current_flag_name[:flag_prefix_last_symbol_index]
43
+ flag_name = current_flag_name[flag_prefix_last_symbol_index:]
44
+
45
+ input_flag = InputFlag(flag_name=flag_name,
46
+ flag_prefix=flag_prefix)
47
+ input_flag.set_value(current_flag_value)
48
+
49
+ all_flags = [x.get_string_entity() for x in flags.get_flags()]
50
+ if input_flag.get_string_entity() not in all_flags:
51
+ flags.add_flag(input_flag)
52
+ else:
53
+ raise RepeatedInputFlagsException(input_flag)
54
+
55
+ current_flag_name = None
56
+ current_flag_value = None
57
+ if any([current_flag_name, current_flag_value]):
58
+ raise IncorrectInputFlagException()
59
+ if len(flags.get_flags()) == 0:
60
+ return InputCommand(command=command)
61
+ else:
62
+ input_command = InputCommand(command=command)
63
+ input_command.set_input_flags(flags)
64
+ return input_command
65
+
66
+
@@ -0,0 +1,24 @@
1
+ from ..params.flag.input_flag.entity import InputFlag
2
+
3
+
4
+ class InvalidInputFlagException(Exception):
5
+ def __init__(self, flag: InputFlag):
6
+ self.flag = flag
7
+ def __str__(self):
8
+ return ("Invalid Input Flags\n"
9
+ f"Unknown or invalid input flag: '{self.flag.get_string_entity()} {self.flag.get_value()}'")
10
+
11
+ class IncorrectInputFlagException(Exception):
12
+ def __str__(self):
13
+ return "Incorrect Input Flags"
14
+
15
+
16
+ class RepeatedInputFlagsException(Exception):
17
+ def __init__(self, flag: InputFlag):
18
+ self.flag = flag
19
+ def __str__(self):
20
+ return ("Repeated Input Flags\n"
21
+ f"Duplicate flag was detected in the input: '{self.flag.get_string_entity()}'")
22
+
23
+
24
+
File without changes
File without changes
@@ -0,0 +1,45 @@
1
+ from typing import Literal
2
+
3
+
4
+ class Flag:
5
+ def __init__(self, flag_name: str,
6
+ flag_prefix: Literal['-', '--', '---'] = '-',
7
+ ignore_flag_value_register: bool = False,
8
+ possible_flag_values: list[str] = False):
9
+ self._flag_name = flag_name
10
+ self._flag_prefix = flag_prefix
11
+ self.possible_flag_values = possible_flag_values
12
+ self.ignore_flag_value_register = ignore_flag_value_register
13
+
14
+ self._value = None
15
+
16
+ def get_string_entity(self):
17
+ string_entity: str = self._flag_prefix + self._flag_name
18
+ return string_entity
19
+
20
+ def get_flag_name(self):
21
+ return self._flag_name
22
+
23
+ def get_flag_prefix(self):
24
+ return self._flag_prefix
25
+
26
+ def get_value(self):
27
+ return self._value
28
+
29
+ def set_value(self, value):
30
+ self._value = value
31
+
32
+ def validate_input_flag_value(self, input_flag_value: str):
33
+ if self.possible_flag_values:
34
+ if self.ignore_flag_value_register:
35
+ if input_flag_value.lower() in [x.lower() for x in self.possible_flag_values]:
36
+ return True
37
+ else:
38
+ return False
39
+ else:
40
+ if input_flag_value in self.possible_flag_values:
41
+ return True
42
+ else:
43
+ return False
44
+ else:
45
+ return True
File without changes
@@ -0,0 +1,22 @@
1
+ from argenta.command.params.flag.entity import Flag
2
+ from argenta.command.params.flag.input_flag.entity import InputFlag
3
+
4
+
5
+ class FlagsGroup:
6
+ def __init__(self, flags: list[Flag | InputFlag] = None):
7
+ self._flags: list[Flag | InputFlag] = [] if not flags else flags
8
+
9
+ def get_flags(self):
10
+ return self._flags
11
+
12
+ def add_flag(self, flag: Flag | InputFlag):
13
+ self._flags.append(flag)
14
+
15
+ def add_flags(self, flags: list[Flag | InputFlag]):
16
+ self._flags.extend(flags)
17
+
18
+ def __iter__(self):
19
+ return iter(self._flags)
20
+
21
+ def __next__(self):
22
+ return next(iter(self))
File without changes
@@ -0,0 +1,11 @@
1
+ from ...flag.entity import Flag
2
+
3
+
4
+ class InputFlag(Flag):
5
+ def set_value(self, value: str):
6
+ self._value = value
7
+
8
+ def get_value(self) -> str:
9
+ return self._value
10
+
11
+
@@ -1,4 +1,3 @@
1
1
  from .entity import Router
2
2
  from .exceptions import (UnknownCommandHandlerHasAlreadyBeenCreatedException,
3
- InvalidDescriptionInstanceException,
4
- InvalidCommandInstanceException)
3
+ InvalidDescriptionInstanceException)
argenta/router/entity.py CHANGED
@@ -1,8 +1,10 @@
1
1
  from typing import Callable, Any
2
- from ..router.exceptions import (InvalidCommandInstanceException,
3
- UnknownCommandHandlerHasAlreadyBeenCreatedException,
4
- InvalidDescriptionInstanceException,
5
- RepeatedCommandException)
2
+ from ..command.entity import Command
3
+ from ..command.input_comand.entity import InputCommand
4
+ from ..command.input_comand.exceptions import InvalidInputFlagException
5
+ from ..command.params.flag.flags_group.entity import FlagsGroup
6
+ from ..router.exceptions import (UnknownCommandHandlerHasAlreadyBeenCreatedException,
7
+ RepeatedCommandException, RepeatedFlagNameException)
6
8
 
7
9
 
8
10
  class Router:
@@ -13,20 +15,19 @@ class Router:
13
15
  self.title = title
14
16
  self.name = name
15
17
 
16
- self._command_entities: list[dict[str, Callable[[], None] | str]] = []
18
+ self._command_entities: list[dict[str, Callable[[], None] | Command]] = []
17
19
  self.unknown_command_func: Callable[[str], None] | None = None
18
20
  self._is_main_router: bool = False
19
21
  self.ignore_command_register: bool = False
20
22
 
21
23
 
22
- def command(self, command: str, description: str = None) -> Callable[[Any], Any]:
23
- processed_description = Router._validate_description(command, description)
24
+ def command(self, command: Command) -> Callable[[Any], Any]:
25
+ command.validate_commands_params()
24
26
  self._validate_command(command)
25
27
 
26
28
  def command_decorator(func):
27
29
  self._command_entities.append({'handler_func': func,
28
- 'command': command,
29
- 'description': processed_description})
30
+ 'command': command})
30
31
  def wrapper(*args, **kwargs):
31
32
  return func(*args, **kwargs)
32
33
  return wrapper
@@ -45,38 +46,48 @@ class Router:
45
46
  return wrapper
46
47
 
47
48
 
48
- def input_command_handler(self, input_command):
49
+ def input_command_handler(self, input_command: InputCommand):
50
+ input_command_name: str = input_command.get_string_entity()
49
51
  for command_entity in self._command_entities:
50
- if input_command.lower() == command_entity['command'].lower():
52
+ if input_command_name.lower() == command_entity['command'].get_string_entity().lower():
51
53
  if self.ignore_command_register:
52
- return command_entity['handler_func']()
53
- else:
54
- if input_command == command_entity['command']:
54
+ if input_command.get_input_flags():
55
+ for flag in input_command.get_input_flags():
56
+ is_valid = command_entity['command'].validate_input_flag(flag)
57
+ if not is_valid:
58
+ raise InvalidInputFlagException(flag)
59
+ return command_entity['handler_func'](input_command.get_input_flags())
60
+ else:
55
61
  return command_entity['handler_func']()
62
+ else:
63
+ if input_command_name == command_entity['command'].get_string_entity():
64
+ if input_command.get_input_flags():
65
+ for flag in input_command.get_input_flags():
66
+ is_valid = command_entity['command'].validate_input_flag(flag)
67
+ if not is_valid:
68
+ raise InvalidInputFlagException(flag)
69
+ return command_entity['handler_func'](input_command.get_input_flags())
70
+ else:
71
+ return command_entity['handler_func']()
56
72
 
57
73
 
58
74
  def unknown_command_handler(self, unknown_command):
59
75
  self.unknown_command_func(unknown_command)
60
76
 
61
77
 
62
- def _validate_command(self, command: str):
63
- if not isinstance(command, str):
64
- raise InvalidCommandInstanceException()
78
+ def _validate_command(self, command: Command):
79
+ command_name: str = command.get_string_entity()
65
80
  if command in self.get_all_commands():
66
81
  raise RepeatedCommandException()
67
82
  if self.ignore_command_register:
68
- if command.lower() in [x.lower() for x in self.get_all_commands()]:
83
+ if command_name.lower() in [x.lower() for x in self.get_all_commands()]:
69
84
  raise RepeatedCommandException()
70
85
 
71
-
72
- @staticmethod
73
- def _validate_description(command: str, description: str):
74
- if not isinstance(description, str):
75
- if description is None:
76
- description = f'description for "{command}" command'
77
- else:
78
- raise InvalidDescriptionInstanceException()
79
- return description
86
+ flags: FlagsGroup = command.get_flags()
87
+ if flags:
88
+ flags_name: list = [x.get_string_entity().lower() for x in flags]
89
+ if len(set(flags_name)) < len(flags_name):
90
+ raise RepeatedFlagNameException()
80
91
 
81
92
 
82
93
  def set_router_as_main(self):
@@ -89,7 +100,7 @@ class Router:
89
100
  self.ignore_command_register = ignore_command_register
90
101
 
91
102
 
92
- def get_command_entities(self) -> list[dict[str, Callable[[], None] | str]]:
103
+ def get_command_entities(self) -> list[dict[str, Callable[[], None] | Command]]:
93
104
  return self._command_entities
94
105
 
95
106
 
@@ -118,6 +129,13 @@ class Router:
118
129
  def get_all_commands(self) -> list[str]:
119
130
  all_commands: list[str] = []
120
131
  for command_entity in self._command_entities:
121
- all_commands.append(command_entity['command'])
132
+ all_commands.append(command_entity['command'].get_string_entity())
122
133
 
123
134
  return all_commands
135
+
136
+ def get_all_flags(self) -> list[FlagsGroup]:
137
+ all_flags: list[FlagsGroup] = []
138
+ for command_entity in self._command_entities:
139
+ all_flags.append(command_entity['command'].get_flags())
140
+
141
+ return all_flags
@@ -1,8 +1,3 @@
1
- class InvalidCommandInstanceException(Exception):
2
- def __str__(self):
3
- return "Invalid Command Instance"
4
-
5
-
6
1
  class InvalidDescriptionInstanceException(Exception):
7
2
  def __str__(self):
8
3
  return "Invalid Description Instance"
@@ -16,3 +11,8 @@ class UnknownCommandHandlerHasAlreadyBeenCreatedException(Exception):
16
11
  class RepeatedCommandException(Exception):
17
12
  def __str__(self):
18
13
  return "Commands in handler cannot be repeated"
14
+
15
+
16
+ class RepeatedFlagNameException(Exception):
17
+ def __str__(self):
18
+ return "Repeated flag name in register command"
@@ -0,0 +1,289 @@
1
+ Metadata-Version: 2.3
2
+ Name: argenta
3
+ Version: 0.3.0a0
4
+ Summary: python library for creating custom shells
5
+ License: MIT
6
+ Author: kolo
7
+ Author-email: kolo.is.main@gmail.com
8
+ Requires-Python: >=3.11
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Argenta
17
+
18
+ ---
19
+
20
+ ## Описание
21
+ **Argenta** — это библиотека для создания CLI-приложений на Python. Она предоставляет удобные инструменты для маршрутизации команд и обработки пользовательского ввода.
22
+
23
+ ---
24
+
25
+ # Установка
26
+ ```bash
27
+ pip install argenta
28
+ ```
29
+ or
30
+ ```bash
31
+ poetry add argenta
32
+ ```
33
+
34
+ ---
35
+
36
+ # Быстрый старт
37
+ Пример базового CLI-приложения с Argenta:
38
+ ```python
39
+ #routers.py
40
+ from argenta.router import Router
41
+
42
+ router = Router()
43
+
44
+ @router.command("hello")
45
+ def hello():
46
+ print("Hello, world!")
47
+
48
+ @router.unknown_command
49
+ def unlnown_command(command):
50
+ print(f'Command "{command}" undefined')
51
+ ```
52
+ ```python
53
+ #main.py
54
+ from argenta.app import App
55
+ from routers import router
56
+
57
+ app: App = App()
58
+
59
+ def main() -> None:
60
+ app.include_router(router)
61
+ app.start_polling()
62
+
63
+
64
+ if __name__ == '__main__':
65
+ main()
66
+ ```
67
+
68
+ ---
69
+
70
+ # Техническая документация
71
+
72
+ ---
73
+
74
+ ## declared *classes* :
75
+
76
+ ---
77
+
78
+ ### *class* :: `App`
79
+ Класс, определяющий поведение и состояние приложения
80
+
81
+ #### Конструктор
82
+ ```python
83
+ App(prompt: str = 'Enter a command',
84
+ initial_greeting: str = '\nHello, I am Argenta\n',
85
+ farewell_message: str = '\nGoodBye\n',
86
+ exit_command: str = 'Q',
87
+ exit_command_description: str = 'Exit command',
88
+ exit_command_title: str = 'System points:',
89
+ ignore_exit_command_register: bool = True,
90
+ ignore_command_register: bool = False,
91
+ line_separate: str = '',
92
+ command_group_description_separate: str = '',
93
+ repeat_command_groups: bool = True,
94
+ print_func: Callable[[str], None] = print)
95
+ ```
96
+ **Аргументы:**
97
+ - **name : mean**
98
+ - `prompt` (`str`): Сообщение перед вводом команды.
99
+ - `initial_greeting` (`str`): Приветственное сообщение при запуске.
100
+ - `farewell_message` (`str`): Сообщение при выходе.
101
+ - `exit_command` (`str`): Команда выхода (по умолчанию `'Q'`).
102
+ - `exit_command_description` (`str`): Описание команды выхода.
103
+ - `exit_command_title` (`str`): Заголовок перед списком команд выхода.
104
+ - `ignore_exit_command_register` (`bool`): Игнорировать регистр команды выхода.
105
+ - `ignore_command_register` (`bool`): Игнорировать регистр всех команд.
106
+ - `line_separate` (`str`): Разделительная строка между командами.
107
+ - `command_group_description_separate` (`str`): Разделитель между группами команд.
108
+ - `repeat_command_groups` (`bool`): Повторять описание команд перед вводом.
109
+ - `print_func` (`Callable[[str], None]`): Функция вывода текста в терминал (по умолчанию `print`).
110
+
111
+ ---
112
+
113
+ #### **declared *methods***
114
+
115
+ ---
116
+
117
+ **App().**`start_polling() -> None`
118
+
119
+ *method mean* **::** запускает жизненный цикл приложения
120
+
121
+ ---
122
+
123
+ **App().**`include_router(router: Router, is_main: bool = False) -> None`
124
+
125
+ *param* `router: Router` **::** регистрируемый роутер
126
+
127
+ *param* `is_main: bool` **::** будет ли являться регистрируемый роутер главным
128
+ *example* **::** `True` или `False`
129
+
130
+ *method mean* **::** регистрирует роутер в приложении
131
+
132
+ ---
133
+
134
+ **App().**`set_initial_message(message: str) -> None`
135
+
136
+ *param* `message: str` **::** устанавливаемое приветственное сообщение
137
+ *example* **::** `"Hello, I'm a cli example app"`
138
+
139
+ *method mean* **::** устанавливает сообщение, которое будет отображено при запуске программы
140
+
141
+ ---
142
+
143
+ **App().**`set_farewell_message(message: str) -> None`
144
+
145
+ *param* `message: str` **::** устанавливаемое сообщение при выходе
146
+ *example* **::** `"GoodBye !"`
147
+
148
+ *method mean* **::** устанавливает сообщение, которое будет отображено при выходе
149
+
150
+ ---
151
+
152
+ **App().**`set_description_message_pattern(pattern: str) -> None`
153
+
154
+ *param* `pattern: str` **::** паттерн описания команды при её выводе в консоль
155
+ *example* **::** `"[{command}] *=*=* {description}"`
156
+
157
+ *method mean* **::** устанавливает приветственное сообщение
158
+
159
+ ---
160
+
161
+ **App().**`get_main_router() -> Router`
162
+
163
+ *method mean* **::** возвращает `Router()`, который является главным в приложении
164
+
165
+ ---
166
+
167
+ **App().**`get_all_app_commands() -> list[str]`
168
+
169
+ *method mean* **::** возвращает список команд всех зарегистрированных роутеров, сохраняя их регистр
170
+
171
+ ---
172
+
173
+ #### Примечания
174
+
175
+ - Среди зарегистрированных в приложении роутеров должен быть один главный, является ли роутер главным
176
+ определяется значением аргумента `is_main` равным `True`, в методе `App().include_router()`, который по умолчанию равен
177
+ `False`, если в приложении зарегистрирован лишь один роутер, то он неявно устанавливается главным, если
178
+ зарегистрировано больше одного роутера, то требуется явное указание главного. При регистрации более одного
179
+ главного роутера вызывается исключение `OnlyOneMainRouterIsAllowedException`. При регистрации более одного
180
+ роутера и отсутствии указания главного вызывается исключение `MissingMainRouterException`
181
+
182
+ - В устанавливаемом паттерне сообщения описания команды необходимы быть два ключевых слова:
183
+ `command` и `description`, каждое из которых должно быть заключено в фигурные скобки, после обработки
184
+ паттерна на места этих ключевых слов будут подставлены соответствующие значения команды, при отсутствии
185
+ этих двух ключевых слов будет вызвано исключение `InvalidDescriptionMessagePatternException`
186
+
187
+ - Команды приложения не должны повторяться, при значении атрибута `ignore_command_register` равным `True`
188
+ допускается создание обработчиков для разных регистров одинаковых символов в команде, для примера `u` и `U`,
189
+ при значении атрибута `ignore_command_register` класса `App` равным `False` тот же пример вызывает исключение
190
+ `RepeatedCommandInDifferentRoutersException`. Исключение вызывается только при наличии пересекающихся команд
191
+ у __<u>разных</u>__ роутеров
192
+
193
+ - У главного обработчика должен быть зарегистрирован обработчик неизвестных команд:
194
+ ```python
195
+ router = Router()
196
+
197
+ @router.unknown_command
198
+ def unknown_command(command):
199
+ print(f'Command "{command}" undefined')
200
+ ```
201
+ При отсутствии обработчика неизвестных команд у главного роутера будет вызвано исключение
202
+ `MissingHandlerForUnknownCommandsException`. При регистрации обработчика неизвестных команд у
203
+ __<u>не</u>__ главного роутера будет вызвано исключение `HandlerForUnknownCommandsOnNonMainRouterException`
204
+
205
+
206
+
207
+
208
+ #### Исключения
209
+
210
+ - `InvalidRouterInstanceException` — Переданный объект в метод `App().include_router()` не является экземпляром класса `Router`.
211
+ - `InvalidDescriptionMessagePatternException` — Неправильный формат паттерна описания команд.
212
+ - `OnlyOneMainRouterIsAllowedException` — Регистрация более одного главного роутера.
213
+ - `MissingMainRouterException` — Отсутствует главный роутер.
214
+ - `MissingHandlerForUnknownCommandsException` — В основном роутере отсутствует обработчик неизвестных команд.
215
+ - `HandlerForUnknownCommandsOnNonMainRouterException` — Обработчик неизвестных команд определён не у основного роутера.
216
+ - `NoRegisteredRoutersException` — Отсутствуют зарегистрированные роутеры.
217
+ - `NoRegisteredHandlersException` — У роутера нет ни одного обработчика команд.
218
+ - `RepeatedCommandInDifferentRoutersException` — Одна и та же команда зарегистрирована в разных роутерах.
219
+
220
+ ---
221
+
222
+ ### *class* :: `Router`
223
+ Класс, который определяет и конфигурирует обработчики команд
224
+
225
+ #### Конструктор
226
+ ```python
227
+ Router(title: str = 'Commands group title:',
228
+ name: str = 'subordinate')
229
+ ```
230
+
231
+ **Аргументы:**
232
+ - **name : mean**
233
+ - `title` (`str`): Заголовок группы команд.
234
+ - `name` (`str`): Персональное название роутера
235
+
236
+
237
+
238
+ #### **declared *methods***
239
+
240
+ ---
241
+
242
+ **`@`Router().**`command(command: str, description: str = None)`
243
+
244
+ *param* `command: str` **::** строковый триггер, который будет выполнять указанные действия
245
+ *example* **::** `U` / `update` / `ExaMPLE`
246
+
247
+ *param* `description: str` **::** описание команды, которое будет выведено в консоль
248
+ *example* **::** `description for update command` или `example description`
249
+
250
+ *method mean* **::** декоратор регистрирует функцию как обработчик команды
251
+
252
+ ---
253
+
254
+ **`@`Router().**`unknown_command`
255
+
256
+ *method mean* **::** декоратор регистрирует функцию как обработчик неизвестных команд
257
+
258
+ ---
259
+
260
+ **Router().**`get_name() -> str`
261
+
262
+ *method mean* **::** возвращает установленное название роутера
263
+
264
+ ---
265
+
266
+ **Router().**`get_title() -> str`
267
+
268
+ *method mean* **::** возвращает установленный заголовок группы команд данного роутера
269
+
270
+ ---
271
+
272
+ **Router().**`get_router_info() -> dict`
273
+
274
+ *method mean* **::** возвращает информацию о роутере
275
+
276
+ ---
277
+
278
+ **Router().**`get_all_commands() -> list[str]`
279
+
280
+ *method mean* **::** возвращает все зарегистрированные команды для данного роутера
281
+
282
+ ---
283
+
284
+ #### Исключения
285
+ - `InvalidCommandInstanceException` - Переданный объект для регистрации команды не является строкой
286
+ - `InvalidDescriptionInstanceException` - Переданный объект для регистрации описания команды не является строкой
287
+ - `UnknownCommandHandlerHasAlreadyBeenCreatedException` - Обработчик неизвестных команд уже создан
288
+ - `RepeatedCommandException` - Одна и та же команда зарегистрирована в одном роутере
289
+
@@ -0,0 +1,27 @@
1
+ argenta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ argenta/app/__init__.py,sha256=jXP3ishSp3fF7fePZOtd_LAbBfn_RuNwnGidpk9H-74,415
3
+ argenta/app/entity.py,sha256=2DiDC4OVh5AzH1oGIyRGbPUq1A_WyrWHNSWkfUMzk1U,10456
4
+ argenta/app/exceptions.py,sha256=8p8_ucklfmHlUPaiMS7D_026laep-fr4bTXdRRJtB_k,2030
5
+ argenta/command/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ argenta/command/entity.py,sha256=9FkU_NbI1WsXrnKA1Ba86xwYoRwLLdk81yI9dj7RsF8,2451
7
+ argenta/command/exceptions.py,sha256=qTt3G0XaWW5BBQyxNkVWFY0SMGn92VuxvSRs0G37lHI,366
8
+ argenta/command/input_comand/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ argenta/command/input_comand/__pycache__/__init__.cpython-313.pyc,sha256=oXTcVktQx5e5Dsmm7PCcNJ9LlYtsEkjAVvY0iH8iTJU,176
10
+ argenta/command/input_comand/__pycache__/entity.cpython-313.pyc,sha256=T0w7m9juwsZ33u_EiEzzNq0TtGvYtfVtR033QfIaLj4,3073
11
+ argenta/command/input_comand/__pycache__/exceptions.cpython-313.pyc,sha256=xbS7jUHBF6fmFfqv3YYMDP1PNCWxzcM9LsZR3JM3daw,2082
12
+ argenta/command/input_comand/entity.py,sha256=YyJPMV8Hy1QSgvgu_w9cjWdiQ2JXG21EbCabns4w_ek,2585
13
+ argenta/command/input_comand/exceptions.py,sha256=rVFOMkF-8ItwAs_JXofAZG3aTQvdn11SwJ3d39hH-4k,748
14
+ argenta/command/params/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ argenta/command/params/flag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ argenta/command/params/flag/entity.py,sha256=gUax6hkuSuarH8yQwFC4QsGql8n1POi19Ww4yEh2c2k,1446
17
+ argenta/command/params/flag/flags_group/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ argenta/command/params/flag/flags_group/entity.py,sha256=aFbo5mzevuDxVb8VpaRCUSgUCLn6GK-ODCz5N5650Q8,638
19
+ argenta/command/params/flag/input_flag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ argenta/command/params/flag/input_flag/entity.py,sha256=KHoZRE7pRc30LyS6yF_7G7IrA8DrH-gS-Hg_qNstkzU,195
21
+ argenta/router/__init__.py,sha256=RvVORE4g0uIWWuQHav0KK-I7AlCuXW4HeW-8MW7fOyo,168
22
+ argenta/router/entity.py,sha256=oBj76pJNPce6YQo67BWhnVLFBOcCyqkD_cse7jE1KPg,5484
23
+ argenta/router/exceptions.py,sha256=np8hclunhbyt9E2oZym3g9-5a6UpEj9s_52OR6QA56s,551
24
+ argenta-0.3.0a0.dist-info/LICENSE,sha256=zmqoGh2n5rReBv4s8wPxF_gZEZDgauJYSPMuPczgOiU,1082
25
+ argenta-0.3.0a0.dist-info/METADATA,sha256=xxEFo-BqP-uPywceXQOcGIczd6pfc8qIgfbAK7jPBX4,12640
26
+ argenta-0.3.0a0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
27
+ argenta-0.3.0a0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: argenta
3
- Version: 0.2.1
4
- Summary: python library for creating cli apps
5
- License: MIT
6
- Author: kolo
7
- Author-email: kolo.is.main@gmail.com
8
- Requires-Python: >=3.11
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Programming Language :: Python :: 3.13
14
- Description-Content-Type: text/markdown
15
-
16
- # Argenta
17
- Python library for creating cli apps
18
-
@@ -1,11 +0,0 @@
1
- argenta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- argenta/app/__init__.py,sha256=WGPNy7LzkE6vjgRIITFYuJIB96vgDMFPRLOh4SV3R3E,443
3
- argenta/app/entity.py,sha256=6EufZeJBctdsID5lExFvxUKw-lf8Nd8N0vW3dqRQucU,9474
4
- argenta/app/exceptions.py,sha256=krz4CEeh7GorhV9rrv3mUmjYPYK16oYN6I-LJ1-Bz4k,2058
5
- argenta/router/__init__.py,sha256=gjneUFVbKVgwil8TbHRvCN89wT_U9CaakSbFmMC_fxk,227
6
- argenta/router/entity.py,sha256=1cI8I2ps6ZaiDZJ8Vt2PDAsVjaWPPdSVHfZk11KAPdY,4266
7
- argenta/router/exceptions.py,sha256=fgJEsMfdN6sjbfie8Ea9jbopF7HKQi-6vKCCRQrVlTA,543
8
- argenta-0.2.1.dist-info/LICENSE,sha256=zmqoGh2n5rReBv4s8wPxF_gZEZDgauJYSPMuPczgOiU,1082
9
- argenta-0.2.1.dist-info/METADATA,sha256=ShrLAkL-AeIygQ4qCqmPgb1FBYSzhx7u-U0elRNExRQ,525
10
- argenta-0.2.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
11
- argenta-0.2.1.dist-info/RECORD,,