如何扩展client.command的功能?

时间:2019-04-22 16:35:36

标签: python discord.py discord.py-rewrite

我试图增加对client.commandclientdiscord.ext.commands.Bot实例)的错误,args,kwargs和函数的处理。 基本上,我试图使所有命令具有某些共同的自定义行为。

我最初的想法是创建一个返回装饰器的函数,该装饰器使用client.command装饰包装器。

但是,我遇到的最大问题是client.command(...)返回的装饰器的参数处理完全取决于装饰函数的参数和注释的排列方式,这意味着包装器及其像这样的参数

async def wrapper(*args, **kwargs):

将接收原始参数。那将意味着我将不得不自己处理包装器中的所有内容,这一开始就破坏了使用discord.ext.commands的全部目的。

阅读PEP 3107时,我试图提出一种解决方法。这是代码的草图,其中的一部分与问题无关:

from discord.ext import commands as c
import discord as d
client = c.Bot(command_prefix = "insert_prefix_here$")



def command(*args, **kwargs):
    def decorator(func):
        command_name = kwargs.setdefault("name", func.__name__)

        async def wrapper(ctx, *args, **kwargs):
            # do stuff with func and command_name

        # ...eh? this down here is the dirtiest thing i've ever seen
        wrapper.__defaults__ = func.__defaults__
        wrapper.__annotations__ = func.__annotations__

        wrapper = client.command(*args, **kwargs)(wrapper)


        @wrapper.error
        async def wrapper_error(ctx, error):
            # do stuff with ctx, error, command_name, ... etc

        return wrapper

    return decorator

# insert commands with @command(...) decorator here

我简短地想到了“触发” client.command(...)返回的装饰器,以为包装器的参数结构与装饰函数之一相同,方法是设置包装器的__default__和{{ 1}}属于装饰功能的属性。

是的,我完全意识到这是一个可怕的想法,并且没有那么周到(甚至不起作用)。这就是为什么我发布此信息,这意味着我的方向不好。

有什么建议吗?

是否有一种更简单的方式来做我完全不知道的事情?

我是否应该自己创建一个__annotations__装饰器并坚持使用command而不是尝试添加到discord.Client中?

1 个答案:

答案 0 :(得分:1)

我认为您根本不需要扩展Command的功能。相反,您可以拥有机器人范围的on_command_erroron_command_completion事件来提供所需的功能。

唯一的问题是返回值。最简单的方法可能是分配ctx的未使用属性,而不是尝试捕获返回值(您也可以使用返回值引发自定义错误)

from discord.commands.ext import Bot, BadArgument, MissingRequiredArgument
import sys

bot = Bot("!")

@bot.command()
async def some_command(ctx):
    ctx.return_value = 1

@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, BadArgument):
        await ctx.send("That's a bad argument")
    elif isinstance(error, MissingRequiredArgument):
        await ctx.send("You're missing an argument")
    else:
        # This is what the standard on_command_error does
        print('Ignoring exception in command {}:'.format(context.command), file=sys.stderr)
        traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr)

@bot.event
async def on_command_completion(ctx):
    await ctx.send(str(ctx.return_value))

bot.run("TOKEN")