Как установить telegram ext

Foodband

Пишем диалоговые Telegram-боты на Питоне

Думаю, всем здесь в той или иной мере известен мессенджер Telegram. Создатель заявляет, что это самый безопасный мессенджер с убойным алгоритмом шифрования собственной разработки, но нас, разработчиков, конечно же, куда сильнее интересует другое. Боты!

Тема эта, конечно, не раз поднималась на Хабре: ботов писали на Python с tornado, Node.js, Ruby со специальным гемом, Ruby on Rails, C#, C# с WCF и даже PHP; ботов писали для RSS-каналов, мониторинга сайтов, удалённого включения компьютера и, вероятно, для многого, многого другого.

И всё же я возьму на себя смелость изъездить эту тему ещё раз и вдобавок к этому показать немного магии Питона. Мы будем писать фреймворк™ для удобного написания нетривиальных диалоговых ботов на основе пакета python-telegram-bot.

Как зачать бота?

На этот вопрос лучше всего отвечает официальная документация. Выглядит процесс примерно так:

Просто, не правда ли? (Будьте благоразумны и не занимайте хорошие никнеймы без убедительной причины!)

Самый простой бот

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

создаёт бота, который сухо отвечает «Здравствуйте.» при нажатии на кнопку Start (или ручном вводе команды /start ) и многозначительно молчит при любых последующих действиях с вашей стороны.

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

(За дальнейшими подробностями с чистой совестью отсылаю к документации python-telegram-bot.)

Нагруженные этим теоретическим минимумом, мы можем наконец подумать, как нам писать своего нетривиального бота. Для начала давайте вернёмся к постановке задачи. Под диалоговым ботом я подразумеваю бота, который главным образом ведёт обычный текстовый диалог с пользователем — с вопросами, ответами, нелинейным сюжетом, разочаровывающими концовками и всем в таком духе (играли в «Бесконечное лето»?) Напротив, не попадают в сферу наших текущих интересов боты, разным образом расширяющие функционал Telegram (вроде бота для лайков); соответственно, мы опустим добавление всяких плюшек вроде инлайнового режима, игр, обновления элементов управления на лету и всего такого прочего.

Проблема сложных диалоговых ботов в том, что нетривиальный диалог требует хранения состояния. Работа асинхронных диалогов требует постоянных прерываний на ожидание сообщения от пользователя; состояние нужно сохранять, потом восстанавливать, прыгать к коду, ответственному за обработку очередного сообщения, и так далее; в общем, организация кода становится проблемой довольно угнетающей. Прервать, продолжить… ничего не напоминает? Что ж, посмотрим, как обозначенную проблему можно изящнейше обойти с помощью магии yield .

50 оттенков yield

Что мы знаем про yield ? Ну, все мы знаем, что это такая штука, чтобы писать генераторы, то есть этакие ленивые и потенциально бесконечные списки:

Теперь объект f — это такая волшебная коробка; стоит сунуть в неё руку написать next(f) , и мы получим очередное число Фибоначчи, но стоит перевернуть её написать list(f) , как мы уйдём в бесконечный цикл, который, скорее всего, закончится трагической смертью системы от нехватки оперативной памяти.

Мы знаем, что генераторы — это быстро, удобно и очень в стиле Python. У нас есть модуль itertools , предлагающий генераторы на любой вкус и цвет. Но у нас есть кое-что ещё.

Куда менее известными навыками слова yield являются способности… возвращать значения и бросать исключения! Да-да, если мы напишем:

То вычисление чисел Фибоначчи оборвётся самым трагическим образом — исключением в строчке с yield .

В свою очередь вызов f.send(something) заставит конструкцию yield вернуть значение, а потом сразу вернёт next(f) . Достаточно приравнять yield переменную, чтобы переданное значение поймать:

Но и это ещё не всё. Начиная с Python 3.3, генераторы умеют делегировать выполнение друг другу с помощью конструкции yield from : вместо

она позволяет нам писать

Но было бы преуменьшением сказать, что yield from позволяет нам лишь сэкономить строки кода на циклах. Дело в том, что она также заботится о send и throw — при вызове они будут взаимодействовать не с функцией concatenate , а с одним из двух генераторов, которым она передаёт управление. (Если это окажутся не генераторы… ну упс.)

А ещё yield from тоже умеет возвращать значение: для этого функциям-генераторам вернули право на нетривиальный (то есть возвращающий что-то, а не просто заканчивающий выполнение) return :

К чему я всё это? Ах да. Эти фокусы, вместе взятые, позволят нам легко и естественно писать наших диалоговых ботов.

Пишем обёртку

Итак, пусть диалог с каждым пользователем ведётся генератором. yield будет выдавать наружу сообщение, которое надо отправить пользователю, и возвращать внутрь его ответ (как только он появится). Давайте напишем простенький класс, который умеет это делать.

Что ж, осталось сочинить диалог, который мы будем отыгрывать! Давайте поговорим о Питоне.

И это работает! Результат выглядит примерно так:

