argenta 0.5.0b0__py3-none-any.whl → 1.0.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.
@@ -3,13 +3,25 @@ import readline
3
3
 
4
4
 
5
5
  class AutoCompleter:
6
- def __init__(self, history_filename: str = False, autocomplete_button: str = 'tab'):
6
+ def __init__(self, history_filename: str = False, autocomplete_button: str = 'tab') -> None:
7
+ """
8
+ Public. Configures and implements auto-completion of input command
9
+ :param history_filename: the name of the file for saving the history of the autocompleter
10
+ :param autocomplete_button: the button for auto-completion
11
+ :return: None
12
+ """
7
13
  self.history_filename = history_filename
8
14
  self.autocomplete_button = autocomplete_button
9
- self.matches = []
15
+ self.matches: list[str] = []
10
16
 
11
- def complete(self, text, state):
12
- matches = sorted(cmd for cmd in self.get_history_items() if cmd.startswith(text))
17
+ def complete(self, text, state) -> str | None:
18
+ """
19
+ Private. Auto-completion function
20
+ :param text: part of the command being entered
21
+ :param state: the current cursor position is relative to the beginning of the line
22
+ :return: the desired candidate as str or None
23
+ """
24
+ matches: list[str] = sorted(cmd for cmd in self.get_history_items() if cmd.startswith(text))
13
25
  if len(matches) > 1:
14
26
  common_prefix = matches[0]
15
27
  for match in matches[1:]:
@@ -26,7 +38,12 @@ class AutoCompleter:
26
38
  else:
27
39
  return None
28
40
 
29
- def initial_setup(self, all_commands: list[str]):
41
+ def initial_setup(self, all_commands: list[str]) -> None:
42
+ """
43
+ Private. Initial setup function
44
+ :param all_commands: Registered commands for adding them to the autocomplete history
45
+ :return: None
46
+ """
30
47
  if self.history_filename:
31
48
  if os.path.exists(self.history_filename):
32
49
  readline.read_history_file(self.history_filename)
@@ -38,10 +55,18 @@ class AutoCompleter:
38
55
  readline.set_completer_delims(readline.get_completer_delims().replace(' ', ''))
39
56
  readline.parse_and_bind(f'{self.autocomplete_button}: complete')
40
57
 
41
- def exit_setup(self):
58
+ def exit_setup(self) -> None:
59
+ """
60
+ Private. Exit setup function
61
+ :return: None
62
+ """
42
63
  if self.history_filename:
43
64
  readline.write_history_file(self.history_filename)
44
65
 
45
66
  @staticmethod
46
- def get_history_items():
67
+ def get_history_items() -> list[str] | list:
68
+ """
69
+ Private. Returns a list of all commands entered by the user
70
+ :return: all commands entered by the user as list[str]
71
+ """
47
72
  return [readline.get_history_item(i) for i in range(1, readline.get_current_history_length() + 1)]
argenta/app/defaults.py CHANGED
@@ -2,7 +2,10 @@ from dataclasses import dataclass
2
2
 
3
3
 
4
4
  @dataclass
5
- class PredeterminedMessages:
5
+ class PredefinedMessages:
6
+ """
7
+ Public. A dataclass with predetermined messages for quick use
8
+ """
6
9
  USAGE = '[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]'
7
10
  HELP = '[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]'
8
11
  AUTOCOMPLETE = '[b dim]Autocomplete[/b dim]: [i]<part>[/i] [bold]<tab>'
@@ -1,24 +1,68 @@
1
- class BaseDividingLine:
2
- def __init__(self, unit_part: str = '-'):
3
- self.unit_part = unit_part
1
+ from abc import ABC
4
2
 
5
- def get_unit_part(self):
6
- if len(self.unit_part) == 0:
3
+
4
+ class BaseDividingLine(ABC):
5
+ def __init__(self, unit_part: str = '-') -> None:
6
+ """
7
+ Private. The basic dividing line
8
+ :param unit_part: the single part of the dividing line
9
+ :return: None
10
+ """
11
+ self._unit_part = unit_part
12
+
13
+ def get_unit_part(self) -> str:
14
+ """
15
+ Private. Returns the unit part of the dividing line
16
+ :return: unit_part of dividing line as str
17
+ """
18
+ if len(self._unit_part) == 0:
7
19
  return ' '
