Материал по переходу на асинхронный python-telegram-bot
версия 20.x не будет охватывать все множество изменений, которые произошли в версии 20.x. Здесь будут рассмотрены моменты, которые помогут перевести простой (без наворотов) телеграмм бот на асинхронную версию.
Команда разработчиков подготовила Python скрипт (постоянно дополняется/совершенствуется), призванный облегчить переход с многопоточной версии 13.x на асинхронную версию 20.x. Обратите внимание, что этот скрипт в настоящее время просто выполняет поиск и замену на основе регулярных выражений, беря на себя только часть работы по переходу. Это никоим образом не заменит ручную корректировку кода. В дополнение к сценарию, в кодовой базе рекомендуется использовать языковой интерпретатор (например, pylint
) и средство проверки статического типа (например, mypy
), дабы свести к минимуму время проб и ошибок при переходе.
Класс telegram.ext.Updater
больше не является точкой входа в приложение python-telegram-bot
, а также был заменен класс telegram.ext.Dispatcher
новым классом telegram.ext.Application
. Теперь класс Application
- это новая точка входа в приложение, которая объединяет все ее компоненты.
При инициализации приложения можно настроить множество параметров для отдельных компонентов. Стремясь сделать это воплощение понятным и чистым, команда разработчиков приняла так называемый шаблон построителя. Это означает, что вместо передачи аргументов непосредственно в Application
создается построитель с помощью Application.builder()
, а затем указываются все необходимые аргументы через этот построитель. Наконец, приложение создается путем вызова builder.build()
.
Простой пример:
from telegram.ext import Application, CommandHandler ... app = Application.builder().token('TOKEN').build() app.add_handler(CommandHandler('start', start_callback)) app.run_polling()
asyncio
.Самым глубоким структурным изменением является введение в python-telegram-bot
модуля asyncio
. Модуль asyncio
- это библиотека для написания параллельного кода с использованием синтаксиса async
/await
.
Пакет python-telegram-bot
- это библиотека, основной целью которой является взаимодействие с Telegram Bot API через веб-запросы. При выполнении веб-запросов код обычно тратит много времени на ожидание сетевых соединений. А именно ждем ответа от Telegram. То же самое верно для многих так называемых задач ввода-вывода.
Для решения этой проблемы:
python-telegram-bot
13.x использует модуль threading
. python-telegram-bot
20.x использует модуль asyncio
- это современная альтернатива многопоточности, которая имеет множество преимуществ. Основные моменты изменения в python-telegram-bot
с вводом asyncio
:
telegram.Bot
теперь являются функциями-сопрограммами, т.е. в коде перед ними должен ставится оператор await
.async
, например async def callback(update, context):
.run_async
был заменен на block
, имеющий аналогичный функционал. Dispatcher.run_async
больше не существует. Близкое к его функциональности, это Application.create_task()
.telegram
.Класс telegram.Bot
:
get_updates_request
в дополнение к request
, и соответствующий экземпляр запроса будет использоваться исключительно для вызова метода Bot.getUpdates
.media
метода Bot.edit_message_media
теперь является первым позиционным аргументом, как указано Bot API.url
метода Bot.set_webhook
теперь требуется, как указано в Bot API.description
метода Bot.set_chat_description
теперь является необязательным, как указано в Bot API.Класс telegram.ChatAction
был удален, так как он не является частью официального Bot API. Вместо него нужно использовать telegram.constants.ChatAction
.
Если у telegram.InlineQuery.answer
указаны оба параметра current_offset
и auto_pagination
, то метод теперь вызывает ValueError
, а не TypeError
.
Класс telegram.ParseMode
был удален, так как он не является частью официального Bot API. Вместо него используйте telegram.constants.ParseMode
.
Класс telegram.ReplyMarkup
был удален, так как он не является частью официального Bot API.
У класса telegram.EncryptedPassportElement
, аргумент hash
теперь является вторым позиционным аргументом, как указано в Bot API.
У класса telegram.PassportFile
, аргумент file_size
теперь является необязательным, как указано в Bot API.
У класса telegram.VideoChat
, аргумент users
теперь является необязательным, как указано в Bot API.
В версии 20.x был удален метод telegram.InputFile.is_image()
.
Ранее некоторые классы, например, telegram.Message
, telegram.User
, telegram.Chat
имели атрибут .bot
, который использовался для ссылок, например, Message.reply_text
. Этот атрибут был удален. Вместо него используется новый метод TelegramObject.set_bot()
, TelegramObject.get_bot()
.
telegram.ext
.Класс telegram.ext.CallbackContext
:
CallbackContext.from_error
имеет новый необязательный аргумент job
. Когда внутри обратного вызова ext.Job
возникает исключение, то будет передан этот параметр. Соответственно атрибут CallbackContext.job
теперь также будет присутствовать в обработчиках ошибок, если ошибка была вызвана ext.Job
.CallbackContext.DEFAULT_TYPE
удалена. Теперь ее можно найти как ContextTypes.DEFAULT_TYPE
.Модуль telegram.ext.filters
был переписан практически с нуля и использует новую политику пространства имен. Изменения примерно такие:
telegram.ext.Filters
больше не существует. Вместо него нужно использовать модуль telegram.ext.filters
напрямую. Например, Filters.text
нужно заменить на filter.TEXT
.SCREAMING_SNAKE_CASE
, например filter.TEXT
. Классы фильтров, которым нужны аргументы, теперь пишутся в стиле CamelCase
, например filters.User
.filter.Document
нельзя использовать в MessageHandler
. Чтобы отфильтровать сообщения с вложенным документом, нужно использовать filter.Document.ALL
.my_filter.check_update(update)
.Класс telegram.ext.JobQueue
:
Новые аргументы chat_id
и user_id
: все методы JobQueue.run_*
имеют два новых аргумента chat_id
и user_id
, что позволяет легко связать пользователя/чат с заданием. При указании этих аргументов соответствующий идентификатор будет доступен в обратном вызове задания через context.job.chat_id
и context.job.user_id
.
Кроме того, будут доступны context.job.chat_data
и context.job.user_data
. Это имеет некоторые тонкие преимущества по сравнению с предыдущим обходным решением job_queue.run_*(..., context=context.chat_data)
, и вместо этого рекомендуется использовать эту новую функциональность.
Переименован аргумент context
в data
: чтобы устранить частую путаницу между context
и context.job.context
, аргумент context
всех методов JobQueue.run_*
был переименован в аргумент data
. Это также относится к соответствующему атрибуту Job
.
Изменения в методе JobQueue.run_daily()
. поведение этого метода согласовано с cron
, т. е. 0 - это воскресенье, а 6 - суббота.
Изменения в методе JobQueue.run_monthly()
: аргумент day_is_strict
работал некорректно и поэтому был удален. Вместо него теперь можно передать day='last'
, чтобы задание выполнялось в последний день месяца.
Класс telegram.ext.Job
:
Job.job_queue
: было удалено, потому что если есть доступ к заданию, то также есть доступ либо непосредственно к JobQueue
, либо, по крайней мере, к экземпляру CallbackContext
, который уже содержит job_queue
.Job.context
был переименован в Job.data
.Класс telegram.ext.ConversationHandler
теперь выдает предупреждения о дополнительных обработчиках, которые добавляются в неправильном контексте или вообще не должны быть в обработчике.
В версии 20.0 переименовали базовый класс обработчика Handler
в BaseHandler
, чтобы подчеркнуть, что этот класс является абстрактным базовым классом.
Теперь единственной целью класса Updater
является получение обновлений из Telegram. Теперь он принимает только аргументы bot
и update_queue
и имеет только эти атрибуты.
В версии 20.x был удален модуль telegram.utils
. Части этого модуля, которые считаются частью общедоступного API, были перемещены в модули telegram.helpers
, telegram.request
, telegram.warnings
.
В версии 20.x убрали возможность устанавливать пользовательские атрибуты для всех объектов, кроме telegram.ext.CallbackContext
. Для хранения данных рекомендовано использовать встроенный механизм хранения данных. Если необходимо добавить к какому-то классу дополнительную функциональность, то необходимо сделать его подклассом.
Начиная с версии 20.0, все аргументы методов бота, которые были добавлены python-telegram-bot
, теперь являются только ключевыми аргументами. Самое главное, это касается аргументов *_timeout
и api_kwargs
.
Ранее класс telegram.utils.request.Request
формировал сетевой бэкэнд. Теперь, вместо него есть новый модуль telegram.request
, который содержит класс интерфейса BaseRequest
, а также реализацию HTTPXRequest
этого класса через библиотеку httpx
. По умолчанию класс HTTPXRequest
используется для серверной части сети. Опытные пользователи могут использовать настраиваемый бэкэнд, реализовав настраиваемый подкласс BaseRequest
.
Модуль telegram.error
и telegram.constants
:
Модуль telegram.constants
был переписан с нуля. Константы теперь сгруппированы с помощью перечислений.
Ранее некоторые части telegram.error
, telegram.constants
были доступны непосредственно через пакет telegram
- например:
from telegram import TelegramError
Этот импорт больше не будет работать. Теперь непосредственно через пакет telegram
доступны только классы, которые отражают официальный API бота. Константы и ошибки доступны через модули telegram.error
или telegram.constants
- например:
from telegram.error import TelegramError
Класс telegram.error.Unauthorized
был заменен на telegram.error.Forbidden
. Более того, telegram.error.Forbidden
теперь вызывается только в том случае, если бот пытается выполнить действия, на которые у него недостаточно прав. Если токен бота недействителен, то возбуждается telegram.error.InvalidToken
.