last steps work on new docs, full complete write docstring for all objects

This commit is contained in:
2025-04-23 20:54:03 +03:00
parent 7281fdeabf
commit 036c17ec9a
17 changed files with 1496 additions and 78 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
## Описание ## Описание
**Argenta** — Python library for creating TUI **Argenta** — Python library for creating TUI
![preview](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_preview3.png?raw=True)
Пример внешнего вида TUI, написанного с помощью Argenta Пример внешнего вида TUI, написанного с помощью Argenta
--- ---
+1351
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -40,7 +40,7 @@ class AutoCompleter:
def initial_setup(self, all_commands: list[str]) -> None: def initial_setup(self, all_commands: list[str]) -> None:
""" """
Public. Initial setup function Private. Initial setup function
:param all_commands: Registered commands for adding them to the autocomplete history :param all_commands: Registered commands for adding them to the autocomplete history
:return: None :return: None
""" """
@@ -57,7 +57,7 @@ class AutoCompleter:
def exit_setup(self) -> None: def exit_setup(self) -> None:
""" """
Public. Exit setup function Private. Exit setup function
:return: None :return: None
""" """
if self.history_filename: if self.history_filename:
+5 -5
View File
@@ -230,7 +230,7 @@ class BaseApp:
self._exit_command_handler() self._exit_command_handler()
if system_router not in self._registered_routers.get_registered_routers(): if system_router not in self._registered_routers.get_registered_routers():
system_router.set_ignore_command_register(self._ignore_command_register) system_router.set_command_register_ignore(self._ignore_command_register)
self._registered_routers.add_registered_router(system_router) self._registered_routers.add_registered_router(system_router)
@@ -240,10 +240,10 @@ class BaseApp:
:return: None :return: None
""" """
if not self._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._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' 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') f'[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] ' self._description_message_gen = lambda command, description: (f'[bold red]{escape("[" + command + "]")}[/bold red] '
f'[blue dim]*=*=*[/blue dim] ' f'[blue dim]*=*=*[/blue dim] '
f'[bold yellow italic]{escape(description)}') f'[bold yellow italic]{escape(description)}')
self._invalid_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}') self._invalid_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}')
@@ -369,7 +369,7 @@ class App(BaseApp):
:param router: registered router :param router: registered router
:return: None :return: None
""" """
router.set_ignore_command_register(self._ignore_command_register) router.set_command_register_ignore(self._ignore_command_register)
self._registered_routers.add_registered_router(router) self._registered_routers.add_registered_router(router)
+10
View File
@@ -168,6 +168,11 @@ class BaseFlags(ABC):
class Flags(BaseFlags, ABC): class Flags(BaseFlags, ABC):
def __init__(self, *flags: Flag): def __init__(self, *flags: Flag):
"""
Public. A model that combines the registered flags
:param flags: the flags that will be registered
:return: None
"""
self._flags = flags if flags else [] self._flags = flags if flags else []
def get_flags(self) -> list[Flag]: def get_flags(self) -> list[Flag]:
@@ -189,6 +194,11 @@ class Flags(BaseFlags, ABC):
class InputFlags(BaseFlags, ABC): class InputFlags(BaseFlags, ABC):
def __init__(self, *flags: InputFlag): def __init__(self, *flags: InputFlag):
"""
Public. A model that combines the input flags of the input command
:param flags: all input flags
:return: None
"""
self._flags = flags if flags else [] self._flags = flags if flags else []
def get_flags(self) -> list[InputFlag]: def get_flags(self) -> list[InputFlag]:
+1 -1
View File
@@ -18,7 +18,7 @@ class BaseCommand:
def get_trigger(self) -> str: def get_trigger(self) -> str:
""" """
Returns the trigger of the command Public. Returns the trigger of the command
:return: the trigger of the command as str :return: the trigger of the command as str
""" """
return self._trigger return self._trigger
+2 -2
View File
@@ -1,4 +1,4 @@
__all__ = ["ArgParse"] __all__ = ["ArgParser"]
from argenta.orchestrator.argparse.entity import ArgParse from argenta.orchestrator.argparser.entity import ArgParser
@@ -1,6 +1,6 @@
__all__ = ["BooleanArgument", "PositionalArgument", "OptionalArgument"] __all__ = ["BooleanArgument", "PositionalArgument", "OptionalArgument"]
from argenta.orchestrator.argparse.arguments.models import (BooleanArgument, from argenta.orchestrator.argparser.arguments.models import (BooleanArgument,
PositionalArgument, PositionalArgument,
OptionalArgument) OptionalArgument)
+4 -4
View File
@@ -1,11 +1,11 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from argenta.orchestrator.argparse.arguments.models import (BooleanArgument, from argenta.orchestrator.argparser.arguments.models import (BooleanArgument,
OptionalArgument, OptionalArgument,
PositionalArgument) PositionalArgument)
class ArgParse: class ArgParser:
def __init__(self, def __init__(self,
processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument], processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument],
name: str = 'Argenta', name: str = 'Argenta',
+6 -6
View File
@@ -1,24 +1,24 @@
from argparse import Namespace from argparse import Namespace
from argenta.app import App from argenta.app import App
from argenta.orchestrator.argparse import ArgParse from argenta.orchestrator.argparser import ArgParser
class Orchestrator: class Orchestrator:
def __init__(self, arg_parser: ArgParse = False): def __init__(self, arg_parser: ArgParser = False):
""" """
An orchestrator and configurator that defines the behavior of an integrated system, one level higher than the App 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 :param arg_parser: Cmd argument parser and configurator at startup
:return: None :return: None
""" """
self.arg_parser: ArgParse | False = arg_parser self.arg_parser: ArgParser | False = arg_parser
if arg_parser: if arg_parser:
self.arg_parser.register_args() self.arg_parser.register_args()
@staticmethod @staticmethod
def start_polling(app: App) -> None: def start_polling(app: App) -> None:
""" """
Starting the user input processing cycle Public. Starting the user input processing cycle
:param app: a running application :param app: a running application
:return: None :return: None
""" """
@@ -26,7 +26,7 @@ class Orchestrator:
def get_input_args(self) -> Namespace | None: def get_input_args(self) -> Namespace | None:
""" """
Returns the arguments parsed Public. Returns the arguments parsed
:return: None :return: None
""" """
if self.arg_parser: if self.arg_parser:
+41 -5
View File
@@ -7,33 +7,69 @@ from argenta.command.flag import InputFlags
class CommandHandler: class CommandHandler:
def __init__(self, handler: Callable[[], None] | Callable[[InputFlags], None], handled_command: Command): def __init__(self, handler: Callable[[], None] | Callable[[InputFlags], None], handled_command: Command):
"""
Private. Entity of the model linking the handler and the command being processed
:param handler: the handler being called
:param handled_command: the command being processed
"""
self._handler = handler self._handler = handler
self._handled_command = handled_command self._handled_command = handled_command
def handling(self, input_flags: InputFlags = None): def handling(self, input_flags: InputFlags = None) -> None:
"""
Private. Direct processing of an input command
:param input_flags: the flags of the input command
:return: None
"""
if input_flags is not None: if input_flags is not None:
self._handler(input_flags) self._handler(input_flags)
else: else:
self._handler() self._handler()
def get_handler(self): def get_handler(self) -> Callable[[], None] | Callable[[InputFlags], None]:
"""
Private. Returns the handler being called
:return: the handler being called as Callable[[], None] or Callable[[InputFlags], None]
"""
return self._handler return self._handler
def get_handled_command(self): def get_handled_command(self) -> Command:
"""
Private. Returns the command being processed
:return: the command being processed as Command
"""
return self._handled_command return self._handled_command
class CommandHandlers: class CommandHandlers:
def __init__(self, command_handlers: list[CommandHandler] = None): def __init__(self, command_handlers: list[CommandHandler] = None):
"""
Private. The model that unites all CommandHandler of the routers
:param command_handlers: list of CommandHandlers for register
"""
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_command_handlers(self) -> list[CommandHandler]:
"""
Private. Returns the list of CommandHandlers
:return: the list of CommandHandlers as list[CommandHandler]
"""
return self.command_handlers return self.command_handlers
def add_command_handler(self, command_handler: CommandHandler): def add_command_handler(self, command_handler: CommandHandler) -> None:
"""
Private. Adds a CommandHandler to the list of CommandHandlers
:param command_handler: CommandHandler to be added
:return: None
"""
self.command_handlers.append(command_handler) self.command_handlers.append(command_handler)
def add_command_handlers(self, *command_handlers: CommandHandler): def add_command_handlers(self, *command_handlers: CommandHandler) -> None:
"""
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) self.command_handlers.extend(command_handlers)
def __iter__(self): def __iter__(self):
+1 -2
View File
@@ -1,5 +1,4 @@
from argenta.router import Router from argenta.router import Router
system_router = Router(title='System points:', system_router = Router(title='System points:')
name='System')
+56 -21
View File
@@ -1,6 +1,5 @@
from typing import Callable from typing import Callable
from inspect import getfullargspec from inspect import getfullargspec
from argenta.command import Command from argenta.command import Command
from argenta.command.models import InputCommand from argenta.command.models import InputCommand
from argenta.router.command_handler.entity import CommandHandlers, CommandHandler from argenta.router.command_handler.entity import CommandHandlers, CommandHandler
@@ -9,21 +8,18 @@ from argenta.router.exceptions import (RepeatedFlagNameException,
TooManyTransferredArgsException, TooManyTransferredArgsException,
RequiredArgumentNotPassedException, RequiredArgumentNotPassedException,
IncorrectNumberOfHandlerArgsException, IncorrectNumberOfHandlerArgsException,
TriggerCannotContainSpacesException) TriggerContainSpacesException)
class Router: class Router:
def __init__(self, def __init__(self,
title: str = None, title: str = None):
name: str = 'Default'):
""" """
Public. Directly configures and manages handlers Public. Directly configures and manages handlers
:param title: the title of the router :param title: the title of the router, displayed when displaying the available commands
:param name: the name of the router
:return: None :return: None
""" """
self._title = title self._title = title
self._name = name
self._command_handlers: CommandHandlers = CommandHandlers() self._command_handlers: CommandHandlers = CommandHandlers()
self._ignore_command_register: bool = False self._ignore_command_register: bool = False
@@ -105,9 +101,15 @@ class Router:
return return
def _validate_input_flags(self, handle_command: Command, input_flags: InputFlags): def _validate_input_flags(self, handled_command: Command, input_flags: InputFlags) -> bool:
"""
Private. Validates flags of input command
:param handled_command: entity of the handled command
:param input_flags:
:return: is flags of input command valid as bool
"""
for flag in input_flags: for flag in input_flags:
is_valid = handle_command.validate_input_flag(flag) is_valid: bool = handled_command.validate_input_flag(flag)
if not is_valid: if not is_valid:
self._not_valid_flag_handler(flag) self._not_valid_flag_handler(flag)
return False return False
@@ -115,10 +117,15 @@ class Router:
@staticmethod @staticmethod
def _validate_command(command: Command): 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.get_trigger() command_name: str = command.get_trigger()
if command_name.find(' ') != -1: if command_name.find(' ') != -1:
raise TriggerCannotContainSpacesException() raise TriggerContainSpacesException()
flags: Flags = command.get_registered_flags() flags: Flags = command.get_registered_flags()
if flags: if flags:
@@ -128,7 +135,13 @@ class Router:
@staticmethod @staticmethod
def _validate_func_args(command: Command, func: Callable): def _validate_func_args(command: Command, func: Callable) -> None:
"""
Private. Validates the arguments of the handler
:param command: registered command in handler
:param func: entity of the handler func
:return: None if func is valid else raise exception
"""
registered_args = command.get_registered_flags() registered_args = command.get_registered_flags()
transferred_args = getfullargspec(func).args transferred_args = getfullargspec(func).args
if registered_args.get_flags() and transferred_args: if registered_args.get_flags() and transferred_args:
@@ -140,18 +153,31 @@ class Router:
raise TooManyTransferredArgsException() raise TooManyTransferredArgsException()
def set_ignore_command_register(self, ignore_command_register: bool): def set_command_register_ignore(self, _: bool) -> None:
self._ignore_command_register = ignore_command_register """
Private. Sets the router behavior on the input commands register
:param _: is command register ignore
:return: None
"""
self._ignore_command_register = _
def get_triggers(self): def get_triggers(self) -> list[str]:
"""
Public. Gets registered triggers
:return: registered in router triggers as list[str]
"""
all_triggers: list[str] = [] all_triggers: list[str] = []
for command_handler in self._command_handlers: for command_handler in self._command_handlers:
all_triggers.append(command_handler.get_handled_command().get_trigger()) all_triggers.append(command_handler.get_handled_command().get_trigger())
return all_triggers return all_triggers
def get_aliases(self): def get_aliases(self) -> list[str]:
"""
Public. Gets registered aliases
:return: registered in router aliases as list[str]
"""
all_aliases: list[str] = [] all_aliases: list[str] = []
for command_handler in self._command_handlers: for command_handler in self._command_handlers:
if command_handler.get_handled_command().get_aliases(): if command_handler.get_handled_command().get_aliases():
@@ -160,16 +186,25 @@ class Router:
def get_command_handlers(self) -> CommandHandlers: def get_command_handlers(self) -> CommandHandlers:
"""
Private. Gets registered command handlers
:return: registered command handlers as CommandHandlers
"""
return self._command_handlers return self._command_handlers
def get_name(self) -> str:
return self._name
def get_title(self) -> str | None: def get_title(self) -> str | None:
"""
Public. Gets title of the router
:return: the title of the router as str or None
"""
return self._title return self._title
def set_title(self, title: str): def set_title(self, title: str) -> None:
"""
Public. Sets the title of the router
:param title: title that will be setted
:return: None
"""
self._title = title self._title = title
+1 -1
View File
@@ -30,7 +30,7 @@ class IncorrectNumberOfHandlerArgsException(Exception):
return "Handler has incorrect number of arguments" return "Handler has incorrect number of arguments"
class TriggerCannotContainSpacesException(Exception): class TriggerContainSpacesException(Exception):
""" """
Private. Raised when there is a space in the trigger being registered Private. Raised when there is a space in the trigger being registered
""" """
+4 -14
View File
@@ -9,27 +9,17 @@ from .handlers_implementation.help_command import help_command
work_router: Router = Router(title='Work points:') work_router: Router = Router(title='Work points:')
settings_router: Router = Router()
console = Console() 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(): def command_help():
help_command() pass
@work_router.command(Command('start', 'Start Solving', @work_router.command(Command('run', 'Run All'))
flags=Flags(PredefinedFlags.HOST, PredefinedFlags.PORT), def command_start_solving():
aliases=['starting'])) pass
def command_start_solving(args: InputFlags):
print(args.get_flag('host'))
@settings_router.command(Command('update', 'Update WordMath'))
def command_update():
print('eeeeeee')
+6 -9
View File
@@ -1,30 +1,27 @@
from argenta.command import Command from mock.mock_app.handlers.routers import work_router
from mock.mock_app.handlers.routers import work_router, settings_router
from argenta.app import App from argenta.app import App
from argenta.app.defaults import PredefinedMessages from argenta.app.defaults import PredefinedMessages
from argenta.app.dividing_line import DynamicDividingLine from argenta.app.dividing_line import DynamicDividingLine
from argenta.app.autocompleter import AutoCompleter from argenta.app.autocompleter import AutoCompleter
from argenta.orchestrator import Orchestrator from argenta.orchestrator import Orchestrator
from argenta.orchestrator.argparse import ArgParse from argenta.orchestrator.argparser import ArgParser
from argenta.orchestrator.argparse.arguments import BooleanArgument from argenta.orchestrator.argparser.arguments import BooleanArgument
arg_parser = ArgParse(processed_args=[BooleanArgument('repeat')]) arg_parser = ArgParser(processed_args=[BooleanArgument('repeat')])
app: App = App(dividing_line=DynamicDividingLine(), app: App = App(dividing_line=DynamicDividingLine(),
autocompleter=AutoCompleter('./mock/.hist'), autocompleter=AutoCompleter('./mock/.hist'))
exit_command=Command('w', aliases=['test']))
orchestrator: Orchestrator = Orchestrator(arg_parser) orchestrator: Orchestrator = Orchestrator(arg_parser)
def main(): def main():
app.include_routers(work_router, settings_router) app.include_router(work_router)
app.add_message_on_startup(PredefinedMessages.USAGE) app.add_message_on_startup(PredefinedMessages.USAGE)
app.add_message_on_startup(PredefinedMessages.AUTOCOMPLETE) app.add_message_on_startup(PredefinedMessages.AUTOCOMPLETE)
app.add_message_on_startup(PredefinedMessages.HELP) app.add_message_on_startup(PredefinedMessages.HELP)
print(orchestrator.get_input_args())
orchestrator.start_polling(app) orchestrator.start_polling(app)
if __name__ == "__main__": if __name__ == "__main__":
+2 -2
View File
@@ -1,6 +1,6 @@
from argenta.router import Router from argenta.router import Router
from argenta.command import Command from argenta.command import Command
from argenta.router.exceptions import TriggerCannotContainSpacesException from argenta.router.exceptions import TriggerContainSpacesException
import unittest import unittest
@@ -14,7 +14,7 @@ class TestRouter(unittest.TestCase):
def test_register_command_with_spaces_in_trigger(self): def test_register_command_with_spaces_in_trigger(self):
router = Router() router = Router()
with self.assertRaises(TriggerCannotContainSpacesException): with self.assertRaises(TriggerContainSpacesException):
@router.command(Command(trigger='command with spaces')) @router.command(Command(trigger='command with spaces'))
def test(): def test():
return 'correct result' return 'correct result'