argenta 1.0.7__py3-none-any.whl → 1.1.1__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/command/models.py CHANGED
@@ -1,35 +1,28 @@
1
- from argenta.command.flag.models import Flag, InputFlag
1
+ from argenta.command.flag.models import Flag, InputFlag, ValidationStatus
2
2
  from argenta.command.flag.flags.models import InputFlags, Flags
3
3
  from argenta.command.exceptions import (
4
4
  UnprocessedInputFlagException,
5
5
  RepeatedInputFlagsException,
6
6
  EmptyInputCommandException,
7
7
  )
8
- from typing import cast, Literal
8
+ from typing import Never, Self, cast, Literal
9
9
 
10
10
 
11
- class BaseCommand:
12
- def __init__(self, trigger: str) -> None:
13
- """
14
- Private. Base class for all commands
15
- :param trigger: A string trigger, which, when entered by the user, indicates that the input corresponds to the command
16
- """
17
- self._trigger = trigger
11
+ ParseFlagsResult = tuple[InputFlags, str | None, str | None]
12
+ ParseResult = tuple[str, InputFlags]
18
13
 
19
- def get_trigger(self) -> str:
20
- """
21
- Public. Returns the trigger of the command
22
- :return: the trigger of the command as str
23
- """
24
- return self._trigger
14
+ MIN_FLAG_PREFIX: str = "-"
15
+ DEFAULT_WITHOUT_FLAGS: Flags = Flags()
16
+
17
+ DEFAULT_WITHOUT_INPUT_FLAGS: InputFlags = InputFlags()
25
18
 
26
19
 
27
- class Command(BaseCommand):
20
+ class Command:
28
21
  def __init__(
29
22
  self,
30
- trigger: str,
23
+ trigger: str, *,
31
24
  description: str | None = None,
32
- flags: Flag | Flags | None = None,
25
+ flags: Flag | Flags = DEFAULT_WITHOUT_FLAGS,
33
26
  aliases: list[str] | None = None,
34
27
  ):
35
28
  """
@@ -39,157 +32,120 @@ class Command(BaseCommand):
39
32
  :param flags: processed commands
40
33
  :param aliases: string synonyms for the main trigger
41
34
  """
42
- super().__init__(trigger)
43
- self._registered_flags: Flags = (
44
- flags
45
- if isinstance(flags, Flags)
46
- else Flags(flags)
47
- if isinstance(flags, Flag)
48
- else Flags()
49
- )
50
- self._description = "Very useful command" if not description else description
51
- self._aliases = aliases if isinstance(aliases, list) else []
52
-
53
- def get_registered_flags(self) -> Flags:
54
- """
55
- Private. Returns the registered flags
56
- :return: the registered flags as Flags
57
- """
58
- return self._registered_flags
59
-
60
- def get_aliases(self) -> list[str] | list:
61
- """
62
- Public. Returns the aliases of the command
63
- :return: the aliases of the command as list[str] | list
64
- """
65
- return self._aliases
35
+ self.registered_flags: Flags = flags if isinstance(flags, Flags) else Flags([flags])
36
+ self.trigger: str = trigger
37
+ self.description: str = description if description else "Command without description"
38
+ self.aliases: list[str] = aliases if aliases else []
66
39
 
67
40
  def validate_input_flag(
68
41
  self, flag: InputFlag
69
- ) -> Literal["Undefined", "Valid", "Invalid"]:
42
+ ) -> ValidationStatus:
70
43
  """
71
44
  Private. Validates the input flag
72
45
  :param flag: input flag for validation
73
46
  :return: is input flag valid as bool
74
47
  """
75
- registered_flags: Flags | None = self.get_registered_flags()
76
- if registered_flags:
77
- if isinstance(registered_flags, Flag):
78
- if registered_flags.get_string_entity() == flag.get_string_entity():
79
- is_valid = registered_flags.validate_input_flag_value(
80
- flag.get_value()
81
- )
82
- if is_valid:
83
- return "Valid"
84
- else:
85
- return "Invalid"
48
+ registered_flags: Flags = self.registered_flags
49
+ for registered_flag in registered_flags:
50
+ if registered_flag.string_entity == flag.string_entity:
51
+ is_valid = registered_flag.validate_input_flag_value(flag.input_value)
52
+ if is_valid:
53
+ return ValidationStatus.VALID
86
54
  else:
