from typing import Callable, Any from inspect import getfullargspec from argenta.command import Command from argenta.router.models import CommandHandler, CommandHandlers from argenta.command.flag import Flag, FlagsGroup from argenta.router.exceptions import (RepeatedCommandException, RepeatedFlagNameException, TooManyTransferredArgsException, RequiredArgumentNotPassedException, IncorrectNumberOfHandlerArgsException, TriggerCannotContainSpacesException) class Router: def __init__(self, title: str = 'Commands group title:', name: str = 'Default'): self._title = title self._name = name self._command_handlers: CommandHandlers = CommandHandlers() self._ignore_command_register: bool = False self._not_valid_flag_handler: Callable[[Flag], None] = lambda flag: print(f"Undefined or incorrect input flag: {flag.get_string_entity()}{(' '+flag.get_value()) if flag.get_value() else ''}") def command(self, command: Command) -> Callable[[Any], Any]: self._validate_command(command) def command_decorator(func): Router._validate_func_args(command, func) self._command_handlers.add_command_handler(CommandHandler(func, command)) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper return command_decorator def set_invalid_input_flag_handler(self, func): processed_args = getfullargspec(func).args if len(processed_args) != 1: raise IncorrectNumberOfHandlerArgsException() else: self._not_valid_flag_handler = func def input_command_handler(self, input_command: Command): input_command_name: str = input_command.get_trigger() input_command_flags: FlagsGroup = input_command.get_input_flags() for command_handler in self._command_handlers: handle_command = command_handler.get_handled_command() if input_command_name.lower() == handle_command.get_trigger().lower(): if handle_command.get_registered_flags(): if input_command_flags: for flag in input_command_flags: is_valid = handle_command.validate_input_flag(flag) if not is_valid: self._not_valid_flag_handler(flag) return return command_handler.handling(input_command_flags.unparse_to_dict()) else: return command_handler.handling({}) else: if input_command_flags: self._not_valid_flag_handler(input_command_flags[0]) return else: return command_handler.handling() def _validate_command(self, command: Command): command_name: str = command.get_trigger() if command_name.find(' ') != -1: raise TriggerCannotContainSpacesException() if command_name in self.get_all_commands(): raise RepeatedCommandException() if self._ignore_command_register: if command_name.lower() in [x.lower() for x in self.get_all_commands()]: raise RepeatedCommandException() flags: FlagsGroup = command.get_registered_flags() if flags: flags_name: list = [x.get_string_entity().lower() for x in flags] if len(set(flags_name)) < len(flags_name): raise RepeatedFlagNameException() @staticmethod def _validate_func_args(command: Command, func: Callable): registered_args = command.get_registered_flags() transferred_args = getfullargspec(func).args if registered_args and transferred_args: if len(transferred_args) != 1: raise TooManyTransferredArgsException() elif registered_args and not transferred_args: raise RequiredArgumentNotPassedException() elif not registered_args and transferred_args: raise TooManyTransferredArgsException() def set_ignore_command_register(self, ignore_command_register: bool): self._ignore_command_register = ignore_command_register def get_command_handlers(self) -> CommandHandlers: return self._command_handlers def get_name(self) -> str: return self._name def get_title(self) -> str: return self._title def set_title(self, title: str): self._title = title def get_all_commands(self) -> list[str]: all_commands: list[str] = [] for command_handler in self._command_handlers: all_commands.append(command_handler.get_handled_command().get_trigger()) return all_commands