8
20
  else:
9
- return self.unit_part[0]
21
+ return self._unit_part[0]
22
+
10
23
 
11
24
  class StaticDividingLine(BaseDividingLine):
12
- def __init__(self, unit_part: str = '-', length: int = 25):
25
+ def __init__(self, unit_part: str = '-', length: int = 25) -> None:
26
+ """
27
+ Public. The static dividing line
28
+ :param unit_part: the single part of the dividing line
29
+ :param length: the length of the dividing line
30
+ :return: None
31
+ """
13
32
  super().__init__(unit_part)
14
33
  self.length = length
15
34
 
16
- def get_full_line(self):
17
- return f'\n[dim]{self.length * self.get_unit_part()}[/dim]\n'
35
+ def get_full_static_line(self, is_override: bool) -> str:
36
+ """
37
+ Private. Returns the full line of the dividing line
38
+ :param is_override: has the default text layout been redefined
39
+ :return: full line of dividing line as str
40
+ """
41
+ if is_override:
42
+ return f'\n{self.length * self.get_unit_part()}\n'
43
+ else:
44
+ return f'\n[dim]{self.length * self.get_unit_part()}[/dim]\n'
18
45
 
19
46
 
20
47
  class DynamicDividingLine(BaseDividingLine):
21
- def get_full_line(self, length: int):
22
- return f'\n[dim]{self.get_unit_part() * length}[/dim]\n'
48
+ def __init__(self, unit_part: str = '-') -> None:
49
+ """
50
+ Public. The dynamic dividing line
51
+ :param unit_part: the single part of the dividing line
52
+ :return: None
53
+ """
54
+ super().__init__(unit_part)
55
+
56
+ def get_full_dynamic_line(self, length: int, is_override: bool) -> str:
57
+ """
58
+ Private. Returns the full line of the dividing line
59
+ :param length: the length of the dividing line
60
+ :param is_override: has the default text layout been redefined
61
+ :return: full line of dividing line as str
62
+ """
63
+ if is_override:
64
+ return f'\n{length * self.get_unit_part()}\n'
65
+ else:
66
+ return f'\n[dim]{self.get_unit_part() * length}[/dim]\n'
23
67
 
24
68
 
argenta/app/exceptions.py CHANGED
@@ -1,15 +1,8 @@
1
- class InvalidRouterInstanceException(Exception):
2
- def __str__(self):
3
- return "Invalid Router Instance"
4
-
5
-
6
- class NoRegisteredRoutersException(Exception):
7
- def __str__(self):
8
- return "No Registered Router Found"
9
-
10
-
11
1
  class NoRegisteredHandlersException(Exception):
12
- def __init__(self, router_name):
2
+ """
3
+ The router has no registered handlers
4
+ """
5
+ def __init__(self, router_name) -> None:
13
6
  self.router_name = router_name
14
7
  def __str__(self):
15
8
  return f"No Registered Handlers Found For '{self.router_name}'"
argenta/app/models.py CHANGED
@@ -15,30 +15,29 @@ from argenta.command.exceptions import (UnprocessedInputFlagException,
15
15
  RepeatedInputFlagsException,
16
16
  EmptyInputCommandException,
17
17
  BaseInputCommandException)
18
- from argenta.app.exceptions import (InvalidRouterInstanceException,
19
- NoRegisteredRoutersException,
20
- NoRegisteredHandlersException)
18
+ from argenta.app.exceptions import NoRegisteredHandlersException
21
19
  from argenta.app.registered_routers.entity import RegisteredRouters
22
20
 
23
21
 
24
22
 