Добавляем разметку

Боты в Telegram сильны тем, что могут кидаться в своих пользователей HTML- и Markdown-разметкой; эту возможность обойти стороной нам было бы непозволительно. Чтобы понять, как послать сообщение с разметкой, давайте взглянем на описание функции Bot.sendMessage :

Ага! Достаточно передавать аргумент parse_mode="HTML" или parse_mode="Markdown" . Можно было бы просто добавить это в наш вызов, но давайте сделаем чуть-чуть погибче: добавим специальные объекты, которые нужно будет yield’ить, чтобы спровоцировать использование разметки:

Теперь отправка сообщений будет выглядеть так:

Для демонстрации давайте модифицируем ask_yes_or_no() :

Добавляем кнопки

Единственное, чего нам не хватает и что могло бы вполне себе пригодиться при написании диалоговых ботов — клавиатура с выбором вариантов ответа. Для создания клавиатуры нам достаточно добавить в Message.options ключ reply_markup ; но давайте постараемся максимально упростить и абстрагировать наш код внутри генераторов. Здесь напрашивается решение попроще. Пусть, например, yield выдаёт не один объект, а сразу несколько; если среди них есть список или список списков со строками, например:

, то мы считаем, что это кнопки клавиатуры, и хотим получить примерно следующий результат:

_send_answer() тогда преобразуется в нечто такое:

В качестве демонстрации поменяем ask_yes_or_no() и discuss_bad_python() :

Заключение

Генераторы в Питоне — мощный инструмент, и использование его в нужных ситуациях позволяет значительно сокращать и упрощать код. Посмотрите, как красиво мы, например, вынесли вопрос «да или нет» в отдельную функцию, притом оставив за ним право проводить дополнительное общение с пользователем. Так же мы могли бы вынести в отдельную функцию и вопрошание имени, и научить его уточнять у пользователя, верно ли мы его поняли, и так далее, и тому подобное. Генераторы сами хранят за нас состояние диалога, и сами умеют продолжать его с требуемого момента. Всё для нас!

Надеюсь, эта статья была кому-то полезной. Как водится, не стесняйтесь сообщать обо всех опечатках, орфографических и грамматических ошибках в личку. Весь код к статье лежит в репозитории на Github (ветка habrahabr-316666 ). На бота ссылку не дам и живым его держать, конечно, ближайшее время не буду, иначе хабраэффект накроет его вместе с моим компьютером. Успехов в создании своих диалоговых ботов 😉

No module named 'telegram.ext'

Использую библиотеку python-telegram-bot Выдает ошибку:

Запуск твоей программы происходит путем команды python main.py . Если ты запустишь интерпретатор командой python , то увидишь, что он запускает python 2.7, а тебе нужно 3+ Для этого воспользуйся командой python3 main.py .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками python telegram-bot или задайте свой вопрос.

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.11.24.40828

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

telegram.ext.Updater¶

This class, which employs the telegram.ext.Dispatcher , provides a frontend to telegram.Bot to the programmer, so they can focus on coding the bot. Its purpose is to receive the updates from Telegram and to deliver them to said dispatcher. It also runs in a separate thread, so the user can interact with the bot, for example on the command line. The dispatcher supports handlers for different kinds of data: Updates from Telegram, basic text commands and even arbitrary types. The updater can be started as a polling service or, for production, use a webhook to receive updates. This is achieved using the WebhookServer and WebhookHandler classes.

You must supply either a bot or a token argument.

If you supply a bot , you will need to pass arbitrary_callback_data , and defaults to the bot instead of the telegram.ext.Updater . In this case, you’ll have to use the class telegram.ext.ExtBot .

Changed in version 13.6.

token ( str , optional) – The bot’s token given by the @BotFather.

base_url ( str , optional) – Base_url for the bot.

base_file_url ( str , optional) – Base_file_url for the bot.

workers ( int , optional) – Amount of threads in the thread pool for functions decorated with @run_async (ignored if dispatcher argument is used).

bot ( telegram.Bot , optional) – A pre-initialized bot instance (ignored if dispatcher argument is used). If a pre-initialized bot is used, it is the user’s responsibility to create it using a Request instance with a large enough connection pool.

dispatcher ( telegram.ext.Dispatcher , optional) – A pre-initialized dispatcher instance. If a pre-initialized dispatcher is used, it is the user’s responsibility to create it with proper arguments.

private_key ( bytes , optional) – Private key for decryption of telegram passport data.

private_key_password ( bytes , optional) – Password for above private key.

user_sig_handler ( function , optional) – Takes signum, frame as positional arguments. This will be called when a signal is received, defaults are (SIGINT, SIGTERM, SIGABRT) settable with idle .

request_kwargs ( dict , optional) – Keyword args to control the creation of a telegram.utils.request.Request object (ignored if bot or dispatcher argument is used). The request_kwargs are very useful for the advanced users who would like to control the default timeouts and/or control the proxy used for http communication.