87
- return "Undefined"
88
- else:
89
- for registered_flag in registered_flags:
90
- if registered_flag.get_string_entity() == flag.get_string_entity():
91
- is_valid = registered_flag.validate_input_flag_value(
92
- flag.get_value()
93
- )
94
-
95
- if is_valid:
96
- return "Valid"
97
- else:
98
- return "Invalid"
99
- return "Undefined"
100
- return "Undefined"
101
-
102
- def get_description(self) -> str:
103
- """
104
- Private. Returns the description of the command
105
- :return: the description of the command as str
106
- """
107
- return self._description
55
+ return ValidationStatus.INVALID
56
+ return ValidationStatus.UNDEFINED
108
57
 
109
58
 
110
- class InputCommand(BaseCommand):
111
- def __init__(self, trigger: str, input_flags: InputFlag | InputFlags | None = None):
59
+ class InputCommand:
60
+ def __init__(self, trigger: str, *,
61
+ input_flags: InputFlag | InputFlags = DEFAULT_WITHOUT_INPUT_FLAGS):
112
62
  """
113
63
  Private. The model of the input command, after parsing
114
64
  :param trigger:the trigger of the command
115
65
  :param input_flags: the input flags
116
66
  :return: None
117
67
  """
118
- super().__init__(trigger)
119
- self._input_flags: InputFlags = (
120
- input_flags
121
- if isinstance(input_flags, InputFlags)
122
- else InputFlags(input_flags)
123
- if isinstance(input_flags, InputFlag)
124
- else InputFlags()
125
- )
126
-
127
- def _set_input_flags(self, input_flags: InputFlags) -> None:
128
- """
129
- Private. Sets the input flags
130
- :param input_flags: the input flags to set
131
- :return: None
132
- """
133
- self._input_flags = input_flags
134
-
135
- def get_input_flags(self) -> InputFlags:
136
- """
137
- Private. Returns the input flags
138
- :return: the input flags as InputFlags
139
- """
140
- return self._input_flags
68
+ self.trigger: str = trigger
69
+ self.input_flags: InputFlags = input_flags if isinstance(input_flags, InputFlags) else InputFlags([input_flags])
141
70
 
142
- @staticmethod
143
- def parse(raw_command: str) -> "InputCommand":
71
+ @classmethod
72
+ def parse(cls, raw_command: str) -> Self:
144
73
  """
145
74
  Private. Parse the raw input command
146
75
  :param raw_command: raw input command
147
76
  :return: model of the input command, after parsing as InputCommand
148
77
  """
149
- if not raw_command:
150
- raise EmptyInputCommandException()
78
+ trigger, input_flags = CommandParser(raw_command).parse_raw_command()
151
79
 
152
- list_of_tokens = raw_command.split()
153
- command = list_of_tokens.pop(0)
154
-
155
- input_flags: InputFlags = InputFlags()
156
- current_flag_name, current_flag_value = None, None
157
-
158
- for k, _ in enumerate(list_of_tokens):
159
- if _.startswith("-"):
160
- if len(_) < 2 or len(_[: _.rfind("-")]) > 3:
161
- raise UnprocessedInputFlagException()
162
- current_flag_name = _
163
- else:
164
- if not current_flag_name or current_flag_value:
165
- raise UnprocessedInputFlagException()
166
- current_flag_value = _
167
-
168
- if current_flag_name:
169
- if not len(list_of_tokens) == k + 1:
170
- if not list_of_tokens[k + 1].startswith("-"):
171
- continue
172
-
173
- input_flag = InputFlag(
174
- name=current_flag_name[current_flag_name.rfind("-") + 1 :],
175
- prefix=cast(
176
- Literal["-", "--", "---"],
177
- current_flag_name[: current_flag_name.rfind("-") + 1],
178
- ),
179
- value=current_flag_value,
180
- )
181
-
182
- all_flags = [
183
- flag.get_string_entity() for flag in input_flags.get_flags()
184
- ]
185
- if input_flag.get_string_entity() not in all_flags:
186
- input_flags.add_flag(input_flag)
187
- else:
188
- raise RepeatedInputFlagsException(input_flag)
80
+ return cls(trigger=trigger, input_flags=input_flags)
81
+
82
+
83
+ class CommandParser:
84
+ def __init__(self, raw_command: str) -> None:
85
+ self.raw_command: str = raw_command
86
+ self._parsed_input_flags: InputFlags = InputFlags()
87
+
88
+ def parse_raw_command(self) -> ParseResult:
89
+ if not self.raw_command:
90
+ raise EmptyInputCommandException()
189
91
 
