#python #discord.py #discord.py-rewrite
#python #discord.py
Вопрос:
Я пытаюсь добавить к обработке ошибок аргументы, kwargs и функциональные элементы client.command
( client
являясь discord.ext.commands.Bot
экземпляром). По сути, я пытаюсь сделать так, чтобы все мои команды имели определенное общее поведение.
Моя первоначальная идея состояла в том, чтобы создать функцию, которая возвращает декоратор, который украшает свою оболочку с помощью 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__
и __annotations__
на атрибуты оформленной функции.
Да, я полностью осознаю, что это ужасная и не очень хорошо продуманная идея (и она даже не работает). Вот почему я опубликовал это, это означает, что мое направление никуда не годится.
Есть предложения?
Есть ли гораздо более простой способ сделать что-то подобное, о котором я совершенно не знал?
Должен ли я просто создать command
декоратор самостоятельно с нуля и придерживаться discord.Client
вместо того, чтобы пытаться добавить к client.command
?
Комментарии:
1. Какие именно изменения вы хотите внести? Может быть возможно создать подкласс
Command
и передать ваш подкласс вclient.command
сcls
аргументом.2. Чтобы быть более конкретным, прямо сейчас я пытаюсь обработать
BadArgument
,MissingRequiredArgument
ситуацию, когда возникает другое исключение, и ситуацию, когда исключения не возникает (и что-то сделать с возвращаемым значением). Я хочу, чтобы все команды делали это одинаково.
Ответ №1:
Я не думаю, что вам вообще нужно расширять функциональность Command
. Вместо этого у вас могут быть боты on_command_error
и on_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")