use_context ( bool , optional) – If set to True uses the context based callback API (ignored if dispatcher argument is used). Defaults to True . New users: set this to True .

persistence ( telegram.ext.BasePersistence , optional) – The persistence class to store data that should be persistent over restarts (ignored if dispatcher argument is used).

Foodband

defaults ( telegram.ext.Defaults , optional) – An object containing default values to be used if not set explicitly in the bot methods.

arbitrary_callback_data ( bool | int | None , optional) –

Whether to allow arbitrary objects as callback data for telegram.InlineKeyboardButton . Pass an integer to specify the maximum number of cached objects. For more details, please see our wiki. Defaults to False .

New in version 13.6.

context_types ( telegram.ext.ContextTypes , optional) –

Pass an instance of telegram.ext.ContextTypes to customize the types used in the context interface. If not passed, the defaults documented in telegram.ext.ContextTypes will be used.

New in version 13.6.

ValueError – If both token and bot are passed or none of them.

The bot used with this Updater.

Optional. Function to be called when a signal is received.

Queue for the updates.

Jobqueue for the updater.

Dispatcher that handles the updates and dispatches them to the handlers.

Indicates if the updater is running.

Optional. The persistence class to store data that should be persistent over restarts.

Optional. True if using context based callbacks.

idle ( stop_signals=(<Signals.SIGINT: 2> , <Signals.SIGTERM: 15> , <Signals.SIGABRT: 6>) ) ¶

Blocks until one of the signals are received and stops the updater.

stop_signals ( list | tuple ) – List containing signals from the signal module that should be subscribed to. Updater.stop() will be called on receiving one of those signals. Defaults to ( SIGINT , SIGTERM , SIGABRT ).

start_polling ( poll_interval = 0.0 , timeout = 10 , clean = None , bootstrap_retries = — 1 , read_latency = 2.0 , allowed_updates = None , drop_pending_updates = None ) ¶

Starts polling updates from Telegram.

poll_interval ( float , optional) – Time to wait between polling updates from Telegram in seconds. Default is 0.0 .

timeout ( float , optional) – Passed to telegram.Bot.get_updates() .

drop_pending_updates ( bool , optional) –

Whether to clean any pending updates on Telegram servers before actually starting to poll. Default is False .

New in version 13.4.

clean ( bool , optional) –

Alias for drop_pending_updates .

Deprecated since version 13.4: Use drop_pending_updates instead.

bootstrap_retries ( int , optional) –

Whether the bootstrapping phase of the telegram.ext.Updater will retry on failures on the Telegram server.

< 0 — retry indefinitely (default)

> 0 — retry up to X times

allowed_updates (List[ str ], optional) – Passed to telegram.Bot.get_updates() .

read_latency ( float | int , optional) – Grace time in seconds for receiving the reply from server. Will be added to the timeout value and used as the read timeout from server (Default: 2 ).

The update queue that can be filled from the main thread.

start_webhook ( listen = ‘127.0.0.1’ , port = 80 , url_path = » , cert = None , key = None , clean = None , bootstrap_retries = 0 , webhook_url = None , allowed_updates = None , force_event_loop = None , drop_pending_updates = None , ip_address = None , max_connections = 40 ) ¶

Starts a small http server to listen for updates via webhook. If cert and key are not provided, the webhook will be started directly on http://listen:port/url_path, so SSL can be handled by another application. Else, the webhook will be started on https://listen:port/url_path. Also calls telegram.Bot.set_webhook() as required.

Changed in version 13.4: start_webhook() now always calls telegram.Bot.set_webhook() , so pass webhook_url instead of calling updater.bot.set_webhook(webhook_url) manually.

listen ( str , optional) – IP-Address to listen on. Default 127.0.0.1 .

port ( int , optional) – Port the bot should be listening on. Default 80 .

url_path ( str , optional) – Path inside url.

cert ( str , optional) – Path to the SSL certificate file.

key ( str , optional) – Path to the SSL key file.

drop_pending_updates ( bool , optional) –

Whether to clean any pending updates on Telegram servers before actually starting to poll. Default is False .

New in version 13.4.

clean ( bool , optional) –

Alias for drop_pending_updates .

Deprecated since version 13.4: Use drop_pending_updates instead.

bootstrap_retries ( int , optional) –

Whether the bootstrapping phase of the telegram.ext.Updater will retry on failures on the Telegram server.

< 0 — retry indefinitely (default)

> 0 — retry up to X times

webhook_url ( str , optional) – Explicitly specify the webhook url. Useful behind NAT, reverse proxy, etc. Default is derived from listen , port & url_path .

ip_address ( str , optional) –

New in version 13.4.

allowed_updates (List[ str ], optional) – Passed to telegram.Bot.set_webhook() .

force_event_loop ( bool , optional) –

Legacy parameter formerly used for a workaround on Windows + Python 3.8+. No longer has any effect.

Deprecated since version 13.6: Since version 13.6, tornade>=6.1 is required, which resolves the former issue.

Foodband

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *