argenta 0.4.1__py3-none-any.whl → 0.4.6__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 +1,3 @@
1
- from .entity import App
1
+ __all__ = ["App"]
2
+
3
+ from .models import App
@@ -0,0 +1,8 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class PredeterminedMessages:
6
+ USAGE = '[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]'
7
+ HELP = '[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]'
8
+
argenta/app/exceptions.py CHANGED
@@ -23,13 +23,3 @@ class NoRegisteredHandlersException(Exception):
23
23
  self.router_name = router_name
24
24
  def __str__(self):
25
25
  return f"No Registered Handlers Found For '{self.router_name}'"
26
-
27
-
28
- class RepeatedCommandInDifferentRoutersException(Exception):
29
- def __str__(self):
30
- return "Commands in different handlers cannot be repeated"
31
-
32
-
33
- class IncorrectNumberOfHandlerArgsException(Exception):
34
- def __str__(self):
35
- return "Incorrect Input Flags Handler has incorrect number of arguments"
argenta/app/models.py ADDED
@@ -0,0 +1,214 @@
1
+ from typing import Callable
2
+ from rich.console import Console
3
+ from art import text2art
4
+ import re
5
+
6
+ from argenta.command.models import Command, InputCommand
7
+ from argenta.router import Router
8
+ from argenta.router.defaults import system_router
9
+ from argenta.command.exceptions import (UnprocessedInputFlagException,
10
+ RepeatedInputFlagsException,
11
+ EmptyInputCommandException,
12
+ BaseInputCommandException)
13
+ from argenta.app.exceptions import (InvalidRouterInstanceException,
14
+ InvalidDescriptionMessagePatternException,
15
+ NoRegisteredRoutersException,
16
+ NoRegisteredHandlersException)
17
+ from argenta.app.registered_routers.entity import RegisteredRouters
18
+
19
+
20
+
21
+ class BaseApp:
22
+ def __init__(self,
23
+ prompt: str = '[italic dim bold]What do you want to do?\n',
24
+ initial_message: str = 'Argenta',
25
+ farewell_message: str = 'See you',
26
+ exit_command: str = 'Q',
27
+ exit_command_description: str = 'Exit command',
28
+ system_points_title: str = 'System points:',
29
+ ignore_command_register: bool = True,
30
+ line_separate: str = '-----',
31
+ repeat_command_groups: bool = True,
32
+ print_func: Callable[[str], None] = Console().print) -> None:
33
+ self._prompt = prompt
34
+ self._print_func = print_func
35
+ self._exit_command = exit_command
36
+ self._exit_command_description = exit_command_description
37
+ self._system_points_title = system_points_title
38
+ self._line_separate = line_separate
39
+ self._ignore_command_register = ignore_command_register
40
+ self._repeat_command_groups_description = repeat_command_groups
41
+
42
+ self.farewell_message = farewell_message
43
+ self.initial_message = initial_message
44
+
45
+ self._description_message_pattern: str = '[bold red][{command}][/bold red] [blue dim]*=*=*[/blue dim] [bold yellow italic]{description}'
46
+ self._registered_routers: RegisteredRouters = RegisteredRouters()
47
+ self._messages_on_startup = []
48
+
49
+ self.invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Incorrect flag syntax: {raw_command}')
50
+ self.repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Repeated input flags: {raw_command}')
51
+ self.empty_input_command_handler: Callable[[], None] = lambda: print_func('[red bold]Empty input command')
52
+ self.unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"[red bold]Unknown command: {command.get_trigger()}")
53
+ self.exit_command_handler: Callable[[], None] = lambda: print_func(self.farewell_message)
54
+
55
+ self._setup_default_view(is_initial_message_default=initial_message == 'Argenta',
56
+ is_farewell_message_default=farewell_message == 'See you',
57
+ is_line_separate_default=line_separate == '-----')
58
+
59
+
60
+ def _setup_default_view(self, is_initial_message_default: bool,
61
+ is_farewell_message_default: bool,
62
+ is_line_separate_default: bool):
63
+ if is_initial_message_default:
64
+ self.initial_message = f'\n[bold red]{text2art('Argenta', font='tarty1')}\n\n'
65
+ if is_farewell_message_default:
66
+ self.farewell_message = (f'[bold red]\n{text2art('\nSee you\n', font='chanky')}[/bold red]\n'
67
+ f'[red i]github.com/koloideal/Argenta[/red i] | '
68
+ f'[red bold i]made by kolo[/red bold i]\n')
69
+ if is_line_separate_default:
70
+ self._line_separate = f'\n[dim]{"-" * 50}\n'
71
+
72
+
73
+ def _validate_number_of_routers(self) -> None:
74
+ if not self._registered_routers:
75
+ raise NoRegisteredRoutersException()
76
+
77
+
78
+ def _validate_included_routers(self) -> None:
79
+ for router in self._registered_routers:
80
+ if not router.get_command_handlers():
81
+ raise NoRegisteredHandlersException(router.get_name())
82
+
83
+
84
+ def _is_exit_command(self, command: InputCommand):
85
+ if command.get_trigger().lower() == self._exit_command.lower():
86
+ if self._ignore_command_register:
87
+ system_router.input_command_handler(command)
88
+ return True
89
+ elif command.get_trigger() == self._exit_command:
90
+ system_router.input_command_handler(command)
91
+ return True
92
+ return False
93
+
94
+
95
+ def _is_unknown_command(self, command: InputCommand):
96
+ for router_entity in self._registered_routers:
97
+ for command_handler in router_entity.get_command_handlers():
98
+ handled_command_trigger = command_handler.get_handled_command().get_trigger()
99
+ if handled_command_trigger.lower() == command.get_trigger().lower() and self._ignore_command_register:
100
+ return False
101
+ elif handled_command_trigger == command.get_trigger():
102
+ return False
103
+ self.unknown_command_handler(command)
104
+ return True
105
+
106
+
107
+ def _print_command_group_description(self):
108
+ for registered_router in self._registered_routers:
109
+ self._print_func(registered_router.get_title())
110
+ for command_handler in registered_router.get_command_handlers():
111
+ self._print_func(self._description_message_pattern.format(
112
+ command=command_handler.get_handled_command().get_trigger(),
113
+ description=command_handler.get_handled_command().get_description()))
114
+ self._print_func('')
115
+
116
+
117
+ def _error_handler(self, error: BaseInputCommandException, raw_command: str) -> None:
118
+ match error:
119
+ case UnprocessedInputFlagException():
120
+ self.invalid_input_flags_handler(raw_command)
121
+ case RepeatedInputFlagsException():
122
+ self.repeated_input_flags_handler(raw_command)
123
+ case EmptyInputCommandException():
124
+ self.empty_input_command_handler()
125
+
126
+
127
+
128
+ class App(BaseApp):
129
+ def start_polling(self) -> None:
130
+ self._setup_system_router()
131
+ self._validate_number_of_routers()
132
+ self._validate_included_routers()
133
+
134
+ self._print_func(self.initial_message)
135
+
136
+ for message in self._messages_on_startup:
137
+ self._print_func(message)
138
+
139
+ if not self._repeat_command_groups_description:
140
+ self._print_command_group_description()
141
+
142
+ while True:
143
+ if self._repeat_command_groups_description:
144
+ self._print_command_group_description()
145
+
146
+ raw_command: str = Console().input(self._prompt)
147
+
148
+ try:
149
+ input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
150
+ except BaseInputCommandException as error:
151
+ self._print_func(self._line_separate)
152
+ self._error_handler(error, raw_command)
153
+ self._print_func(self._line_separate)
154
+
155
+ if not self._repeat_command_groups_description:
156
+ self._print_func(self._prompt)
157
+ continue
158
+
159
+ if self._is_exit_command(input_command):
160
+ return
161
+
162
+ self._print_func(self._line_separate)
163
+
164
+ if self._is_unknown_command(input_command):
165
+ self._print_func(self._line_separate)
166
+ if not self._repeat_command_groups_description:
167
+ self._print_func(self._prompt)
168
+ continue
169
+
170
+ for registered_router in self._registered_routers:
171
+ registered_router.input_command_handler(input_command)
172
+
173
+ self._print_func(self._line_separate)
174
+ if not self._repeat_command_groups_description:
175
+ self._print_func(self._prompt)
176
+
177
+
178
+ def include_router(self, router: Router) -> None:
179
+ if not isinstance(router, Router):
180
+ raise InvalidRouterInstanceException()
181
+
182
+ router.set_ignore_command_register(self._ignore_command_register)
183
+ self._registered_routers.add_registered_router(router)
184
+
185
+
186
+ def include_routers(self, *routers: Router) -> None:
187
+ for router in routers:
188
+ self.include_router(router)
189
+
190
+
191
+ def add_message_on_startup(self, message: str) -> None:
192
+ self._messages_on_startup.append(message)
193
+
194
+
195
+ def set_description_message_pattern(self, pattern: str) -> None:
196
+ first_check = re.match(r'.*{command}.*', pattern)
197
+ second_check = re.match(r'.*{description}.*', pattern)
198
+
199
+ if bool(first_check) and bool(second_check):
200
+ self._description_message_pattern: str = pattern
201
+ else:
202
+ raise InvalidDescriptionMessagePatternException(pattern)
203
+
204
+
205
+ def _setup_system_router(self):
206
+ system_router.set_title(self._system_points_title)
207
+ @system_router.command(Command(self._exit_command, self._exit_command_description))
208
+ def exit_command():
209
+ self.exit_command_handler()
210
+
211
+ if system_router not in self._registered_routers.get_registered_routers():
212
+ self.include_router(system_router)
213
+
214
+
File without changes
@@ -0,0 +1,21 @@
1
+ from argenta.router import Router
2
+
3
+
4
+ class RegisteredRouters:
5
+ def __init__(self, registered_routers: list[Router] = None) -> None:
6
+ self._registered_routers = registered_routers if registered_routers else []
7
+
8
+ def get_registered_routers(self) -> list[Router]:
9
+ return self._registered_routers
10
+
11
+ def add_registered_router(self, router: Router):
12
+ self._registered_routers.append(router)
13
+
14
+ def add_registered_routers(self, *routers: Router):
15
+ self._registered_routers.extend(routers)
16
+
17
+ def __iter__(self):
18
+ return iter(self._registered_routers)
19
+
20
+ def __next__(self):
21
+ return next(iter(self._registered_routers))
@@ -1 +1,3 @@
1
- from .entity import Command
1
+ __all__ = ["Command"]
2
+
3
+ from .models import Command
@@ -1,19 +1,23 @@
1
- from argenta.command.flag.entity import Flag
1
+ from argenta.command.flag.models import InputFlag, Flag
2
2
 
3
3
 
4
- class UnprocessedInputFlagException(Exception):
4
+ class BaseInputCommandException(Exception):
5
+ pass
6
+
7
+
8
+ class UnprocessedInputFlagException(BaseInputCommandException):
5
9
  def __str__(self):
6
10
  return "Unprocessed Input Flags"
7
11
 
8
12
 
9
- class RepeatedInputFlagsException(Exception):
10
- def __init__(self, flag: Flag):
13
+ class RepeatedInputFlagsException(BaseInputCommandException):
14
+ def __init__(self, flag: Flag | InputFlag):
11
15
  self.flag = flag
12
16
  def __str__(self):
13
17
  return ("Repeated Input Flags\n"
14
18
  f"Duplicate flag was detected in the input: '{self.flag.get_string_entity()}'")
15
19
 
16
20
 
17
- class EmptyInputCommandException(Exception):
21
+ class EmptyInputCommandException(BaseInputCommandException):
18
22
  def __str__(self):
19
- return "Input Command is empty"
23
+ return "Input Command is empty"
@@ -1,2 +1,4 @@
1
- from .entity import Flag
2
- from .flags_group.entity import FlagsGroup
1
+ __all__ = ('InputFlags', 'InputFlag', 'Flag', 'Flags')
2
+
3
+
4
+ from .models import InputFlags, InputFlag, Flags, Flag
@@ -1,21 +1,21 @@
1
1
  from dataclasses import dataclass