25
- class AppInit:
23
+ class BaseApp:
26
24
  def __init__(self,
27
- prompt: str = '[italic dim bold]What do you want to do?\n',
28
- initial_message: str = '\nArgenta\n',
29
- farewell_message: str = '\nSee you\n',
30
- exit_command: Command = Command('Q', 'Exit command'),
31
- system_points_title: str | None = 'System points:',
32
- ignore_command_register: bool = True,
33
- dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(),
34
- repeat_command_groups: bool = True,
35
- override_system_messages: bool = False,
36
- autocompleter: AutoCompleter = AutoCompleter(),
37
- print_func: Callable[[str], None] = Console().print) -> None:
25
+ prompt: str,
26
+ initial_message: str,
27
+ farewell_message: str,
28
+ exit_command: Command,
29
+ system_router_title: str | None,
30
+ ignore_command_register: bool,
31
+ dividing_line: StaticDividingLine | DynamicDividingLine,
32
+ repeat_command_groups: bool,
33
+ override_system_messages: bool,
34
+ autocompleter: AutoCompleter,
35
+ print_func: Callable[[str], None]) -> None:
36
+
38
37
  self._prompt = prompt
39
38
  self._print_func = print_func
40
39
  self._exit_command = exit_command
41
- self._system_points_title = system_points_title
40
+ self._system_router_title = system_router_title
42
41
  self._dividing_line = dividing_line
43
42
  self._ignore_command_register = ignore_command_register
44
43
  self._repeat_command_groups_description = repeat_command_groups
@@ -49,44 +48,79 @@ class AppInit:
49
48
  self._initial_message = initial_message
50
49
 
51
50
 
52
- self._description_message_gen: Callable[[str, str], str] = lambda command, description: f'[bold red]{escape('['+command+']')}[/bold red] [blue dim]*=*=*[/blue dim] [bold yellow italic]{escape(description)}'
51
+ self._description_message_gen: Callable[[str, str], str] = lambda command, description: f'[{command}] *=*=* {description}'
53
52
  self._registered_routers: RegisteredRouters = RegisteredRouters()
54
- self._messages_on_startup = []
53
+ self._messages_on_startup: list[str] = []
54
+
55
+ self._all_registered_triggers_in_lower: list[str] = []
56
+ self._all_registered_triggers_in_default_case: list[str] = []
55
57
 
56
- self._invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}')
57
- self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Repeated input flags: {escape(raw_command)}')
58
- self._empty_input_command_handler: Callable[[], None] = lambda: print_func('[red bold]Empty input command')
59
- self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"[red bold]Unknown command: {escape(command.get_trigger())}")
58
+ self._invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Incorrect flag syntax: {raw_command}')
59
+ self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Repeated input flags: {raw_command}')
60
+ self._empty_input_command_handler: Callable[[], None] = lambda: print_func('Empty input command')
61
+ self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"Unknown command: {command.get_trigger()}")
60
62
  self._exit_command_handler: Callable[[], None] = lambda: print_func(self._farewell_message)
61
63
 
62
64
 
63
- class AppSetters(AppInit):
64
65
  def set_description_message_pattern(self, pattern: Callable[[str, str], str]) -> None:
66
+ """
67
+ Public. Sets the output pattern of the available commands
68
+ :param pattern: output pattern of the available commands
69
+ :return: None
70
+ """
65
71
  self._description_message_gen: Callable[[str, str], str] = pattern
66
72
 
67
73
 
68
74
  def set_invalid_input_flags_handler(self, handler: Callable[[str], None]) -> None:
75
+ """
76
+ Public. Sets the handler for incorrect flags when entering a command
77
+ :param handler: handler for incorrect flags when entering a command
78
+ :return: None
79
+ """
69
80
  self._invalid_input_flags_handler = handler
70
81
 
71
82
 
72
83
  def set_repeated_input_flags_handler(self, handler: Callable[[str], None]) -> None:
84
+ """
85
+ Public. Sets the handler for repeated flags when entering a command
86
+ :param handler: handler for repeated flags when entering a command
87
+ :return: None
88
+ """
73
89
  self._repeated_input_flags_handler = handler
74
90
 
75
91
 
76
92
  def set_unknown_command_handler(self, handler: Callable[[str], None]) -> None:
93
+ """
94
+ Public. Sets the handler for unknown commands when entering a command
95
+ :param handler: handler for unknown commands when entering a command
96
+ :return: None
97
+ """
77
98
  self._unknown_command_handler = handler
