Получить доступ к переменной контекста, не передавая ее из команды в функции более низкого уровня в боте Discord?Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Получить доступ к переменной контекста, не передавая ее из команды в функции более низкого уровня в боте Discord?

Сообщение Anonymous »

Я хотел отправить сообщение об ошибке пользователю без доступа к контексту из команды.
Это было в функции, которая не имела объектов разногласий и в основном имела дело с данными.
Я это делал, вызывая ошибку CommandError

Код: Выделить всё

raise CommandError(message, logger)
и обрабатываем это с помощью on_command_error

Код: Выделить всё

async def on_command_error(self, ctx, error):
...
if isinstance(error, commands.CommandError):
# Internal error called to kill a command call due to error
try:
message, logger = error.args
except (TypeError, ValueError):
message = error
logger = self.logger
else:
logger = logger or self.logger
logger.warning(message)
await ctx.send(f"{message}")
return
Хотя это и сработало, но не сработало, если бы я также не хотел прерывать поток выполнения из-за поднятия.
Тогда возникает вопрос: что с этим делать?
Вы можете передать переменную контекста в каждую функцию/метод, которая в ней нуждается. Это нормально для методов/классов более высокого уровня, но для вещей, которые в основном манипулируют данными, это не обязательно, и это просто вызов ошибки. Выглядит неуклюже.
Временное хранение контекстной переменной где-либо на самом деле не работает в ситуациях с несколькими пользователями/гильдиями.
Раньше я обходился этим, просто указывая конкретную гильдию. канал ошибки, но это также не работает, поскольку я открываю бота для большего количества пользователей на большем количестве каналов.
Есть ли лучший способ?
Решение
Для доступа к стеку кадров.
Каждая функция в цепочке в discord.py вызывается с помощью Даже если она не вызывается явно с помощью вызова.
Это означает, что вы может извлечь контекст (называемый ctx) из стека

Код: Выделить всё

def _get_frame_context(self, logger=None):
"""Inspect the stack to find the context object from invoke

Potential to increase speed as inspect.stack() is expensive
"""
frame_stack = inspect_stack()
for frame_info in frame_stack:
if frame_info.function.lower() == "invoke":
context = frame_info.frame.f_locals["ctx"]
break
else:
logger = self.logger if not logger else logger
raise CommandError("Could not find context object", logger)
del frame_stack # to not leak frames
return context

async def send_error(self, message: str, logger: logging.Logger, context=None):
"""
:param message: The error message
:param logger: The logger from where the error occured

Send a message to the invocation channel, without disrupting execution
if can find context
"""
if context is None:
try:
context = await self._get_frame_context()
except CommandError:
raise CommandError(f"Could not find context object:\n{message}", logger)

await context.send(message)
logger.warning(message)
Примечание:
inspect.stack() работает медленно и дорого, поэтому для более крупных вызовов есть варианты получше


Подробнее здесь: https://stackoverflow.com/questions/791 ... lower-leve
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»