From 1d8b16add0be1983f6cce6538ef504ba6354d14a Mon Sep 17 00:00:00 2001 From: Dusty Pianalto Date: Tue, 5 Nov 2019 18:46:11 -0900 Subject: [PATCH] Create command decorator Create process_commands method Only allow coroutine functions as commands Finish add_command method --- morpheus/exts/bot.py | 44 +++++++++++++++++++++++----------------- morpheus/exts/command.py | 8 ++++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/morpheus/exts/bot.py b/morpheus/exts/bot.py index 8cfc52b..1c2a27f 100644 --- a/morpheus/exts/bot.py +++ b/morpheus/exts/bot.py @@ -9,6 +9,7 @@ from morpheus.core.utils import maybe_coroutine from morpheus.core.events import RoomEvent from morpheus.core.content import MessageContentBase from .context import Context +from .command import Command class Bot(Client): @@ -19,8 +20,7 @@ class Bot(Client): ): self.loop = asyncio.get_event_loop() super(Bot, self).__init__(prefix=prefix, homeserver=homeserver) - self.commands: Dict[str, dict] = {} - self.aliases: Dict[str, str] = {} + self.commands: Dict[str, Command] = {} def run(self, user_id: str = None, password: str = None, token: str = None, loop: Optional[asyncio.AbstractEventLoop] = None): loop = loop or self.loop or asyncio.get_event_loop() @@ -70,32 +70,38 @@ class Bot(Client): if not ctx: return - command_name = self.aliases.get(ctx.called_with) - if not command_name: + command = self.commands.get(ctx.called_with) + if not command: return - command_dict = self.commands.get(command_name) - if not command_dict: - del self.aliases[ctx.called_with] - parser: ArgumentParser = command_dict['parser'] - command = command_dict['command'] - args = parser.parse_args(ctx.body.split(' ')) + await command.invoke(ctx, ctx.body.split(' ')) def listener(self, name=None): def decorator(func): self.register_handler(name, func) return decorator - def add_command(self, name: str, func: callable): - if not callable(func): - raise TypeError('Command function must be callable') - - if not isawaitable(func): - raise TypeError('Command function must be a coroutine') - + def add_command(self, name: str, aliases: list, func: callable): if not name: name = func.__name__ - if name in self.commands: + if name.startswith('_'): + raise RuntimeWarning(f'Command names cannot start with an underscore') + + if aliases is None: + aliases = [] + + if not isinstance(aliases, list) or any([not isinstance(alias, str) for alias in aliases]): + raise RuntimeWarning(f'Aliases must be a list of strings.') + + if name in self.commands or any([alias in self.commands for alias in aliases]): raise RuntimeWarning(f'Command {name} has already been registered') - self.commands[name] = func + command = Command(func) + self.commands[name] = command + for alias in aliases: + self.commands[alias] = command + + def command(self, name: Optional[str] = None, aliases: Optional[list] = None): + def decorator(func): + self.add_command(name=name, aliases=aliases, func=func) + return decorator diff --git a/morpheus/exts/command.py b/morpheus/exts/command.py index 7da0167..2d10f1d 100644 --- a/morpheus/exts/command.py +++ b/morpheus/exts/command.py @@ -8,8 +8,8 @@ class Command: if not callable(function): raise RuntimeError('The function to make a command from must be a callable') - # if not inspect.isawaitable(function): - # raise RuntimeError('The function to make a command from must be a coroutine') + if not inspect.iscoroutinefunction(function): + raise RuntimeError('The function to make a command from must be a coroutine') self.extension = extension self.signature = inspect.signature(function) @@ -53,7 +53,7 @@ class Command: return parser - def invoke(self, ctx, args_list): + async def invoke(self, ctx, args_list): iterator = iter(self.signature.parameters.items()) if self.extension: @@ -78,4 +78,4 @@ class Command: else: kwargs[key] = params.__dict__[key] - self.function(ctx, *args, **kwargs) + await self.function(ctx, *args, **kwargs)