6 Commits

Author SHA1 Message Date
kolo c9dbf2bbae fix print framed text with static dividing line 2025-04-27 23:27:08 +03:00
kolo e768c1bd2c fix 2025-04-27 21:29:14 +03:00
kolo 408450ec12 fix 2025-04-27 21:20:44 +03:00
kolo 106ca058be new tests 2025-04-27 14:11:01 +03:00
kolo b5ddfb3b35 new tests 2025-04-27 13:28:11 +03:00
kolo 61e4502e41 work, fix etc. 2025-04-26 22:23:35 +03:00
14 changed files with 172 additions and 203 deletions
+4 -102
View File
@@ -176,9 +176,9 @@ class App(BaseApp)
#### \_\_init\_\_ #### \_\_init\_\_
```python ```python
def __init__(prompt: str = '[italic dim bold]What do you want to do?\n', def __init__(prompt: str = 'What do you want to do?',
initial_message: str = '\nArgenta\n', initial_message: str = 'Argenta',
farewell_message: str = '\nSee you\n', farewell_message: str = 'See you',
exit_command: Command = Command('Q', 'Exit command'), exit_command: Command = Command('Q', 'Exit command'),
system_router_title: str | None = 'System points:', system_router_title: str | None = 'System points:',
ignore_command_register: bool = True, ignore_command_register: bool = True,
@@ -218,8 +218,7 @@ Configures and manages all aspects of the behavior and presentation of the user
#### set\_description\_message\_pattern #### set\_description\_message\_pattern
```python ```python
def set_description_message_pattern( def set_description_message_pattern(pattern: Callable[[str, str], str]) -> None
pattern: Callable[[str, str], str]) -> None
``` ```
Public. Sets the output pattern of the available commands Public. Sets the output pattern of the available commands
@@ -334,22 +333,6 @@ Public. Sets the handler for exit command when entering a command
--- ---
<a id="argenta.app.models.App.run_polling"></a>
#### run\_polling
```python
def run_polling() -> None
```
Private. Starts the user input processing cycle
**Returns**:
`None`
---
<a id="argenta.app.models.App.include_router"></a> <a id="argenta.app.models.App.include_router"></a>
#### include\_router #### include\_router
@@ -494,26 +477,6 @@ Public. The static dividing line
--- ---
<a id="argenta.app.dividing_line.models.StaticDividingLine.get_full_static_line"></a>
#### get\_full\_static\_line
```python
def get_full_static_line(is_override: bool) -> str
```
Private. Returns the full line of the dividing line
**Arguments**:
- `is_override`: has the default text layout been redefined
**Returns**:
full line of dividing line as str
---
<a id="argenta.app.dividing_line.models.DynamicDividingLine"></a> <a id="argenta.app.dividing_line.models.DynamicDividingLine"></a>
## DynamicDividingLine Objects ## DynamicDividingLine Objects
@@ -542,27 +505,6 @@ Public. The dynamic dividing line
--- ---
<a id="argenta.app.dividing_line.models.DynamicDividingLine.get_full_dynamic_line"></a>
#### get\_full\_dynamic\_line
```python
def get_full_dynamic_line(length: int, is_override: bool) -> str
```
Private. Returns the full line of the dividing line
**Arguments**:
- `length`: the length of the dividing line
- `is_override`: has the default text layout been redefined
**Returns**:
full line of dividing line as str
---
<a id="argenta.app.exceptions"></a> <a id="argenta.app.exceptions"></a>
# `.app.exceptions` # `.app.exceptions`
@@ -1233,46 +1175,6 @@ Public. Registers handler for invalid input flag
--- ---
<a id="argenta.router.entity.Router.input_command_handler"></a>
#### input\_command\_handler
```python
def input_command_handler(input_command: InputCommand) -> None
```
Private. One handler for all input commands
**Arguments**:
- `input_command`: input command as InputCommand
**Returns**:
`None`
---
<a id="argenta.router.entity.Router.set_command_register_ignore"></a>
#### set\_command\_register\_ignore
```python
def set_command_register_ignore(_: bool) -> None
```
Private. Sets the router behavior on the input commands register
**Arguments**:
- `_`: is command register ignore
**Returns**:
`None`
---
<a id="argenta.router.entity.Router.get_triggers"></a> <a id="argenta.router.entity.Router.get_triggers"></a>
#### get\_triggers #### get\_triggers
+23 -3
View File
@@ -1,7 +1,27 @@
#from mock.mock_app.handlers.routers import work_router
from argenta.app import App from argenta.app import App
from argenta.app.defaults import PredefinedMessages
from argenta.app.dividing_line import DynamicDividingLine
from argenta.app.autocompleter import AutoCompleter
from argenta.orchestrator import Orchestrator from argenta.orchestrator import Orchestrator
from argenta.orchestrator.argparser import ArgParser
from argenta.orchestrator.argparser.arguments import BooleanArgument
app = App(repeat_command_groups=True)
orchestrator = Orchestrator() arg_parser = ArgParser(processed_args=[BooleanArgument('repeat')])
orchestrator.start_polling(app) app: App = App()
orchestrator: Orchestrator = Orchestrator()
def main():
#app.include_router(work_router)
'''app.add_message_on_startup(PredefinedMessages.USAGE)
app.add_message_on_startup(PredefinedMessages.AUTOCOMPLETE)
app.add_message_on_startup(PredefinedMessages.HELP)'''
orchestrator.start_polling(app)
if __name__ == "__main__":
main()
+5 -12
View File
@@ -1,13 +1,6 @@
from argenta.command.flag.defaults import PredefinedFlags from argenta.app import App
from argenta.command.models import InputCommand
router = Router() app = App()
flag = PredefinedFlags.SHORT_HELP app._all_registered_triggers_in_lower = ['fr', 'Tre', 'Pre']
print(app._is_unknown_command(InputCommand('fr')))
@router.command(Command('test', flags=flag))
def test(args: InputFlags):
print(f'help for {args.get_flag('h').get_name()} flag')
app = App(override_system_messages=True,
print_func=print)
app.include_router(router)
app.run_polling()
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "argenta" name = "argenta"
version = "1.0.0-alpha1" version = "1.0.0-alpha5"
description = "Python library for creating TUI" description = "Python library for creating TUI"
authors = [{ name = "kolo", email = "kolo.is.main@gmail.com" }] authors = [{ name = "kolo", email = "kolo.is.main@gmail.com" }]
requires-python = ">=3.11, <4.0" requires-python = ">=3.11, <4.0"
+2 -2
View File
@@ -14,7 +14,7 @@ class AutoCompleter:
self.autocomplete_button = autocomplete_button self.autocomplete_button = autocomplete_button
self.matches: list[str] = [] self.matches: list[str] = []
def complete(self, text, state) -> str | None: def _complete(self, text, state) -> str | None:
""" """
Private. Auto-completion function Private. Auto-completion function
:param text: part of the command being entered :param text: part of the command being entered
@@ -51,7 +51,7 @@ class AutoCompleter:
for line in all_commands: for line in all_commands:
readline.add_history(line) readline.add_history(line)
readline.set_completer(self.complete) readline.set_completer(self._complete)
readline.set_completer_delims(readline.get_completer_delims().replace(' ', '')) readline.set_completer_delims(readline.get_completer_delims().replace(' ', ''))
readline.parse_and_bind(f'{self.autocomplete_button}: complete') readline.parse_and_bind(f'{self.autocomplete_button}: complete')
-8
View File
@@ -1,8 +0,0 @@
class NoRegisteredHandlersException(Exception):
"""
The router has no registered handlers
"""
def __init__(self, router_name) -> None:
self.router_name = router_name
def __str__(self):
return f"No Registered Handlers Found For '{self.router_name}'"
+23 -36
View File
@@ -15,7 +15,6 @@ from argenta.command.exceptions import (UnprocessedInputFlagException,
RepeatedInputFlagsException, RepeatedInputFlagsException,
EmptyInputCommandException, EmptyInputCommandException,
BaseInputCommandException) BaseInputCommandException)
from argenta.app.exceptions import NoRegisteredHandlersException
from argenta.app.registered_routers.entity import RegisteredRouters from argenta.app.registered_routers.entity import RegisteredRouters
@@ -62,58 +61,58 @@ class BaseApp:
self._exit_command_handler: Callable[[], None] = lambda: print_func(self._farewell_message) self._exit_command_handler: Callable[[], None] = lambda: print_func(self._farewell_message)
def set_description_message_pattern(self, pattern: Callable[[str, str], str]) -> None: def set_description_message_pattern(self, _: Callable[[str, str], str]) -> None:
""" """
Public. Sets the output pattern of the available commands Public. Sets the output pattern of the available commands
:param pattern: output pattern of the available commands :param _: output pattern of the available commands
:return: None :return: None
""" """
self._description_message_gen: Callable[[str, str], str] = pattern self._description_message_gen: Callable[[str, str], str] = _
def set_invalid_input_flags_handler(self, handler: Callable[[str], None]) -> None: def set_invalid_input_flags_handler(self, _: Callable[[str], None]) -> None:
""" """
Public. Sets the handler for incorrect flags when entering a command Public. Sets the handler for incorrect flags when entering a command
:param handler: handler for incorrect flags when entering a command :param _: handler for incorrect flags when entering a command
:return: None :return: None
""" """
self._invalid_input_flags_handler = handler self._invalid_input_flags_handler = _
def set_repeated_input_flags_handler(self, handler: Callable[[str], None]) -> None: def set_repeated_input_flags_handler(self, _: Callable[[str], None]) -> None:
""" """
Public. Sets the handler for repeated flags when entering a command Public. Sets the handler for repeated flags when entering a command
:param handler: handler for repeated flags when entering a command :param _: handler for repeated flags when entering a command
:return: None :return: None
""" """
self._repeated_input_flags_handler = handler self._repeated_input_flags_handler = _
def set_unknown_command_handler(self, handler: Callable[[str], None]) -> None: def set_unknown_command_handler(self, _: Callable[[str], None]) -> None:
""" """
Public. Sets the handler for unknown commands when entering a command Public. Sets the handler for unknown commands when entering a command
:param handler: handler for unknown commands when entering a command :param _: handler for unknown commands when entering a command
:return: None :return: None
""" """
self._unknown_command_handler = handler self._unknown_command_handler = _
def set_empty_command_handler(self, handler: Callable[[], None]) -> None: def set_empty_command_handler(self, _: Callable[[], None]) -> None:
""" """
Public. Sets the handler for empty commands when entering a command Public. Sets the handler for empty commands when entering a command
:param handler: handler for empty commands when entering a command :param _: handler for empty commands when entering a command
:return: None :return: None
""" """
self._empty_input_command_handler = handler self._empty_input_command_handler = _
def set_exit_command_handler(self, handler: Callable[[], None]) -> None: def set_exit_command_handler(self, _: Callable[[], None]) -> None:
""" """
Public. Sets the handler for exit command when entering a command Public. Sets the handler for exit command when entering a command
:param handler: handler for exit command when entering a command :param _: handler for exit command when entering a command
:return: None :return: None
""" """
self._exit_command_handler = handler self._exit_command_handler = _
def _print_command_group_description(self) -> None: def _print_command_group_description(self) -> None:
@@ -139,7 +138,7 @@ class BaseApp:
""" """
if isinstance(self._dividing_line, StaticDividingLine): if isinstance(self._dividing_line, StaticDividingLine):
self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages)) self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
self._print_func(text) print(text.strip('\n'))
self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages)) self._print_func(self._dividing_line.get_full_static_line(self._override_system_messages))
elif isinstance(self._dividing_line, DynamicDividingLine): elif isinstance(self._dividing_line, DynamicDividingLine):
@@ -184,11 +183,6 @@ class BaseApp:
else: else:
if input_command_trigger in self._all_registered_triggers_in_default_case: if input_command_trigger in self._all_registered_triggers_in_default_case:
return False return False
with redirect_stdout(io.StringIO()) as f:
self._unknown_command_handler(command)
res: str = f.getvalue()
self._print_framed_text(res)
return True return True
@@ -208,16 +202,6 @@ class BaseApp:
self._empty_input_command_handler() self._empty_input_command_handler()
def _validate_included_routers(self) -> None:
"""
Private. Validates included routers
:return: None
"""
for router in self._registered_routers:
if not router.get_command_handlers():
raise NoRegisteredHandlersException(router.get_name())
def _setup_system_router(self) -> None: def _setup_system_router(self) -> None:
""" """
Private. Sets up system router Private. Sets up system router
@@ -259,7 +243,6 @@ class BaseApp:
""" """
self._setup_default_view() self._setup_default_view()
self._setup_system_router() self._setup_system_router()
self._validate_included_routers()
for router_entity in self._registered_routers: for router_entity in self._registered_routers:
self._all_registered_triggers_in_default_case.extend(router_entity.get_triggers()) self._all_registered_triggers_in_default_case.extend(router_entity.get_triggers())
@@ -351,6 +334,10 @@ class App(BaseApp):
return return
if self._is_unknown_command(input_command): if self._is_unknown_command(input_command):
with redirect_stdout(io.StringIO()) as f:
self._unknown_command_handler(input_command)
res: str = f.getvalue()
self._print_framed_text(res)
continue continue
with redirect_stdout(io.StringIO()) as f: with redirect_stdout(io.StringIO()) as f:
+4 -10
View File
@@ -1,3 +1,5 @@
from typing import Iterator
from argenta.router import Router from argenta.router import Router
@@ -25,16 +27,8 @@ class RegisteredRouters:
""" """
self._registered_routers.append(router) self._registered_routers.append(router)
def add_registered_routers(self, *routers: Router) -> None: def __iter__(self) -> Iterator[Router]:
"""
Private. Adds new registered routers
:param routers: registered routers
:return: None
"""
self._registered_routers.extend(routers)
def __iter__(self):
return iter(self._registered_routers) return iter(self._registered_routers)
def __next__(self): def __next__(self) -> Router:
return next(iter(self._registered_routers)) return next(iter(self._registered_routers))
+1 -1
View File
@@ -1,4 +1,4 @@
__all__ = ["Router"] __all__ = ["Router"]
from src.argenta.router.entity import Router from argenta.router.entity import Router
+5 -13
View File
@@ -1,4 +1,4 @@
from typing import Callable from typing import Callable, Iterator
from argenta.command import Command from argenta.command import Command
from argenta.command.flag import InputFlags from argenta.command.flag import InputFlags
@@ -49,14 +49,14 @@ class CommandHandlers:
""" """
self.command_handlers = command_handlers if command_handlers else [] self.command_handlers = command_handlers if command_handlers else []
def get_command_handlers(self) -> list[CommandHandler]: def get_handlers(self) -> list[CommandHandler]:
""" """
Private. Returns the list of CommandHandlers Private. Returns the list of CommandHandlers
:return: the list of CommandHandlers as list[CommandHandler] :return: the list of CommandHandlers as list[CommandHandler]
""" """
return self.command_handlers return self.command_handlers
def add_command_handler(self, command_handler: CommandHandler) -> None: def add_handler(self, command_handler: CommandHandler) -> None:
""" """
Private. Adds a CommandHandler to the list of CommandHandlers Private. Adds a CommandHandler to the list of CommandHandlers
:param command_handler: CommandHandler to be added :param command_handler: CommandHandler to be added
@@ -64,16 +64,8 @@ class CommandHandlers:
""" """
self.command_handlers.append(command_handler) self.command_handlers.append(command_handler)
def add_command_handlers(self, *command_handlers: CommandHandler) -> None: def __iter__(self) -> Iterator[CommandHandler]:
"""
Private. Extend a many CommandHandler to the list of CommandHandlers
:param command_handlers: many CommandHandler to be added
:return: None
"""
self.command_handlers.extend(command_handlers)
def __iter__(self):
return iter(self.command_handlers) return iter(self.command_handlers)
def __next__(self): def __next__(self) -> CommandHandler:
return next(iter(self.command_handlers)) return next(iter(self.command_handlers))
+6 -6
View File
@@ -1,10 +1,10 @@
from typing import Callable from typing import Callable
from inspect import getfullargspec from inspect import getfullargspec
from src.argenta.command import Command from argenta.command import Command
from src.argenta.command.models import InputCommand from argenta.command.models import InputCommand
from src.argenta.router.command_handler.entity import CommandHandlers, CommandHandler from argenta.router.command_handler.entity import CommandHandlers, CommandHandler
from src.argenta.command.flag.models import Flag, Flags, InputFlags from argenta.command.flag.models import Flag, Flags, InputFlags
from src.argenta.router.exceptions import (RepeatedFlagNameException, from argenta.router.exceptions import (RepeatedFlagNameException,
TooManyTransferredArgsException, TooManyTransferredArgsException,
RequiredArgumentNotPassedException, RequiredArgumentNotPassedException,
TriggerContainSpacesException) TriggerContainSpacesException)
@@ -35,7 +35,7 @@ class Router:
def command_decorator(func): def command_decorator(func):
Router._validate_func_args(command, func) Router._validate_func_args(command, func)
self._command_handlers.add_command_handler(CommandHandler(func, command)) self._command_handlers.add_handler(CommandHandler(func, command))
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
return func(*args, **kwargs) return func(*args, **kwargs)
+73
View File
@@ -0,0 +1,73 @@
from argenta.command.models import InputCommand, Command
from argenta.app import App
import unittest
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._all_registered_triggers_in_lower = ['fr', 'tr', 'de']
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._all_registered_triggers_in_lower = ['fr', 'tr', 'de']
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._all_registered_triggers_in_default_case = ['Pr', 'tW', 'deQW']
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._all_registered_triggers_in_default_case = ['Pr', 'tW', 'deQW']
self.assertEqual(app._is_unknown_command(InputCommand('tW')), False)
+16
View File
@@ -31,3 +31,19 @@ class TestInputCommand(unittest.TestCase):
command = Command('some', flags=Flags(Flag('test'), Flag('more'))) command = Command('some', flags=Flags(Flag('test'), Flag('more')))
self.assertEqual(command.validate_input_flag(InputFlag('more')), True) self.assertEqual(command.validate_input_flag(InputFlag('more')), True)
def test_validate_incorrect_input_flag1(self):
command = Command('some', flags=Flags(Flag('test')))
self.assertEqual(command.validate_input_flag(InputFlag('more')), False)
def test_validate_incorrect_input_flag2(self):
command = Command('some', flags=Flags(Flag('test'), Flag('more')))
self.assertEqual(command.validate_input_flag(InputFlag('case')), False)
def test_validate_incorrect_input_flag3(self):
command = Command('some')
self.assertEqual(command.validate_input_flag(InputFlag('case')), False)
def test_isinstance_parse_correct_raw_command(self):
cmd = InputCommand.parse('ssh --host 192.168.0.3')
self.assertIsInstance(cmd, InputCommand)
+3 -3
View File
@@ -1,7 +1,7 @@
from argenta.command.flag import InputFlags, InputFlag, Flag, Flags from argenta.command.flag import InputFlags, InputFlag, Flag, Flags
from src.argenta.router import Router from argenta.router import Router
from src.argenta.command import Command from argenta.command import Command
from src.argenta.router.exceptions import (TriggerContainSpacesException, from argenta.router.exceptions import (TriggerContainSpacesException,
RepeatedFlagNameException, RepeatedFlagNameException,
TooManyTransferredArgsException, TooManyTransferredArgsException,
RequiredArgumentNotPassedException) RequiredArgumentNotPassedException)