190
- current_flag_name, current_flag_value = None, None
92
+ input_flags, crnt_flag_name, crnt_flag_val = self._parse_flags(self.raw_command.split()[1:])
191
93
 
192
- if any([current_flag_name, current_flag_value]):
94
+ if any([crnt_flag_name, crnt_flag_val]):
193
95
  raise UnprocessedInputFlagException()
194
96
  else:
195
- return InputCommand(trigger=command, input_flags=input_flags)
97
+ return (self.raw_command.split()[0], input_flags)
98
+
99
+ def _parse_flags(self, _tokens: list[str] | list[Never]) -> ParseFlagsResult:
100
+ crnt_flg_name, crnt_flg_val = None, None
101
+ for index, token in enumerate(_tokens):
102
+ crnt_flg_name, crnt_flg_val = _parse_single_token(token, crnt_flg_name, crnt_flg_val)
103
+
104
+ if not crnt_flg_name or self._is_next_token_value(index, _tokens):
105
+ continue
106
+
107
+ input_flag = InputFlag(
108
+ name=crnt_flg_name[crnt_flg_name.rfind(MIN_FLAG_PREFIX) + 1:],
109
+ prefix=cast(
110
+ Literal["-", "--", "---"],
111
+ crnt_flg_name[:crnt_flg_name.rfind(MIN_FLAG_PREFIX) + 1],
112
+ ),
113
+ input_value=crnt_flg_val,
114
+ status=None
115
+ )
116
+
117
+ if input_flag in self._parsed_input_flags:
118
+ raise RepeatedInputFlagsException(input_flag)
119
+
120
+ self._parsed_input_flags.add_flag(input_flag)
121
+ crnt_flg_name, crnt_flg_val = None, None
122
+
123
+ return (self._parsed_input_flags, crnt_flg_name, crnt_flg_val)
124
+
125
+ def _is_next_token_value(self, current_index: int,
126
+ _tokens: list[str] | list[Never]) -> bool:
127
+ next_index = current_index + 1
128
+ if next_index >= len(_tokens):
129
+ return False
130
+
131
+ next_token = _tokens[next_index]
132
+ return not next_token.startswith(MIN_FLAG_PREFIX)
133
+
134
+ def _parse_single_token(
135
+ token: str,
136
+ crnt_flag_name: str | None,
137
+ crnt_flag_val: str | None
138
+ ) -> tuple[str | None, str | None]:
139
+ if not token.startswith(MIN_FLAG_PREFIX):
140
+ if not crnt_flag_name or crnt_flag_val:
141
+ raise UnprocessedInputFlagException
142
+ return crnt_flag_name, token
143
+
144
+ prefix = token[:token.rfind(MIN_FLAG_PREFIX)]
145
+ if len(token) < 2 or len(prefix) > 2:
146
+ raise UnprocessedInputFlagException
147
+
148
+ new_flag_name = token
149
+ new_flag_value = None
150
+
151
+ return new_flag_name, new_flag_value
argenta/metrics/main.py CHANGED
@@ -2,7 +2,7 @@ import io
2
2
  from contextlib import redirect_stdout
3
3
  from time import time
4
4
 
5
- from argenta.app import App
5
+ from argenta import App
6
6
 
7
7
 
8
8
  def get_time_of_pre_cycle_setup(app: App) -> float:
