import discord import config def istrue(value, key): return hasattr(value, key) and getattr(value, key) class Context: def __init__(self, msg, args): self.msg = msg self.args = args self.guild = msg.guild async def answer(self, value): await self.msg.channel.send(f'{self.msg.author.mention} {value}') class CommandClientMeta(type): def __new__(cls, name, bases, dct): commands = [] for item in dct.copy().values(): if callable(item) and istrue(item, 'command'): if istrue(item, 'help_command'): dct['help_command'] = item commands.append(item) dct['commands'] = commands return super().__new__(cls, name, bases, dct) class CommandClient(discord.Client, metaclass=CommandClientMeta): def get_commands(self): return type(self).commands.copy() async def run_help(self, ctx): return await type(self).help_command(self, ctx) async def on_message(self, msg): text = msg.content.strip() if not text.startswith(config.COMMAND_PREFIX): return try: cmd, *args = [v for v in text[len(config.COMMAND_PREFIX):].split(' ') if v] except ValueError: return await self.run_help(Context(msg, [])) ctx = Context(msg, args) for command in self.get_commands(): if cmd in command.names: return await command(self, ctx) return await self.run_help(ctx) def command(names=[], description='', is_help=False): def meta(f): f.command = True f.names = names f.description = description if is_help: f.help_command = is_help return f return meta