78
99
 
79
100
 
80
101
  def set_empty_command_handler(self, handler: Callable[[], None]) -> None:
102
+ """
103
+ Public. Sets the handler for empty commands when entering a command
104
+ :param handler: handler for empty commands when entering a command
105
+ :return: None
106
+ """
81
107
  self._empty_input_command_handler = handler
82
108
 
83
109
 
84
110
  def set_exit_command_handler(self, handler: Callable[[], None]) -> None:
111
+ """
112
+ Public. Sets the handler for exit command when entering a command
113
+ :param handler: handler for exit command when entering a command
114
+ :return: None
115
+ """
85
116
  self._exit_command_handler = handler
86
117
 
87
118
 
88
- class AppPrinters(AppInit):
89
- def _print_command_group_description(self):
119
+ def _print_command_group_description(self) -> None:
120
+ """
121
+ Private. Prints the description of the available commands
122
+ :return: None
123
+ """
90
124
  for registered_router in self._registered_routers:
91
125
  if registered_router.get_title():
92
126
  self._print_func(registered_router.get_title())
@@ -97,54 +131,74 @@ class AppPrinters(AppInit):
97
131
  self._print_func('')
98
132
 
99
133
 
100
- def _print_framed_text_with_dynamic_line(self, text: str):
101
- clear_text = re.sub(r'\u001b\[[0-9;]*m', '', text)
102
- max_length_line = max([len(line) for line in clear_text.split('\n')])
103
- max_length_line = max_length_line if 10 <= max_length_line <= 80 else 80 if max_length_line > 80 else 10
104
- self._print_func(self._dividing_line.get_full_line(max_length_line))
105
- print(text.strip('\n'))
106
- self._print_func(self._dividing_line.get_full_line(max_length_line))
107
-
134
+ def _print_framed_text(self, text: str) -> None:
135
+ """
136
+ Private. Outputs text by framing it in a static or dynamic split strip
137
+ :param text: framed text
138
+ :return: None
139
+ """
140
+ if isinstance(self._dividing_line, StaticDividingLine):
141
+ self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
142
+ self._print_func(text)
143
+ self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
108
144
 
109
- class AppNonStandardHandlers(AppPrinters):
110
- def _is_exit_command(self, command: InputCommand):
111
- if command.get_trigger().lower() == self._exit_command.get_trigger().lower():
112
- if self._ignore_command_register:
113
- system_router.input_command_handler(command)
145
+ elif isinstance(self._dividing_line, DynamicDividingLine):
146
+ clear_text = re.sub(r'\u001b\[[0-9;]*m', '', text)
147
+ max_length_line = max([len(line) for line in clear_text.split('\n')])
148
+ max_length_line = max_length_line if 10 <= max_length_line <= 80 else 80 if max_length_line > 80 else 10
149
+
150
+ self._print_func(self._dividing_line.get_full_dynamic_line(max_length_line, self._override_system_messages))
151
+ print(text.strip('\n'))
152
+ self._print_func(self._dividing_line.get_full_dynamic_line(max_length_line, self._override_system_messages))
153
+
154
+
155
+ def _is_exit_command(self, command: InputCommand) -> bool:
156
+ """
157
+ Private. Checks if the given command is an exit command
158
+ :param command: command to check
159
+ :return: is it an exit command or not as bool
160
+ """
161
+ if self._ignore_command_register:
162
+ if command.get_trigger().lower() == self._exit_command.get_trigger().lower():
114
163
  return True
115
- elif command.get_trigger() == self._exit_command.get_trigger():
116
- system_router.input_command_handler(command)
164
+ elif command.get_trigger().lower() in [x.lower() for x in self._exit_command.get_aliases()]:
165
+ return True
166
+ else:
167
+ if command.get_trigger() == self._exit_command.get_trigger():
168
+ return True
169
+ elif command.get_trigger() in self._exit_command.get_aliases():
117
170
  return True
118
171
  return False
119
172
 
120
173
 
