diff --git a/README.md b/README.md index 3d7e947..6bd8734 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Описание **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 --- diff --git a/README2.md b/README2.md new file mode 100644 index 0000000..04af00a --- /dev/null +++ b/README2.md @@ -0,0 +1,1351 @@ +# Argenta + +### Python library for creating TUI + +![preview](https://github.com/koloideal/Argenta/blob/kolo/imgs/mock_app_preview3.png?raw=True) +An example of the TUI appearance + +--- + +# Installing +```bash +pip install argenta +``` +or +```bash +poetry add argenta +``` + +--- + +# Quick start + +Example of the simplest TUI with a single command +```python +# routers.py +from argenta.router import Router +from argenta.command import Command + + +router = Router() + +@router.command(Command("hello")) +def handler(): + print("Hello, world!") +``` + +```python +# main.py +from argenta.app import App +from argenta.orchestrator import Orchestrator +from routers import router + +app: App = App() +orchestrator: Orchestrator = Orchestrator() + + +def main() -> None: + app.include_router(router) + orchestrator.start_polling(app) + + +if __name__ == '__main__': + main() +``` +Example TUI with a command that has processed flags + +```python +# routers.py +import re +from argenta.router import Router +from argenta.command import Command +from argenta.orchestrator import Orchestrator +from argenta.command.flag.defaults import PredefinedFlags +from argenta.command.flag import Flags, Flag, InputFlags + +router = Router() + +registered_flags = Flags(PredefinedFlags.HOST, + Flag('port', '--', re.compile(r'^[0-9]{1,4}$'))) + + +@router.command(Command("hello")) +def handler(): + print("Hello, world!") + + +@router.command(Command(trigger="ssh", + description='connect via ssh', + flags=registered_flags)) +def handler_with_flags(flags: InputFlags): + for flag in flags: + print(f'Flag name: {flag.get_name()}\n' + f'Flag value: {flag.get_value()}') +``` + +--- + + + +# `.app.autocompleter` + + + +## AutoCompleter Objects + +```python +class AutoCompleter() +``` + + + +#### \_\_init\_\_ + +```python +def __init__(history_filename: str = False, + autocomplete_button: str = 'tab') -> None +``` + +Public. Configures and implements auto-completion of input command + +**Arguments**: + +- `history_filename`: the name of the file for saving the history of the autocompleter +- `autocomplete_button`: the button for auto-completion + +**Returns**: + +`None` + +--- + + + +# `.app.defaults` + + + +## PredefinedMessages Objects + +```python +@dataclass +class PredefinedMessages() +``` + +Public. A dataclass with predetermined messages for quick use + +--- + + + +# `.app.dividing_line` + + + +## StaticDividingLine Objects + +```python +class StaticDividingLine(BaseDividingLine) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(unit_part: str = '-', length: int = 25) -> None +``` + +Public. The static dividing line + +**Arguments**: + +- `unit_part`: the single part of the dividing line +- `length`: the length of the dividing line + +**Returns**: + +`None` + +--- + + + +#### 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 + +--- + + + +## DynamicDividingLine Objects + +```python +class DynamicDividingLine(BaseDividingLine) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(unit_part: str = '-') -> None +``` + +Public. The dynamic dividing line + +**Arguments**: + +- `unit_part`: the single part of the dividing line + +**Returns**: + +`None` + +--- + + + +#### 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 + +--- + + + +# `.app.exceptions` + + + +## NoRegisteredHandlersException Objects + +```python +class NoRegisteredHandlersException(Exception) +``` + +The router has no registered handlers + +--- + + + +# `.app` + + + +## App Objects + +```python +class App(BaseApp) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(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_router_title: str | None = 'System points:', + ignore_command_register: bool = True, + dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(), + repeat_command_groups: bool = True, + override_system_messages: bool = False, + autocompleter: AutoCompleter = AutoCompleter(), + print_func: Callable[[str], None] = Console().print) -> None +``` + +Public. The essence of the application itself. + +Configures and manages all aspects of the behavior and presentation of the user interacting with the user + +**Arguments**: + +- `prompt`: displayed before entering the command +- `initial_message`: displayed at the start of the app +- `farewell_message`: displayed at the end of the app +- `exit_command`: the entity of the command that will be terminated when entered +- `system_router_title`: system router title +- `ignore_command_register`: whether to ignore the case of the entered commands +- `dividing_line`: the entity of the dividing line +- `repeat_command_groups`: whether to repeat the available commands and their description +- `override_system_messages`: whether to redefine the default formatting of system messages +- `autocompleter`: the entity of the autocompleter +- `print_func`: system messages text output function + +**Returns**: + +`None` + +--- + + + +#### set\_description\_message\_pattern + +```python +def set_description_message_pattern( + pattern: Callable[[str, str], str]) -> None +``` + +Public. Sets the output pattern of the available commands + +**Arguments**: + +- `pattern`: output pattern of the available commands + +**Returns**: + +`None` + +--- + + + +#### set\_invalid\_input\_flags\_handler + +```python +def set_invalid_input_flags_handler(handler: Callable[[str], None]) -> None +``` + +Public. Sets the handler for incorrect flags when entering a command + +**Arguments**: + +- `handler`: handler for incorrect flags when entering a command + +**Returns**: + +`None` + +--- + + + +#### set\_repeated\_input\_flags\_handler + +```python +def set_repeated_input_flags_handler(handler: Callable[[str], None]) -> None +``` + +Public. Sets the handler for repeated flags when entering a command + +**Arguments**: + +- `handler`: handler for repeated flags when entering a command + +**Returns**: + +`None` + +--- + + + +#### set\_unknown\_command\_handler + +```python +def set_unknown_command_handler(handler: Callable[[str], None]) -> None +``` + +Public. Sets the handler for unknown commands when entering a command + +**Arguments**: + +- `handler`: handler for unknown commands when entering a command + +**Returns**: + +`None` + +--- + + + +#### set\_empty\_command\_handler + +```python +def set_empty_command_handler(handler: Callable[[], None]) -> None +``` + +Public. Sets the handler for empty commands when entering a command + +**Arguments**: + +- `handler`: handler for empty commands when entering a command + +**Returns**: + +`None` + +--- + + + +#### set\_exit\_command\_handler + +```python +def set_exit_command_handler(handler: Callable[[], None]) -> None +``` + +Public. Sets the handler for exit command when entering a command + +**Arguments**: + +- `handler`: handler for exit command when entering a command + +**Returns**: + +`None` + +--- + + + +#### run\_polling + +```python +def run_polling() -> None +``` + +Private. Starts the user input processing cycle + +**Returns**: + +`None` + +--- + + + +#### include\_router + +```python +def include_router(router: Router) -> None +``` + +Public. Registers the router in the application + +**Arguments**: + +- `router`: registered router + +**Returns**: + +`None` + +--- + + + +#### include\_routers + +```python +def include_routers(*routers: Router) -> None +``` + +Public. Registers the routers in the application + +**Arguments**: + +- `routers`: registered routers + +**Returns**: + +`None` + +--- + + + +#### add\_message\_on\_startup + +```python +def add_message_on_startup(message: str) -> None +``` + +Public. Adds a message that will be displayed when the application is launched + +**Arguments**: + +- `message`: the message being added + +**Returns**: + +`None` + +--- + + + +# `.command.exceptions` + + + +## UnprocessedInputFlagException Objects + +```python +class UnprocessedInputFlagException(BaseInputCommandException) +``` + +Private. Raised when an unprocessed input flag is detected + +--- + + + +## RepeatedInputFlagsException Objects + +```python +class RepeatedInputFlagsException(BaseInputCommandException) +``` + +Private. Raised when repeated input flags are detected + +--- + + + +## EmptyInputCommandException Objects + +```python +class EmptyInputCommandException(BaseInputCommandException) +``` + +Private. Raised when an empty input command is detected + +--- + + + +# `.command.flag.defaults` + + + +## PredefinedFlags Objects + +```python +@dataclass +class PredefinedFlags() +``` + +Public. A dataclass with predefined flags and most frequently used flags for quick use + +--- + + + +# `.command.flag` + + + +## InputFlag Objects + +```python +class InputFlag(BaseFlag) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(name: str, + prefix: Literal['-', '--', '---'] = '--', + value: str = None) +``` + +Public. The entity of the flag of the entered command + +**Arguments**: + +- `name`: the name of the input flag +- `prefix`: the prefix of the input flag +- `value`: the value of the input flag + +**Returns**: + +`None` + +--- + + + +#### get\_value + +```python +def get_value() -> str | None +``` + +Public. Returns the value of the flag + +**Returns**: + +the value of the flag as str + +--- + + + +## Flag Objects + +```python +class Flag(BaseFlag) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(name: str, + prefix: Literal['-', '--', '---'] = '--', + possible_values: list[str] | Pattern[str] | False = True) -> None +``` + +Public. The entity of the flag being registered for subsequent processing + +**Arguments**: + +- `name`: The name of the flag +- `prefix`: The prefix of the flag +- `possible_values`: The possible values of the flag, if False then the flag cannot have a value + +**Returns**: + +`None` + +--- + + + +## Flags Objects + +```python +class Flags(BaseFlags) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(*flags: Flag) +``` + +Public. A model that combines the registered flags + +**Arguments**: + +- `flags`: the flags that will be registered + +**Returns**: + +`None` + +--- + + +#### get\_flags + +```python +def get_flags() -> list[Flag] +``` + +Public. Returns a list of flags + +**Returns**: + +list of flags as list[Flag] + +--- + + + +#### add\_flag + +```python +def add_flag(flag: Flag) -> None +``` + +Public. Adds a flag to the list of flags + +**Arguments**: + +- `flag`: flag to add + +**Returns**: + +`None` + +--- + + + +#### add\_flags + +```python +def add_flags(flags: list[Flag]) -> None +``` + +Public. Adds a list of flags to the list of flags + +**Arguments**: + +- `flags`: list of flags to add + +**Returns**: + +`None` + +--- + + + +#### get\_flag + +```python +def get_flag(name: str) -> Flag | None +``` + +Public. Returns the flag entity by its name or None if not found + +**Arguments**: + +- `name`: the name of the flag to get + +**Returns**: + +entity of the flag or None + +--- + + + +## InputFlags Objects + +```python +class InputFlags(BaseFlags) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(*flags: InputFlag) +``` + +Public. A model that combines the input flags of the input command + +**Arguments**: + +- `flags`: all input flags + +**Returns**: + +`None` + +--- + + + +#### get\_flags + +```python +def get_flags() -> list[InputFlag] +``` + +Public. Returns a list of flags + +**Returns**: + +list of flags + +--- + + + +#### add\_flag + +```python +def add_flag(flag: InputFlag) -> None +``` + +Public. Adds a flag to the list of flags + +**Arguments**: + +- `flag`: flag to add + +**Returns**: + +`None` + +--- + + + +#### add\_flags + +```python +def add_flags(flags: list[InputFlag]) -> None +``` + +Public. Adds a list of flags to the list of flags + +**Arguments**: + +- `flags`: list of flags to add + +**Returns**: + +`None` + +--- + + + +#### get\_flag + +```python +def get_flag(name: str) -> InputFlag +``` + +Public. Returns the flag entity by its name or None if not found + +**Arguments**: + +- `name`: the name of the flag to get + +**Returns**: + +entity of the flag or None + +--- + + + +# `.command.models` + + + +## Command Objects + +```python +class Command(BaseCommand) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(trigger: str, + description: str = None, + flags: Flag | Flags = None, + aliases: list[str] = None) +``` + +Public. The command that can and should be registered in the Router + +**Arguments**: + +- `trigger`: A string trigger, which, when entered by the user, indicates that the input corresponds to the command +- `description`: the description of the command +- `flags`: processed commands +- `aliases`: string synonyms for the main trigger + +--- + + + +# `.orchestrator.argparse.arguments` + + + +## PositionalArgument Objects + +```python +class PositionalArgument(BaseArgument) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(name: str) +``` + +Public. Required argument at startup + +**Arguments**: + +- `name`: name of the argument, must not start with minus (-) + +--- + + + +## OptionalArgument Objects + +```python +class OptionalArgument(BaseArgument) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(name: str, prefix: Literal['-', '--', '---'] = '--') +``` + +Public. Optional argument, must have the value + +**Arguments**: + +- `name`: name of the argument +- `prefix`: prefix of the argument + +--- + + + +## BooleanArgument Objects + +```python +class BooleanArgument(BaseArgument) +``` + + + +#### \_\_init\_\_ + +```python +def __init__(name: str, + prefix: Literal['-', '--', '---'] = '--') +``` + +Public. Boolean argument, does not require a value + +**Arguments**: + +- `name`: name of the argument +- `prefix`: prefix of the argument + +--- + + + +# `.orchestrator.argparser` + + + +## ArgParse Objects + +```python +class ArgParse() +``` + + + +#### \_\_init\_\_ + +```python +def __init__(processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument], + name: str = 'Argenta', + description: str = 'Argenta available arguments', + epilog: str = 'github.com/koloideal/Argenta | made by kolo') -> None +``` + +Public. Cmd argument parser and configurator at startup + +**Arguments**: + +- `name`: the name of the ArgParse instance +- `description`: the description of the ArgParse instance +- `epilog`: the epilog of the ArgParse instance +- `processed_args`: registered and processed arguments + +--- + + + +#### set\_args + +```python +def set_args(*args: PositionalArgument | OptionalArgument | BooleanArgument) -> None +``` + +Public. Sets the arguments to be processed + +**Arguments**: + +- `args`: processed arguments + +**Returns**: + +`None` + +--- + +# `.orchestrator` + + + +## Orchestrator Objects + +```python +class Orchestrator() +``` + + + +#### \_\_init\_\_ + +```python +def __init__(arg_parser: ArgParse = False) +``` + +Public. An orchestrator and configurator that defines the behavior of an integrated system, one level higher than the App + +**Arguments**: + +- `arg_parser`: Cmd argument parser and configurator at startup + +**Returns**: + +`None` + +--- + + + +#### start\_polling + +```python +@staticmethod +def start_polling(app: App) -> None +``` + +Public. Starting the user input processing cycle + +**Arguments**: + +- `app`: a running application + +**Returns**: + +`None` + +--- + + + +#### get\_input\_args + +```python +def get_input_args() -> Namespace | None +``` + +Public. Returns the arguments parsed + +**Returns**: + +`None` + +--- + + + +# `.router` + + + +## Router Objects + +```python +class Router() +``` + + + +#### \_\_init\_\_ + +```python +def __init__(title: str = None) +``` + +Public. Directly configures and manages handlers + +**Arguments**: + +- `title`: the title of the router, displayed when displaying the available commands + +**Returns**: + +`None` + +--- + + + +#### @command + +```python +def command(command: Command) -> Callable +``` + +Public. Registers handler + +**Arguments**: + +- `command`: Registered command + +**Returns**: + +decorated handler as Callable[[Any], Any] + +--- + + + +#### set\_invalid\_input\_flag\_handler + +```python +def set_invalid_input_flag_handler(func) -> None +``` + +Public. Registers handler for invalid input flag + +**Arguments**: + +- `func`: registered handler + +**Returns**: + +`None` + +--- + + + +#### 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` + +--- + + + +#### 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` + +--- + + + +#### get\_triggers + +```python +def get_triggers() -> list[str] +``` + +Public. Gets registered triggers + +**Returns**: + +registered in router triggers as list[str] + +--- + + + +#### get\_aliases + +```python +def get_aliases() -> list[str] +``` + +Public. Gets registered aliases + +**Returns**: + +registered in router aliases as list[str] + +--- + + + +#### get\_title + +```python +def get_title() -> str | None +``` + +Public. Gets title of the router + +**Returns**: + +the title of the router as str or None + +--- + + + +#### set\_title + +```python +def set_title(title: str) -> None +``` + +Public. Sets the title of the router + +**Arguments**: + +- `title`: title that will be setted + +**Returns**: + +`None` + +--- + + + +# `.router.exceptions` + + + +## RepeatedFlagNameException Objects + +```python +class RepeatedFlagNameException(Exception) +``` + +Private. Raised when a repeated flag name is registered + +--- + + + +## TooManyTransferredArgsException Objects + +```python +class TooManyTransferredArgsException(Exception) +``` + +Private. Raised when too many arguments are passed + +--- + + + +## RequiredArgumentNotPassedException Objects + +```python +class RequiredArgumentNotPassedException(Exception) +``` + +Private. Raised when a required argument is not passed + +--- + + + +## IncorrectNumberOfHandlerArgsException Objects + +```python +class IncorrectNumberOfHandlerArgsException(Exception) +``` + +Private. Raised when incorrect number of arguments are passed + +--- + + + +## TriggerContainSpacesException Objects + +```python +class TriggerContainSpacesException(Exception) +``` + +Private. Raised when there is a space in the trigger being registered + + + +--- + +# Tests + +Run tests: + +```bash +python -m unittest discover +``` +or +```bash +python -m unittest discover -v +``` + +--- + +# made by kolo `MIT` `2025` + diff --git a/argenta/app/autocompleter/entity.py b/argenta/app/autocompleter/entity.py index dcdb743..560d067 100644 --- a/argenta/app/autocompleter/entity.py +++ b/argenta/app/autocompleter/entity.py @@ -40,7 +40,7 @@ class AutoCompleter: 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 :return: None """ @@ -57,7 +57,7 @@ class AutoCompleter: def exit_setup(self) -> None: """ - Public. Exit setup function + Private. Exit setup function :return: None """ if self.history_filename: diff --git a/argenta/app/models.py b/argenta/app/models.py index 028406c..c1a9bf7 100644 --- a/argenta/app/models.py +++ b/argenta/app/models.py @@ -230,7 +230,7 @@ class BaseApp: self._exit_command_handler() 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) @@ -240,10 +240,10 @@ class BaseApp: :return: None """ 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' + 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' 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'[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)}') @@ -369,7 +369,7 @@ class App(BaseApp): :param router: registered router :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) diff --git a/argenta/command/flag/models.py b/argenta/command/flag/models.py index d77c527..36add2f 100644 --- a/argenta/command/flag/models.py +++ b/argenta/command/flag/models.py @@ -168,6 +168,11 @@ class BaseFlags(ABC): class Flags(BaseFlags, ABC): 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 [] def get_flags(self) -> list[Flag]: @@ -189,6 +194,11 @@ class Flags(BaseFlags, ABC): class InputFlags(BaseFlags, ABC): 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 [] def get_flags(self) -> list[InputFlag]: diff --git a/argenta/command/models.py b/argenta/command/models.py index 8013e8c..7ebf472 100644 --- a/argenta/command/models.py +++ b/argenta/command/models.py @@ -18,7 +18,7 @@ class BaseCommand: 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 self._trigger diff --git a/argenta/orchestrator/argparser/__init__.py b/argenta/orchestrator/argparser/__init__.py index 408d251..3e33bb8 100644 --- a/argenta/orchestrator/argparser/__init__.py +++ b/argenta/orchestrator/argparser/__init__.py @@ -1,4 +1,4 @@ -__all__ = ["ArgParse"] +__all__ = ["ArgParser"] -from argenta.orchestrator.argparse.entity import ArgParse \ No newline at end of file +from argenta.orchestrator.argparser.entity import ArgParser \ No newline at end of file diff --git a/argenta/orchestrator/argparser/arguments/__init__.py b/argenta/orchestrator/argparser/arguments/__init__.py index c6b74a4..dc4f216 100644 --- a/argenta/orchestrator/argparser/arguments/__init__.py +++ b/argenta/orchestrator/argparser/arguments/__init__.py @@ -1,6 +1,6 @@ __all__ = ["BooleanArgument", "PositionalArgument", "OptionalArgument"] -from argenta.orchestrator.argparse.arguments.models import (BooleanArgument, - PositionalArgument, - OptionalArgument) +from argenta.orchestrator.argparser.arguments.models import (BooleanArgument, + PositionalArgument, + OptionalArgument) diff --git a/argenta/orchestrator/argparser/entity.py b/argenta/orchestrator/argparser/entity.py index 7c11119..82105b6 100644 --- a/argenta/orchestrator/argparser/entity.py +++ b/argenta/orchestrator/argparser/entity.py @@ -1,11 +1,11 @@ from argparse import ArgumentParser -from argenta.orchestrator.argparse.arguments.models import (BooleanArgument, - OptionalArgument, - PositionalArgument) +from argenta.orchestrator.argparser.arguments.models import (BooleanArgument, + OptionalArgument, + PositionalArgument) -class ArgParse: +class ArgParser: def __init__(self, processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument], name: str = 'Argenta', diff --git a/argenta/orchestrator/entity.py b/argenta/orchestrator/entity.py index 6c11857..7ec4daa 100644 --- a/argenta/orchestrator/entity.py +++ b/argenta/orchestrator/entity.py @@ -1,24 +1,24 @@ from argparse import Namespace from argenta.app import App -from argenta.orchestrator.argparse import ArgParse +from argenta.orchestrator.argparser import ArgParser 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 :return: None """ - self.arg_parser: ArgParse | False = arg_parser + self.arg_parser: ArgParser | False = arg_parser if arg_parser: self.arg_parser.register_args() @staticmethod def start_polling(app: App) -> None: """ - Starting the user input processing cycle + Public. Starting the user input processing cycle :param app: a running application :return: None """ @@ -26,7 +26,7 @@ class Orchestrator: def get_input_args(self) -> Namespace | None: """ - Returns the arguments parsed + Public. Returns the arguments parsed :return: None """ if self.arg_parser: diff --git a/argenta/router/command_handler/entity.py b/argenta/router/command_handler/entity.py index 9b371d0..76cb8c8 100644 --- a/argenta/router/command_handler/entity.py +++ b/argenta/router/command_handler/entity.py @@ -7,33 +7,69 @@ from argenta.command.flag import InputFlags class CommandHandler: 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._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: self._handler(input_flags) else: 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 - 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 class CommandHandlers: 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 [] 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 - 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) - 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) def __iter__(self): diff --git a/argenta/router/defaults.py b/argenta/router/defaults.py index cd9b999..a56e7ad 100644 --- a/argenta/router/defaults.py +++ b/argenta/router/defaults.py @@ -1,5 +1,4 @@ from argenta.router import Router -system_router = Router(title='System points:', - name='System') +system_router = Router(title='System points:') diff --git a/argenta/router/entity.py b/argenta/router/entity.py index dc8fbdb..20ce841 100644 --- a/argenta/router/entity.py +++ b/argenta/router/entity.py @@ -1,6 +1,5 @@ from typing import Callable from inspect import getfullargspec - from argenta.command import Command from argenta.command.models import InputCommand from argenta.router.command_handler.entity import CommandHandlers, CommandHandler @@ -9,21 +8,18 @@ from argenta.router.exceptions import (RepeatedFlagNameException, TooManyTransferredArgsException, RequiredArgumentNotPassedException, IncorrectNumberOfHandlerArgsException, - TriggerCannotContainSpacesException) + TriggerContainSpacesException) class Router: def __init__(self, - title: str = None, - name: str = 'Default'): + title: str = None): """ Public. Directly configures and manages handlers - :param title: the title of the router - :param name: the name of the router + :param title: the title of the router, displayed when displaying the available commands :return: None """ self._title = title - self._name = name self._command_handlers: CommandHandlers = CommandHandlers() self._ignore_command_register: bool = False @@ -105,9 +101,15 @@ class Router: 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: - is_valid = handle_command.validate_input_flag(flag) + is_valid: bool = handled_command.validate_input_flag(flag) if not is_valid: self._not_valid_flag_handler(flag) return False @@ -115,10 +117,15 @@ class Router: @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() if command_name.find(' ') != -1: - raise TriggerCannotContainSpacesException() + raise TriggerContainSpacesException() flags: Flags = command.get_registered_flags() if flags: @@ -128,7 +135,13 @@ class Router: @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() transferred_args = getfullargspec(func).args if registered_args.get_flags() and transferred_args: @@ -140,18 +153,31 @@ class Router: raise TooManyTransferredArgsException() - def set_ignore_command_register(self, ignore_command_register: bool): - self._ignore_command_register = ignore_command_register + def set_command_register_ignore(self, _: bool) -> None: + """ + 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] = [] for command_handler in self._command_handlers: all_triggers.append(command_handler.get_handled_command().get_trigger()) 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] = [] for command_handler in self._command_handlers: if command_handler.get_handled_command().get_aliases(): @@ -160,16 +186,25 @@ class Router: def get_command_handlers(self) -> CommandHandlers: + """ + Private. Gets registered command handlers + :return: registered command handlers as CommandHandlers + """ return self._command_handlers - def get_name(self) -> str: - return self._name - - 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 - 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 diff --git a/argenta/router/exceptions.py b/argenta/router/exceptions.py index ca3ed1f..201415e 100644 --- a/argenta/router/exceptions.py +++ b/argenta/router/exceptions.py @@ -30,7 +30,7 @@ class IncorrectNumberOfHandlerArgsException(Exception): 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 """ diff --git a/mock/mock_app/handlers/routers.py b/mock/mock_app/handlers/routers.py index 104e8d9..307a2f3 100644 --- a/mock/mock_app/handlers/routers.py +++ b/mock/mock_app/handlers/routers.py @@ -9,27 +9,17 @@ from .handlers_implementation.help_command import help_command work_router: Router = Router(title='Work points:') -settings_router: Router = Router() - console = Console() @work_router.command(Command('get', 'Get Help', aliases=['help', 'Get_help'])) def command_help(): - help_command() + pass -@work_router.command(Command('start', 'Start Solving', - flags=Flags(PredefinedFlags.HOST, PredefinedFlags.PORT), - aliases=['starting'])) -def command_start_solving(args: InputFlags): - print(args.get_flag('host')) - - -@settings_router.command(Command('update', 'Update WordMath')) -def command_update(): - print('eeeeeee') - +@work_router.command(Command('run', 'Run All')) +def command_start_solving(): + pass diff --git a/mock/mock_app/main.py b/mock/mock_app/main.py index 199a217..4835799 100644 --- a/mock/mock_app/main.py +++ b/mock/mock_app/main.py @@ -1,30 +1,27 @@ -from argenta.command import Command -from mock.mock_app.handlers.routers import work_router, settings_router +from mock.mock_app.handlers.routers import work_router 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.argparse import ArgParse -from argenta.orchestrator.argparse.arguments import BooleanArgument +from argenta.orchestrator.argparser import ArgParser +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(), - autocompleter=AutoCompleter('./mock/.hist'), - exit_command=Command('w', aliases=['test'])) + autocompleter=AutoCompleter('./mock/.hist')) orchestrator: Orchestrator = Orchestrator(arg_parser) 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.AUTOCOMPLETE) app.add_message_on_startup(PredefinedMessages.HELP) - print(orchestrator.get_input_args()) orchestrator.start_polling(app) if __name__ == "__main__": diff --git a/tests/unit_tests/test_router.py b/tests/unit_tests/test_router.py index 2c7f279..e55b38f 100644 --- a/tests/unit_tests/test_router.py +++ b/tests/unit_tests/test_router.py @@ -1,6 +1,6 @@ from argenta.router import Router from argenta.command import Command -from argenta.router.exceptions import TriggerCannotContainSpacesException +from argenta.router.exceptions import TriggerContainSpacesException import unittest @@ -14,7 +14,7 @@ class TestRouter(unittest.TestCase): def test_register_command_with_spaces_in_trigger(self): router = Router() - with self.assertRaises(TriggerCannotContainSpacesException): + with self.assertRaises(TriggerContainSpacesException): @router.command(Command(trigger='command with spaces')) def test(): return 'correct result'