diff --git a/mock/local_test.py b/mock/local_test.py index bfed62e..e526fdf 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -1,15 +1,5 @@ -from argenta import App, Router, Command, Response +from argenta import App - -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 +app = App() +app._setup_default_view() +app._empty_input_command_handler() \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index eb84794..6e1f23e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,10 @@ reportUnusedFunction = false [tool.coverage.run] branch = true +omit = [ + "src/argenta/app/protocols.py", + "src/argenta/command/exceptions.py" +] [tool.mypy] disable_error_code = "import-untyped" diff --git a/src/argenta/app/models.py b/src/argenta/app/models.py index c1d76a8..af50cb1 100644 --- a/src/argenta/app/models.py +++ b/src/argenta/app/models.py @@ -19,7 +19,6 @@ from argenta.app.protocols import ( ) from argenta.app.registered_routers.entity import RegisteredRouters from argenta.command.exceptions import ( - EmptyInputCommandException, InputCommandException, RepeatedInputFlagsException, UnprocessedInputFlagException, @@ -40,7 +39,7 @@ class BaseApp: initial_message: str, farewell_message: str, exit_command: Command, - system_router_title: str | None, + system_router_title: str, ignore_command_register: bool, dividing_line: StaticDividingLine | DynamicDividingLine, repeat_command_groups_printing: bool, @@ -51,7 +50,7 @@ class BaseApp: self._prompt: str = prompt self._print_func: Printer = print_func self._exit_command: Command = exit_command - self._system_router_title: str | None = system_router_title + self._system_router_title: str = system_router_title self._dividing_line: StaticDividingLine | DynamicDividingLine = dividing_line self._ignore_command_register: bool = ignore_command_register self._repeat_command_groups_printing_description: bool = repeat_command_groups_printing @@ -144,8 +143,7 @@ class BaseApp: :return: None """ for registered_router in self.registered_routers: - if registered_router.title: - self._print_func(registered_router.title) + self._print_func(registered_router.title) for command_handler in registered_router.command_handlers: handled_command = command_handler.handled_command self._print_func( @@ -239,7 +237,7 @@ class BaseApp: self._incorrect_input_syntax_handler(raw_command) elif isinstance(error, RepeatedInputFlagsException): self._repeated_input_flags_handler(raw_command) - elif isinstance(error, EmptyInputCommandException): + else: self._empty_input_command_handler() def _setup_system_router(self) -> None: @@ -253,9 +251,8 @@ class BaseApp: def _(response: Response) -> None: self._exit_command_handler(response) - if system_router not in self.registered_routers.registered_routers: - system_router.command_register_ignore = self._ignore_command_register - self.registered_routers.add_registered_router(system_router) + system_router.command_register_ignore = self._ignore_command_register + self.registered_routers.add_registered_router(system_router) def _most_similar_command(self, unknown_command: str) -> str | None: all_commands = list(self._current_matching_triggers_with_routers.keys()) @@ -342,6 +339,28 @@ class BaseApp: print("\n") if not self._repeat_command_groups_printing_description: self._print_command_group_description() + + def _process_exist_and_valid_command(self, input_command: InputCommand): + processing_router = self._current_matching_triggers_with_routers[input_command.trigger.lower()] + + if processing_router.disable_redirect_stdout: + dividing_line_unit_part: str = self._dividing_line.get_unit_part() + self._print_func( + StaticDividingLine(dividing_line_unit_part).get_full_static_line( + is_override=self._override_system_messages + ) + ) + processing_router.finds_appropriate_handler(input_command) + self._print_func( + StaticDividingLine(dividing_line_unit_part).get_full_static_line( + is_override=self._override_system_messages + ) + ) + else: + with redirect_stdout(io.StringIO()) as stdout: + processing_router.finds_appropriate_handler(input_command) + stdout_result: str = stdout.getvalue() + self._print_framed_text(stdout_result) AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine @@ -360,7 +379,7 @@ class App(BaseApp): initial_message: str = "Argenta\n", farewell_message: str = "\nSee you\n", exit_command: Command = DEFAULT_EXIT_COMMAND, - system_router_title: str | None = "System points:", + system_router_title: str = "System points:", ignore_command_register: bool = True, dividing_line: AVAILABLE_DIVIDING_LINES = DEFAULT_DIVIDING_LINE, repeat_command_groups_printing: bool = False, @@ -433,27 +452,7 @@ class App(BaseApp): self._print_framed_text(stdout_res) continue - processing_router = self._current_matching_triggers_with_routers[input_command.trigger.lower()] - - if processing_router.disable_redirect_stdout: - dividing_line_unit_part: str = self._dividing_line.get_unit_part() - self._print_func( - StaticDividingLine(dividing_line_unit_part).get_full_static_line( - is_override=self._override_system_messages - ) - ) - processing_router.finds_appropriate_handler(input_command) - self._print_func( - StaticDividingLine(dividing_line_unit_part).get_full_static_line( - is_override=self._override_system_messages - ) - ) - else: - with redirect_stdout(io.StringIO()) as stdout: - processing_router.finds_appropriate_handler(input_command) - stdout_result: str = stdout.getvalue() - if stdout_result: - self._print_framed_text(stdout_result) + self._process_exist_and_valid_command(input_command) def include_router(self, router: Router) -> None: """ diff --git a/src/argenta/app/protocols.py b/src/argenta/app/protocols.py index 8300be5..530b520 100644 --- a/src/argenta/app/protocols.py +++ b/src/argenta/app/protocols.py @@ -2,11 +2,12 @@ __all__ = ["NonStandardBehaviorHandler", "EmptyCommandHandler", "Printer", "Desc from typing import Protocol, TypeVar + T = TypeVar("T", contravariant=True) # noqa: WPS111 class NonStandardBehaviorHandler(Protocol[T]): - def __call__(self, __param: T) -> None: + def __call__(self, _param: T, /) -> None: raise NotImplementedError @@ -16,10 +17,10 @@ class EmptyCommandHandler(Protocol): class Printer(Protocol): - def __call__(self, __text: str) -> None: + def __call__(self, _text: str, /) -> None: raise NotImplementedError class DescriptionMessageGenerator(Protocol): - def __call__(self, __first_param: str, __second_param: str) -> str: + def __call__(self, _command: str, _description: str, /) -> str: raise NotImplementedError diff --git a/src/argenta/app/registered_routers/entity.py b/src/argenta/app/registered_routers/entity.py index 2212389..366676e 100644 --- a/src/argenta/app/registered_routers/entity.py +++ b/src/argenta/app/registered_routers/entity.py @@ -24,6 +24,3 @@ class RegisteredRouters: def __iter__(self) -> Iterator[Router]: return iter(self.registered_routers) - - def __next__(self) -> Router: - return next(iter(self.registered_routers)) diff --git a/src/argenta/router/entity.py b/src/argenta/router/entity.py index 972bf1d..fa9a5ea 100644 --- a/src/argenta/router/entity.py +++ b/src/argenta/router/entity.py @@ -22,7 +22,7 @@ HandlerFunc: TypeAlias = Callable[..., None] class Router: def __init__( self, - title: str | None = "Default title", + title: str = "Default title", *, disable_redirect_stdout: bool = False, ): @@ -36,7 +36,7 @@ class Router: which is ambiguous behavior and can lead to unexpected work :return: None """ - self.title: str | None = title + self.title: str = title self.disable_redirect_stdout: bool = disable_redirect_stdout self.command_handlers: CommandHandlers = CommandHandlers() diff --git a/tests/system_tests/test_system_handling_normal_behavior.py b/tests/system_tests/test_system_handling_normal_behavior.py index 3ebc80d..92ade73 100644 --- a/tests/system_tests/test_system_handling_normal_behavior.py +++ b/tests/system_tests/test_system_handling_normal_behavior.py @@ -99,8 +99,11 @@ class TestSystemHandlerNormalWork(PatchedArgvTestCase): if valid_flag and valid_flag.status == ValidationStatus.VALID: print(f'flag value for {valid_flag.name} flag : {valid_flag.input_value}') - app = App(override_system_messages=True, - print_func=print) + app = App( + override_system_messages=True, + repeat_command_groups_printing=True, + print_func=print + ) app.include_router(router) orchestrator.start_polling(app) diff --git a/tests/unit_tests/test_app.py b/tests/unit_tests/test_app.py index a6249ec..7e88545 100644 --- a/tests/unit_tests/test_app.py +++ b/tests/unit_tests/test_app.py @@ -131,7 +131,7 @@ def test_print_framed_text3(capsys: CaptureFixture[str]): assert '\n--------------\n\nsome long test\n\n--------------\n' in captured.out -def test_print_framed_text4(capsys: CaptureFixture[str]): +def test_print_framed_text4(): class OtherDividingLine: pass @@ -211,7 +211,7 @@ def test_most_similiar_command4(): assert app._most_similar_command('nonexists') is None -def test_most_similiar_command3(): +def test_most_similiar_command5(): app = App(override_system_messages=True) router = Router() @@ -230,7 +230,7 @@ def test_most_similiar_command3(): def test_app_set_description_message_gen(): app = App() - descr_gen: DescriptionMessageGenerator = lambda command, description: print(command + '-+-' + description) + descr_gen: DescriptionMessageGenerator = lambda command, description: command + '-+-' + description app.set_description_message_pattern(descr_gen) assert app._description_message_gen is descr_gen @@ -242,3 +242,55 @@ def test_app_set_exit_handler(): assert app._exit_command_handler is handler +def test_app_is_exit_command(): + app = App(exit_command=Command('q', aliases={'exit'})) + assert app._is_exit_command(InputCommand('exit')) is True + +def test_app_is_exit_command2(): + app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False) + assert app._is_exit_command(InputCommand('exit')) is True + +def test_app_is_exit_command3(): + app = App(exit_command=Command('q', aliases={'exit'})) + assert app._is_exit_command(InputCommand('quit')) is False + +def test_app_is_exit_command4(): + app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False) + assert app._is_exit_command(InputCommand('Exit')) is False + +def test_app_setup_default_view(): + app = App(prompt='>>') + app._setup_default_view() + + assert app._prompt == '[italic dim bold]>>' + +def test_app_setup_default_view2(): + app = App() + app._setup_default_view() + assert app._unknown_command_handler(InputCommand('nonexists')) is None + +def test_app_pre_cycle_setup(capsys: CaptureFixture[str]): + app = App() + app.add_message_on_startup('some message') + app._pre_cycle_setup() + stdout = capsys.readouterr() + + assert 'some message' in stdout.out + +def test_app_with_router_with_disable_redirect_stdout(capsys: CaptureFixture[str]): + app = App(repeat_command_groups_printing=True) + router = Router(disable_redirect_stdout=True) + + @router.command('command') + def handler(res: Response): + print("Hello!") + + app.include_router(router) + + app._pre_cycle_setup() + app._process_exist_and_valid_command(InputCommand('command')) + + stdout = capsys.readouterr() + + assert 'Hello!' in stdout.out +