121
- def _is_unknown_command(self, command: InputCommand):
122
- for router_entity in self._registered_routers:
123
- for command_handler in router_entity.get_command_handlers():
124
- handled_command_trigger = command_handler.get_handled_command().get_trigger()
125
- handled_command_aliases = command_handler.get_handled_command().get_aliases()
126
- if handled_command_trigger.lower() == command.get_trigger().lower() and self._ignore_command_register:
127
- return False
128
- elif handled_command_trigger == command.get_trigger():
129
- return False
130
- elif handled_command_aliases:
131
- if (command.get_trigger().lower() in [x.lower() for x in handled_command_aliases]) and self._ignore_command_register:
132
- return False
133
- elif command.get_trigger() in handled_command_trigger:
134
- return False
135
- if isinstance(self._dividing_line, StaticDividingLine):
136
- self._print_func(self._dividing_line.get_full_line())
174
+ def _is_unknown_command(self, command: InputCommand) -> bool:
175
+ """
176
+ Private. Checks if the given command is an unknown command
177
+ :param command: command to check
178
+ :return: is it an unknown command or not as bool
179
+ """
180
+ input_command_trigger = command.get_trigger()
181
+ if self._ignore_command_register:
182
+ if input_command_trigger.lower() in self._all_registered_triggers_in_lower:
183
+ return False
184
+ else:
185
+ if input_command_trigger in self._all_registered_triggers_in_default_case:
186
+ return False
187
+
188
+ with redirect_stdout(io.StringIO()) as f:
137
189
  self._unknown_command_handler(command)
138
- self._print_func(self._dividing_line.get_full_line())
139
- elif isinstance(self._dividing_line, DynamicDividingLine):
140
- with redirect_stdout(io.StringIO()) as f:
141
- self._unknown_command_handler(command)
142
- res: str = f.getvalue()
143
- self._print_framed_text_with_dynamic_line(res)
190
+ res: str = f.getvalue()
191
+ self._print_framed_text(res)
144
192
  return True
145
193
 
146
194
 
147
195
  def _error_handler(self, error: BaseInputCommandException, raw_command: str) -> None:
196
+ """
197
+ Private. Handles parsing errors of the entered command
198
+ :param error: error being handled
199
+ :param raw_command: the raw input command
200
+ :return: None
201
+ """
148
202
  match error:
149
203
  case UnprocessedInputFlagException():
150
204
  self._invalid_input_flags_handler(raw_command)
@@ -154,60 +208,127 @@ class AppNonStandardHandlers(AppPrinters):
154
208
  self._empty_input_command_handler()
155
209
 
156
210
 
157
- class AppValidators(AppInit):
158
- def _validate_number_of_routers(self) -> None:
159
- if not self._registered_routers:
160
- raise NoRegisteredRoutersException()
161
-
162
-
163
211
  def _validate_included_routers(self) -> None:
212
+ """
213
+ Private. Validates included routers
214
+ :return: None
215
+ """
164
216
  for router in self._registered_routers:
165
217
  if not router.get_command_handlers():
166
218
  raise NoRegisteredHandlersException(router.get_name())
167
219
 
168
220
 
169
- class AppSetups(AppValidators, AppPrinters):
170
- def _setup_system_router(self):
171
- system_router.set_title(self._system_points_title)
221
+ def _setup_system_router(self) -> None:
222
+ """
223
+ Private. Sets up system router
224
+ :return: None
225
+ """
226
+ system_router.set_title(self._system_router_title)
172
227
 
173
228
  @system_router.command(self._exit_command)
174
229
  def exit_command():
175
230
  self._exit_command_handler()
176
231
 
177
232
  if system_router not in self._registered_routers.get_registered_routers():
178
- system_router.set_ignore_command_register(self._ignore_command_register)
233
+ system_router.set_command_register_ignore(self._ignore_command_register)
179
234
  self._registered_routers.add_registered_router(system_router)
180
235
 
181
- def _setup_default_view(self):
182
- if not self._override_system_messages:
183
- self._initial_message = f'\n[bold red]{text2art(self._initial_message, font='tarty1')}\n\n'
184
- self._farewell_message = (
185
- f'[bold red]\n{text2art(f'\n{self._farewell_message}\n', font='chanky')}[/bold red]\n'
186
- f'[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n')
187
236
 
188
- def _pre_cycle_setup(self):
237
+ def _setup_default_view(self) -> None:
238
+ """
239
+ Private. Sets up default app view
240
+ :return: None
241
+ """
242
+ if not self._override_system_messages:
243
+ self._initial_message = f'\n[bold red]{text2art(self._initial_message, font="tarty1")}\n\n'
244
+ self._farewell_message = (f'[bold red]\n{text2art(f"\n{self._farewell_message}\n", font="chanky")}[/bold red]\n'
245
+ f'[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n')
246
+ self._description_message_gen = lambda command, description: (f'[bold red]{escape("[" + command + "]")}[/bold red] '
247
+ f'[blue dim]*=*=*[/blue dim] '
248
+ f'[bold yellow italic]{escape(description)}')
249
+ self._invalid_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}')
250
+ self._repeated_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Repeated input flags: {escape(raw_command)}')
251
+ self._empty_input_command_handler = lambda: self._print_func('[red bold]Empty input command')
252
+ self._unknown_command_handler = lambda command: self._print_func(f"[red bold]Unknown command: {escape(command.get_trigger())}")
253
+
254
+
255
+ def _pre_cycle_setup(self) -> None:
256
+ """
257
+ Private. Configures various aspects of the application before the start of the cycle
258
+ :return: None
259
+ """
189
260
  self._setup_default_view()
190
261
  self._setup_system_router()
191
- self._validate_number_of_routers()
192
262
  self._validate_included_routers()
193
263
 
194
- all_triggers: list[str] = []
195
264
  for router_entity in self._registered_routers:
196
- all_triggers.extend(router_entity.get_triggers())
197
- all_triggers.extend(router_entity.get_aliases())
198
- self._autocompleter.initial_setup(all_triggers)
265
+ self._all_registered_triggers_in_default_case.extend(router_entity.get_triggers())
266
+ self._all_registered_triggers_in_default_case.extend(router_entity.get_aliases())
267
+
268
+ self._all_registered_triggers_in_lower.extend([x.lower() for x in router_entity.get_triggers()])
269
+ self._all_registered_triggers_in_lower.extend([x.lower() for x in router_entity.get_aliases()])
270
+
271
+ self._autocompleter.initial_setup(self._all_registered_triggers_in_lower)
199
272
 
200
273
  self._print_func(self._initial_message)
201
274
 
202
275
  for message in self._messages_on_startup:
203
276
  self._print_func(message)
277
+ if self._messages_on_startup:
278
+ print('\n\n')
204
279
 
205
280
  if not self._repeat_command_groups_description:
206
281
  self._print_command_group_description()
207
282
 
208
283
 
209
- class App(AppSetters, AppNonStandardHandlers, AppSetups):
210
- def start_polling(self) -> None:
284
+
285
+ class App(BaseApp):
286
+ def __init__(self,
287
+ prompt: str = '[italic dim bold]What do you want to do?\n',
288
+ initial_message: str = '\nArgenta\n',
289
+ farewell_message: str = '\nSee you\n',
290
+ exit_command: Command = Command('Q', 'Exit command'),
291
+ system_router_title: str | None = 'System points:',
292
+ ignore_command_register: bool = True,
293
+ dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(),
294
+ repeat_command_groups: bool = True,
295
+ override_system_messages: bool = False,
296
+ autocompleter: AutoCompleter = AutoCompleter(),
297
+ print_func: Callable[[str], None] = Console().print) -> None:
298
+ """
299
+ Public. The essence of the application itself.
300
+ Configures and manages all aspects of the behavior and presentation of the user interacting with the user
301
+ :param prompt: displayed before entering the command
302
+ :param initial_message: displayed at the start of the app
303
+ :param farewell_message: displayed at the end of the app
304
+ :param exit_command: the entity of the command that will be terminated when entered
305
+ :param system_router_title: system router title
306
+ :param ignore_command_register: whether to ignore the case of the entered commands
307
+ :param dividing_line: the entity of the dividing line
308
+ :param repeat_command_groups: whether to repeat the available commands and their description
309
+ :param override_system_messages: whether to redefine the default formatting of system messages
310
+ :param autocompleter: the entity of the autocompleter
311
+ :param print_func: system messages text output function
312
+ :return: None
313
+ """
314
+ super().__init__(prompt=prompt,
315
+ initial_message=initial_message,
316
+ farewell_message=farewell_message,
317
+ exit_command=exit_command,
318
+ system_router_title=system_router_title,
319
+ ignore_command_register=ignore_command_register,
320
+ dividing_line=dividing_line,
321
+ repeat_command_groups=repeat_command_groups,
322
+ override_system_messages=override_system_messages,
323
+ autocompleter=autocompleter,
324
+ print_func=print_func)
325
+
326
+
327
+ def run_polling(self) -> None:
328
+ """
329
+ Private. Starts the user input processing cycle
330
+ :return: None
331
+ """
211
332
  self._pre_cycle_setup()