@@ -13,6 +13,6 @@ def get_time_of_pre_cycle_setup(app: App) -> float:
13
13
  """
14
14
  start = time()
15
15
  with redirect_stdout(io.StringIO()):
16
- app.pre_cycle_setup()
16
+ app._pre_cycle_setup() # pyright: ignore[reportPrivateUsage]
17
17
  end = time()
18
18
  return end - start
@@ -1,4 +1,8 @@
1
- __all__ = ["Orchestrator"]
1
+ __all__ = [
2
+ "Orchestrator",
3
+ "ArgParser"
4
+ ]
2
5
 
3
6
 
4
7
  from argenta.orchestrator.entity import Orchestrator
8
+ from argenta.orchestrator.argparser.entity import ArgParser
@@ -1,4 +1,12 @@
1
- __all__ = ["ArgParser"]
1
+ __all__ = [
2
+ "ArgParser",
3
+ "PositionalArgument",
4
+ "OptionalArgument",
5
+ "BooleanArgument"
6
+ ]
2
7
 
3
8
 
4
9
  from argenta.orchestrator.argparser.entity import ArgParser
10
+ from argenta.orchestrator.argparser.arguments import (BooleanArgument,
11
+ PositionalArgument,
12
+ OptionalArgument)
@@ -1,19 +1,19 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import Literal
2
+ from typing import Literal, override
3
3
 
4
4
 
5
5
  class BaseArgument(ABC):
6
6
  """
7
7
  Private. Base class for all arguments
8
8
  """
9
-
9
+ @property
10
10
  @abstractmethod
11
- def get_string_entity(self) -> str:
11
+ def string_entity(self) -> str:
12
12
  """
13
13
  Public. Returns the string representation of the argument
14
14
  :return: the string representation as a str
15
15
  """
16
- pass
16
+ raise NotImplementedError
17
17
 
18
18
 
19
19
  class PositionalArgument(BaseArgument):
@@ -22,9 +22,11 @@ class PositionalArgument(BaseArgument):
22
22
  Public. Required argument at startup
23
23
  :param name: name of the argument, must not start with minus (-)
24
24
  """
25
- self.name = name
25
+ self.name: str = name
26
26
 
27
- def get_string_entity(self):
27
+ @property
28
+ @override
29
+ def string_entity(self) -> str:
28
30
  return self.name
29
31
 
30
32
 
@@ -35,10 +37,12 @@ class OptionalArgument(BaseArgument):
35
37
  :param name: name of the argument
36
38
  :param prefix: prefix of the argument
37
39
  """
38
- self.name = name
39
- self.prefix = prefix
40
+ self.name: str = name
41
+ self.prefix: Literal["-", "--", "---"] = prefix
40
42
 
41
- def get_string_entity(self):
43
+ @property
44
+ @override
45
+ def string_entity(self) -> str:
42
46
  return self.prefix + self.name
43
47
 
44
48
 
@@ -49,8 +53,10 @@ class BooleanArgument(BaseArgument):
49
53
  :param name: name of the argument
50
54
  :param prefix: prefix of the argument
51
55
  """
52
- self.name = name
53
- self.prefix = prefix
56
+ self.name: str = name
57
+ self.prefix: Literal["-", "--", "---"] = prefix
54
58
 
55
- def get_string_entity(self):
59
+ @property
60
+ @override
61
+ def string_entity(self) -> str:
56
62
  return self.prefix + self.name
@@ -1,4 +1,4 @@
1
- from argparse import ArgumentParser
1
+ from argparse import ArgumentParser, Namespace
2
2
 