2
- from argenta.command.flag import Flag
2
+ from argenta.command.flag.models import Flag
3
3
  import re
4
4
 
5
5
 
6
6
  @dataclass
7
- class DefaultFlags:
8
- help_flag = Flag(flag_name='help', possible_flag_values=False)
9
- short_help_flag = Flag(flag_name='h', flag_prefix='-', possible_flag_values=False)
7
+ class PredeterminedFlags:
8
+ HELP = Flag(name='help', possible_values=False)
9
+ SHORT_HELP = Flag(name='h', prefix='-', possible_values=False)
10
10
 
11
- info_flag = Flag(flag_name='info', possible_flag_values=False)
12
- short_info_flag = Flag(flag_name='i', flag_prefix='-', possible_flag_values=False)
11
+ INFO = Flag(name='info', possible_values=False)
12
+ SHORT_INFO = Flag(name='i', prefix='-', possible_values=False)
13
13
 
14
- all_flag = Flag(flag_name='all', possible_flag_values=False)
15
- short_all_flag = Flag(flag_name='a', flag_prefix='-', possible_flag_values=False)
14
+ ALL = Flag(name='all', possible_values=False)
15
+ SHORT_ALL = Flag(name='a', prefix='-', possible_values=False)
16
16
 
17
- host_flag = Flag(flag_name='host', possible_flag_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'))
18
- short_host_flag = Flag(flag_name='h', flag_prefix='-', possible_flag_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'))
17
+ HOST = Flag(name='host', possible_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'))
18
+ SHORT_HOST = Flag(name='h', prefix='-', possible_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'))
19
19
 
20
- port_flag = Flag(flag_name='port', possible_flag_values=re.compile(r'^\d{1,5}$'))
21
- short_port_flag = Flag(flag_name='p', flag_prefix='-', possible_flag_values=re.compile(r'^\d{1,5}$'))
20
+ PORT = Flag(name='port', possible_values=re.compile(r'^\d{1,5}$'))
21
+ SHORT_PORT = Flag(name='p', prefix='-', possible_values=re.compile(r'^\d{1,5}$'))
@@ -0,0 +1,140 @@
1
+ from typing import Literal, Pattern
2
+ from abc import ABC, abstractmethod
3
+
4
+
5
+ class BaseFlag:
6
+ def __init__(self, name: str,
7
+ prefix: Literal['-', '--', '---'] = '--'):
8
+ self._name = name
9
+ self._prefix = prefix
10
+
11
+ def get_string_entity(self):
12
+ string_entity: str = self._prefix + self._name
13
+ return string_entity
14
+
15
+ def get_name(self):
16
+ return self._name
17
+
18
+ def get_prefix(self):
19
+ return self._prefix
20
+
21
+
22
+
23
+ class InputFlag(BaseFlag):
24
+ def __init__(self, name: str,
25
+ prefix: Literal['-', '--', '---'] = '--',
26
+ value: str = None):
27
+ super().__init__(name, prefix)
28
+ self._flag_value = value
29
+
30
+ def get_value(self):
31
+ return self._flag_value
32
+
33
+ def set_value(self, value):
34
+ self._flag_value = value
35
+
36
+
37
+
38
+ class Flag(BaseFlag):
39
+ def __init__(self, name: str,
40
+ prefix: Literal['-', '--', '---'] = '--',
41
+ possible_values: list[str] | Pattern[str] | False = True):
42
+ super().__init__(name, prefix)
43
+ self.possible_values = possible_values
44
+
45
+ def validate_input_flag_value(self, input_flag_value: str | None):
46
+ if self.possible_values is False:
47
+ if input_flag_value is None:
48
+ return True
49
+ else:
50
+ return False
51
+ elif isinstance(self.possible_values, Pattern):
52
+ if isinstance(input_flag_value, str):
53
+ is_valid = bool(self.possible_values.match(input_flag_value))
54
+ if bool(is_valid):
55
+ return True
56
+ else:
57
+ return False
58
+ else:
59
+ return False
60
+
61
+ elif isinstance(self.possible_values, list):
62
+ if input_flag_value in self.possible_values:
63
+ return True
64
+ else:
65
+ return False
66
+ else:
67
+ return True
68
+
69
+
70
+
71
+ class BaseFlags(ABC):
72
+ __slots__ = ('_flags',)
73
+
74
+ @abstractmethod
75
+ def get_flags(self):
76
+ pass
77
+
78
+ @abstractmethod
79
+ def add_flag(self, flag: Flag | InputFlag):
80
+ pass
81
+
82
+ @abstractmethod
83
+ def add_flags(self, flags: list[Flag] | list[InputFlag]):
84
+ pass
85
+
86
+ @abstractmethod
87
+ def get_flag(self, name: str):
88
+ pass
89
+
90
+ def __iter__(self):
91
+ return iter(self._flags)
92
+
93
+ def __next__(self):
94
+ return next(iter(self))
95
+
96
+ def __getitem__(self, item):
97
+ return self._flags[item]
98
+
99
+
100
+
101
+ class Flags(BaseFlags, ABC):
102
+ def __init__(self, *flags: Flag):
103
+ self._flags = flags if flags else []
104
+
105
+ def get_flags(self) -> list[Flag]:
106
+ return self._flags
107
+
108
+ def add_flag(self, flag: Flag):
109
+ self._flags.append(flag)
110
+
111
+ def add_flags(self, flags: list[Flag]):
112
+ self._flags.extend(flags)
113
+
114
+ def get_flag(self, name: str) -> Flag | None:
115
+ if name in [flag.get_name() for flag in self._flags]:
116
+ return list(filter(lambda flag: flag.get_name() == name, self._flags))[0]
117
+ else:
118
+ return None
119
+
120
+
121
+
122
+ class InputFlags(BaseFlags, ABC):
123
+ def __init__(self, *flags: InputFlag):
124
+ self._flags = flags if flags else []
125
+
126
+ def get_flags(self) -> list[InputFlag]:
127
+ return self._flags
128
+
129
+ def add_flag(self, flag: InputFlag):
130
+ self._flags.append(flag)
131
+
132
+ def add_flags(self, flags: list[InputFlag]):
133
+ self._flags.extend(flags)
134
+
135
+ def get_flag(self, name: str) -> InputFlag | None:
136
+ if name in [flag.get_name() for flag in self._flags]:
137
+ return list(filter(lambda flag: flag.get_name() == name, self._flags))[0]
138
+ else:
139
+ return None
140
+
@@ -0,0 +1,106 @@
1
+ from argenta.command.flag.models import Flag, InputFlag, Flags, InputFlags
2
+ from argenta.command.exceptions import (UnprocessedInputFlagException,
3
+ RepeatedInputFlagsException,
4
+ EmptyInputCommandException)
5
+ from typing import Generic, TypeVar, cast, Literal
6
+
7
+
8
+ InputCommandType = TypeVar('InputCommandType')
9
+
10
+
11
+ class BaseCommand:
12
+ def __init__(self, trigger: str):
13
+ self._trigger = trigger
14
+
15
+ def get_trigger(self) -> str:
16
+ return self._trigger
17
+
18
+
19
+ class Command(BaseCommand):
20
+ def __init__(self, trigger: str,
21
+ description: str = None,
22
+ flags: Flag | Flags = None):
23
+ super().__init__(trigger)
24
+ self._registered_flags: Flags = flags if isinstance(flags, Flags) else Flags(flags) if isinstance(flags, Flag) else Flags()
25
+ self._description = f'description for "{self._trigger}" command' if not description else description
26
+
27
+ def get_registered_flags(self) -> Flags:
28
+ return self._registered_flags
29
+
30
+ def validate_input_flag(self, flag: InputFlag):
31
+ registered_flags: Flags | None = self.get_registered_flags()
32
+ if registered_flags:
33
+ if isinstance(registered_flags, Flag):
34
+ if registered_flags.get_string_entity() == flag.get_string_entity():
35
+ is_valid = registered_flags.validate_input_flag_value(flag.get_value())
36
+ if is_valid:
37
+ return True
38
+ else:
39
+ for registered_flag in registered_flags:
40
+ if registered_flag.get_string_entity() == flag.get_string_entity():
41
+ is_valid = registered_flag.validate_input_flag_value(flag.get_value())
42
+ if is_valid:
43
+ return True
44
+ return False
45
+
46
+ def get_description(self) -> str:
47
+ return self._description
48
+
49
+
50
+
51
+ class InputCommand(BaseCommand, Generic[InputCommandType]):
52
+ def __init__(self, trigger: str,
53
+ input_flags: InputFlag | InputFlags = None):
54
+ super().__init__(trigger)
55
+ self._input_flags: InputFlags = input_flags if isinstance(input_flags, InputFlags) else InputFlags(input_flags) if isinstance(input_flags, InputFlag) else InputFlags()
56
+
57
+ def _set_input_flags(self, input_flags: InputFlags):
58
+ self._input_flags = input_flags
59
+
60
+ def get_input_flags(self) -> InputFlags:
61
+ return self._input_flags
62
+
63
+ @staticmethod
64
+ def parse(raw_command: str) -> InputCommandType:
65
+ if not raw_command:
66
+ raise EmptyInputCommandException()
67
+
68
+ list_of_tokens = raw_command.split()
69
+ command = list_of_tokens.pop(0)
70
+
71
+ input_flags: InputFlags = InputFlags()
72
+ current_flag_name, current_flag_value = None, None
73
+
74
+ for k, _ in enumerate(list_of_tokens):
75
+ if _.startswith('-'):
76
+ if current_flag_name or len(_) < 2 or len(_[:_.rfind('-')]) > 3:
77
+ raise UnprocessedInputFlagException()
78
+ current_flag_name = _
79
+ else:
80
+ if not current_flag_name:
81
+ raise UnprocessedInputFlagException()
82
+ current_flag_value = _
83
+
84
+ if current_flag_name:
85
+ if not len(list_of_tokens) == k+1:
86
+ if not list_of_tokens[k+1].startswith('-'):
87
+ continue
88
+
89
+ input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-')+1:],
90
+ prefix=cast(Literal['-', '--', '---'],
91
+ current_flag_name[:current_flag_name.rfind('-')+1]),
92
+ value=current_flag_value)
93
+
94
+ all_flags = [flag.get_string_entity() for flag in input_flags.get_flags()]
95
+ if input_flag.get_string_entity() not in all_flags:
96
+ input_flags.add_flag(input_flag)
97
+ else:
98
+ raise RepeatedInputFlagsException(input_flag)
99
+
100
+ current_flag_name, current_flag_value = None, None
101
+
102
+ if any([current_flag_name, current_flag_value]):
103
+ raise UnprocessedInputFlagException()
104
+ else:
105
+ return InputCommand(trigger=command, input_flags=input_flags)
106
+
@@ -1 +1,4 @@
1
+ __all__ = ["Router"]
2
+
3
+
1
4
  from .entity import Router
File without changes
@@ -0,0 +1,21 @@
1
+ from typing import Callable
2
+ from argenta.command import Command
3
+ from argenta.command.flag.models import InputFlags
4
+
5
+
6
+ class CommandHandler:
7
+ def __init__(self, handler: Callable[[], None] | Callable[[InputFlags], None], handled_command: Command):
8
+ self.handler = handler
9
+ self.handled_command = handled_command
10
+
11
+ def handling(self, input_flags: InputFlags = None):
12
+ if input_flags is not None:
13
+ self.handler(input_flags)
14
+ else:
15
+ self.handler()
16
+
17
+ def get_handler(self):
18
+ return self.handler
19
+
20
+ def get_handled_command(self):
21
+ return self.handled_command
File without changes
@@ -0,0 +1,21 @@
1
+ from argenta.router.command_handler.entity import CommandHandler
2
+
3
+
4
+ class CommandHandlers:
5
+ def __init__(self, command_handlers: list[CommandHandler] = None):
6
+ self.command_handlers = command_handlers if command_handlers else []
7
+
8
+ def get_command_handlers(self) -> list[CommandHandler]:
9
+ return self.command_handlers
10
+
11
+ def add_command_handler(self, command_handler: CommandHandler):
12
+ self.command_handlers.append(command_handler)
13
+
14
+ def add_command_handlers(self, *command_handlers: CommandHandler):
15
+ self.command_handlers.extend(command_handlers)
16
+
17
+ def __iter__(self):
18
+ return iter(self.command_handlers)
19
+
20
+ def __next__(self):
21
+ return next(iter(self.command_handlers))