212
333
  while True:
213
334
  if self._repeat_command_groups_description:
@@ -218,53 +339,55 @@ class App(AppSetters, AppNonStandardHandlers, AppSetups):
218
339
  try:
219
340
  input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
220
341
  except BaseInputCommandException as error:
221
- if isinstance(self._dividing_line, StaticDividingLine):
222
- self._print_func(self._dividing_line.get_full_line())
342
+ with redirect_stdout(io.StringIO()) as f:
223
343
  self._error_handler(error, raw_command)
224
- self._print_func(self._dividing_line.get_full_line())
225
- elif isinstance(self._dividing_line, DynamicDividingLine):
226
- with redirect_stdout(io.StringIO()) as f:
227
- self._error_handler(error, raw_command)
228
- res: str = f.getvalue()
229
- self._print_framed_text_with_dynamic_line(res)
344
+ res: str = f.getvalue()
345
+ self._print_framed_text(res)
230
346
  continue
231
347
 
232
348
  if self._is_exit_command(input_command):
349
+ system_router.finds_appropriate_handler(input_command)
233
350
  self._autocompleter.exit_setup()
234
351
  return
235
352
 
236
353
  if self._is_unknown_command(input_command):
237
354
  continue
238
355
 
239
- if isinstance(self._dividing_line, StaticDividingLine):
240
- self._print_func(self._dividing_line.get_full_line())
356
+ with redirect_stdout(io.StringIO()) as f:
241
357
  for registered_router in self._registered_routers:
242
- registered_router.input_command_handler(input_command)
243
- self._print_func(self._dividing_line.get_full_line())
244
- elif isinstance(self._dividing_line, DynamicDividingLine):
245
- with redirect_stdout(io.StringIO()) as f:
246
- for registered_router in self._registered_routers:
247
- registered_router.input_command_handler(input_command)
248
- res: str = f.getvalue()
249
- self._print_framed_text_with_dynamic_line(res)
358
+ registered_router.finds_appropriate_handler(input_command)
359
+ res: str = f.getvalue()
360
+ self._print_framed_text(res)
250
361
 
251
362
  if not self._repeat_command_groups_description:
252
363
  self._print_func(self._prompt)
253
364
 
254
365
 
255
366
  def include_router(self, router: Router) -> None:
256
- if not isinstance(router, Router):
257
- raise InvalidRouterInstanceException()
258
-
259
- router.set_ignore_command_register(self._ignore_command_register)
367
+ """
368
+ Public. Registers the router in the application
369
+ :param router: registered router
370
+ :return: None
371
+ """
372
+ router.set_command_register_ignore(self._ignore_command_register)
260
373
  self._registered_routers.add_registered_router(router)
261
374
 
262
375
 
263
376
  def include_routers(self, *routers: Router) -> None:
377
+ """
378
+ Public. Registers the routers in the application
379
+ :param routers: registered routers
380
+ :return: None
381
+ """
264
382
  for router in routers:
265
383
  self.include_router(router)
266
384
 
267
385
 
268
386
  def add_message_on_startup(self, message: str) -> None:
387
+ """
388
+ Public. Adds a message that will be displayed when the application is launched
389
+ :param message: the message being added
390
+ :return: None
391
+ """
269
392
  self._messages_on_startup.append(message)
270
393