From 04d3329572b9e2b225bae5925b5f086191f5ac73 Mon Sep 17 00:00:00 2001 From: kolo Date: Fri, 11 Apr 2025 13:12:44 +0300 Subject: [PATCH] 0.5.0-beta --- README.md | 46 ++++++++++++++----- argenta/app/autocompleter/entity.py | 1 - argenta/app/models.py | 16 +++---- mock/local_test.py | 18 +++++--- mock/mock_app/handlers/routers.py | 2 +- mock/mock_app/main.py | 3 +- pyproject.toml | 2 +- ...t_system_handling_non_standard_behavior.py | 31 +++++++++---- .../test_system_handling_normal_behavior.py | 35 +++++++++----- tests/unit_tests/test_dividing_line.py | 21 +++++++++ 10 files changed, 122 insertions(+), 53 deletions(-) create mode 100644 tests/unit_tests/test_dividing_line.py diff --git a/README.md b/README.md index 8622ec2..584abbb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +from argenta.app.autocompleter import AutoCompleter + # Argenta --- @@ -5,7 +7,7 @@ ## Описание **Argenta** — Python library for creating TUI -![prewiev](https://github.com/koloideal/Argenta/blob/kolo/imgs/mock_app_preview_last.png?raw=True) +![preview](https://github.com/koloideal/Argenta/blob/kolo/imgs/mock_app_preview_last.png?raw=True) Пример внешнего вида TUI, написанного с помощью Argenta --- @@ -95,16 +97,16 @@ def handler_with_flags(flags: InputFlags): ### Конструктор ```python -App(prompt: str = 'What do you want to do?\n', - initial_message: str = 'Argenta', - farewell_message: str = 'See you', - exit_command: str = 'Q', - exit_command_description: str = 'Exit command', - system_points_title: str = 'System points:', +App(prompt: str = '[italic dim bold]What do you want to do?\n', + initial_message: str = '\nArgenta\n', + farewell_message: str = '\nSee you\n', + exit_command: Command = Command('Q', 'Exit command'), + system_points_title: str | None = 'System points:', ignore_command_register: bool = True, dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(), repeat_command_groups: bool = True, - full_override_system_messages: bool = False + override_system_messages: bool = False, + autocompleter: AutoCompleter = AutoCompleter(), print_func: Callable[[str], None] = Console().print) ``` **Аргументы:** @@ -112,13 +114,13 @@ App(prompt: str = 'What do you want to do?\n', - `prompt` (`str`): Сообщение перед вводом команды. - `initial_message` (`str`): Приветственное сообщение при запуске. - `farewell_message` (`str`): Сообщение при выходе. -- `exit_command` (`str`): Команда выхода (по умолчанию `'Q'`). -- `exit_command_description` (`str`): Описание команды выхода. +- `exit_command` (`Command`): Сущность команды, которая будет отвечать за завершение работы. - `system_points_title` (`str`): Заголовок перед списком системных команд. - `ignore_command_register` (`bool`): Игнорировать регистр всех команд. - `dividing_line` (`StaticDividingLine | DynamicDividingLine`): Разделительная строка. - `repeat_command_groups` (`bool`): Повторять описание команд перед вводом. -- `full_override_system_messages` (`bool`): Переопределить ли дефолтное оформление сообщений ([подробнее см.](#override_defaults)) +- `override_system_messages` (`bool`): Переопределить ли дефолтное оформление сообщений ([подробнее см.](#override_defaults)) +- `autocompleter` (`AutoCompleter`): Сущность автодополнителя ввода. - `print_func` (`Callable[[str], None]`): Функция вывода текста в терминал. --- @@ -243,6 +245,26 @@ App(prompt: str = 'What do you want to do?\n', --- +## *class* :: `AutoCompleter` +Класс, экземпляр которого представляет собой автодополнитель ввода + +### Конструктор +```python +AutoCompleter(history_filename: str = False, + autocomplete_button: str = 'tab') +``` + +**Аргументы:** +- **name : mean** +- `history_filename` (`str` | `False`): Путь к файлу, который будет являться или является +историй пользовательского ввода, в последующем эти команды будут автодополняться, файл +может не существовать при инициализации, тогда он будет создан, при значении аргумента `False` +история пользовательского ввода будет существовать только в пределах сессии и не сохраняться в файл +- `autocomplete_button` (`str`): Строковое обозначение кнопки на клавиатуре, которая будет +использоваться для автодополнения при вводе, по умолчанию `tab` + +--- + ## *class* :: `StaticDivideLine` Класс, экземпляр которого представляет собой строковый разделитель фиксированной длины @@ -278,7 +300,7 @@ DinamicDivideLine(unit_part: str = '-') ### Конструктор ```python -Router(title: str = 'Commands group title:', +Router(title: str | None = None, name: str = 'Default') ``` diff --git a/argenta/app/autocompleter/entity.py b/argenta/app/autocompleter/entity.py index 4ed4641..f3e99c0 100644 --- a/argenta/app/autocompleter/entity.py +++ b/argenta/app/autocompleter/entity.py @@ -1,5 +1,4 @@ import os - import readline diff --git a/argenta/app/models.py b/argenta/app/models.py index 2367c2a..135c867 100644 --- a/argenta/app/models.py +++ b/argenta/app/models.py @@ -32,7 +32,7 @@ class AppInit: ignore_command_register: bool = True, dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(), repeat_command_groups: bool = True, - full_override_system_messages: bool = False, + override_system_messages: bool = False, autocompleter: AutoCompleter = AutoCompleter(), print_func: Callable[[str], None] = Console().print) -> None: self._prompt = prompt @@ -42,7 +42,7 @@ class AppInit: self._dividing_line = dividing_line self._ignore_command_register = ignore_command_register self._repeat_command_groups_description = repeat_command_groups - self._full_override_system_messages = full_override_system_messages + self._override_system_messages = override_system_messages self._autocompleter = autocompleter self._farewell_message = farewell_message @@ -53,10 +53,10 @@ class AppInit: self._registered_routers: RegisteredRouters = RegisteredRouters() self._messages_on_startup = [] - self._invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Incorrect flag syntax: {raw_command}') - self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Repeated input flags: {raw_command}') + self._invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}') + self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'[red bold]Repeated input flags: {escape(raw_command)}') self._empty_input_command_handler: Callable[[], None] = lambda: print_func('[red bold]Empty input command') - self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"[red bold]Unknown command: {command.get_trigger()}") + self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"[red bold]Unknown command: {escape(command.get_trigger())}") self._exit_command_handler: Callable[[], None] = lambda: print_func(self._farewell_message) @@ -112,7 +112,7 @@ class AppNonStandardHandlers(AppPrinters): if self._ignore_command_register: system_router.input_command_handler(command) return True - elif command.get_trigger() == self._exit_command: + elif command.get_trigger() == self._exit_command.get_trigger(): system_router.input_command_handler(command) return True return False @@ -128,7 +128,7 @@ class AppNonStandardHandlers(AppPrinters): elif handled_command_trigger == command.get_trigger(): return False elif handled_command_aliases: - if command.get_trigger().lower() in [x.lower() for x in handled_command_aliases] and self._ignore_command_register: + if (command.get_trigger().lower() in [x.lower() for x in handled_command_aliases]) and self._ignore_command_register: return False elif command.get_trigger() in handled_command_trigger: return False @@ -179,7 +179,7 @@ class AppSetups(AppValidators, AppPrinters): self._registered_routers.add_registered_router(system_router) def _setup_default_view(self): - if not self._full_override_system_messages: + if not self._override_system_messages: self._initial_message = f'\n[bold red]{text2art(self._initial_message, font='tarty1')}\n\n' self._farewell_message = ( f'[bold red]\n{text2art(f'\n{self._farewell_message}\n', font='chanky')}[/bold red]\n' diff --git a/mock/local_test.py b/mock/local_test.py index 89e6abd..848cd4d 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -1,8 +1,14 @@ -from rich.console import Console -from rich.markup import escape +from argenta.app import App +from argenta.command import Command +from argenta.router import Router +router = Router() -console = Console() -text = lambda command, description: f'[bold red]{escape('['+command+']')}[/bold red] [blue dim]*=*=*[/blue dim] [bold yellow italic]{escape(description)}' -print(text('start', 'command start')) -console.print(text('start', 'command start')) +@router.command(Command('test')) +def test(): + print('test command') + +app = App(ignore_command_register=False) +app.include_router(router) +app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.get_trigger()}')) +app.start_polling() \ No newline at end of file diff --git a/mock/mock_app/handlers/routers.py b/mock/mock_app/handlers/routers.py index 202d6b8..f3e040f 100644 --- a/mock/mock_app/handlers/routers.py +++ b/mock/mock_app/handlers/routers.py @@ -14,7 +14,7 @@ settings_router: Router = Router() console = Console() -@work_router.command(Command('get', 'Get Help', aliases=['help', 'get_help'])) +@work_router.command(Command('get', 'Get Help', aliases=['help', 'Get_help'])) def command_help(): help_command() diff --git a/mock/mock_app/main.py b/mock/mock_app/main.py index 445dd2f..76a91a0 100644 --- a/mock/mock_app/main.py +++ b/mock/mock_app/main.py @@ -8,8 +8,7 @@ from argenta.app.autocompleter import AutoCompleter autocompleter = AutoCompleter('./mock/.hist') app: App = App(dividing_line=DynamicDividingLine(), - autocompleter=autocompleter, - system_points_title=None) + autocompleter=autocompleter) def main(): diff --git a/pyproject.toml b/pyproject.toml index f5ae06e..3519f81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "argenta" -version = "0.5.0-alpha" +version = "0.5.0-beta" description = "Python library for creating TUI" authors = [ {name = "kolo", email = "kolo.is.main@gmail.com"} diff --git a/tests/system_tests/test_system_handling_non_standard_behavior.py b/tests/system_tests/test_system_handling_non_standard_behavior.py index 6610d97..4277aeb 100644 --- a/tests/system_tests/test_system_handling_non_standard_behavior.py +++ b/tests/system_tests/test_system_handling_non_standard_behavior.py @@ -22,7 +22,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print('test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.get_trigger()}')) app.start_polling() @@ -41,7 +42,9 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print('test command') - app = App(ignore_command_register=False) + app = App(ignore_command_register=False, + override_system_messages=True, + print_func=print) app.include_router(router) app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.get_trigger()}')) app.start_polling() @@ -60,7 +63,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -78,7 +82,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print('test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -97,7 +102,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print(f'connecting to host {args.get_flag('host').get_value()}') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -115,7 +121,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.get_trigger()}')) app.start_polling() @@ -138,7 +145,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'more command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.get_trigger()}')) app.start_polling() @@ -157,7 +165,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_invalid_input_flags_handler(lambda command: print(f'Incorrect flag syntax: "{command}"')) app.start_polling() @@ -176,7 +185,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_empty_command_handler(lambda: print('Empty input command')) app.start_polling() @@ -195,7 +205,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print('test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.set_repeated_input_flags_handler(lambda command: print(f'Repeated input flags: "{command}"')) app.start_polling() diff --git a/tests/system_tests/test_system_handling_normal_behavior.py b/tests/system_tests/test_system_handling_normal_behavior.py index c26dc26..5aa4a46 100644 --- a/tests/system_tests/test_system_handling_normal_behavior.py +++ b/tests/system_tests/test_system_handling_normal_behavior.py @@ -22,7 +22,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print('test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -40,7 +41,9 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print('test command') - app = App(ignore_command_register=True) + app = App(ignore_command_register=True, + override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -59,7 +62,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print(f'\nhelp for {args.get_flag('help').get_name()} flag\n') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -77,7 +81,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print(f'flag value for {args.get_flag('port').get_name()} flag : {args.get_flag('port').get_value()}') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -93,10 +98,11 @@ class TestSystemHandlerNormalWork(unittest.TestCase): flag = PredeterminedFlags.SHORT_HELP @router.command(Command('test', flags=flag)) - def test(args: dict): - print(f'help for {args[0].get_name()} flag') + def test(args: InputFlags): + print(f'help for {args.get_flag('h').get_name()} flag') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -116,7 +122,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): if args.get_flag('info'): print('info about test command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -135,7 +142,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print(f'connecting to host {args[0].get_value()}') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -154,7 +162,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(args: InputFlags): print(f'connecting to host {args[0].get_value()} and port {args[1].get_value()}') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -176,7 +185,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test2(): print(f'some command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() @@ -202,7 +212,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase): def test(): print(f'more command') - app = App() + app = App(override_system_messages=True, + print_func=print) app.include_router(router) app.start_polling() diff --git a/tests/unit_tests/test_dividing_line.py b/tests/unit_tests/test_dividing_line.py new file mode 100644 index 0000000..498a797 --- /dev/null +++ b/tests/unit_tests/test_dividing_line.py @@ -0,0 +1,21 @@ +from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine + +import unittest + + +class TestDividingLine(unittest.TestCase): + def test_get_static_dividing_line_full_line(self): + line = StaticDividingLine('-') + self.assertEqual(line.get_full_line().count('-'), 25) + + def test_get_dynamic_dividing_line_full_line(self): + line = DynamicDividingLine() + self.assertEqual(line.get_full_line(20).count('-'), 20) + + 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(), '+')