Сообщить об ошибке.

Использование декораторов в python-telegram-bot

Внимание! Пакеты python-telegram-bot версии 13.x будут придерживаться многопоточной парадигмы программирования (*на данный момент актуальна версия 13.15). Пакеты версий 20.x и новее предоставляют чистый асинхронный Python интерфейс для Telegram Bot API. Дополнительно смотрите основные изменения в пакете python-telegram-bot версии 20.x.

В материале рассматривается создание и использование различных декораторов для python-telegram-bot в стиле библиотеки pyTelegramBotAPI.

Содержание:


Обработчики Handler как декораторы для функций обратного вызова.

Представленный ниже декоратор позволяет зарегистрировать функцию в качестве обработчика команд в стиле библиотеки pyTelegramBotAPI.

def command_handler(command):
    def decorator(func):
        handler = CommandHandler(command, func)
        application.add_handler(handler)
        return func
    return decorator

Теперь просто необходимо добавить декоратор @command_handler(command) поверх функции-обработчика:

# использование в версии 13.x
@command_handler("hello")
def hello(update, context):
    context.bot.send_message(chat_id=update.effective_chat.id, text="Hello world!")

# использование в версии 20.x
@command_handler("hello")
async def hello(update, context):
    await context.bot.send_message(chat_id=update.effective_chat.id, text="Hello world!")

Примечание. Можно изменить этот декоратор, чтобы зарегистрировать обработчик любого типа. Также обратите внимание, что python-telegram-bot намеренно не предоставляет такую ​​функциональность из коробки по двум причинам:

  • Одна из основных проблем заключается в том, что люди теряют контроль над порядком, в котором регистрируются обработчики (увеличение количества кода меду регистрацией обработчиков при помощи декораторов).
  • Определение метода регистрации обработчика на уровне модуля, уже является жизнеспособным промежуточным способом, который позволяет настроить обработчики в том же месте, где определяются обратные вызовы.

Декоратор для ограничения доступа к обработчику.

Этот декоратор позволяет ограничить доступ обработчика только к указанным user_id, перечисленным в списке LIST_OF_ADMINS.

Пример для python-telegram-bot версии 13.x:

from functools import wraps

LIST_OF_ADMINS = [12345678, 87654321]

def restricted(func):
    @wraps(func)
    def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in LIST_OF_ADMINS:
            print(f"Несанкционированный доступ запрещен для {user_id}.")
            return
        return func(update, context, *args, **kwargs)
    return wrapped

Пример для python-telegram-bot версии 20.x:

from functools import wraps

LIST_OF_ADMINS = [12345678, 87654321]

def restricted(func):
    @wraps(func)
    async def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in LIST_OF_ADMINS:
            print(f"Несанкционированный доступ запрещен для {user_id}.")
            return
        return await func(update, context, *args, **kwargs)
    return wrapped

Теперь нужно просто добавить декоратор @restricted поверх объявления функции-обработчика. Функции-обработчик сработает только в том случае, если user_id находится в LIST_OF_ADMINS:

# использование в версии 13.x
@restricted
def my_handler(update, context):
    # функции-обработчик сработает только в том случае, 
    # если `user_id` находится в `LIST_OF_ADMINS`.
    pass

# использование в версии 20.x
@restricted
async def my_handler(update, context):
    pass

Декоратор для отправки действие при обработке команды.

Следующий параметризованный декоратор позволяет сигнализировать о различных действиях в зависимости от типа ответа бота. Таким образом, у пользователей будет такая же обратная связь от бота, как и от реального человека.

Код для версии 13.x:

from functools import wraps

def send_action(action):
    """Отправляет "действие" во время обработки команды."""
    def decorator(func):
        @wraps(func)
        def command_func(update, context, *args, **kwargs):
            chat_id = update.effective_message.chat_id
            context.bot.send_chat_action(chat_id=chat_id, action=action)
            return func(update, context,  *args, **kwargs)
        return command_func
    return decorator

Код для версии 20.x:

from functools import wraps

def send_action(action):
    """Отправляет "действие" во время обработки команды."""
    def decorator(func):
        @wraps(func)
        async def command_func(update, context, *args, **kwargs):
            chat_id = update.effective_message.chat_id
            await context.bot.send_chat_action(chat_id=chat_id, action=action)
            return await func(update, context,  *args, **kwargs)
        return command_func
    return decorator

Можно декорировать функции обратных вызовов обработчиков напрямую с помощью @send_action(ChatAction. Action) или создавать псевдонимы и декорировать их (более читабельно).

# определяем псевдонимы
send_typing_action = send_action(ChatAction.TYPING)
send_upload_video_action = send_action(ChatAction.UPLOAD_VIDEO)
send_upload_photo_action = send_action(ChatAction.UPLOAD_PHOTO)

С приведенными выше псевдонимами следующие декораторы эквивалентны:

# пользователь увидит анимацию ввода, 
# пока бот обрабатывает запрос.
# код для версии 13.x
@send_typing_action
def my_handler(update, context):
    pass  

# эквивалентно
# код для версии 13.x
@send_action(ChatAction.TYPING)
def my_handler(update, context):
    pass

Класс telegram.constants.ChatAction.

Класс telegram.constants.ChatAction представляет собой вспомогательный класс для предоставления констант для различных "действий" в чате telegram.Bot.send_chat_action().

Класс определяет следующие константы:

  • ChatAction.CHOOSE_STICKER - бот выбирает стикер.
  • ChatAction.FIND_LOCATION - бот выбирает местоположение.
  • ChatAction.RECORD_VIDEO - бот записывает видео.
  • ChatAction.RECORD_VIDEO_NOTE - бот записывает видеозапись.
  • ChatAction.RECORD_VOICE - бот записывает голосовое сообщение.
  • ChatAction.TYPING - бот набирает текст.
  • ChatAction.UPLOAD_DOCUMENT - бот загружает документ.
  • ChatAction.UPLOAD_PHOTO - бот загружает фото.
  • ChatAction.UPLOAD_VIDEO - бот загружает видео.
  • ChatAction.UPLOAD_VIDEO_NOTE - бот загружает видеозаметку.
  • ChatAction.UPLOAD_VOICE - бот загружает голосовое сообщение.