diff --git a/justfile b/justfile index 1649082..b13b6a7 100644 --- a/justfile +++ b/justfile @@ -13,6 +13,10 @@ tests: tests-cov: python -m pytest --cov=argenta tests +# Запустить тесты с отчетом о покрытии с html репортом +tests-cov-html: + python -m pytest --cov=argenta tests --cov-report=html + # Отформатировать код (Ruff + isort) format: python -m ruff format ./src diff --git a/mock/local_test.py b/mock/local_test.py index 285a5ec..bfed62e 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -1,2 +1,15 @@ -import sys -print(sys.version_info >= (3, 13)) \ No newline at end of file +from argenta import App, Router, Command, Response + + +app = App(override_system_messages=True) +router = Router() + +@router.command(Command('test', aliases={'alias', 'primer'})) +def handler(res: Response): + pass + +@router.command(Command('test2', aliases={'alias', 'primer'})) +def handler2(res: Response): + pass + +print(router.aliases) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index be694df..eb84794 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,14 @@ line-length=90 [tool.pyright] typeCheckingMode = "strict" +[[tool.pyright.executionEnvironments]] +root = "tests/" +reportPrivateUsage = false +reportUnusedFunction = false + +[tool.coverage.run] +branch = true + [tool.mypy] disable_error_code = "import-untyped" diff --git a/src/argenta/app/models.py b/src/argenta/app/models.py index 328a87d..562a9a4 100644 --- a/src/argenta/app/models.py +++ b/src/argenta/app/models.py @@ -323,7 +323,7 @@ class BaseApp: for router_entity in self.registered_routers: router_triggers = router_entity.triggers router_aliases = router_entity.aliases - combined = router_triggers + router_aliases + combined = router_triggers | router_aliases for trigger in combined: self._matching_default_triggers_with_routers[trigger] = router_entity @@ -331,15 +331,6 @@ class BaseApp: self._autocompleter.initial_setup(list(self._current_matching_triggers_with_routers.keys())) - seen = {} - for item in list(self._current_matching_triggers_with_routers.keys()): - if item in seen: - Console().print( - f"\n[b red]WARNING:[/b red] Overlapping trigger or alias: [b blue]{item}[/b blue]" - ) - else: - seen[item] = True - if not self._override_system_messages: self._setup_default_view() diff --git a/src/argenta/command/models.py b/src/argenta/command/models.py index 1553b35..6290447 100644 --- a/src/argenta/command/models.py +++ b/src/argenta/command/models.py @@ -17,7 +17,7 @@ ParseResult = tuple[str, InputFlags] MIN_FLAG_PREFIX: str = "-" PREFIX_TYPE = Literal["-", "--", "---"] DEFAULT_WITHOUT_FLAGS: Flags = Flags() -DEFAULT_WITHOUT_ALIASES: list[Never] = [] +DEFAULT_WITHOUT_ALIASES: set[Never] = set() DEFAULT_WITHOUT_INPUT_FLAGS: InputFlags = InputFlags() @@ -29,7 +29,7 @@ class Command: *, description: str = "Some useful command", flags: Flag | Flags = DEFAULT_WITHOUT_FLAGS, - aliases: list[str] | list[Never] = DEFAULT_WITHOUT_ALIASES, + aliases: set[str] | set[Never] = DEFAULT_WITHOUT_ALIASES, ): """ Public. The command that can and should be registered in the Router @@ -41,7 +41,7 @@ class Command: self.registered_flags: Flags = flags if isinstance(flags, Flags) else Flags([flags]) self.trigger: str = trigger self.description: str = description - self.aliases: list[str] | list[Never] = aliases + self.aliases: set[str] | set[Never] = aliases def validate_input_flag(self, flag: InputFlag) -> ValidationStatus: """ diff --git a/src/argenta/router/entity.py b/src/argenta/router/entity.py index cb5d5dd..7c3934b 100644 --- a/src/argenta/router/entity.py +++ b/src/argenta/router/entity.py @@ -41,6 +41,9 @@ class Router: self.command_handlers: CommandHandlers = CommandHandlers() self.command_register_ignore: bool = False + + self.aliases: set[str] = set() + self.triggers: set[str] = set() def command(self, command: Command | str) -> Callable[[HandlerFunc], HandlerFunc]: """ @@ -53,7 +56,13 @@ class Router: else: redefined_command = command - _validate_command(redefined_command) + self._validate_command(redefined_command) + + if overlapping := (self.aliases | self.triggers) & command.aliases: + Console().print(f"\n[b red]WARNING:[/b red] Overlapping trigger or alias: [b blue]{overlapping}[/b blue]") + + self.aliases.update(command.aliases) + self.triggers.add(command.trigger) def decorator(func: HandlerFunc) -> HandlerFunc: _validate_func_args(func) @@ -61,6 +70,20 @@ class Router: return func return decorator + + def _validate_command(self, command: Command) -> None: + """ + Private. Validates the command registered in handler + :param command: validated command + :return: None if command is valid else raise exception + """ + command_name: str = command.trigger + if command_name.find(" ") != -1: + raise TriggerContainSpacesException() + flags: Flags = command.registered_flags + flags_name: list[str] = [flag.string_entity.lower() for flag in flags] + if len(set(flags_name)) < len(flags_name): + raise RepeatedFlagNameException() def finds_appropriate_handler(self, input_command: InputCommand) -> None: """ @@ -105,29 +128,6 @@ class Router: response = Response(ResponseStatus.ALL_FLAGS_VALID) command_handler.handling(response) - @property - def triggers(self) -> list[str]: - """ - Public. Gets registered triggers - :return: registered in router triggers as list[str] - """ - all_triggers: list[str] = [] - for command_handler in self.command_handlers: - all_triggers.append(command_handler.handled_command.trigger) - return all_triggers - - @property - def aliases(self) -> list[str]: - """ - Public. Gets registered aliases - :return: registered in router aliases as list[str] - """ - all_aliases: list[str] = [] - for command_handler in self.command_handlers: - if command_handler.handled_command.aliases: - all_aliases.extend(command_handler.handled_command.aliases) - return all_aliases - class CommandDecorator: def __init__(self, router_instance: Router, command: Command): @@ -188,18 +188,4 @@ def _validate_func_args(func: Callable[..., None]) -> None: + f" [i]but[/i] [bold blue]{response_arg_annotation}[/bold blue] [i]is specified[/i]", highlight=False, ) - - -def _validate_command(command: Command) -> None: - """ - Private. Validates the command registered in handler - :param command: validated command - :return: None if command is valid else raise exception - """ - command_name: str = command.trigger - if command_name.find(" ") != -1: - raise TriggerContainSpacesException() - flags: Flags = command.registered_flags - flags_name: list[str] = [flag.string_entity.lower() for flag in flags] - if len(set(flags_name)) < len(flags_name): - raise RepeatedFlagNameException() + \ No newline at end of file diff --git a/tests/unit_tests/test_app.py b/tests/unit_tests/test_app.py index a30dacf..bf382f8 100644 --- a/tests/unit_tests/test_app.py +++ b/tests/unit_tests/test_app.py @@ -1,74 +1,97 @@ -import unittest +from pytest import CaptureFixture from argenta.app import App +from argenta.response import Response from argenta.command.models import Command, InputCommand from argenta.router import Router -class MyTestCase(unittest.TestCase): - def test_is_exit_command1(self): - app = App() - self.assertEqual(app._is_exit_command(InputCommand('q')), True) - - def test_is_exit_command5(self): - app = App() - self.assertEqual(app._is_exit_command(InputCommand('Q')), True) - - def test_is_exit_command2(self): - app = App(ignore_command_register=False) - self.assertEqual(app._is_exit_command(InputCommand('q')), False) - - def test_is_exit_command3(self): - app = App(exit_command=Command('quit')) - self.assertEqual(app._is_exit_command(InputCommand('quit')), True) - - def test_is_exit_command4(self): - app = App(exit_command=Command('quit')) - self.assertEqual(app._is_exit_command(InputCommand('qUIt')), True) - - def test_is_exit_command6(self): - app = App(ignore_command_register=False, - exit_command=Command('quit')) - self.assertEqual(app._is_exit_command(InputCommand('qUIt')), False) - - def test_is_unknown_command1(self): - app = App() - app.set_unknown_command_handler(lambda command: None) - app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()} - self.assertEqual(app._is_unknown_command(InputCommand('fr')), False) - - def test_is_unknown_command2(self): - app = App() - app.set_unknown_command_handler(lambda command: None) - app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()} - self.assertEqual(app._is_unknown_command(InputCommand('cr')), True) - - def test_is_unknown_command3(self): - app = App(ignore_command_register=False) - app.set_unknown_command_handler(lambda command: None) - app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()} - self.assertEqual(app._is_unknown_command(InputCommand('pr')), True) - - def test_is_unknown_command4(self): - app = App(ignore_command_register=False) - app.set_unknown_command_handler(lambda command: None) - app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()} - self.assertEqual(app._is_unknown_command(InputCommand('tW')), False) +def test_is_exit_command1(): + app = App() + assert app._is_exit_command(InputCommand('q')) is True +def test_is_exit_command5(): + app = App() + assert app._is_exit_command(InputCommand('Q')) is True +def test_is_exit_command2(): + app = App(ignore_command_register=False) + assert app._is_exit_command(InputCommand('q')) is False +def test_is_exit_command3(): + app = App(exit_command=Command('quit')) + assert app._is_exit_command(InputCommand('quit')) is True +def test_is_exit_command4(): + app = App(exit_command=Command('quit')) + assert app._is_exit_command(InputCommand('qUIt')) is True +def test_is_exit_command6(): + app = App(ignore_command_register=False, + exit_command=Command('quit')) + assert app._is_exit_command(InputCommand('qUIt')) is False +def test_is_unknown_command1(): + app = App() + app.set_unknown_command_handler(lambda command: None) + app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()} + assert app._is_unknown_command(InputCommand('fr')) is False +def test_is_unknown_command2(): + app = App() + app.set_unknown_command_handler(lambda command: None) + app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()} + assert app._is_unknown_command(InputCommand('cr')) is True + +def test_is_unknown_command3(): + app = App(ignore_command_register=False) + app.set_unknown_command_handler(lambda command: None) + app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()} + assert app._is_unknown_command(InputCommand('pr')) is True +def test_is_unknown_command4(): + app = App(ignore_command_register=False) + app.set_unknown_command_handler(lambda command: None) + app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()} + assert app._is_unknown_command(InputCommand('tW')) is False + +def test_add_messages_on_startup(): + app = App() + app.add_message_on_startup('Some message') + assert app._messages_on_startup == ['Some message'] + +def test_include_routers(): + app = App() + router = Router() + router2 = Router() + app.include_routers(router, router2) + + assert app.registered_routers.registered_routers == [router, router2] + +def test_overlapping_aliases(capsys: CaptureFixture[str]): + app = App(override_system_messages=True) + router = Router() + + @router.command(Command('test', aliases=['alias'])) + def handler(res: Response): + pass + + @router.command(Command('test2', aliases=['alias'])) + def handler2(res: Response): + pass + app.include_routers(router) + app._pre_cycle_setup() + + captured = capsys.readouterr() + + assert "Overlapping" in captured.out diff --git a/tests/unit_tests/test_dividing_line.py b/tests/unit_tests/test_dividing_line.py index 2496d8d..151fd2a 100644 --- a/tests/unit_tests/test_dividing_line.py +++ b/tests/unit_tests/test_dividing_line.py @@ -1,21 +1,36 @@ -import unittest - from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine -class TestDividingLine(unittest.TestCase): - def test_get_static_dividing_line_full_line(self): - line = StaticDividingLine('-') - self.assertEqual(line.get_full_static_line(is_override=True).count('-'), 25) +def test_get_static_dividing_line_full_line(): + line = StaticDividingLine('-') + assert line.get_full_static_line(is_override=True).count('-') == 25 + +def test_get_static_dividing_line2_full_line(): + line = StaticDividingLine('-', length=5) + assert line.get_full_static_line(is_override=False) == '\n[dim]-----[/dim]\n' + +def test_get_dividing_line_unit_part(): + line = StaticDividingLine('') + assert line.get_unit_part() == ' ' - def test_get_dynamic_dividing_line_full_line(self): - line = DynamicDividingLine() - self.assertEqual(line.get_full_dynamic_line(length=20, is_override=True).count('-'), 20) +def test_get_dividing_line2_unit_part(): + line = StaticDividingLine('+-0987654321!@#$%^&*()_') + assert line.get_unit_part() == '+' + +def test_get_dynamic_dividing_line_full_line(): + line = DynamicDividingLine() + assert line.get_full_dynamic_line(length=20, is_override=True).count('-') == 20 + +def test_get_dynamic_dividing_line2_full_line(): + line = DynamicDividingLine() + assert line.get_full_dynamic_line(length=5, is_override=False) == '\n[dim]-----[/dim]\n' + +def test_get_dynamic_dividing_line_unit_part(): + line = DynamicDividingLine('') + assert line.get_unit_part() == ' ' + +def test_get_dynamic_dividing_line2_unit_part(): + line = DynamicDividingLine('45n352834528&^%@&*T$G') + assert line.get_unit_part() == '4' - def test_get_dividing_line_unit_part(self): - line = StaticDividingLine('') - self.assertEqual(line.get_unit_part(), ' ') - def test_get_dividing_line2_unit_part(self): - line = StaticDividingLine('+-0987654321!@#$%^&*()_') - self.assertEqual(line.get_unit_part(), '+') diff --git a/tests/unit_tests/test_router.py b/tests/unit_tests/test_router.py index 95ea8e9..073edea 100644 --- a/tests/unit_tests/test_router.py +++ b/tests/unit_tests/test_router.py @@ -1,5 +1,5 @@ import re -import unittest +import pytest from argenta.command import Command from argenta.command.flag import Flag, InputFlag @@ -7,97 +7,98 @@ from argenta.command.flag.flags import Flags, InputFlags from argenta.command.flag.models import PossibleValues, ValidationStatus from argenta.response.entity import Response from argenta.router import Router -from argenta.router.entity import _structuring_input_flags, _validate_command, _validate_func_args # pyright: ignore[reportPrivateUsage] +from argenta.router.entity import _structuring_input_flags, _validate_func_args # pyright: ignore[reportPrivateUsage] from argenta.router.exceptions import (RepeatedFlagNameException, RequiredArgumentNotPassedException, TriggerContainSpacesException) -class TestRouter(unittest.TestCase): - def test_register_command_with_spaces_in_trigger(self): - with self.assertRaises(TriggerContainSpacesException): - _validate_command(Command(trigger='command with spaces')) +def test_register_command_with_spaces_in_trigger(): + router = Router() + with pytest.raises(TriggerContainSpacesException): + router._validate_command(Command(trigger='command with spaces')) - def test_register_command_with_repeated_flags(self): - with self.assertRaises(RepeatedFlagNameException): - _validate_command(Command(trigger='command', flags=Flags([Flag('test'), Flag('test')]))) +def test_register_command_with_repeated_flags(): + router = Router() + with pytest.raises(RepeatedFlagNameException): + router._validate_command(Command(trigger='command', flags=Flags([Flag('test'), Flag('test')]))) - def test_structuring_input_flags1(self): - cmd = Command('cmd') - input_flags = InputFlags([InputFlag('ssh', input_value=None, status=None)]) - self.assertEqual(_structuring_input_flags(cmd, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value=None, status=ValidationStatus.UNDEFINED)])) +def test_structuring_input_flags1(): + cmd = Command('cmd') + input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)]) + assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.UNDEFINED)]) - def test_structuring_input_flags2(self): - cmd = Command('cmd') - input_flags = InputFlags([InputFlag('ssh', input_value='some', status=None)]) - self.assertEqual(_structuring_input_flags(cmd, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='some', status=ValidationStatus.UNDEFINED)])) +def test_structuring_input_flags2(): + cmd = Command('cmd') + input_flags = InputFlags([InputFlag('ssh', input_value='some', status=None)]) + assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some', status=ValidationStatus.UNDEFINED)]) - def test_structuring_input_flags3(self): - cmd = Command('cmd', flags=Flag('port')) - input_flags = InputFlags([InputFlag('ssh', input_value='some2', status=None)]) - self.assertEqual(_structuring_input_flags(cmd, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='some2', status=ValidationStatus.UNDEFINED)])) +def test_structuring_input_flags3(): + cmd = Command('cmd', flags=Flag('port')) + input_flags = InputFlags([InputFlag('ssh', input_value='some2', status=None)]) + assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some2', status=ValidationStatus.UNDEFINED)]) - def test_structuring_input_flags4(self): - command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) - input_flags = InputFlags([InputFlag('ssh', input_value='some3', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='some3', status=ValidationStatus.INVALID)])) +def test_structuring_input_flags4(): + command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) + input_flags = InputFlags([InputFlag('ssh', input_value='some3', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some3', status=ValidationStatus.INVALID)]) - def test_structuring_input_flags5(self): - command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$'))) - input_flags = InputFlags([InputFlag('ssh', input_value='some40', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='some40', status=ValidationStatus.INVALID)])) +def test_structuring_input_flags5(): + command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$'))) + input_flags = InputFlags([InputFlag('ssh', input_value='some40', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some40', status=ValidationStatus.INVALID)]) - def test_structuring_input_flags6(self): - command = Command('cmd', flags=Flag('ssh', possible_values=['example'])) - input_flags = InputFlags([InputFlag('ssh', input_value='example2', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='example2', status=ValidationStatus.INVALID)])) +def test_structuring_input_flags6(): + command = Command('cmd', flags=Flag('ssh', possible_values=['example'])) + input_flags = InputFlags([InputFlag('ssh', input_value='example2', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='example2', status=ValidationStatus.INVALID)]) - def test_structuring_input_flags7(self): - command = Command('cmd', flags=Flag('port')) - input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)])) +def test_structuring_input_flags7(): + command = Command('cmd', flags=Flag('port')) + input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)]) - def test_structuring_input_flags8(self): - command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3'])) - input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)])) +def test_structuring_input_flags8(): + command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3'])) + input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)]) - def test_structuring_input_flags9(self): - command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$'))) - input_flags = InputFlags([InputFlag('ssh', input_value='more5', status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value='more5', status=ValidationStatus.VALID)])) +def test_structuring_input_flags9(): + command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$'))) + input_flags = InputFlags([InputFlag('ssh', input_value='more5', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='more5', status=ValidationStatus.VALID)]) - def test_structuring_input_flags10(self): - command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) - input_flags = InputFlags([InputFlag('ssh', input_value=None, status=None)]) - self.assertEqual(_structuring_input_flags(command, input_flags).input_flags, InputFlags([InputFlag('ssh', input_value=None, status=ValidationStatus.VALID)])) +def test_structuring_input_flags10(): + command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) + input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)]) + assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.VALID)]) - def test_validate_incorrect_func_args1(self): - def handler(): - pass - with self.assertRaises(RequiredArgumentNotPassedException): - _validate_func_args(handler) # pyright: ignore[reportArgumentType] +def test_validate_incorrect_func_args1(): + def handler(): + pass + with pytest.raises(RequiredArgumentNotPassedException): + _validate_func_args(handler) # pyright: ignore[reportArgumentType] - def test_get_router_aliases(self): - router = Router() - @router.command(Command('some', aliases=['test', 'case'])) - def handler(response: Response) -> None: # pyright: ignore[reportUnusedFunction] - pass - self.assertListEqual(router.aliases, ['test', 'case']) +def test_get_router_aliases(): + router = Router() + @router.command(Command('some', aliases={'test', 'case'})) + def handler(response: Response) -> None: + pass + assert router.aliases == {'test', 'case'} - def test_get_router_aliases2(self): - router = Router() - @router.command(Command('some', aliases=['test', 'case'])) - def handler(response: Response): # pyright: ignore[reportUnusedFunction] - pass - @router.command(Command('ext', aliases=['more', 'foo'])) - def handler2(response: Response): # pyright: ignore[reportUnusedFunction] - pass - self.assertListEqual(router.aliases, ['test', 'case', 'more', 'foo']) +def test_get_router_aliases2(): + router = Router() + @router.command(Command('some', aliases={'test', 'case'})) + def handler(response: Response): + pass + @router.command(Command('ext', aliases={'more', 'foo'})) + def handler2(response: Response): + pass + assert router.aliases == {'test', 'case', 'more', 'foo'} - def test_get_router_aliases3(self): - router = Router() - @router.command(Command('some')) - def handler(response: Response): # pyright: ignore[reportUnusedFunction] - pass - self.assertListEqual(router.aliases, []) +def test_get_router_aliases3(): + router = Router() + @router.command(Command('some')) + def handler(response: Response): + pass + assert router.aliases == set()