Merge remote-tracking branch 'origin/master'

# Conflicts:
#	Examples.md
Hinrich Mahler 2021-04-25 17:05:16 +02:00
commit cda9407039
20 changed files with 214 additions and 130 deletions

@ -4,7 +4,7 @@ When working with PTB, you will sooner or later have a question. And that's fine
This article is about *how to ask good questions*, focusing on questions appearing when working with PTB.
Before we begin, please try to keep one rule of thumb in mind:
> You want something from from somebody else, so please put some effort in it.
> You want something from somebody else, so please put some effort in it.
Putting effort in it makes it easier for others to actually help you and it's more pleasant for both sides ;)
@ -20,7 +20,7 @@ Please be aware that neither the PTBs user group on Telegram nor the issue track
## Design Questions
Many questions are not about how to use a specific method/class of PTB, but more along the lines "If a users does this, I want my bot do react like that. What can I use for that?"
When asking how to build a specific functionality with PTB, please try describe it precisely and include all relevant information. Try to answer the following questions:
When asking how to build a specific functionality with PTB, please try describe it precisely and include all relevant information. Answering the following questions usually is a good starting point:
1. What kind of event should trigger the functionality? Possible triggers are e.g.
* User sends a message containing a command/specific expression/an image/…
@ -50,6 +50,7 @@ Again, please try to be precise and include all relevant information. This means
* What kind of handler did you set up to handle this? What is it supposed to do?
2. What is actually happening?
* If you're encountering an exception, please provide the full [traceback](https://realpython.com/python-traceback/)
* Make sure that you activate [logging](https://github.com/python-telegram-bot/python-telegram-bot/#logging) or an [error handler](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Exception-Handling) so that you can actually see the traceback!
3. Where exactly are things going south? If you can locate the line/s of code that are misbehaving, please include them in your question.
If you have a hard time laying your finger on where exactly things go south, it might be helpful to provide a [minimal working example](https://telegra.ph/Minimal-Working-Example-for-PTB-07-18).

@ -1,3 +1,6 @@
# Deprecation Notice
`MessageQueue` in its current form is deprecated and will be reinvented in a future release. See [#2139](https://github.com/python-telegram-bot/python-telegram-bot/issues/2139) for a list of known bugs.
## What the spam limits are and why you should avoid hitting them
Considering [Telegram's Bot documentation](https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this), currently the maximum amount of messages being sent by bots is limited to 30 messages/second for all ordinary messages and 20 messages/minute for group messages. According to [@BotSupport](https://t.me/BotSupport) the limit for group also applies to channels (this is not confirmed by Telegram in their documentation however). When your bot hits spam limits, it starts to get 429 errors from Telegram API. And assuming that error handling in such case usually is coded as simple retrials, the running machine would spend a lot of CPU time retrying (or got locked down, depending on bot implementation details). And constantly retrying to send messages while ignoring API errors could result in your bot being banned for some time.
@ -25,7 +28,7 @@ If you need more details on MQ implementation, [follow its docs](http://python-t
## MessageQueue from user perspective
### Current status
For now, it's still under development and has some bugs (see [#2139](https://github.com/python-telegram-bot/python-telegram-bot/issues/2139) for details), but **could be already used**. More detailed, now it's detached from other Python-Telegram-Bot lib components and therefore you should do a little extra work to use it. We plan to tightly couple it with [`telegram.Bot`](http://python-telegram-bot.readthedocs.io/en/latest/telegram.bot.html) so that it could be used more conveniently (and even implicitly unless other specified). But anyway, **the future releases would be backwards compatible with current [`MessageQueue`](http://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.messagequeue.html) class and `queuedmessage` decorator**.
**`MessageQueue` in its current form is deprecated and will be reinvented in a future release. See [#2139](https://github.com/python-telegram-bot/python-telegram-bot/issues/2139) for a list of known bugs.**
### Using MQ with @queuedmessage decorator
[`MessageQueue`](http://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.messagequeue.html) module includes a convenient `@queuedmessage` decorator, which allows to delegate the required send method calls to MQ. However, it requires you to do a little work by hand, mainly create a [`telegram.Bot`](http://python-telegram-bot.readthedocs.io/en/latest/telegram.bot.html) subclass and decorate those methods.

@ -32,7 +32,7 @@ It is also a follow-up to the page [Introduction to the API](https://github.com/
* [Other useful stuff](#other-useful-stuff)
+ [Generate flag emojis from country codes](#generate-flag-emojis-from-country-codes)
+ [Map a Slot Machine Dice value to the corresponding symbols](#map-a-slot-machine-dice-value-to-the-corresponding-symbols)
+ [Get the add group message](#get-the-add-group-message)
+ [Get the new members group message](#get-the-new-members-message)
+ [Exclude forwarded channel posts in discussion groups from MessageHandlers](#exclude-forwarded-channel-posts-in-discussion-groups-from-messagehandlers)
+ [Exclude messages from anonymous admins](#exclude-messages-from-anonymous-admins)
- [Advanced snippets](#advanced-snippets)
@ -47,7 +47,7 @@ It is also a follow-up to the page [Introduction to the API](https://github.com/
+ [Store ConversationHandler States](#store-conversationhandler-states)
- [Usage](#usage-3)
+ [Save and load jobs using pickle](#save-and-load-jobs-using-pickle)
+ [An (good) error handler](#an-good-error-handler)
+ [Telegram web login widget](#verify-data-from-telegram-web-login-widget)
- [What to read next?](#what-to-read-next)
<small><i><a href='http://ecotrust-canada.github.io/markdown-toc/'>Table of contents generated with markdown-toc</a></i></small>
@ -146,6 +146,8 @@ bot.send_message(chat_id=chat_id,
... reply_markup=reply_markup)
```
To catch the incoming message with the location/contact, use `MessageHandler` with `Filters.location` and `Filters.contact`, respectively.
### Message Formatting (bold, italic, code, ...)
#### Post a text message with Markdown formatting
@ -472,11 +474,11 @@ slot_machine_value = {
}
```
#### Get the add group message
#### Get the new members message
```python
def add_group(update, context):
def add_group(update: Update, context: CallbackContext):
for member in update.message.new_chat_members:
update.message.reply_text("{username} add group".format(username=member.username))
update.message.reply_text(f"{member.full_name} just joined the group")
add_group_handle = MessageHandler(Filters.status_update.new_chat_members, add_group)
dispatcher.add_handler(add_group_handle)
@ -792,54 +794,56 @@ if __name__ == '__main__':
main()
```
#### An (good) error handler
The following snippet is an example of an error handler. It notifies the user when an error happens and notifies the dev(s) of the error, including the traceback and where it happend. The comments in the code try to explain exactly what happens when and why, so editing it to fit your special needs should be a breeze.
---
#### Verify data from [Telegram Web Login Widget](https://core.telegram.org/widgets/login).
When using a [`LoginUrl`](https://core.telegram.org/bots/api#loginurl) in an [`InlineKeyboardButton`](https://core.telegram.org/bots/api#inlinekeyboardbutton) to authorize a user on your website via Telegram, you'll have to to check the hash of the received data to verify the data of the integrity as described [here](https://core.telegram.org/widgets/login#checking-authorization)
The data JSON data will have the following form:
```python
{
"id": XXXXXXXXX
"first_name": "XXX"
"last_name": "XXX"
"username": "XXXXX"
"photo_url": "https://t.meXXXXXX.jpg"
"auth_date": XXXXXXXXXX
"hash": "XXXXXXXXXXXXXXXXXXXXXX....."
}
```
The following is an example implementation in Python:
```python
from telegram import ParseMode
from telegram.utils.helpers import mention_html
import sys
import traceback
import hashlib
import hmac
# this is a general error handler function. If you need more information about specific type of update, add it to the
# payload in the respective if clause
def error(update, context):
# add all the dev user_ids in this list. You can also add ids of channels or groups.
devs = [208589966]
# we want to notify the user of this problem. This will always work, but not notify users if the update is an
# callback or inline query, or a poll update. In case you want this, keep in mind that sending the message
# could fail
if update.effective_message:
text = "Hey. I'm sorry to inform you that an error happened while I tried to handle your update. " \
"My developer(s) will be notified."
update.effective_message.reply_text(text)
# This traceback is created with accessing the traceback object from the sys.exc_info, which is returned as the
# third value of the returned tuple. Then we use the traceback.format_tb to get the traceback as a string, which
# for a weird reason separates the line breaks in a list, but keeps the linebreaks itself. So just joining an
# empty string works fine.
trace = "".join(traceback.format_tb(sys.exc_info()[2]))
# lets try to get as much information from the telegram update as possible
payload = ""
# normally, we always have an user. If not, its either a channel or a poll update.
if update.effective_user:
payload += f' with the user {mention_html(update.effective_user.id, update.effective_user.first_name)}'
# there are more situations when you don't get a chat
if update.effective_chat:
payload += f' within the chat <i>{update.effective_chat.title}</i>'
if update.effective_chat.username:
payload += f' (@{update.effective_chat.username})'
# but only one where you have an empty payload by now: A poll (buuuh)
if update.poll:
payload += f' with the poll id {update.poll.id}.'
# lets put this in a "well" formatted text
text = f"Hey.\n The error <code>{context.error}</code> happened{payload}. The full traceback:\n\n<code>{trace}" \
f"</code>"
# and send it to the dev(s)
for dev_id in devs:
context.bot.send_message(dev_id, text, parse_mode=ParseMode.HTML)
# we raise the error again, so the logger module catches it. If you don't use the logger module, use it.
raise
```
BOT_TOKEN = 'YOUR BOT TOKEN'
## What to read next?
If you haven't read the tutorial "[Extensions Your first Bot](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions--Your-first-Bot)" yet, you might want to do it now.
def verify(request_data):
request_data = request_data.copy()
tg_hash = request_data['hash']
request_data.pop('hash', None)
request_data_alphabetical_order = sorted(request_data.items(), key=lambda x: x[0])
data_check_string = []
for data_pair in request_data_alphabetical_order:
key, value = data_pair[0], data_pair[1]
data_check_string.append(f"{key}={value}")
data_check_string = '\n'.join(data_check_string)
secret_key = hashlib.sha256(BOT_TOKEN.encode()).digest()
received_hash = hmac.new(secret_key, msg=data_check_string.encode(), digestmod=hashlib.sha256).hexdigest()
if received_hash == tg_hash:
# The user clicked to the Auth Button and data is verified.
print('User Logged in.')
return True
else:
# The data is not valid
print('User data mis-matched.')
return False
# Optionally use another if-else block to check the auth_date in order to prevent outdated data from being verified.
```
A sample of Flask app can be found [here.](https://gist.github.com/jainamoswal/279e5259a5c24f37cd44ea446c373ac4)

@ -10,16 +10,6 @@ text = "🌈⛈🎉🌹🐧😊"
In the code you may see squares with numbers in them instead of the emoji themself. This means the font in your text editor does not have an image for that character, but it is still there.
This will work without problems on Python 3. On Python 2 you need to declare the encoding of your source file, put this line at the top:
```python
# -*- coding: utf-8 -*-
```
this tells Python that your source file is encoded in UTF8. Note that if you have a shebang at the top, the encoding line comes second:
```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
```
Finally, test your emoji by sending it to yourself over Telegram. Know that Telegram does not support all the emoji.
# The emoji module

@ -2,9 +2,9 @@ A non-exhaustive list of open-source bots built on `python-telegram-bot` in the
# Updater
Bots built using the `telegram.ext.Updater` class.
* [AlarmBot](https://github.com/guysoft/AlarmBot) — This bot uses [crontab](https://en.wikipedia.org/wiki/Cron) to schedule audio alarms. The alarm command can be edited to schedule any kind of cron job for an IOT device. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/alarmbot)
* [AmbroBot](https://github.com/Ambro17/AmbroBot) — This bot can search series or movies by name and lets you download them, it can also list latest yts movies, lets you set reminders, solve linear equations and a few other neat things [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/CuervoBot)
* [BibTeXBot](https://gitlab.com/-/snippets/2069000) — This bot can convert bibliography identifiers to BibTeX entries [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/BibTexBot)
* [BlackJackBot](https://github.com/d-Rickyy-b/Python-BlackJackBot) for a nice round of BlackJack - alone or in a group. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/blackjackbot)
* [BotAgainstHumanity](https://gitlab.com/OctoNezd/bot_against_humanity) - a clone of "Cards Against Humanity" for telegram [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/humanity_against_bot)
* [BotListBot](https://github.com/JosXa/BotListBot) — Large project, maintains the [@BotList channel](https://t.me/botlist). Simplifies navigation, allows submitting and editing bots by the [@BotListChat community](https://t.me/botlistchat) community. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/botlistbot)
@ -25,8 +25,11 @@ Bots built using the `telegram.ext.Updater` class.
* [GoIP Configurator](https://github.com/dangoriaynov/goip-configurator) - A specialised telegram bot and application to monitor and adjust the GoIP-1 VoIP gateway.
* [Hera](https://github.com/xlanor/SIM-UoW-Timetable-bot) - A specialised telegram bot to scrape students' timetables from the SIMConnect portal. I'm adding it here because I couldn't find any examples of bots using celery to delegate tasks.
* [HomeworkHelp](https://github.com/leeweiminsg/homework-help-bot) - A telegram bot to facilitate communication between tutors and their students!
* [Hey bot](https://github.com/HassanHeydariNasab/heybot) - I'm Hey and I repeat what I learn. You can teach me in Regex! [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/hooybot)
* [Instagram Engagement Push bot](https://github.com/konichar/Engagement-Pushbot) [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/chukwudi_pushbot)— This is a Telegram Engagement Push bot designed to organize and pair members together in an Engagement Pod to help increase engagement on each others content.
* [italy_coviddata](https://github.com/MCilento93/italy_coviddata) - A telegram bot providing data, plots and news about COVID-19 diffusion in Italy. Fully-written with python-telegram-bot wrapper. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/italycoviddataBot)
* [Library Genesis Bot](https://github.com/adenosinetp10/Library-Genesis-Bot) - Search for Books and Articles from Library Genesis within Telegram. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/Lib_Genesis_bot)
* [Lugodev Example Bot](https://github.com/lugodev/lugodev-example-bot) - YouTube video series teaching how to make a Telegram bot in Spanish
* [LogBot](https://github.com/apiad/logbot) — A simple bot that accepts messages through a REST API and redirects them to Telegram, with optional actionable buttons. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/apiad_demo_logbot)
* [Marie](https://github.com/PaulSonOfLars/tgbot) — A sassy group administration bot, with some fun extra features.
* [Matilda](https://github.com/xlanor/matilda) — A news scraping bot for Straits Times and ChannelNewsAsia.
@ -36,6 +39,7 @@ Bots built using the `telegram.ext.Updater` class.
* [moodify](https://github.com/samsontmr/moodify) — Takes your selfie and recommends a playlist for your mood. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/moodifybot)
* [Motivational Quotes Bot](https://github.com/SumitAgr/MotivationalQuotes-Bot) - A simple Telegram bot that generates a new motivational quote with a single command. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](http://t.me/MotivationalQuotes_Bot)
* [Motivator bot](https://github.com/SabaunT/bot-motivator) - Telegram bot (with celery engine) that will motivate you to do something good or stop doing something bad. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/PersuaderBot)
* [MusicToolBot](https://github.com/amirhoseinsalimi/music-tool-bot) - A bot to edit, convert, and cut music files and MP3s. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/MusicToolBot)
* [MVC sample](https://github.com/mmdaz/mvc_model_bot_developing) -- This is a great sample for bot developing using python-telegram-bot and based on MVC model. I will be happy if I get comments and pull requests for improving it.
* [Natalia](https://github.com/Whalepool/Natalia) — An administrative assistant bot. Lots of useful commands and functions for helping admins moderate multiple groups with large users
* [Needs more JPEG Bot](https://github.com/zeroone2numeral2/nmjpeg-bot) — Lowers the quality of photos [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/nmjpegbot)
@ -45,12 +49,14 @@ Bots built using the `telegram.ext.Updater` class.
* [PriceBot](https://github.com/lytves/pricebot) - Bot for group chats to receive CoinmarketCap crypto prices [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/iamcryptobot)
* [privibot](https://github.com/pawamoy/privibot) - A Python library to add a privilege/permission system to your Telegram bot.
* [reactor](https://github.com/vanyakosmos/reactor) - like @like but with a dynamic number of buttons. Users can add their own reactions to messages, similarly to slack/discord reactions. [try it out](https://t.me/emojinator_bot)
* [Reddit2Telegram](https://gitlab.com/tea-project/reddit2telegram) - A simple and effective solution to create Telegram channels out of subreddits.
* [Reddit1Telegram](https://gitlab.com/tea-project/reddit1telegram) - A simple and effective solution to create Telegram channels out of subreddits.
* [RemindMeBot](https://github.com/dmakeienko/remind_me_bot) - create reminders, check it's statuses, update/delete them. [try it out](https://t.me/how_to_find_name_for_bot)
* [RRemindersBot](https://github.com/Ambro17/RemindersBot) — Set reminders for your tasks. With support for custom timezones and smart date parsing. Never forget your tasks again [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/RRemindersBot)
* [RSS_Feedbot](https://github.com/Dextroz/RSS_Feederbot/) - A Telegram bot for reading RSS feeds.
* [Sierra Death Generator](https://github.com/skhaz/telegram-sierradeathgenerator) - Generate images using https://deathgenerator.com/
* [sed/regex bot](https://github.com/zeroone2numeral2/regex-bot) — Provides sed-like pattern-replacement commands based on Python's regexp module [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/sedbbot)
* [Sierra Death Generator](https://github.com/skhaz/telegram-sierradeathgenerator) - Generate images using https://deathgenerator.com/
* [Simple Stock Bot](https://gitlab.com/simple-stock-bots/simple-telegram-stock-bot) - A simple bot for getting stock market information. [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/SimpleStockBot)
* [Slovodel Bot](https://github.com/weiss-d/slovodel-bot) — Generates non-existent Russian words of different types. Another example of the MVC approach.[ᴛʀʏ ɪᴛ ᴏᴜᴛ](http://t.me/slovodel_bot)
* [Smokey Bot](https://github.com/udit-001/smokey-bot) - A telegram bot that provides real-time worldwide air pollution data [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/smokey_bot)
* [@someone bot](https://github.com/zeroone2numeral2/someone-bot) — Bot that randomly mentions people when @someone is used [ᴛʀʏ ɪᴛ ᴏᴜᴛ](https://t.me/randmentionbot)
@ -60,6 +66,7 @@ Bots built using the `telegram.ext.Updater` class.
* [Sticker thief](https://github.com/zeroone2numeral2/sticker-thief) — Let people create custom sticker packs from existing stickers
* [Subscription bot](https://github.com/AlexLoushkin/TelegramSubscriptionBot) — Helps organize a subscription for a news web site
* [sudobot](https://github.com/bvanrijn/sudobot) — Runs commands on your server and lets you easily share the output
* [SurfSpot Bot](https://github.com/ereid7/surfspot-bot-telegram) - Bot which retrieves the surf report for a given surf spot
* [teleGit Bot](https://github.com/HeavenH/teleGit) — A bot to list the GitHub repositories, show users information.
* [TimeZone Bot](https://gist.github.com/guysoft/4f220fe407a9bff37e3feff9f60f83a7) — Lets you pick a timezone. This bot also uses a class for its design pattern.
* [Telegram-Facebook-bot](https://github.com/MorenK1/telegram-facebook-bot/blob/master/README.md) - a bot to load content from Facebok pages and send it to Telegram channels
@ -79,6 +86,7 @@ Bots built using the `telegram.ext.Updater` class.
* [XiaomiVacuumCleanerTelegramBot](https://github.com/Matze693/XiaomiVacuumCleanerTelegramBot) - A useful telegram bot to control Xiaomi Vacuum Cleaner V2.
* [YOURLS Bot](https://gitlab.com/HirschHeissIch/yourls-bot/) - A Telegram bot that acts as GUI front end for the [YOURLS](https://yourls.org/) link shortener. You can host it for your own YOURLS instance.
* [Youtrack-Time-Tracking-Bot](https://github.com/MgCoders/tt-bot) — Allows easy time tracking on youtrack issues.
# API
Bots using the raw API.

@ -1,4 +1,4 @@
This page describes advanced use cases for the filters used with `MessageHandler` from `telegram.ext`.
This page describes advanced use cases for the filters used with `MessageHandler` (also with `CommandHandler` and `PrefixHandler`) from `telegram.ext`.
# Combining filters
When using `MessageHandler` it is sometimes useful to have more than one filter. This can be done using so called bit-wise operators. In Python those operators are `&`, `|` and `~` meaning AND, OR and NOT respectively. Since version 13.1 filters support `^` for XOR.
@ -64,7 +64,9 @@ awesome_handler = MessageHandler(filter_awesome, callback)
You may have noticed that when using `Filters.regex`, the attributes `context.matches` and `context.match` are set to the corresponding matches. To achieve something like this for your custom filter, you can do the following:
1. Set `self.data_filter=True` for your filter.
2. If the update should be handled return a dictionary of the form `{attributen_name: value}`. This dict will be merged with the internal dict of the `context` argument making `value` available as `context.attribute_name`. This currently works with `MessageHandler`, `CommandHandler` and `PrefixHandler`, which are the only handlers that accept filters.
2. If the update should be handled return a dictionary of the form `{attribute_name: [values]}`. This dict will be merged with the internal dict of the `context` argument making `value` available as `context.attribute_name`. This currently works with `MessageHandler`, `CommandHandler` and `PrefixHandler`, which are the only handlers that accept filters.
**Note:** The values of the returned dict must be *lists*. This is necessary to make sure that multiple data filters can be merged meaningfully.
If you want this to work with your custom handler, make sure that `YourHandler.collect_additional_context` does something like

@ -10,7 +10,7 @@ The extension class `telegram.ext.JobQueue` allows you to perform tasks with a d
## Example
In addition to the tuorial below there is also the `timerbot.py` example at the [examples directory](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples).
In addition to the tutorial below there is also the `timerbot.py` example at the [examples directory](https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples).
# Usage
The `JobQueue` class is tightly integrated with other `telegram.ext` classes. Similar to `Updater` and `Dispatcher`, it runs asynchronously in a separate thread.

@ -18,6 +18,10 @@
- [How can I list all messages of a particular chat or search through them based on a search query?](#how-can-i-list-all-messages-of-a-particular-chat-or-search-through-them-based-on-a-search-query)
- [How can I disable logging for the `APScheduler` module?](#how-can-i-disable-logging-for-the-apscheduler-module)
- [How do I enforce users joining a specific channel before using my bot?](#how-do-i-enforce-users-joining-a-specific-channel-before-using-my-bot)
- [Why am I getting an error `The following arguments have not been supplied`?](#why-am-i-getting-an-error-the-following-arguments-have-not-been-supplied)
- [How can I check the version of PTB I am using?](#how-can-i-check-the-version-of-ptb-i-am-using)
- [Is there a limit on the number of buttons in an inline keyboard?](#is-there-a-limit-on-the-number-of-buttons-in-an-inline-keyboard)
- [How do I access info about the message my bot sent?](#how-do-I-access-info-about-the-message-my-bot-sent)
### What messages can my Bot see?
@ -42,6 +46,8 @@ From the official [Telegram Bot FAQ](https://core.telegram.org/bots/faq#what-mes
> **Note that each particular message can only be available to one privacy-enabled bot at a time, i.e., a reply to bot A containing an explicit command for bot B or sent via bot C will only be available to bot A. Replies have the highest priority.**
***
Note that turning off the privacy mode has no effect for groups the bot is already in (because obviously that would be a security issue). You need to re-add your bot to those groups.
### What about messages from other Bots?
***
> Bots talking to each other could potentially get stuck in unwelcome loops. To avoid this, we decided that bots will not be able to see messages from other bots regardless of mode.
@ -113,7 +119,7 @@ The user now starts *both* conversations and sees *two* such keyboards. Now, whi
In order to clear this issue up, if you set `per_message=True`, the `ConversationHandler` will use the `message_id` of the message with the keyboard.
Note that this approach can only work, if all the handlers in the conversation are `CallbackQueryHandler`s. This is useful for building interactive menus.
**Note:** If you have a `CallbackQueryHandler` in your `ConversationHandler`, you will see a warning `If 'per_message=True/Fales', …`. It is a *warning*, not an error. If you're sure that you set `per_message` to the correct value, you can just ignore it.
**Note:** If you have a `CallbackQueryHandler` in your `ConversationHandler`, you will see a warning `If 'per_message=True/False', …`. It is a *warning*, not an error. If you're sure that you set `per_message` to the correct value, you can just ignore it.
### Can I check, if a `ConversationHandler` is currently active for a user?
@ -145,6 +151,35 @@ Note that:
* the bot needs to be admin in that channel
* the user must have started the bot for this approach to work. If you try to run `get_chat_member` for a user that has not started the bot, the bot can not find the user in a chat, even if it is a member of it.
Otherwise the method call will fail with an error.
Otherwise depending on whether the user in the channel, has joind and left again, has been banned, ... (there are multiple situations possible), the method may
* raise an exception and in this case the error message will probably be helpful
* return a `ChatMember` instance. In that case make sure to check the [`ChatMember.status`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.chatmember.html#telegram.ChatMember.status) attribute
If the user has not yet joined the channel, you can ignore incoming updates from that user or reply to them with a corresponding warning. A convenient way to do that is to add at [`TypeHandler(telegram.Update, callback)`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.typehandler.html) to a low group and have the `callback` raise [`DispatcherHandlerStop`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) if the user did not join yet. See the docs of [`Dispatcher.add_handler`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) for more info on handler groups and `DispatcherHandlerStop`.
If the user has not yet joined the channel, you can ignore incoming updates from that user or reply to them with a corresponding warning. A convenient way to do that is to add at [`TypeHandler(telegram.Update, callback)`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.typehandler.html) to a low group and have the `callback` raise [`DispatcherHandlerStop`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) if the user did not join yet. See the docs of [`Dispatcher.add_handler`](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcherhandlerstop.html) for more info on handler groups and `DispatcherHandlerStop`.
### Why am I getting an error `The following arguments have not been supplied`?
The `callback` method you pass to `JobQueue.run_*` only takes *one* argument of type `CallbackContext`. This is, because jobs are triggered by a schedule and not by an update from Telegram. If you want to access data in the callback that changes at runtime (e.g. because you schedule jobs on demand), you can either access `context.bot_data` or pass the data to `run_*` as `run_*(…, context=additional_data)`. It can then be accessed within the `callback` as `context.job.context`. Note that `context.{user, chat}_data` will be `None`, as those can only be present, when the `context` object is related to an update, which is not the case for jobs.
### How can I check the version of PTB I am using?
There are three easy ways to do this. Two work from the command line: `pip show python-telegram-bot` or `python -m telegram`. One you run inside a python script (or the python console): `import telegram`, then call `print(telegram.__version__)`.
### Is there a limit on the number of buttons in an inline keyboard?
* max. 100 buttons in total
* max. 8 buttons per row
Note that this is undocumented and may be changed by Telegram.
### How do I access info about the message my bot sent?
All bot methods have a return value. For example to get the `message_id` of a text message sent by your bot, you can do
```python
message = bot.send_message(…)
message_id = message.message_id
```
Please check the docs for details about the return value of each bot method.

@ -12,22 +12,19 @@ if __name__ == '__main__':
## main
```python
updater = Updater("TOKEN", use_context=True)
updater = Updater("TOKEN")
```
[The first line](../blob/master/examples/inlinekeyboard.py#L48) in the main function, it creates an updater instance from the [Updater class](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.updater.html). The "TOKEN" part is where you put the bot token, use_context means that we use context based handlers.
[The first line](../blob/master/examples/inlinekeyboard.py#L49) in the main function, it creates an updater instance from the [Updater class](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.updater.html). The "TOKEN" part is where you put the bot token.
```python
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(button))
updater.dispatcher.add_handler(CommandHandler('help', help))
updater.dispatcher.add_error_handler(error)
```
[Line 50 to 53](../blob/master/examples/inlinekeyboard.py#L50-53) registers our four handlers. The first handler is a [CommandHandler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.commandhandler.html). Whenever an user sends a /start command to the bot, the function `start` is called. Same situation with the third handler: Whenever an user sends the /help command, `help` gets called.
[Line 51 to 53](../blob/master/examples/inlinekeyboard.py#L50-53) registers our three handlers. The first handler is a [CommandHandler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.commandhandler.html). Whenever an user sends a /start command to the bot, the function `start` is called. Same situation with the third handler: Whenever an user sends the /help command, `help` gets called.
The second handler is a [CallbackQueryHandler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.callbackqueryhandler.html). A [Callbackquery](https://python-telegram-bot.readthedocs.io/en/stable/telegram.callbackquery.html) is what an user sends after he presses an [InlineButton](https://python-telegram-bot.readthedocs.io/en/stable/telegram.inlinekeyboardbutton.html). Every press of a button gets send to the `button` handler.
The last handler is an [error handler](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.dispatcher.html#telegram.ext.Dispatcher.add_error_handler). Every error which was raised after an update, wherever it happens in this code, will get send to the `error` handler and can be dealt with there.
```python
updater.start_polling()
```
@ -43,58 +40,71 @@ Let's start our way through the handlers in the same way we would expect an user
## start
```python
def start(update, context):
def start(update: Update, _: CallbackContext) -> None:
```
[Line 18](../blob/master/examples/inlinekeyboard.py#L18) we define a function called start. It takes the two arguments update (instance of an [Update](https://python-telegram-bot.readthedocs.io/en/stable/telegram.update.html)) and context (instance of a [CallbackContext](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.callbackcontext.html)).
[Line 19](../blob/master/examples/inlinekeyboard.py#L19) we define a function called start. It takes the two arguments update (instance of an [Update](https://python-telegram-bot.readthedocs.io/en/stable/telegram.update.html)) and context (instance of a [CallbackContext](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.callbackcontext.html)). Context is just an underscore because we do not use this parameter in the code. The -> indicates a type checker that this function returns nothing.
```python
keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2')],
[InlineKeyboardButton("Option 3", callback_data='3')]]
keyboard = [
[
InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),
],
[InlineKeyboardButton("Option 3", callback_data='3')],
]
```
[Line 19 to 22](../blob/master/examples/inlinekeyboard.py#L19-L22) a variable called keyboard is defined. It is a double list. Every entry in the first list is a row in the actual inline keyboard, every entry in the list entry is a column. So this keyboard will have two rows, Option 1 and Option 2 will be in the first; Option 3 in the second one.
[Line 20 to 26](../blob/master/examples/inlinekeyboard.py#L20-L26) a variable called keyboard is defined. It is a double list. Every entry in the first list is a row in the actual inline keyboard, every entry in the list entry is a column. So this keyboard will have two rows, Option 1 and Option 2 will be in the first; Option 3 in the second one.
```python
reply_markup = InlineKeyboardMarkup(keyboard)
```
[Line 24](../blob/master/examples/inlinekeyboard.py#L24) turns our list into an actual Inline Keyboard that we can pass along with our message.
[Line 28](../blob/master/examples/inlinekeyboard.py#L28) turns our list into an actual Inline Keyboard that we can pass along with our message.
```python
update.message.reply_text('Please choose:', reply_markup=reply_markup)
```
[Line 26](../blob/master/examples/inlinekeyboard.py#L26) we reply to the update message with a text (hence [reply_text](https://python-telegram-bot.readthedocs.io/en/stable/telegram.message.html#telegram.Message.reply_text)) and pass the keyboard along in the reply_markup argument.
[Line 30](../blob/master/examples/inlinekeyboard.py#L30) we reply to the update message with a text (hence [reply_text](https://python-telegram-bot.readthedocs.io/en/stable/telegram.message.html#telegram.Message.reply_text)) and pass the keyboard along in the reply_markup argument.
Now we expect people to press one of the provided buttons, so let's jump to the button callback
## button
```python
def button(update, context):
def button(update: Update, _: CallbackContext) -> None:
```
[Line 29](../blob/master/examples/inlinekeyboard.py#L29) we define a function called button. It takes the two arguments update and context.
[Line 29](../blob/master/examples/inlinekeyboard.py#L29) we define a function called button. It takes the two arguments update and context, basically the same as `start`.
```python
query = update.callback_query
query.edit_message_text(text="Selected option: {}".format(query.data))
```
[Line 30 to 32](../blob/master/examples/inlinekeyboard.py#L30-L32) query is defined as a shortcut to access the provided callbackquery. Then we edit the message where to callbackquery originates from with the text where we tell the user which option we picked. We insert `query.data` into the string, which is the data we defined in the keyboard, so the number 1, 2 or 3. Since we don't pass the inline keyboard along again, it will disappear.
[Line 34](../blob/master/examples/inlinekeyboard.py#L34) query is defined as a shortcut to access the provided [CallbackQuery](https://python-telegram-bot.readthedocs.io/en/stable/telegram.callbackquery.html). This is the part of the update which has all the information in it, remember, it gets generated/send to the bot once a user presses a button.
```python
query.answer()
```
[Line 38](../blob/master/examples/inlinekeyboard.py#L38) here we answer the `CallbackQuery`. We use a convenient shortcut PTB provides. It takes care of calling the [actual function](https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html#telegram.Bot.answer_callback_query) and passing all the required parameters to it. If you check out the function, you see that you can pass a `text` argument to it, which will be displayed in a little pop-up on the client end, and if you pass `show_alert` on top of it, the user has to dismiss the pop-up. Not useful for this example, so we just pass it without these optional arguments.
```python
query.edit_message_text(text=f"Selected option: {query.data}")
```
[Line 40](../blob/master/examples/inlinekeyboard.py#L40) then we edit the message where `CallbackQuery` originates from with the text where we tell the user which option we picked. We insert `query.data` into the string, which is the data we defined in the keyboard, so the number 1, 2 or 3. Since we don't pass the inline keyboard along again, it will disappear.
## help
```python
def help(update, context):
def help_command(update: Update, _: CallbackContext) -> None:
update.message.reply_text("Use /start to test this bot.")
```
[Line 35 to 36](../blob/master/examples/inlinekeyboard.py#L35-L36) in this simple callback, we reply to the /help command with the provided text, that they should use /start to use this bot.
[Line 43 to 44](../blob/master/examples/inlinekeyboard.py#L43-L44) in this simple callback, we reply to the /help command with the provided text, that they should use /start to use this bot.
## error
```python
def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)
logger = logging.getLogger(__name__)
```
[Line 39 to 41](../blob/master/examples/inlinekeyboard.py#L39-41) we simply log in the logger that the provided update raised the provided error.
[Line 13 to 16](../blob/master/examples/inlinekeyboard.py#L13-16) are the only lines of the code we haven't covered yet. Here we set up the logging module to have the format we want, and we define logger in case we want to use it later. More docs regarding logging can be found [here](https://docs.python.org/3/library/logging.html)
***

@ -14,4 +14,4 @@ Bot API 5.0 (and therefore local API server) is supported by PTB since v13.1.
### Working with files
* When running the server with the `--local` flag, `get_file` will give you the local file path as `file_path`. PTB detects that, so that `get_file(…).download()` just returns the local file string instead of downloading it.
* When running the server with the `--local` flag, you can send files by passing `'file:///absolute/path/to/file'` instead of an URL or a file handler. Skipping the `'file://'` prefix, passing relative paths (without prefix) or even passing `pathlib.Path` objects is supported as well as a convenience feature by PTB.
* When running the server *without* the `--local` flag, the Bot API server does *not* automatically serve the files obtained by `get_file()`. See [telegram-bot-api/#26](https://github.com/tdlib/telegram-bot-api/issues/26). SO be aware that you have to run a web server which serves them, otherwise you will run into 404 errors.
* When running the server *without* the `--local` flag, the Bot API server does *not* automatically serve the files obtained by `get_file()`. See [telegram-bot-api/#26](https://github.com/tdlib/telegram-bot-api/issues/26). So be aware that you have to run a web server which serves them, otherwise you will run into 404 errors.

@ -29,7 +29,7 @@ If you've written a persistence class that could benefit others (e.g. a general
To make your bot persistent you need to do the following.
- Create a persistence object (e.g. `my_persistence = PicklePersistence(filename='my_file')`)
- Construct Updater with the persistence (`Updater('TOKEN', persistence=my_persistence, use_context=True)`)
- Construct `Updater` with the persistence (`Updater('TOKEN', persistence=my_persistence, use_context=True)`). If you don't use the `Updater` class, you can pass the persistence directly to the `Dispatcher`.
This is enough to make `user_data`, `bot_data` and `chat_data` persistent.
To make a conversation handler persistent (save states between bot restarts) you **must name it** and set `persistent` to `True`.

@ -30,7 +30,7 @@ So, how do you get around that? Note that I said **by default**. To solve this k
I don't want to bore you with *words* any further, so let's see some code! Sticking with the Echobot example, this is how you can mark the `echo` function to run in a thread:
```python
dispatcher.add_handler(MessagHandler(Filters.text & ~Filters.command, echo, run_async=True))
dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, echo, run_async=True))
```
Simple and straightforward, right? So, why did I bore you with all that stuff before?
@ -99,7 +99,7 @@ To be fair, you probably don't write software for banks (if you do, you should a
There are many ways to fix race conditions in a multithreaded environment, but I won't explain any of them here. Mostly because it probably isn't worth the work; partly because it's cumbersome and I feel lazy. Instead, as promised in the first paragraph, I'll show you how to avoid them completely. That's not always as easy as it is in this case, but we're lucky:
1. Our set of tools is very limited - `@run_async` is the only thread-related tool we're using
1. Our set of tools is very limited - `Dispatcher.run_async` is the only thread-related tool we're using
2. Our goals are not very ambitious - we only want to speed up our I/O
There are two relatively simple steps you have to follow. First, identify those parts of the code that **must** run sequentially (the opposite of *in parallel* or *asynchronously*). Usually, that is code that fits **at least one** of these criteria:
@ -227,18 +227,17 @@ If an asynchronous function is called from anywhere, including the Dispatcher, a
This can lead to a so-called [deadlock](https://en.wikipedia.org/wiki/Deadlock), especially with nested function calls:
```python
@run_async
def grandchild():
pass
@run_async
def child():
grandchild()
dispatcher.run_async(grandchild)
@run_async
def parent():
child()
child()
dispatcher.run_async(child)
dispatcher.run_async(child)
dispatcher.run_async(parent)
```
If you limited the maximum amount of threads to 2 and call the `parent` function, you start a thread. This thread calls the `child` function and starts another thread, so the amount of concurrent threads is 2. It now tries to call the `child` function a second time, but has to wait until the just started `child` thread ended. The `child` thread tries to call `grandchild`, but it has to wait until the `parent` thread ended. Now both threads are waiting for each other and blocking all other code that tries to run an asynchronous function. The calling thread (usually the Dispatcher) is effectively dead, hence the term *deadlock*.

@ -1,7 +1,7 @@
# Groups
* [@pythontelegrambotgroup](https://t.me/pythontelegrambotgroup) is the on-topic user group for questions about PTB. Currently owned by Leandro.
* [@pythontelegrambottalk](https://t.me/pythontelegrambottalk) is the off-topic user group were we can redirect people who have off-topic questions about e.g. python in general and where meta-discussions can happen. Currently owned by @jh0ker
* [@pythontelegrambottalk](https://t.me/pythontelegrambottalk) is the off-topic user group were we can redirect people who have off-topic questions about e.g. python in general and where meta-discussions can happen. It's owned by the test user account, who is an anonymous admin (in order to hide it from the user list).
# Bots
Besides the test bots, the developers team maintains a few helper bots:
@ -15,7 +15,7 @@ Moreover [@python_telegram_bot](https://t.me/python_telegram_bot) is *not* owned
# Channels
* [@pythontelegrambotchannel](https://t.me/pythontelegrambotchannel) is the offical channel of PTB where the release notes go. Currently owned by Leandro.
* [@ptbfaq](https://t.me/PTBFaq) is a channel that was supposed to hold FAQ messages, but was never really in use (roolsbot can still forward to there?!). @josxa is still admin, be he lost the phone with the owner account.
* [@ptbfaq](https://t.me/PTBFaq) is a channel that was supposed to hold FAQ messages, but was never really in use (roolsbot can still forward to there?!). @josxa is still admin, but he lost the phone with the owner account.
Moreover [@run_async](https://t.me/run_async) is *not* owned by any of the developers and also irrelevant since the deprecation of `@run_async` in v13.0

@ -35,13 +35,14 @@ Process
* Bump version:
* telegram/version.py
* docs/source/conf.py
* (if the release includes a Bot API update, update README.rst)
* `telegram/version.py`
* `docs/source/conf.py`
* if the release includes a Bot API update, update `README(_RAW).rst`
* if the release drops a Python version, update `README(_RAW).rst` and `setup.py`
* Log changes to:
* CHANGES.rst
* `CHANGES.rst`
Since writing adding the correct links is a bit tiresome, here is a little `something`_ to help you with it.
@ -53,9 +54,13 @@ Process
$ python setup.py sdist bdist_wheel
This will also build PTB-Raw
* Upload to PyPI (-s to sign the package with your GnuPG key)::
$ twine upload -s dist/python*
This will also upload PTB-Raw
* Push all changes
@ -69,6 +74,7 @@ Process
* create sha1 signature:
```bash
sha1sum --binary dist/python-telegram-bot-X.Y.tar.gz > dist/python-telegram-bot-X.Y.tar.gz.sha1
sha1sum --binary dist/python-telegram-bot-raw-X.Y.tar.gz > dist/python-telegram-bot-raw-X.Y.tar.gz.sha1
```
* Upload the source distribution from pypi as binary attachment + asc (gpg signature) + sha1 (create it yourself).
@ -78,7 +84,7 @@ Process
* `Close milestones`_ for this version.
* Test in a clean virtualenv that ``pip install python-telegram-bot`` works with the new version.
* Test in a clean virtualenv that ``pip install python-telegram-bot`` and ``pip install python-telegram-bot-raw`` work with the new version.
Public Announcements

@ -10,7 +10,7 @@ from telegram.ext import Updater, CommandHandler
def put(update, context):
"""Usage: /put value"""
# Generate ID and seperate value from command
# Generate ID and separate value from command
key = str(uuid4())
# We don't use context.args here, because the value may contain whitespaces
value = update.message.text.partition(' ')[2]

@ -16,6 +16,7 @@
- [Rich Comparison](#rich-comparison)
* [Special note on `Message`](#special-note-on--message-)
- [Refactoring of Filters](#refactoring-of-filters)
- [Special Note on `Updater.start_webhook`](#special-note-on-updaterstart_webhook)
# Deprecations
@ -153,3 +154,16 @@ and
both inheriting from `BaseFilter`.
If you have custom filters inheriting from `BaseFilter`, you will need to change their parent class to `MessageFilter` or, if you're currently setting `update_filter = True`, to `UpdateFilter`. In that case, you can remove the `update_filter = True`.
# Special Note on `Updater.start_webhook`
If you're upgrading directly to v13.4+ and use something like
```python
updater.start_webhook(…)
updater.bot.set_webhook(my_url)
```
you will have to change that to
```python
updater.start_webhook(…, webhook_url=my_url)
```

@ -19,7 +19,7 @@ For different kinds of user input, the received `telegram.Update` will have diff
The special thing about `MessageHandler` is that there is such a vast variety of message types (text, gif, image, document, sticker, …) that it's infeasible to provide a different `Handler` for each type. Instead `MessageHandler` is coupled with so called [filters](https://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.filters.html) that allow to make fine-grained distinctions: `MessageHandler(Filters.all, callback)` will handle all updates that contain
* `updat.message`
* `update.message`
* `update.edited_message`
* `update.channel_post`
* `update.edited_channel_post`

@ -59,7 +59,7 @@ To solve this problem, you can use a reverse proxy like *nginx* or *haproxy*.
In this model, a single server application listening on the public IP, the *reverse proxy*, accepts all webhook requests and forwards them to the correct instance of locally running *integrated webhook servers.* It also performs the *SSL termination*, meaning it decrypts the HTTPS connection, so the webhook servers receive the already decrypted traffic. These servers can run on *any* port, not just the four ports allowed by Telegram, because Telegram only connects to the reverse proxy directly.
**Note:** In this server model, you have to call `set_webhook` yourself.
**Note:** In this server model, you have to call `set_webhook` yourself, if you are on PTB version <13.4.
Depending on the reverse proxy application you (or your hosting provider) is using, the implementation will look a bit different. In the following, there are a few possible setups listed.
@ -76,22 +76,26 @@ updater = Updater(TOKEN)
# add handlers
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN)
updater.bot.set_webhook("https://<appname>.herokuapp.com/" + TOKEN)
url_path=TOKEN,
webhook_url="https://<appname>.herokuapp.com/" + TOKEN)
updater.idle()
```
#### Using nginx with one domain/port for all bots
This is similar to the Heroku approach, just that you set up the reverse proxy yourself. All bots set their `webhook_url` to the same domain and port, but with a different `url_path`. The integrated server should usually be started on the `localhost` or `127.0.0.1` address, the port can be any port you choose.
This is similar to the Heroku approach, just that you set up the reverse proxy yourself. All bots set their `url` to the same domain and port, but with a different `url_path`. The integrated server should usually be started on the `localhost` or `127.0.0.1` address, the port can be any port you choose.
**Note:** `example.com` could be replaced by an IP address, if you have no domain associated to your server.
Example code to start the bot:
```python
updater.start_webhook(listen='127.0.0.1', port=5000, url_path='TOKEN1')
updater.bot.set_webhook(webhook_url='https://example.com/TOKEN1',
certificate=open('cert.pem', 'rb'))
updater.start_webhook(
listen='127.0.0.1',
port=5000,
url_path='TOKEN1',
webhook_url='https://example.com/TOKEN1',
cert=open('cert.pem', 'rb')
)
```
Example configuration for `nginx` (reduced to important parts) with two bots configured:
@ -119,9 +123,13 @@ In this approach, each bot is assigned their own *subdomain*. If your server has
Example code to start the bot:
```python
updater.start_webhook(listen='127.0.0.1', port=5000, url_path='TOKEN')
updater.bot.set_webhook(webhook_url='https://bot1.example.com/TOKEN',
certificate=open('cert_bot1.pem', 'rb'))
updater.start_webhook(
listen='127.0.0.1',
port=5000,
url_path='TOKEN',
webhook_url='https://bot1.example.com/TOKEN,
cert=open('cert_bot1.pem', 'rb')
)
```
Example configuration for `haproxy` (reduced to important parts) with two bots configured. Again: The FQDN of both certificates must match the value in `ssl_fc_sni`. Also, the `.pem` files are the `private.key` file and `cert.pem` files concatenated:

@ -8,14 +8,17 @@ Look at [Hosting your bot](https://github.com/python-telegram-bot/python-telegra
* **[How to create a Bot on Google App Engine](https://github.com/sooyhwang/Simple-Echo-Telegram-Bot)** by [sooyhwang](https://github.com/sooyhwang) (NOTE: This might be obsolete)
* [Google Cloud Functions](https://cloud.google.com/functions/)
* **[Building a serverless Telegram bot](https://seminar.io/2018/09/03/building-serverless-telegram-bot/)** by [pabluk](https://github.com/pabluk)
* [Google Cloud Run](https://cloud.google.com/run/)
* **[Hosting Telegram bots on Cloud Run for free](https://nullonerror.org/2021/01/08/hosting-telegram-bots-on-google-cloud-run/)** by [skhaz](https://github.com/skhaz/)
* [Heroku](https://www.heroku.com/)
* **[Heroku getting started with Python](https://devcenter.heroku.com/articles/getting-started-with-python#introduction)**
* **[Webhooks on Heroku](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Webhooks#heroku)**
* **[Skeleton repository](https://github.com/Eldinnie/ptb-heroku-skeleton)**
* **[Skeleton repository](https://github.com/Bibo-Joshi/ptb-heroku-skeleton)**
* [OpenShift](https://www.openshift.com/)
* **[How to run a Bot on Openshift v2](https://github.com/lufte/python-telegram-bot-openshift)**
* **[How to run a Bot on Openshift v3](https://github.com/Gotham13121997/python-telegram-bot-openshift3)**
* [Joyent Triton](https://www.joyent.com/triton)
* [Vercel serverless functions](https://vercel.com/docs/serverless-functions/supported-languages#python)
* [PythonAnywhere](https://www.pythonanywhere.com)
* [Oracle Cloud](https://www.oracle.com/cloud/free/) an AlwaysFree feature for a decent instance.
@ -41,6 +44,7 @@ Look at [Hosting your bot](https://github.com/python-telegram-bot/python-telegra
* **[How to create a Bot on Codenvy](https://github.com/p92camcj/Tutorial-telegram-bot)** by [p92camcj](https://github.com/p92camcj/Tutorial-telegram-bot)
* [Koding](https://koding.com/)
* [Cloud9](https://c9.io/)
* [Repl.it](https://repl.it/)
### Tunnels
* [localtunnel](https://localtunnel.me/)

@ -1 +1 @@
Wiki of [`python-telegram-bot`](https://python-telegram-bot.org/)© Copyright 2015-2020 Licensed by [Creative Commons](https://creativecommons.org/licenses/by/3.0/)
Wiki of [`python-telegram-bot`](https://python-telegram-bot.org/)© Copyright 2015-2021 Licensed by [Creative Commons](https://creativecommons.org/licenses/by/3.0/)