3
3
  from argenta.orchestrator.argparser.arguments.models import (
4
4
  BooleanArgument,
@@ -10,7 +10,7 @@ from argenta.orchestrator.argparser.arguments.models import (
10
10
  class ArgParser:
11
11
  def __init__(
12
12
  self,
13
- processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument],
13
+ processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument], *,
14
14
  name: str = "Argenta",
15
15
  description: str = "Argenta available arguments",
16
16
  epilog: str = "github.com/koloideal/Argenta | made by kolo",
@@ -22,38 +22,18 @@ class ArgParser:
22
22
  :param epilog: the epilog of the ArgParse instance
23
23
  :param processed_args: registered and processed arguments
24
24
  """
25
- self.name = name
26
- self.description = description
27
- self.epilog = epilog
25
+ self._name: str = name
26
+ self._description: str = description
27
+ self._epilog: str = epilog
28
28
 
29
- self.entity: ArgumentParser = ArgumentParser(
30
- prog=name, description=description, epilog=epilog
31
- )
32
- self.args: (
33
- list[PositionalArgument | OptionalArgument | BooleanArgument] | None
34
- ) = processed_args
29
+ self._entity: ArgumentParser = ArgumentParser(prog=name, description=description, epilog=epilog)
30
+ self._processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument] = processed_args
31
+
32
+ for arg in processed_args:
33
+ if isinstance(arg, PositionalArgument) or isinstance(arg, OptionalArgument):
34
+ _ = self._entity.add_argument(arg.string_entity)
35
+ else:
36
+ _ = self._entity.add_argument(arg.string_entity, action="store_true")
35
37
 
36
- def set_args(
37
- self, *args: PositionalArgument | OptionalArgument | BooleanArgument
38
- ) -> None:
39
- """
40
- Public. Sets the arguments to be processed
41
- :param args: processed arguments
42
- :return: None
43
- """
44
- self.args.extend(args)
45
-
46
- def register_args(self) -> None:
47
- """
48
- Private. Registers initialized command line arguments
49
- :return: None
50
- """
51
- if not self.args:
52
- return
53
- for arg in self.args:
54
- if type(arg) is PositionalArgument:
55
- self.entity.add_argument(arg.get_string_entity())
56
- elif type(arg) is OptionalArgument:
57
- self.entity.add_argument(arg.get_string_entity())
58
- elif type(arg) is BooleanArgument:
59
- self.entity.add_argument(arg.get_string_entity(), action="store_true")
38
+ def parse_args(self) -> Namespace:
39
+ return self._entity.parse_args()
@@ -11,12 +11,9 @@ class Orchestrator:
11
11
  :param arg_parser: Cmd argument parser and configurator at startup
12
12
  :return: None
13
13
  """
14
- self.arg_parser: ArgParser | None = arg_parser
15
- if arg_parser:
16
- self.arg_parser.register_args()
14
+ self._arg_parser: ArgParser | None = arg_parser
17
15
 
18
- @staticmethod
19
- def start_polling(app: App) -> None:
16
+ def start_polling(self, app: App) -> None:
20
17
  """
21
18
  Public. Starting the user input processing cycle
22
19
  :param app: a running application
@@ -29,7 +26,7 @@ class Orchestrator:
29
26
  Public. Returns the arguments parsed
30
27
  :return: None
31
28
  """
32
- if self.arg_parser:
33
- return self.arg_parser.entity.parse_args()
29
+ if self._arg_parser:
30
+ return self._arg_parser.parse_args()
34
31
  else:
35
32
  return None
argenta/py.typed ADDED
File without changes
@@ -1,5 +1,5 @@
1
- __all__ = ["Response", "Status"]
1
+ __all__ = ["Response", "ResponseStatus"]
2
2
 
3
3
 
4
4
  from argenta.response.entity import Response
5
- from argenta.response.status import Status
5
+ from argenta.response.status import ResponseStatus
@@ -1,29 +1,23 @@
1
- from argenta.response.status import Status
2
- from argenta.command.flag.flags import (
3
- ValidInputFlags,
4
- UndefinedInputFlags,
5
- InvalidValueInputFlags,
6
- )
1
+ from typing import Literal
2
+ from argenta.command.flag.flags.models import InputFlags
3
+ from argenta.response.status import ResponseStatus
4
+
5
+
6
+ EMPTY_INPUT_FLAGS: InputFlags = InputFlags()
7
7
 
8
8
 
9
9
  class Response:
10
- __slots__ = ("status", "valid_flags", "undefined_flags", "invalid_value_flags")
10
+ __slots__: tuple[Literal['status', 'input_flags'], ...] = ("status", "input_flags")
11
11
 
12
12
  def __init__(
13
13
  self,
14
- status: Status | None = None,
15
- valid_flags: ValidInputFlags = ValidInputFlags(),
16
- undefined_flags: UndefinedInputFlags = UndefinedInputFlags(),
17
- invalid_value_flags: InvalidValueInputFlags = InvalidValueInputFlags(),
14
+ status: ResponseStatus,
15
+ input_flags: InputFlags = EMPTY_INPUT_FLAGS,
18
16
  ):
19
17
  """
20
18
  Public. The entity of the user input sent to the handler
21
19
  :param status: the status of the response
22
- :param valid_flags: valid input flags
23
- :param undefined_flags: undefined input flags
24
- :param invalid_value_flags: input flags with invalid values
20
+ :param input_flags: all input flags
25
21
  """
26
- self.status = status
27
- self.valid_flags = valid_flags
28
- self.undefined_flags = undefined_flags
29
- self.invalid_value_flags = invalid_value_flags
22
+ self.status: ResponseStatus = status
23
+ self.input_flags: InputFlags = input_flags
@@ -1,8 +1,19 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
- class Status(Enum):
4
+ class ResponseStatus(Enum):
5
5
  ALL_FLAGS_VALID = "ALL_FLAGS_VALID"
6
6
  UNDEFINED_FLAGS = "UNDEFINED_FLAGS"
7
7
  INVALID_VALUE_FLAGS = "INVALID_VALUE_FLAGS"
8
8
  UNDEFINED_AND_INVALID_FLAGS = "UNDEFINED_AND_INVALID_FLAGS"
9
+
10
+ @classmethod
11
+ def from_flags(cls, *, has_invalid_value_flags: bool, has_undefined_flags: bool) -> 'ResponseStatus':
12
+ key = (has_invalid_value_flags, has_undefined_flags)
13
+ status_map: dict[tuple[bool, bool], ResponseStatus] = {
14
+ (True, True): cls.UNDEFINED_AND_INVALID_FLAGS,
15
+ (True, False): cls.INVALID_VALUE_FLAGS,
16
+ (False, True): cls.UNDEFINED_FLAGS,
17
+ (False, False): cls.ALL_FLAGS_VALID,
18
+ }
19
+ return status_map[key]
@@ -1,4 +1,4 @@
1
- __all__ = ["Router"]
1
+ from argenta.router.entity import Router
2
2
 
3
3
 
4
- from argenta.router.entity import Router
4
+ __all__ = ["Router"]
@@ -1,18 +1,19 @@
1
- from typing import Callable, Iterator
1
+ from collections.abc import Iterator
2
+ from typing import Callable
2
3
 
3
4
  from argenta.command import Command
4
5
  from argenta.response import Response
5
6
 
6
7
 
7
8
  class CommandHandler:
8
- def __init__(self, handler: Callable[[Response], None], handled_command: Command):
9
+ def __init__(self, handler_as_func: Callable[[Response], None], handled_command: Command):
9
10
  """
10
11
  Private. Entity of the model linking the handler and the command being processed
11
12
  :param handler: the handler being called
12
13
  :param handled_command: the command being processed
13
14
  """
14
- self._handler = handler
15
- self._handled_command = handled_command
15
+ self.handler_as_func: Callable[[Response], None] = handler_as_func
16
+ self.handled_command: Command = handled_command
16
17
 
17
18
  def handling(self, response: Response) -> None:
18
19
  """
@@ -20,21 +21,7 @@ class CommandHandler:
20
21
  :param response: the entity of response: various groups of flags and status of response
21
22
  :return: None
22
23
  """
23
- self._handler(response)
24
-
25
- def get_handler(self) -> Callable[[Response], None]:
26
- """
27
- Private. Returns the handler being called
28
- :return: the handler being called as Callable[[Response], None]
29
- """
30
- return self._handler
31
-
32
- def get_handled_command(self) -> Command:
33
- """
34
- Private. Returns the command being processed
35
- :return: the command being processed as Command
36
- """
37
- return self._handled_command
24
+ self.handler_as_func(response)
38
25
 
39
26
 
40
27
  class CommandHandlers:
@@ -43,14 +30,7 @@ class CommandHandlers:
43
30
  Private. The model that unites all CommandHandler of the routers
44
31
  :param command_handlers: list of CommandHandlers for register
45
32
  """
46
- self.command_handlers = command_handlers if command_handlers else []
47
-
48
- def get_handlers(self) -> list[CommandHandler]:
49
- """
50
- Private. Returns the list of CommandHandlers
51
- :return: the list of CommandHandlers as list[CommandHandler]
52
- """
53
- return self.command_handlers
33
+ self.command_handlers: list[CommandHandler] = command_handlers if command_handlers else []
54
34
 
55
35
  def add_handler(self, command_handler: CommandHandler) -> None:
56
36
  """