From fd287c5da0fbd3f087fcf3647d6b5160d922e330 Mon Sep 17 00:00:00 2001 From: kolo Date: Tue, 20 May 2025 22:44:47 +0300 Subject: [PATCH] fix type hints with ty help, add ability to configure stdout capture when handling input by the router --- README.de.md | 1 - README.md | 1 - README.ru.md | 1 - mock/local_test.py | 11 ++--- mock/mock_app/routers.py | 2 +- pyproject.toml | 7 +--- src/argenta/app/autocompleter/entity.py | 2 +- src/argenta/app/models.py | 31 ++++++++------ src/argenta/app/registered_routers/entity.py | 2 +- src/argenta/command/flag/models.py | 2 +- src/argenta/command/models.py | 17 ++++---- src/argenta/orchestrator/entity.py | 4 +- src/argenta/response/entity.py | 2 +- src/argenta/router/command_handler/entity.py | 2 +- src/argenta/router/entity.py | 44 +++++++++----------- 15 files changed, 59 insertions(+), 70 deletions(-) diff --git a/README.de.md b/README.de.md index 8fc0c00..dccf1a9 100644 --- a/README.de.md +++ b/README.de.md @@ -58,7 +58,6 @@ if __name__ == '__main__': # Funktionen in der Entwicklung - Vollständige Unterstützung für Autocompleter unter Linux -- Möglichkeit zur Konfiguration der Standardausgabeerfassung bei der Verarbeitung von Eingaben durch den Handler ## Vollständige [Dokumentation](https://argenta-docs.vercel.app) | MIT 2025 kolo | made by [kolo](https://t.me/kolo_id) diff --git a/README.md b/README.md index 8386fb3..6d12941 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ if __name__ == '__main__': # Features in development - Full support for autocompleter on Linux -- Ability to configure stdout capture when handling input by the handler ## Full [docs](https://argenta-docs.vercel.app) | MIT 2025 kolo | made by [kolo](https://t.me/kolo_id) diff --git a/README.ru.md b/README.ru.md index b5f83a5..224777d 100644 --- a/README.ru.md +++ b/README.ru.md @@ -58,7 +58,6 @@ if __name__ == '__main__': # Фичи в разработке - Полноценная поддержка автокомплитера на Linux -- Возможность настройки захвата stdout при обработке хэндлером ввода ## Полная [документация](https://argenta-docs.vercel.app) | MIT 2025 kolo | made by [kolo](https://t.me/kolo_id) diff --git a/mock/local_test.py b/mock/local_test.py index d4bf4f7..741b5eb 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -10,19 +10,16 @@ from argenta.orchestrator import Orchestrator router = Router() -for i in range(10000): - trigger = f"cmd{i}" - - @router.command(Command(trigger, aliases=[f'dfs{i}'])) - def handler(response: Response): - print(response.status) +@router.command(Command('case are')) +def handler(response: Response): + print(response.status) app = App(repeat_command_groups=False) app.include_router(router) -print(get_time_of_pre_cycle_setup(app)) +app.run_polling() diff --git a/mock/mock_app/routers.py b/mock/mock_app/routers.py index 4dc0d28..6f83e99 100644 --- a/mock/mock_app/routers.py +++ b/mock/mock_app/routers.py @@ -21,7 +21,7 @@ console = Console() ) ) def command_help(response: Response): - case = input('test') + case = input('test > ') print(case) print(response.status) print(response.undefined_flags.get_flags()) diff --git a/pyproject.toml b/pyproject.toml index 5ff4dda..68d24a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "argenta" -version = "1.0.5" +version = "1.0.6" description = "Python library for building modular CLI applications" authors = [{ name = "kolo", email = "kolo.is.main@gmail.com" }] requires-python = ">=3.8" @@ -26,8 +26,3 @@ exclude = [ requires = ["hatchling"] build-backend = "hatchling.build" -[dependency-groups] -dev = [ - "pandas>=2.0.3", -] - diff --git a/src/argenta/app/autocompleter/entity.py b/src/argenta/app/autocompleter/entity.py index 96ba16b..185d4cc 100644 --- a/src/argenta/app/autocompleter/entity.py +++ b/src/argenta/app/autocompleter/entity.py @@ -5,7 +5,7 @@ from typing import Never class AutoCompleter: def __init__( - self, history_filename: str = False, autocomplete_button: str = "tab" + self, history_filename: str | None = None, autocomplete_button: str = "tab" ) -> None: """ Public. Configures and implements auto-completion of input command diff --git a/src/argenta/app/models.py b/src/argenta/app/models.py index e0cac01..7d15d03 100644 --- a/src/argenta/app/models.py +++ b/src/argenta/app/models.py @@ -208,13 +208,12 @@ class BaseApp: :param raw_command: the raw input command :return: None """ - match error: - case UnprocessedInputFlagException(): - self._incorrect_input_syntax_handler(raw_command) - case RepeatedInputFlagsException(): - self._repeated_input_flags_handler(raw_command) - case EmptyInputCommandException(): - self._empty_input_command_handler() + if isinstance(error, UnprocessedInputFlagException): + self._incorrect_input_syntax_handler(raw_command) + elif isinstance(error, RepeatedInputFlagsException): + self._repeated_input_flags_handler(raw_command) + elif isinstance(error, EmptyInputCommandException): + self._empty_input_command_handler() def _setup_system_router(self) -> None: """ @@ -258,11 +257,11 @@ class BaseApp: """ self._prompt = "[italic dim bold]What do you want to do?\n" self._initial_message = ( - f"\n[bold red]{text2art(self._initial_message, font='tarty1')}\n" + "\n"+f"[bold red]{text2art(self._initial_message, font='tarty1')}"+"\n" ) self._farewell_message = ( - f"[bold red]\n{text2art(f'\n{self._farewell_message}\n', font='chanky')}[/bold red]\n" - f"[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n" + "[bold red]\n\n"+text2art(self._farewell_message, font='chanky')+"\n[/bold red]\n" + "[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n" ) self._description_message_gen = lambda command, description: ( f"[bold red]{escape('[' + command + ']')}[/bold red] " @@ -425,12 +424,20 @@ class App(BaseApp): for registered_router in self._registered_routers: if registered_router.disable_redirect_stdout: - registered_router.finds_appropriate_handler(input_command) + if isinstance(self._dividing_line, StaticDividingLine): + self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages)) + registered_router.finds_appropriate_handler(input_command) + self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages)) + else: + self._print_func(StaticDividingLine(self._dividing_line.get_unit_part()).get_full_static_line(self._override_system_messages)) + registered_router.finds_appropriate_handler(input_command) + self._print_func(StaticDividingLine(self._dividing_line.get_unit_part()).get_full_static_line(self._override_system_messages)) else: with redirect_stdout(io.StringIO()) as f: registered_router.finds_appropriate_handler(input_command) res: str = f.getvalue() - self._print_framed_text(res) + if res: + self._print_framed_text(res) def include_router(self, router: Router) -> None: """ diff --git a/src/argenta/app/registered_routers/entity.py b/src/argenta/app/registered_routers/entity.py index 581a716..2070e2a 100644 --- a/src/argenta/app/registered_routers/entity.py +++ b/src/argenta/app/registered_routers/entity.py @@ -4,7 +4,7 @@ from argenta.router import Router class RegisteredRouters: - def __init__(self, registered_routers: list[Router] = None) -> None: + def __init__(self, registered_routers: list[Router] | None = None) -> None: """ Private. Combines registered routers :param registered_routers: list of the registered routers diff --git a/src/argenta/command/flag/models.py b/src/argenta/command/flag/models.py index 5e880f7..4e0f79d 100644 --- a/src/argenta/command/flag/models.py +++ b/src/argenta/command/flag/models.py @@ -87,7 +87,7 @@ class Flag(BaseFlag): class InputFlag(BaseFlag): def __init__( - self, name: str, prefix: Literal["-", "--", "---"] = "--", value: str = None + self, name: str, prefix: Literal["-", "--", "---"] = "--", value: str | None = None ): """ Public. The entity of the flag of the entered command diff --git a/src/argenta/command/models.py b/src/argenta/command/models.py index eb8dd5f..1e83c82 100644 --- a/src/argenta/command/models.py +++ b/src/argenta/command/models.py @@ -5,10 +5,7 @@ from argenta.command.exceptions import ( RepeatedInputFlagsException, EmptyInputCommandException, ) -from typing import Generic, TypeVar, cast, Literal - - -InputCommandType = TypeVar("InputCommandType") +from typing import cast, Literal class BaseCommand: @@ -31,9 +28,9 @@ class Command(BaseCommand): def __init__( self, trigger: str, - description: str = None, - flags: Flag | Flags = None, - aliases: list[str] = None, + description: str | None = None, + flags: Flag | Flags | None = None, + aliases: list[str] | None = None, ): """ Public. The command that can and should be registered in the Router @@ -109,8 +106,8 @@ class Command(BaseCommand): return self._description -class InputCommand(BaseCommand, Generic[InputCommandType]): - def __init__(self, trigger: str, input_flags: InputFlag | InputFlags = None): +class InputCommand(BaseCommand): + def __init__(self, trigger: str, input_flags: InputFlag | InputFlags | None = None): """ Private. The model of the input command, after parsing :param trigger:the trigger of the command @@ -142,7 +139,7 @@ class InputCommand(BaseCommand, Generic[InputCommandType]): return self._input_flags @staticmethod - def parse(raw_command: str) -> InputCommandType: + def parse(raw_command: str) -> 'InputCommand': """ Private. Parse the raw input command :param raw_command: raw input command diff --git a/src/argenta/orchestrator/entity.py b/src/argenta/orchestrator/entity.py index 0196724..edbc952 100644 --- a/src/argenta/orchestrator/entity.py +++ b/src/argenta/orchestrator/entity.py @@ -5,13 +5,13 @@ from argenta.orchestrator.argparser import ArgParser class Orchestrator: - def __init__(self, arg_parser: ArgParser = False): + def __init__(self, arg_parser: ArgParser | None = None): """ Public. An orchestrator and configurator that defines the behavior of an integrated system, one level higher than the App :param arg_parser: Cmd argument parser and configurator at startup :return: None """ - self.arg_parser: ArgParser | False = arg_parser + self.arg_parser: ArgParser | None = arg_parser if arg_parser: self.arg_parser.register_args() diff --git a/src/argenta/response/entity.py b/src/argenta/response/entity.py index e04511c..b94eac0 100644 --- a/src/argenta/response/entity.py +++ b/src/argenta/response/entity.py @@ -11,7 +11,7 @@ class Response: def __init__( self, - status: Status = None, + status: Status | None = None, valid_flags: ValidInputFlags = ValidInputFlags(), undefined_flags: UndefinedInputFlags = UndefinedInputFlags(), invalid_value_flags: InvalidValueInputFlags = InvalidValueInputFlags(), diff --git a/src/argenta/router/command_handler/entity.py b/src/argenta/router/command_handler/entity.py index af3d95e..1b5519e 100644 --- a/src/argenta/router/command_handler/entity.py +++ b/src/argenta/router/command_handler/entity.py @@ -38,7 +38,7 @@ class CommandHandler: class CommandHandlers: - def __init__(self, command_handlers: list[CommandHandler] = None): + def __init__(self, command_handlers: list[CommandHandler] | None = None): """ Private. The model that unites all CommandHandler of the routers :param command_handlers: list of CommandHandlers for register diff --git a/src/argenta/router/entity.py b/src/argenta/router/entity.py index b0b4ae9..d4b6bf3 100644 --- a/src/argenta/router/entity.py +++ b/src/argenta/router/entity.py @@ -45,13 +45,15 @@ class Router: :param command: Registered command :return: decorated handler as Callable """ - self._validate_command(command) if isinstance(command, str): - command = Command(command) + redefined_command = Command(command) + else: + redefined_command = command + self._validate_command(redefined_command) def command_decorator(func): Router._validate_func_args(func) - self._command_handlers.add_handler(CommandHandler(func, command)) + self._command_handlers.add_handler(CommandHandler(func, redefined_command)) def wrapper(*args, **kwargs): return func(*args, **kwargs) @@ -123,13 +125,12 @@ class Router: flag_status: Literal["Undefined", "Valid", "Invalid"] = ( handled_command.validate_input_flag(flag) ) - match flag_status: - case "Valid": - valid_input_flags.add_flag(flag) - case "Undefined": - undefined_input_flags.add_flag(flag) - case "Invalid": - invalid_value_input_flags.add_flag(flag) + if flag_status == "Valid": + valid_input_flags.add_flag(flag) + elif flag_status == "Undefined": + undefined_input_flags.add_flag(flag) + elif flag_status == "Invalid": + invalid_value_input_flags.add_flag(flag) if ( not invalid_value_input_flags.get_flags() @@ -163,19 +164,14 @@ class Router: :param command: validated command :return: None if command is valid else raise exception """ - match type(command).__name__: - case "Command": - command_name: str = command.get_trigger() - if command_name.find(" ") != -1: - raise TriggerContainSpacesException() - flags: Flags = command.get_registered_flags() - if flags: - flags_name: list = [x.get_string_entity().lower() for x in flags] - if len(set(flags_name)) < len(flags_name): - raise RepeatedFlagNameException() - case "str": - if command.find(" ") != -1: - raise TriggerContainSpacesException() + command_name: str = command.get_trigger() + if command_name.find(" ") != -1: + raise TriggerContainSpacesException() + flags: Flags = command.get_registered_flags() + if flags: + flags_name: list = [x.get_string_entity().lower() for x in flags] + if len(set(flags_name)) < len(flags_name): + raise RepeatedFlagNameException() @staticmethod def _validate_func_args(func: Callable) -> None: @@ -197,7 +193,7 @@ class Router: if arg_annotation is Response: pass else: - file_path: str = getsourcefile(func) + file_path: str | None = getsourcefile(func) source_line: int = getsourcelines(func)[1] fprint = Console().print fprint(f'\nFile "{file_path}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '