ruff format

This commit is contained in:
2025-05-09 23:25:21 +03:00
parent 9a78aa9263
commit 13f7e33db1
29 changed files with 471 additions and 298 deletions
+3 -2
View File
@@ -8,8 +8,8 @@ from argenta.orchestrator.argparser import ArgParser
from argenta.orchestrator.argparser.arguments import BooleanArgument from argenta.orchestrator.argparser.arguments import BooleanArgument
arg_parser = ArgParser(processed_args=[BooleanArgument('repeat')]) arg_parser = ArgParser(processed_args=[BooleanArgument("repeat")])
app: App = App(autocompleter=AutoCompleter('.hist')) app: App = App(autocompleter=AutoCompleter(".hist"))
orchestrator: Orchestrator = Orchestrator() orchestrator: Orchestrator = Orchestrator()
@@ -22,5 +22,6 @@ def main():
orchestrator.start_polling(app) orchestrator.start_polling(app)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
+11 -2
View File
@@ -14,12 +14,14 @@ import socket
# Маршрутизатор для работы с файлами # Маршрутизатор для работы с файлами
file_router = Router("Файловые операции") file_router = Router("Файловые операции")
@file_router.command(Command("list", "Список файлов")) @file_router.command(Command("list", "Список файлов"))
def list_files(response: Response): def list_files(response: Response):
files = os.listdir() files = os.listdir()
for file in files: for file in files:
print(file) print(file)
@file_router.command(Command("size", "Размер файла")) @file_router.command(Command("size", "Размер файла"))
def file_size(response: Response): def file_size(response: Response):
file_name = input("Введите имя файла: ") file_name = input("Введите имя файла: ")
@@ -29,9 +31,11 @@ def file_size(response: Response):
else: else:
print(f"Файл {file_name} не найден") print(f"Файл {file_name} не найден")
# Маршрутизатор для системных операций # Маршрутизатор для системных операций
system_router = Router("Системные операции") system_router = Router("Системные операции")
@system_router.command(Command("info", "Информация о системе")) @system_router.command(Command("info", "Информация о системе"))
def system_info(response: Response): def system_info(response: Response):
print(f"Система: {platform.system()}") print(f"Система: {platform.system()}")
@@ -39,6 +43,7 @@ def system_info(response: Response):
print(f"Архитектура: {platform.architecture()}") print(f"Архитектура: {platform.architecture()}")
print(f"Процессор: {platform.processor()}") print(f"Процессор: {platform.processor()}")
@system_router.command(Command("memory", "Информация о памяти")) @system_router.command(Command("memory", "Информация о памяти"))
def memory_info(response: Response): def memory_info(response: Response):
memory = psutil.virtual_memory() memory = psutil.virtual_memory()
@@ -46,27 +51,31 @@ def memory_info(response: Response):
print(f"Доступно: {memory.available / (1024**3):.2f} ГБ") print(f"Доступно: {memory.available / (1024**3):.2f} ГБ")
print(f"Использовано: {memory.used / (1024**3):.2f} ГБ ({memory.percent}%)") print(f"Использовано: {memory.used / (1024**3):.2f} ГБ ({memory.percent}%)")
# Маршрутизатор для сетевых операций # Маршрутизатор для сетевых операций
network_router = Router("Сетевые операции") network_router = Router("Сетевые операции")
@network_router.command(Command("ping", "Проверка доступности хоста")) @network_router.command(Command("ping", "Проверка доступности хоста"))
def ping_host(response: Response): def ping_host(response: Response):
host = input("Введите имя хоста: ") host = input("Введите имя хоста: ")
print(f"Пингую {host}...") print(f"Пингую {host}...")
subprocess.run(["ping", "-c", "4", host]) subprocess.run(["ping", "-c", "4", host])
@network_router.command(Command("ip", "Показать IP-адреса")) @network_router.command(Command("ip", "Показать IP-адреса"))
def show_ip(response: Response): def show_ip(response: Response):
hostname = socket.gethostname() hostname = socket.gethostname()
print(f"Имя хоста: {hostname}") print(f"Имя хоста: {hostname}")
print(f"IP-адрес: {socket.gethostbyname(hostname)}") print(f"IP-адрес: {socket.gethostbyname(hostname)}")
# Создание приложения и регистрация маршрутизаторов # Создание приложения и регистрация маршрутизаторов
app = App( app = App(
prompt="System> ", prompt="System> ",
initial_message="Pingator", initial_message="Pingator",
dividing_line=DynamicDividingLine("*"), dividing_line=DynamicDividingLine("*"),
autocompleter=AutoCompleter('.hist', 'e'), autocompleter=AutoCompleter(".hist", "e"),
) )
# Добавляем все маршрутизаторы # Добавляем все маршрутизаторы
@@ -77,4 +86,4 @@ app.add_message_on_startup("Для просмотра доступных ком
# Запускаем приложение # Запускаем приложение
orchestrator = Orchestrator() orchestrator = Orchestrator()
orchestrator.start_polling(app) orchestrator.start_polling(app)
@@ -5,6 +5,8 @@ console = Console()
def help_command(): def help_command():
console.print("[italic bold]The main functionality of the script is to convert an expression from a string " console.print(
"to a mathematical one and then calculate this expression. " "[italic bold]The main functionality of the script is to convert an expression from a string "
"Project GitHub: https://github.com/koloideal/WordMath[/italic bold]") "to a mathematical one and then calculate this expression. "
"Project GitHub: https://github.com/koloideal/WordMath[/italic bold]"
)
+10 -6
View File
@@ -7,12 +7,19 @@ from argenta.response import Response
from argenta.router import Router from argenta.router import Router
work_router: Router = Router(title='Work points:') work_router: Router = Router(title="Work points:")
console = Console() console = Console()
@work_router.command(Command('get', 'Get Help', aliases=['help', 'Get_help'], flags=Flags(PredefinedFlags.PORT, PredefinedFlags.HOST))) @work_router.command(
Command(
"get",
"Get Help",
aliases=["help", "Get_help"],
flags=Flags(PredefinedFlags.PORT, PredefinedFlags.HOST),
)
)
def command_help(response: Response): def command_help(response: Response):
print(response.status) print(response.status)
print(response.undefined_flags.get_flags()) print(response.undefined_flags.get_flags())
@@ -20,12 +27,9 @@ def command_help(response: Response):
print(response.invalid_value_flags.get_flags()) print(response.invalid_value_flags.get_flags())
@work_router.command('run') @work_router.command("run")
def command_start_solving(response: Response): def command_start_solving(response: Response):
print(response.status) print(response.status)
print(response.undefined_flags.get_flags()) print(response.undefined_flags.get_flags())
print(response.valid_flags.get_flags()) print(response.valid_flags.get_flags())
print(response.invalid_value_flags.get_flags()) print(response.invalid_value_flags.get_flags())
+7 -4
View File
@@ -9,10 +9,12 @@ from argenta.orchestrator.argparser import ArgParser
from argenta.orchestrator.argparser.arguments import BooleanArgument from argenta.orchestrator.argparser.arguments import BooleanArgument
arg_parser = ArgParser(processed_args=[BooleanArgument('repeat')]) arg_parser = ArgParser(processed_args=[BooleanArgument("repeat")])
app: App = App(dividing_line=DynamicDividingLine(), app: App = App(
autocompleter=AutoCompleter(), dividing_line=DynamicDividingLine(),
repeat_command_groups=False,) autocompleter=AutoCompleter(),
repeat_command_groups=False,
)
orchestrator: Orchestrator = Orchestrator(arg_parser) orchestrator: Orchestrator = Orchestrator(arg_parser)
@@ -25,5 +27,6 @@ def main():
orchestrator.start_polling(app) orchestrator.start_polling(app)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
+22 -11
View File
@@ -4,7 +4,9 @@ from typing import Never
class AutoCompleter: class AutoCompleter:
def __init__(self, history_filename: str = False, autocomplete_button: str = 'tab') -> None: def __init__(
self, history_filename: str = False, autocomplete_button: str = "tab"
) -> None:
""" """
Public. Configures and implements auto-completion of input command Public. Configures and implements auto-completion of input command
:param history_filename: the name of the file for saving the history of the autocompleter :param history_filename: the name of the file for saving the history of the autocompleter
@@ -21,16 +23,22 @@ class AutoCompleter:
:param state: the current cursor position is relative to the beginning of the line :param state: the current cursor position is relative to the beginning of the line
:return: the desired candidate as str or None :return: the desired candidate as str or None
""" """
matches: list[str] = sorted(cmd for cmd in self.get_history_items() if cmd.startswith(text)) matches: list[str] = sorted(
cmd for cmd in self.get_history_items() if cmd.startswith(text)
)
if len(matches) > 1: if len(matches) > 1:
common_prefix = matches[0] common_prefix = matches[0]
for match in matches[1:]: for match in matches[1:]:
i = 0 i = 0
while i < len(common_prefix) and i < len(match) and common_prefix[i] == match[i]: while (
i < len(common_prefix)
and i < len(match)
and common_prefix[i] == match[i]
):
i += 1 i += 1
common_prefix = common_prefix[:i] common_prefix = common_prefix[:i]
if state == 0: if state == 0:
readline.insert_text(common_prefix[len(text):]) readline.insert_text(common_prefix[len(text) :])
readline.redisplay() readline.redisplay()
return None return None
elif len(matches) == 1: elif len(matches) == 1:
@@ -52,8 +60,8 @@ class AutoCompleter:
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")
def exit_setup(self, all_commands: list[str]) -> None: def exit_setup(self, all_commands: list[str]) -> None:
""" """
@@ -62,14 +70,14 @@ class AutoCompleter:
""" """
if self.history_filename: if self.history_filename:
readline.write_history_file(self.history_filename) readline.write_history_file(self.history_filename)
with open(self.history_filename, 'r') as history_file: with open(self.history_filename, "r") as history_file:
raw_history = history_file.read() raw_history = history_file.read()
pretty_history: list[str] = [] pretty_history: list[str] = []
for line in set(raw_history.strip().split('\n')): for line in set(raw_history.strip().split("\n")):
if line.split()[0] in all_commands: if line.split()[0] in all_commands:
pretty_history.append(line) pretty_history.append(line)
with open(self.history_filename, 'w') as history_file: with open(self.history_filename, "w") as history_file:
history_file.write('\n'.join(pretty_history)) history_file.write("\n".join(pretty_history))
@staticmethod @staticmethod
def get_history_items() -> list[str] | list[Never]: def get_history_items() -> list[str] | list[Never]:
@@ -77,4 +85,7 @@ class AutoCompleter:
Private. Returns a list of all commands entered by the user Private. Returns a list of all commands entered by the user
:return: all commands entered by the user as list[str] | list[Never] :return: all commands entered by the user as list[str] | list[Never]
""" """
return [readline.get_history_item(i) for i in range(1, readline.get_current_history_length() + 1)] return [
readline.get_history_item(i)
for i in range(1, readline.get_current_history_length() + 1)
]
+3 -3
View File
@@ -6,7 +6,7 @@ class PredefinedMessages:
""" """
Public. A dataclass with predetermined messages for quick use Public. A dataclass with predetermined messages for quick use
""" """
USAGE = '[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]'
HELP = '[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]'
AUTOCOMPLETE = '[b dim]Autocomplete[/b dim]: [i]<part>[/i] [bold]<tab>'
USAGE = "[b dim]Usage[/b dim]: [i]<command> <[green]flags[/green]>[/i]"
HELP = "[b dim]Help[/b dim]: [i]<command>[/i] [b red]--help[/b red]"
AUTOCOMPLETE = "[b dim]Autocomplete[/b dim]: [i]<part>[/i] [bold]<tab>"
+8 -10
View File
@@ -2,7 +2,7 @@ from abc import ABC
class BaseDividingLine(ABC): class BaseDividingLine(ABC):
def __init__(self, unit_part: str = '-') -> None: def __init__(self, unit_part: str = "-") -> None:
""" """
Private. The basic dividing line Private. The basic dividing line
:param unit_part: the single part of the dividing line :param unit_part: the single part of the dividing line
@@ -16,13 +16,13 @@ class BaseDividingLine(ABC):
:return: unit_part of dividing line as str :return: unit_part of dividing line as str
""" """
if len(self._unit_part) == 0: if len(self._unit_part) == 0:
return ' ' return " "
else: else:
return self._unit_part[0] return self._unit_part[0]
class StaticDividingLine(BaseDividingLine): class StaticDividingLine(BaseDividingLine):
def __init__(self, unit_part: str = '-', length: int = 25) -> None: def __init__(self, unit_part: str = "-", length: int = 25) -> None:
""" """
Public. The static dividing line Public. The static dividing line
:param unit_part: the single part of the dividing line :param unit_part: the single part of the dividing line
@@ -39,13 +39,13 @@ class StaticDividingLine(BaseDividingLine):
:return: full line of dividing line as str :return: full line of dividing line as str
""" """
if is_override: if is_override:
return f'\n{self.length * self.get_unit_part()}\n' return f"\n{self.length * self.get_unit_part()}\n"
else: else:
return f'\n[dim]{self.length * self.get_unit_part()}[/dim]\n' return f"\n[dim]{self.length * self.get_unit_part()}[/dim]\n"
class DynamicDividingLine(BaseDividingLine): class DynamicDividingLine(BaseDividingLine):
def __init__(self, unit_part: str = '-') -> None: def __init__(self, unit_part: str = "-") -> None:
""" """
Public. The dynamic dividing line Public. The dynamic dividing line
:param unit_part: the single part of the dividing line :param unit_part: the single part of the dividing line
@@ -61,8 +61,6 @@ class DynamicDividingLine(BaseDividingLine):
:return: full line of dividing line as str :return: full line of dividing line as str
""" """
if is_override: if is_override:
return f'\n{length * self.get_unit_part()}\n' return f"\n{length * self.get_unit_part()}\n"
else: else:
return f'\n[dim]{self.get_unit_part() * length}[/dim]\n' return f"\n[dim]{self.get_unit_part() * length}[/dim]\n"
+171 -106
View File
@@ -11,28 +11,31 @@ from argenta.router import Router
from argenta.router.defaults import system_router from argenta.router.defaults import system_router
from argenta.app.autocompleter import AutoCompleter from argenta.app.autocompleter import AutoCompleter
from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine
from argenta.command.exceptions import (UnprocessedInputFlagException, from argenta.command.exceptions import (
RepeatedInputFlagsException, UnprocessedInputFlagException,
EmptyInputCommandException, RepeatedInputFlagsException,
BaseInputCommandException) EmptyInputCommandException,
BaseInputCommandException,
)
from argenta.app.registered_routers.entity import RegisteredRouters from argenta.app.registered_routers.entity import RegisteredRouters
from argenta.response import Response from argenta.response import Response
class BaseApp: class BaseApp:
def __init__(self, prompt: str, def __init__(
initial_message: str, self,
farewell_message: str, prompt: str,
exit_command: Command, initial_message: str,
system_router_title: str | None, farewell_message: str,
ignore_command_register: bool, exit_command: Command,
dividing_line: StaticDividingLine | DynamicDividingLine, system_router_title: str | None,
repeat_command_groups: bool, ignore_command_register: bool,
override_system_messages: bool, dividing_line: StaticDividingLine | DynamicDividingLine,
autocompleter: AutoCompleter, repeat_command_groups: bool,
print_func: Callable[[str], None]) -> None: override_system_messages: bool,
autocompleter: AutoCompleter,
print_func: Callable[[str], None],
) -> None:
self._prompt = prompt self._prompt = prompt
self._print_func = print_func self._print_func = print_func
self._exit_command = exit_command self._exit_command = exit_command
@@ -46,20 +49,30 @@ class BaseApp:
self._farewell_message = farewell_message self._farewell_message = farewell_message
self._initial_message = initial_message self._initial_message = initial_message
self._description_message_gen: Callable[[str, str], str] = (
self._description_message_gen: Callable[[str, str], str] = lambda command, description: f'[{command}] *=*=* {description}' lambda command, description: f"[{command}] *=*=* {description}"
)
self._registered_routers: RegisteredRouters = RegisteredRouters() self._registered_routers: RegisteredRouters = RegisteredRouters()
self._messages_on_startup: list[str] = [] self._messages_on_startup: list[str] = []
self._all_registered_triggers_in_lower: list[str] = [] self._all_registered_triggers_in_lower: list[str] = []
self._all_registered_triggers_in_default_case: list[str] = [] self._all_registered_triggers_in_default_case: list[str] = []
self._incorrect_input_syntax_handler: Callable[[str], None] = lambda raw_command: print_func(f'Incorrect flag syntax: {raw_command}') self._incorrect_input_syntax_handler: Callable[[str], None] = (
self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Repeated input flags: {raw_command}') lambda raw_command: print_func(f"Incorrect flag syntax: {raw_command}")
self._empty_input_command_handler: Callable[[], None] = lambda: print_func('Empty input command') )
self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"Unknown command: {command.get_trigger()}") self._repeated_input_flags_handler: Callable[[str], None] = (
self._exit_command_handler: Callable[[Response], None] = lambda response: print_func(self._farewell_message) lambda raw_command: print_func(f"Repeated input flags: {raw_command}")
)
self._empty_input_command_handler: Callable[[], None] = lambda: print_func(
"Empty input command"
)
self._unknown_command_handler: Callable[[InputCommand], None] = (
lambda command: print_func(f"Unknown command: {command.get_trigger()}")
)
self._exit_command_handler: Callable[[Response], None] = (
lambda response: print_func(self._farewell_message)
)
def set_description_message_pattern(self, _: Callable[[str, str], str]) -> None: def set_description_message_pattern(self, _: Callable[[str, str], str]) -> None:
""" """
@@ -69,7 +82,6 @@ class BaseApp:
""" """
self._description_message_gen: Callable[[str, str], str] = _ self._description_message_gen: Callable[[str, str], str] = _
def set_incorrect_input_syntax_handler(self, _: Callable[[str], None]) -> None: def set_incorrect_input_syntax_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
@@ -78,7 +90,6 @@ class BaseApp:
""" """
self._incorrect_input_syntax_handler = _ self._incorrect_input_syntax_handler = _
def set_repeated_input_flags_handler(self, _: 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
@@ -87,7 +98,6 @@ class BaseApp:
""" """
self._repeated_input_flags_handler = _ self._repeated_input_flags_handler = _
def set_unknown_command_handler(self, _: 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
@@ -96,7 +106,6 @@ class BaseApp:
""" """
self._unknown_command_handler = _ self._unknown_command_handler = _
def set_empty_command_handler(self, _: 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
@@ -105,7 +114,6 @@ class BaseApp:
""" """
self._empty_input_command_handler = _ self._empty_input_command_handler = _
def set_exit_command_handler(self, _: 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
@@ -114,7 +122,6 @@ class BaseApp:
""" """
self._exit_command_handler = _ self._exit_command_handler = _
def _print_command_group_description(self) -> None: def _print_command_group_description(self) -> None:
""" """
Private. Prints the description of the available commands Private. Prints the description of the available commands
@@ -124,11 +131,13 @@ class BaseApp:
if registered_router.title: if registered_router.title:
self._print_func(registered_router.title) self._print_func(registered_router.title)
for command_handler in registered_router.get_command_handlers(): for command_handler in registered_router.get_command_handlers():
self._print_func(self._description_message_gen( self._print_func(
self._description_message_gen(
command_handler.get_handled_command().get_trigger(), command_handler.get_handled_command().get_trigger(),
command_handler.get_handled_command().get_description())) command_handler.get_handled_command().get_description(),
self._print_func('') )
)
self._print_func("")
def _print_framed_text(self, text: str) -> None: def _print_framed_text(self, text: str) -> None:
""" """
@@ -137,19 +146,36 @@ class BaseApp:
:return: None :return: None
""" """
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(
print(text.strip('\n')) 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)) )
print(text.strip("\n"))
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):
clear_text = re.sub(r'\u001b\[[0-9;]*m', '', text) clear_text = re.sub(r"\u001b\[[0-9;]*m", "", text)
max_length_line = max([len(line) for line in clear_text.split('\n')]) max_length_line = max([len(line) for line in clear_text.split("\n")])
max_length_line = max_length_line if 10 <= max_length_line <= 80 else 80 if max_length_line > 80 else 10 max_length_line = (
max_length_line
self._print_func(self._dividing_line.get_full_dynamic_line(max_length_line, self._override_system_messages)) if 10 <= max_length_line <= 80
print(text.strip('\n')) else 80
self._print_func(self._dividing_line.get_full_dynamic_line(max_length_line, self._override_system_messages)) if max_length_line > 80
else 10
)
self._print_func(
self._dividing_line.get_full_dynamic_line(
max_length_line, self._override_system_messages
)
)
print(text.strip("\n"))
self._print_func(
self._dividing_line.get_full_dynamic_line(
max_length_line, self._override_system_messages
)
)
def _is_exit_command(self, command: InputCommand) -> bool: def _is_exit_command(self, command: InputCommand) -> bool:
""" """
@@ -158,9 +184,14 @@ class BaseApp:
:return: is it an exit command or not as bool :return: is it an exit command or not as bool
""" """
if self._ignore_command_register: if self._ignore_command_register:
if command.get_trigger().lower() == self._exit_command.get_trigger().lower(): if (
command.get_trigger().lower()
== self._exit_command.get_trigger().lower()
):
return True return True
elif command.get_trigger().lower() in [x.lower() for x in self._exit_command.get_aliases()]: elif command.get_trigger().lower() in [
x.lower() for x in self._exit_command.get_aliases()
]:
return True return True
else: else:
if command.get_trigger() == self._exit_command.get_trigger(): if command.get_trigger() == self._exit_command.get_trigger():
@@ -169,7 +200,6 @@ class BaseApp:
return True return True
return False return False
def _is_unknown_command(self, command: InputCommand) -> bool: def _is_unknown_command(self, command: InputCommand) -> bool:
""" """
Private. Checks if the given command is an unknown command Private. Checks if the given command is an unknown command
@@ -185,8 +215,9 @@ class BaseApp:
return False return False
return True return True
def _error_handler(
def _error_handler(self, error: BaseInputCommandException, raw_command: str) -> None: self, error: BaseInputCommandException, raw_command: str
) -> None:
""" """
Private. Handles parsing errors of the entered command Private. Handles parsing errors of the entered command
:param error: error being handled :param error: error being handled
@@ -201,7 +232,6 @@ class BaseApp:
case EmptyInputCommandException(): case EmptyInputCommandException():
self._empty_input_command_handler() self._empty_input_command_handler()
def _setup_system_router(self) -> None: def _setup_system_router(self) -> None:
""" """
Private. Sets up system router Private. Sets up system router
@@ -217,12 +247,19 @@ class BaseApp:
system_router.set_command_register_ignore(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)
def _most_similar_command(self, unknown_command: str) -> str | None: def _most_similar_command(self, unknown_command: str) -> str | None:
all_commands = self._all_registered_triggers_in_lower if self._ignore_command_register else self._all_registered_triggers_in_default_case all_commands = (
matches: list[str] | list = sorted(cmd for cmd in all_commands if cmd.startswith(unknown_command)) self._all_registered_triggers_in_lower
if self._ignore_command_register
else self._all_registered_triggers_in_default_case
)
matches: list[str] | list = sorted(
cmd for cmd in all_commands if cmd.startswith(unknown_command)
)
if not matches: if not matches:
matches: list[str] | list = sorted(cmd for cmd in all_commands if unknown_command.startswith(cmd)) matches: list[str] | list = sorted(
cmd for cmd in all_commands if unknown_command.startswith(cmd)
)
if len(matches) == 1: if len(matches) == 1:
return matches[0] return matches[0]
elif len(matches) > 1: elif len(matches) > 1:
@@ -230,33 +267,49 @@ class BaseApp:
else: else:
return None return None
def _setup_default_view(self) -> None: def _setup_default_view(self) -> None:
""" """
Private. Sets up default app view Private. Sets up default app view
:return: None :return: None
""" """
self._prompt = '[italic dim bold]What do you want to do?\n' self._prompt = "[italic dim bold]What do you want to do?\n"
self._initial_message = f'\n[bold red]{text2art(self._initial_message, font="tarty1")}\n' self._initial_message = (
self._farewell_message = (f'[bold red]\n{text2art(f"\n{self._farewell_message}\n", font="chanky")}[/bold red]\n' f"\n[bold red]{text2art(self._initial_message, font='tarty1')}\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._farewell_message = (
f'[blue dim]*=*=*[/blue dim] ' f"[bold red]\n{text2art(f'\n{self._farewell_message}\n', font='chanky')}[/bold red]\n"
f'[bold yellow italic]{escape(description)}') f"[red i]github.com/koloideal/Argenta[/red i] | [red bold i]made by kolo[/red bold i]\n"
self._incorrect_input_syntax_handler = lambda raw_command: self._print_func(f'[red bold]Incorrect flag syntax: {escape(raw_command)}') )
self._repeated_input_flags_handler = lambda raw_command: self._print_func(f'[red bold]Repeated input flags: {escape(raw_command)}') self._description_message_gen = lambda command, description: (
self._empty_input_command_handler = lambda: self._print_func('[red bold]Empty input command') f"[bold red]{escape('[' + command + ']')}[/bold red] "
f"[blue dim]*=*=*[/blue dim] "
f"[bold yellow italic]{escape(description)}"
)
self._incorrect_input_syntax_handler = lambda raw_command: self._print_func(
f"[red bold]Incorrect flag syntax: {escape(raw_command)}"
)
self._repeated_input_flags_handler = lambda raw_command: self._print_func(
f"[red bold]Repeated input flags: {escape(raw_command)}"
)
self._empty_input_command_handler = lambda: self._print_func(
"[red bold]Empty input command"
)
def unknown_command_handler(command: InputCommand) -> None: def unknown_command_handler(command: InputCommand) -> None:
cmd_trg: str = command.get_trigger() cmd_trg: str = command.get_trigger()
mst_sim_cmd: str | None = self._most_similar_command(cmd_trg) mst_sim_cmd: str | None = self._most_similar_command(cmd_trg)
first_part_of_text = f"[red]Unknown command:[/red] [blue]{escape(cmd_trg)}[/blue]" first_part_of_text = (
second_part_of_text = ('[red], most similar:[/red] ' + ('[blue]' + mst_sim_cmd + '[/blue]')) if mst_sim_cmd else '' f"[red]Unknown command:[/red] [blue]{escape(cmd_trg)}[/blue]"
)
second_part_of_text = (
("[red], most similar:[/red] " + ("[blue]" + mst_sim_cmd + "[/blue]"))
if mst_sim_cmd
else ""
)
self._print_func(first_part_of_text + second_part_of_text) self._print_func(first_part_of_text + second_part_of_text)
self._unknown_command_handler = unknown_command_handler self._unknown_command_handler = unknown_command_handler
def _pre_cycle_setup(self) -> None: def _pre_cycle_setup(self) -> None:
""" """
Private. Configures various aspects of the application before the start of the cycle Private. Configures various aspects of the application before the start of the cycle
@@ -265,11 +318,19 @@ class BaseApp:
self._setup_system_router() self._setup_system_router()
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(
self._all_registered_triggers_in_default_case.extend(router_entity.get_aliases()) router_entity.get_triggers()
)
self._all_registered_triggers_in_default_case.extend(
router_entity.get_aliases()
)
self._all_registered_triggers_in_lower.extend([x.lower() for x in router_entity.get_triggers()]) self._all_registered_triggers_in_lower.extend(
self._all_registered_triggers_in_lower.extend([x.lower() for x in router_entity.get_aliases()]) [x.lower() for x in router_entity.get_triggers()]
)
self._all_registered_triggers_in_lower.extend(
[x.lower() for x in router_entity.get_aliases()]
)
self._autocompleter.initial_setup(self._all_registered_triggers_in_lower) self._autocompleter.initial_setup(self._all_registered_triggers_in_lower)
@@ -281,26 +342,27 @@ class BaseApp:
for message in self._messages_on_startup: for message in self._messages_on_startup:
self._print_func(message) self._print_func(message)
if self._messages_on_startup: if self._messages_on_startup:
print('\n') print("\n")
if not self._repeat_command_groups_description: if not self._repeat_command_groups_description:
self._print_command_group_description() self._print_command_group_description()
class App(BaseApp): class App(BaseApp):
def __init__(self, def __init__(
prompt: str = 'What do you want to do?\n', self,
initial_message: str = '\nArgenta\n', prompt: str = "What do you want to do?\n",
farewell_message: str = '\nSee you\n', initial_message: str = "\nArgenta\n",
exit_command: Command = Command('Q', 'Exit command'), farewell_message: str = "\nSee you\n",
system_router_title: str | None = 'System points:', exit_command: Command = Command("Q", "Exit command"),
ignore_command_register: bool = True, system_router_title: str | None = "System points:",
dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(), ignore_command_register: bool = True,
repeat_command_groups: bool = True, dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(),
override_system_messages: bool = False, repeat_command_groups: bool = True,
autocompleter: AutoCompleter = AutoCompleter(), override_system_messages: bool = False,
print_func: Callable[[str], None] = Console().print) -> None: autocompleter: AutoCompleter = AutoCompleter(),
print_func: Callable[[str], None] = Console().print,
) -> None:
""" """
Public. The essence of the application itself. Public. The essence of the application itself.
Configures and manages all aspects of the behavior and presentation of the user interacting with the user Configures and manages all aspects of the behavior and presentation of the user interacting with the user
@@ -317,18 +379,19 @@ class App(BaseApp):
:param print_func: system messages text output function :param print_func: system messages text output function
:return: None :return: None
""" """
super().__init__(prompt=prompt, super().__init__(
initial_message=initial_message, prompt=prompt,
farewell_message=farewell_message, initial_message=initial_message,
exit_command=exit_command, farewell_message=farewell_message,
system_router_title=system_router_title, exit_command=exit_command,
ignore_command_register=ignore_command_register, system_router_title=system_router_title,
dividing_line=dividing_line, ignore_command_register=ignore_command_register,
repeat_command_groups=repeat_command_groups, dividing_line=dividing_line,
override_system_messages=override_system_messages, repeat_command_groups=repeat_command_groups,
autocompleter=autocompleter, override_system_messages=override_system_messages,
print_func=print_func) autocompleter=autocompleter,
print_func=print_func,
)
def run_polling(self) -> None: def run_polling(self) -> None:
""" """
@@ -343,7 +406,9 @@ class App(BaseApp):
raw_command: str = Console().input(self._prompt) raw_command: str = Console().input(self._prompt)
try: try:
input_command: InputCommand = InputCommand.parse(raw_command=raw_command) input_command: InputCommand = InputCommand.parse(
raw_command=raw_command
)
except BaseInputCommandException as error: except BaseInputCommandException as error:
with redirect_stdout(io.StringIO()) as f: with redirect_stdout(io.StringIO()) as f:
self._error_handler(error, raw_command) self._error_handler(error, raw_command)
@@ -354,9 +419,13 @@ class App(BaseApp):
if self._is_exit_command(input_command): if self._is_exit_command(input_command):
system_router.finds_appropriate_handler(input_command) system_router.finds_appropriate_handler(input_command)
if self._ignore_command_register: if self._ignore_command_register:
self._autocompleter.exit_setup(self._all_registered_triggers_in_lower) self._autocompleter.exit_setup(
self._all_registered_triggers_in_lower
)
else: else:
self._autocompleter.exit_setup(self._all_registered_triggers_in_default_case) self._autocompleter.exit_setup(
self._all_registered_triggers_in_default_case
)
return return
if self._is_unknown_command(input_command): if self._is_unknown_command(input_command):
@@ -372,7 +441,6 @@ class App(BaseApp):
res: str = f.getvalue() res: str = f.getvalue()
self._print_framed_text(res) self._print_framed_text(res)
def include_router(self, router: Router) -> None: def include_router(self, router: Router) -> None:
""" """
Public. Registers the router in the application Public. Registers the router in the application
@@ -382,7 +450,6 @@ class App(BaseApp):
router.set_command_register_ignore(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)
def include_routers(self, *routers: Router) -> None: def include_routers(self, *routers: Router) -> None:
""" """
Public. Registers the routers in the application Public. Registers the routers in the application
@@ -392,7 +459,6 @@ class App(BaseApp):
for router in routers: for router in routers:
self.include_router(router) self.include_router(router)
def add_message_on_startup(self, message: str) -> None: def add_message_on_startup(self, message: str) -> None:
""" """
Public. Adds a message that will be displayed when the application is launched Public. Adds a message that will be displayed when the application is launched
@@ -400,4 +466,3 @@ class App(BaseApp):
:return: None :return: None
""" """
self._messages_on_startup.append(message) self._messages_on_startup.append(message)
+1 -1
View File
@@ -31,4 +31,4 @@ class RegisteredRouters:
return iter(self._registered_routers) return iter(self._registered_routers)
def __next__(self) -> Router: def __next__(self) -> Router:
return next(iter(self._registered_routers)) return next(iter(self._registered_routers))
+1 -1
View File
@@ -1,3 +1,3 @@
__all__ = ["Command"] __all__ = ["Command"]
from argenta.command.models import Command from argenta.command.models import Command
+9 -2
View File
@@ -5,6 +5,7 @@ class BaseInputCommandException(Exception):
""" """
Private. Base exception class for all exceptions raised when parse input command Private. Base exception class for all exceptions raised when parse input command
""" """
pass pass
@@ -12,6 +13,7 @@ class UnprocessedInputFlagException(BaseInputCommandException):
""" """
Private. Raised when an unprocessed input flag is detected Private. Raised when an unprocessed input flag is detected
""" """
def __str__(self): def __str__(self):
return "Unprocessed Input Flags" return "Unprocessed Input Flags"
@@ -20,16 +22,21 @@ class RepeatedInputFlagsException(BaseInputCommandException):
""" """
Private. Raised when repeated input flags are detected Private. Raised when repeated input flags are detected
""" """
def __init__(self, flag: Flag | InputFlag): def __init__(self, flag: Flag | InputFlag):
self.flag = flag self.flag = flag
def __str__(self): def __str__(self):
return ("Repeated Input Flags\n" return (
f"Duplicate flag was detected in the input: '{self.flag.get_string_entity()}'") "Repeated Input Flags\n"
f"Duplicate flag was detected in the input: '{self.flag.get_string_entity()}'"
)
class EmptyInputCommandException(BaseInputCommandException): class EmptyInputCommandException(BaseInputCommandException):
""" """
Private. Raised when an empty input command is detected Private. Raised when an empty input command is detected
""" """
def __str__(self): def __str__(self):
return "Input Command is empty" return "Input Command is empty"
+17 -10
View File
@@ -8,17 +8,24 @@ class PredefinedFlags:
""" """
Public. A dataclass with predefined flags and most frequently used flags for quick use Public. A dataclass with predefined flags and most frequently used flags for quick use
""" """
HELP = Flag(name='help', possible_values=False)
SHORT_HELP = Flag(name='H', prefix='-', possible_values=False)
INFO = Flag(name='info', possible_values=False) HELP = Flag(name="help", possible_values=False)
SHORT_INFO = Flag(name='I', prefix='-', possible_values=False) SHORT_HELP = Flag(name="H", prefix="-", possible_values=False)
ALL = Flag(name='all', possible_values=False) INFO = Flag(name="info", possible_values=False)
SHORT_ALL = Flag(name='A', prefix='-', possible_values=False) SHORT_INFO = Flag(name="I", prefix="-", possible_values=False)
HOST = Flag(name='host', possible_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')) ALL = Flag(name="all", possible_values=False)
SHORT_HOST = Flag(name='H', prefix='-', possible_values=re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')) SHORT_ALL = Flag(name="A", prefix="-", possible_values=False)
PORT = Flag(name='port', possible_values=re.compile(r'^\d{1,5}$')) HOST = Flag(
SHORT_PORT = Flag(name='P', prefix='-', possible_values=re.compile(r'^\d{1,5}$')) name="host", possible_values=re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
)
SHORT_HOST = Flag(
name="H",
prefix="-",
possible_values=re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"),
)
PORT = Flag(name="port", possible_values=re.compile(r"^\d{1,5}$"))
SHORT_PORT = Flag(name="P", prefix="-", possible_values=re.compile(r"^\d{1,5}$"))
+14 -11
View File
@@ -1,10 +1,8 @@
from typing import Literal, Pattern from typing import Literal, Pattern
class BaseFlag: class BaseFlag:
def __init__(self, name: str, def __init__(self, name: str, prefix: Literal["-", "--", "---"] = "--") -> None:
prefix: Literal['-', '--', '---'] = '--') -> None:
""" """
Private. Base class for flags Private. Base class for flags
:param name: the name of the flag :param name: the name of the flag
@@ -41,9 +39,12 @@ class BaseFlag:
class Flag(BaseFlag): class Flag(BaseFlag):
def __init__(self, name: str, def __init__(
prefix: Literal['-', '--', '---'] = '--', self,
possible_values: list[str] | Pattern[str] | False = True) -> None: name: str,
prefix: Literal["-", "--", "---"] = "--",
possible_values: list[str] | Pattern[str] | False = True,
) -> None:
""" """
Public. The entity of the flag being registered for subsequent processing Public. The entity of the flag being registered for subsequent processing
:param name: The name of the flag :param name: The name of the flag
@@ -85,9 +86,9 @@ class Flag(BaseFlag):
class InputFlag(BaseFlag): class InputFlag(BaseFlag):
def __init__(self, name: str, def __init__(
prefix: Literal['-', '--', '---'] = '--', self, name: str, prefix: Literal["-", "--", "---"] = "--", value: str = None
value: str = None): ):
""" """
Public. The entity of the flag of the entered command Public. The entity of the flag of the entered command
:param name: the name of the input flag :param name: the name of the input flag
@@ -114,5 +115,7 @@ class InputFlag(BaseFlag):
self._flag_value = value self._flag_value = value
def __eq__(self, other) -> bool: def __eq__(self, other) -> bool:
return self.get_string_entity() == other.get_string_entity() and self.get_value() == other.get_value() return (
self.get_string_entity() == other.get_string_entity()
and self.get_value() == other.get_value()
)
+14 -8
View File
@@ -1,10 +1,16 @@
__all__ = ["Flags", "InputFlags", __all__ = [
"UndefinedInputFlags", "Flags",
"InvalidValueInputFlags", "InputFlags",
"ValidInputFlags"] "UndefinedInputFlags",
"InvalidValueInputFlags",
"ValidInputFlags",
]
from argenta.command.flags.models import (Flags, InputFlags, from argenta.command.flags.models import (
UndefinedInputFlags, Flags,
InvalidValueInputFlags, InputFlags,
ValidInputFlags) UndefinedInputFlags,
InvalidValueInputFlags,
ValidInputFlags,
)
+1 -3
View File
@@ -2,8 +2,7 @@ from argenta.command.flag.models import InputFlag, Flag
from typing import Generic, TypeVar from typing import Generic, TypeVar
FlagType = TypeVar("FlagType")
FlagType = TypeVar('FlagType')
class BaseFlags(Generic[FlagType]): class BaseFlags(Generic[FlagType]):
@@ -89,4 +88,3 @@ class UndefinedInputFlags(InputFlags):
class InvalidValueInputFlags(InputFlags): class InvalidValueInputFlags(InputFlags):
pass pass
+60 -35
View File
@@ -1,12 +1,14 @@
from argenta.command.flag.models import Flag, InputFlag from argenta.command.flag.models import Flag, InputFlag
from argenta.command.flags.models import InputFlags, Flags from argenta.command.flags.models import InputFlags, Flags
from argenta.command.exceptions import (UnprocessedInputFlagException, from argenta.command.exceptions import (
RepeatedInputFlagsException, UnprocessedInputFlagException,
EmptyInputCommandException) RepeatedInputFlagsException,
EmptyInputCommandException,
)
from typing import Generic, TypeVar, cast, Literal from typing import Generic, TypeVar, cast, Literal
InputCommandType = TypeVar('InputCommandType') InputCommandType = TypeVar("InputCommandType")
class BaseCommand: class BaseCommand:
@@ -26,10 +28,13 @@ class BaseCommand:
class Command(BaseCommand): class Command(BaseCommand):
def __init__(self, trigger: str, def __init__(
description: str = None, self,
flags: Flag | Flags = None, trigger: str,
aliases: list[str] = None): description: str = None,
flags: Flag | Flags = None,
aliases: list[str] = None,
):
""" """
Public. The command that can and should be registered in the Router Public. The command that can and should be registered in the Router
:param trigger: A string trigger, which, when entered by the user, indicates that the input corresponds to the command :param trigger: A string trigger, which, when entered by the user, indicates that the input corresponds to the command
@@ -38,8 +43,14 @@ class Command(BaseCommand):
:param aliases: string synonyms for the main trigger :param aliases: string synonyms for the main trigger
""" """
super().__init__(trigger) super().__init__(trigger)
self._registered_flags: Flags = flags if isinstance(flags, Flags) else Flags(flags) if isinstance(flags, Flag) else Flags() self._registered_flags: Flags = (
self._description = 'Very useful command' if not description else description flags
if isinstance(flags, Flags)
else Flags(flags)
if isinstance(flags, Flag)
else Flags()
)
self._description = "Very useful command" if not description else description
self._aliases = aliases if isinstance(aliases, list) else [] self._aliases = aliases if isinstance(aliases, list) else []
def get_registered_flags(self) -> Flags: def get_registered_flags(self) -> Flags:
@@ -56,7 +67,9 @@ class Command(BaseCommand):
""" """
return self._aliases return self._aliases
def validate_input_flag(self, flag: InputFlag) -> Literal['Undefined', 'Valid', 'Invalid']: def validate_input_flag(
self, flag: InputFlag
) -> Literal["Undefined", "Valid", "Invalid"]:
""" """
Private. Validates the input flag Private. Validates the input flag
:param flag: input flag for validation :param flag: input flag for validation
@@ -66,23 +79,27 @@ class Command(BaseCommand):
if registered_flags: if registered_flags:
if isinstance(registered_flags, Flag): if isinstance(registered_flags, Flag):
if registered_flags.get_string_entity() == flag.get_string_entity(): if registered_flags.get_string_entity() == flag.get_string_entity():
is_valid = registered_flags.validate_input_flag_value(flag.get_value()) is_valid = registered_flags.validate_input_flag_value(
flag.get_value()
)
if is_valid: if is_valid:
return 'Valid' return "Valid"
else: else:
return 'Invalid' return "Invalid"
else: else:
return 'Undefined' return "Undefined"
else: else:
for registered_flag in registered_flags: for registered_flag in registered_flags:
if registered_flag.get_string_entity() == flag.get_string_entity(): if registered_flag.get_string_entity() == flag.get_string_entity():
is_valid = registered_flag.validate_input_flag_value(flag.get_value()) is_valid = registered_flag.validate_input_flag_value(
flag.get_value()
)
if is_valid: if is_valid:
return 'Valid' return "Valid"
else: else:
return 'Invalid' return "Invalid"
return 'Undefined' return "Undefined"
return 'Undefined' return "Undefined"
def get_description(self) -> str: def get_description(self) -> str:
""" """
@@ -92,10 +109,8 @@ class Command(BaseCommand):
return self._description return self._description
class InputCommand(BaseCommand, Generic[InputCommandType]): class InputCommand(BaseCommand, Generic[InputCommandType]):
def __init__(self, trigger: str, def __init__(self, trigger: str, input_flags: InputFlag | InputFlags = None):
input_flags: InputFlag | InputFlags = None):
""" """
Private. The model of the input command, after parsing Private. The model of the input command, after parsing
:param trigger:the trigger of the command :param trigger:the trigger of the command
@@ -103,7 +118,13 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
:return: None :return: None
""" """
super().__init__(trigger) super().__init__(trigger)
self._input_flags: InputFlags = input_flags if isinstance(input_flags, InputFlags) else InputFlags(input_flags) if isinstance(input_flags, InputFlag) else InputFlags() self._input_flags: InputFlags = (
input_flags
if isinstance(input_flags, InputFlags)
else InputFlags(input_flags)
if isinstance(input_flags, InputFlag)
else InputFlags()
)
def _set_input_flags(self, input_flags: InputFlags) -> None: def _set_input_flags(self, input_flags: InputFlags) -> None:
""" """
@@ -120,7 +141,6 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
""" """
return self._input_flags return self._input_flags
@staticmethod @staticmethod
def parse(raw_command: str) -> InputCommandType: def parse(raw_command: str) -> InputCommandType:
""" """
@@ -138,8 +158,8 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
current_flag_name, current_flag_value = None, None current_flag_name, current_flag_value = None, None
for k, _ in enumerate(list_of_tokens): for k, _ in enumerate(list_of_tokens):
if _.startswith('-'): if _.startswith("-"):
if len(_) < 2 or len(_[:_.rfind('-')]) > 3: if len(_) < 2 or len(_[: _.rfind("-")]) > 3:
raise UnprocessedInputFlagException() raise UnprocessedInputFlagException()
current_flag_name = _ current_flag_name = _
else: else:
@@ -148,16 +168,22 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
current_flag_value = _ current_flag_value = _
if current_flag_name: if current_flag_name:
if not len(list_of_tokens) == k+1: if not len(list_of_tokens) == k + 1:
if not list_of_tokens[k+1].startswith('-'): if not list_of_tokens[k + 1].startswith("-"):
continue continue
input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-') + 1:], input_flag = InputFlag(
prefix=cast(Literal['-', '--', '---'], name=current_flag_name[current_flag_name.rfind("-") + 1 :],
current_flag_name[:current_flag_name.rfind('-')+1]), prefix=cast(
value=current_flag_value) Literal["-", "--", "---"],
current_flag_name[: current_flag_name.rfind("-") + 1],
),
value=current_flag_value,
)
all_flags = [flag.get_string_entity() for flag in input_flags.get_flags()] all_flags = [
flag.get_string_entity() for flag in input_flags.get_flags()
]
if input_flag.get_string_entity() not in all_flags: if input_flag.get_string_entity() not in all_flags:
input_flags.add_flag(input_flag) input_flags.add_flag(input_flag)
else: else:
@@ -169,4 +195,3 @@ class InputCommand(BaseCommand, Generic[InputCommandType]):
raise UnprocessedInputFlagException() raise UnprocessedInputFlagException()
else: else:
return InputCommand(trigger=command, input_flags=input_flags) return InputCommand(trigger=command, input_flags=input_flags)
@@ -1,4 +1,4 @@
__all__ = ["ArgParser"] __all__ = ["ArgParser"]
from argenta.orchestrator.argparser.entity import ArgParser from argenta.orchestrator.argparser.entity import ArgParser
@@ -1,6 +1,8 @@
__all__ = ["BooleanArgument", "PositionalArgument", "OptionalArgument"] __all__ = ["BooleanArgument", "PositionalArgument", "OptionalArgument"]
from argenta.orchestrator.argparser.arguments.models import (BooleanArgument, from argenta.orchestrator.argparser.arguments.models import (
PositionalArgument, BooleanArgument,
OptionalArgument) PositionalArgument,
OptionalArgument,
)
@@ -6,6 +6,7 @@ class BaseArgument(ABC):
""" """
Private. Base class for all arguments Private. Base class for all arguments
""" """
@abstractmethod @abstractmethod
def get_string_entity(self) -> str: def get_string_entity(self) -> str:
""" """
@@ -28,7 +29,7 @@ class PositionalArgument(BaseArgument):
class OptionalArgument(BaseArgument): class OptionalArgument(BaseArgument):
def __init__(self, name: str, prefix: Literal['-', '--', '---'] = '--'): def __init__(self, name: str, prefix: Literal["-", "--", "---"] = "--"):
""" """
Public. Optional argument, must have the value Public. Optional argument, must have the value
:param name: name of the argument :param name: name of the argument
@@ -42,7 +43,7 @@ class OptionalArgument(BaseArgument):
class BooleanArgument(BaseArgument): class BooleanArgument(BaseArgument):
def __init__(self, name: str, prefix: Literal['-', '--', '---'] = '--'): def __init__(self, name: str, prefix: Literal["-", "--", "---"] = "--"):
""" """
Public. Boolean argument, does not require a value Public. Boolean argument, does not require a value
:param name: name of the argument :param name: name of the argument
+22 -12
View File
@@ -1,16 +1,20 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from argenta.orchestrator.argparser.arguments.models import (BooleanArgument, from argenta.orchestrator.argparser.arguments.models import (
OptionalArgument, BooleanArgument,
PositionalArgument) OptionalArgument,
PositionalArgument,
)
class ArgParser: class ArgParser:
def __init__(self, def __init__(
processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument], self,
name: str = 'Argenta', processed_args: list[PositionalArgument | OptionalArgument | BooleanArgument],
description: str = 'Argenta available arguments', name: str = "Argenta",
epilog: str = 'github.com/koloideal/Argenta | made by kolo') -> None: description: str = "Argenta available arguments",
epilog: str = "github.com/koloideal/Argenta | made by kolo",
) -> None:
""" """
Public. Cmd argument parser and configurator at startup Public. Cmd argument parser and configurator at startup
:param name: the name of the ArgParse instance :param name: the name of the ArgParse instance
@@ -22,10 +26,16 @@ class ArgParser:
self.description = description self.description = description
self.epilog = epilog self.epilog = epilog
self.entity: ArgumentParser = ArgumentParser(prog=name, description=description, epilog=epilog) self.entity: ArgumentParser = ArgumentParser(
self.args: list[PositionalArgument | OptionalArgument | BooleanArgument] | None = processed_args prog=name, description=description, epilog=epilog
)
self.args: (
list[PositionalArgument | OptionalArgument | BooleanArgument] | None
) = processed_args
def set_args(self, *args: PositionalArgument | OptionalArgument | BooleanArgument) -> None: def set_args(
self, *args: PositionalArgument | OptionalArgument | BooleanArgument
) -> None:
""" """
Public. Sets the arguments to be processed Public. Sets the arguments to be processed
:param args: processed arguments :param args: processed arguments
@@ -46,4 +56,4 @@ class ArgParser:
elif type(arg) is OptionalArgument: elif type(arg) is OptionalArgument:
self.entity.add_argument(arg.get_string_entity()) self.entity.add_argument(arg.get_string_entity())
elif type(arg) is BooleanArgument: elif type(arg) is BooleanArgument:
self.entity.add_argument(arg.get_string_entity(), action='store_true') self.entity.add_argument(arg.get_string_entity(), action="store_true")
-1
View File
@@ -33,4 +33,3 @@ class Orchestrator:
return self.arg_parser.entity.parse_args() return self.arg_parser.entity.parse_args()
else: else:
return None return None
+13 -11
View File
@@ -1,19 +1,21 @@
from argenta.response.status import Status from argenta.response.status import Status
from argenta.command.flags import (ValidInputFlags, from argenta.command.flags import (
UndefinedInputFlags, ValidInputFlags,
InvalidValueInputFlags) UndefinedInputFlags,
InvalidValueInputFlags,
)
class Response: class Response:
__slots__ = ('status', __slots__ = ("status", "valid_flags", "undefined_flags", "invalid_value_flags")
'valid_flags',
'undefined_flags',
'invalid_value_flags')
def __init__(self, status: Status = None, def __init__(
valid_flags: ValidInputFlags = ValidInputFlags(), self,
undefined_flags: UndefinedInputFlags = UndefinedInputFlags(), status: Status = None,
invalid_value_flags: InvalidValueInputFlags = InvalidValueInputFlags()): valid_flags: ValidInputFlags = ValidInputFlags(),
undefined_flags: UndefinedInputFlags = UndefinedInputFlags(),
invalid_value_flags: InvalidValueInputFlags = InvalidValueInputFlags(),
):
""" """
Public. The entity of the user input sent to the handler Public. The entity of the user input sent to the handler
:param status: the status of the response :param status: the status of the response
+4 -5
View File
@@ -2,8 +2,7 @@ from enum import Enum
class Status(Enum): class Status(Enum):
ALL_FLAGS_VALID = 'ALL_FLAGS_VALID' ALL_FLAGS_VALID = "ALL_FLAGS_VALID"
UNDEFINED_FLAGS = 'UNDEFINED_FLAGS' UNDEFINED_FLAGS = "UNDEFINED_FLAGS"
INVALID_VALUE_FLAGS = 'INVALID_VALUE_FLAGS' INVALID_VALUE_FLAGS = "INVALID_VALUE_FLAGS"
UNDEFINED_AND_INVALID_FLAGS = 'UNDEFINED_AND_INVALID_FLAGS' UNDEFINED_AND_INVALID_FLAGS = "UNDEFINED_AND_INVALID_FLAGS"
+1 -1
View File
@@ -1,4 +1,4 @@
__all__ = ["Router"] __all__ = ["Router"]
from argenta.router.entity import Router from argenta.router.entity import Router
+1 -1
View File
@@ -64,4 +64,4 @@ class CommandHandlers:
return iter(self.command_handlers) return iter(self.command_handlers)
def __next__(self) -> CommandHandler: def __next__(self) -> CommandHandler:
return next(iter(self.command_handlers)) return next(iter(self.command_handlers))
+1 -1
View File
@@ -1,4 +1,4 @@
from argenta.router import Router from argenta.router import Router
system_router = Router(title='System points:') system_router = Router(title="System points:")
+59 -42
View File
@@ -6,18 +6,23 @@ from argenta.command import Command
from argenta.command.models import InputCommand from argenta.command.models import InputCommand
from argenta.response import Response, Status from argenta.response import Response, Status
from argenta.router.command_handler.entity import CommandHandlers, CommandHandler from argenta.router.command_handler.entity import CommandHandlers, CommandHandler
from argenta.command.flags.models import (Flags, InputFlags, from argenta.command.flags.models import (
UndefinedInputFlags, Flags,
ValidInputFlags, InputFlags,
InvalidValueInputFlags) UndefinedInputFlags,
from argenta.router.exceptions import (RepeatedFlagNameException, ValidInputFlags,
TooManyTransferredArgsException, InvalidValueInputFlags,
RequiredArgumentNotPassedException, )
TriggerContainSpacesException) from argenta.router.exceptions import (
RepeatedFlagNameException,
TooManyTransferredArgsException,
RequiredArgumentNotPassedException,
TriggerContainSpacesException,
)
class Router: class Router:
def __init__(self, title: str | None = 'Awesome title'): def __init__(self, title: str | None = "Awesome title"):
""" """
Public. Directly configures and manages handlers Public. Directly configures and manages handlers
:param title: the title of the router, displayed when displaying the available commands :param title: the title of the router, displayed when displaying the available commands
@@ -28,7 +33,6 @@ class Router:
self._command_handlers: CommandHandlers = CommandHandlers() self._command_handlers: CommandHandlers = CommandHandlers()
self._ignore_command_register: bool = False self._ignore_command_register: bool = False
def command(self, command: Command | str) -> Callable: def command(self, command: Command | str) -> Callable:
""" """
Public. Registers handler Public. Registers handler
@@ -45,11 +49,11 @@ class Router:
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper return wrapper
return command_decorator return command_decorator
def finds_appropriate_handler(self, input_command: InputCommand) -> None: def finds_appropriate_handler(self, input_command: InputCommand) -> None:
""" """
Private. Finds the appropriate handler for given input command and passes control to it Private. Finds the appropriate handler for given input command and passes control to it
@@ -66,8 +70,9 @@ class Router:
if input_command_name.lower() in handle_command.get_aliases(): if input_command_name.lower() in handle_command.get_aliases():
self.process_input_command(input_command_flags, command_handler) self.process_input_command(input_command_flags, command_handler)
def process_input_command(
def process_input_command(self, input_command_flags: InputFlags, command_handler: CommandHandler) -> None: self, input_command_flags: InputFlags, command_handler: CommandHandler
) -> None:
""" """
Private. Processes input command with the appropriate handler Private. Processes input command with the appropriate handler
:param input_command_flags: input command flags as InputFlags :param input_command_flags: input command flags as InputFlags
@@ -78,7 +83,9 @@ class Router:
response: Response = Response() response: Response = Response()
if handle_command.get_registered_flags().get_flags(): if handle_command.get_registered_flags().get_flags():
if input_command_flags.get_flags(): if input_command_flags.get_flags():
response: Response = self._structuring_input_flags(handle_command, input_command_flags) response: Response = self._structuring_input_flags(
handle_command, input_command_flags
)
command_handler.handling(response) command_handler.handling(response)
else: else:
response.status = Status.ALL_FLAGS_VALID response.status = Status.ALL_FLAGS_VALID
@@ -93,9 +100,10 @@ class Router:
response.status = Status.ALL_FLAGS_VALID response.status = Status.ALL_FLAGS_VALID
command_handler.handling(response) command_handler.handling(response)
@staticmethod @staticmethod
def _structuring_input_flags(handled_command: Command, input_flags: InputFlags) -> Response: def _structuring_input_flags(
handled_command: Command, input_flags: InputFlags
) -> Response:
""" """
Private. Validates flags of input command Private. Validates flags of input command
:param handled_command: entity of the handled command :param handled_command: entity of the handled command
@@ -106,29 +114,41 @@ class Router:
invalid_value_input_flags: InvalidValueInputFlags = InvalidValueInputFlags() invalid_value_input_flags: InvalidValueInputFlags = InvalidValueInputFlags()
undefined_input_flags: UndefinedInputFlags = UndefinedInputFlags() undefined_input_flags: UndefinedInputFlags = UndefinedInputFlags()
for flag in input_flags: for flag in input_flags:
flag_status: Literal['Undefined', 'Valid', 'Invalid'] = handled_command.validate_input_flag(flag) flag_status: Literal["Undefined", "Valid", "Invalid"] = (
handled_command.validate_input_flag(flag)
)
match flag_status: match flag_status:
case 'Valid': case "Valid":
valid_input_flags.add_flag(flag) valid_input_flags.add_flag(flag)
case 'Undefined': case "Undefined":
undefined_input_flags.add_flag(flag) undefined_input_flags.add_flag(flag)
case 'Invalid': case "Invalid":
invalid_value_input_flags.add_flag(flag) invalid_value_input_flags.add_flag(flag)
if not invalid_value_input_flags.get_flags() and not undefined_input_flags.get_flags(): if (
not invalid_value_input_flags.get_flags()
and not undefined_input_flags.get_flags()
):
status = Status.ALL_FLAGS_VALID status = Status.ALL_FLAGS_VALID
elif invalid_value_input_flags.get_flags() and not undefined_input_flags.get_flags(): elif (
invalid_value_input_flags.get_flags()
and not undefined_input_flags.get_flags()
):
status = Status.INVALID_VALUE_FLAGS status = Status.INVALID_VALUE_FLAGS
elif not invalid_value_input_flags.get_flags() and undefined_input_flags.get_flags(): elif (
not invalid_value_input_flags.get_flags()
and undefined_input_flags.get_flags()
):
status = Status.UNDEFINED_FLAGS status = Status.UNDEFINED_FLAGS
else: else:
status = Status.UNDEFINED_AND_INVALID_FLAGS status = Status.UNDEFINED_AND_INVALID_FLAGS
return Response(invalid_value_flags=invalid_value_input_flags, return Response(
valid_flags=valid_input_flags, invalid_value_flags=invalid_value_input_flags,
status=status, valid_flags=valid_input_flags,
undefined_flags=undefined_input_flags) status=status,
undefined_flags=undefined_input_flags,
)
@staticmethod @staticmethod
def _validate_command(command: Command | str) -> None: def _validate_command(command: Command | str) -> None:
@@ -138,20 +158,19 @@ class Router:
:return: None if command is valid else raise exception :return: None if command is valid else raise exception
""" """
match type(command).__name__: match type(command).__name__:
case 'Command': case "Command":
command_name: str = command.get_trigger() command_name: str = command.get_trigger()
if command_name.find(' ') != -1: if command_name.find(" ") != -1:
raise TriggerContainSpacesException() raise TriggerContainSpacesException()
flags: Flags = command.get_registered_flags() flags: Flags = command.get_registered_flags()
if flags: if flags:
flags_name: list = [x.get_string_entity().lower() for x in flags] flags_name: list = [x.get_string_entity().lower() for x in flags]
if len(set(flags_name)) < len(flags_name): if len(set(flags_name)) < len(flags_name):
raise RepeatedFlagNameException() raise RepeatedFlagNameException()
case 'str': case "str":
if command.find(' ') != -1: if command.find(" ") != -1:
raise TriggerContainSpacesException() raise TriggerContainSpacesException()
@staticmethod @staticmethod
def _validate_func_args(func: Callable) -> None: def _validate_func_args(func: Callable) -> None:
""" """
@@ -173,13 +192,14 @@ class Router:
pass pass
else: else:
file_path: str = getsourcefile(func) file_path: str = getsourcefile(func)
source_line: int = getsourcelines(func)[1]+1 source_line: int = getsourcelines(func)[1] + 1
fprint = Console().print fprint = Console().print
fprint(f'\nFile "{file_path}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint ' fprint(
f'of argument([green]{transferred_arg}[/green]) passed to the handler is [/i][bold blue]{Response}[/bold blue],' f'\nFile "{file_path}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
f' [i]but[/i] [bold blue]{arg_annotation}[/bold blue] [i]is specified[/i]\n', highlight=False) f"of argument([green]{transferred_arg}[/green]) passed to the handler is [/i][bold blue]{Response}[/bold blue],"
f" [i]but[/i] [bold blue]{arg_annotation}[/bold blue] [i]is specified[/i]\n",
highlight=False,
)
def set_command_register_ignore(self, _: bool) -> None: def set_command_register_ignore(self, _: bool) -> None:
""" """
@@ -189,7 +209,6 @@ class Router:
""" """
self._ignore_command_register = _ self._ignore_command_register = _
def get_triggers(self) -> list[str]: def get_triggers(self) -> list[str]:
""" """
Public. Gets registered triggers Public. Gets registered triggers
@@ -200,7 +219,6 @@ class Router:
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) -> list[str]: def get_aliases(self) -> list[str]:
""" """
Public. Gets registered aliases Public. Gets registered aliases
@@ -212,7 +230,6 @@ class Router:
all_aliases.extend(command_handler.get_handled_command().get_aliases()) all_aliases.extend(command_handler.get_handled_command().get_aliases())
return all_aliases return all_aliases
def get_command_handlers(self) -> CommandHandlers: def get_command_handlers(self) -> CommandHandlers:
""" """
Private. Gets registered command handlers Private. Gets registered command handlers
+4
View File
@@ -2,6 +2,7 @@ class RepeatedFlagNameException(Exception):
""" """
Private. Raised when a repeated flag name is registered Private. Raised when a repeated flag name is registered
""" """
def __str__(self): def __str__(self):
return "Repeated registered flag names in register command" return "Repeated registered flag names in register command"
@@ -10,6 +11,7 @@ class TooManyTransferredArgsException(Exception):
""" """
Private. Raised when too many arguments are passed Private. Raised when too many arguments are passed
""" """
def __str__(self): def __str__(self):
return "Too many transferred arguments" return "Too many transferred arguments"
@@ -18,6 +20,7 @@ class RequiredArgumentNotPassedException(Exception):
""" """
Private. Raised when a required argument is not passed Private. Raised when a required argument is not passed
""" """
def __str__(self): def __str__(self):
return "Required argument not passed" return "Required argument not passed"
@@ -26,5 +29,6 @@ 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
""" """
def __str__(self): def __str__(self):
return "Command trigger cannot contain spaces" return "Command trigger cannot contain spaces"