Updating a ton of wiki pages to v12

I've probably missed some stuff... please edit if so ;)
Jasmin Bom 2019-03-03 16:14:26 +01:00
parent d4a3352a54
commit 5339a1a15e
7 changed files with 154 additions and 205 deletions

@ -1,3 +1,9 @@
## Version 12 beta note
This wiki page has been updated to work with the beta version 12 of the python-telegram-bot library.
This version has proven to be generally generally stable enough for most usecases. See [the v12 transistion guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-12.0) for more info.
If you're still using version 11.1.0, please see the [old version of this wiki page](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Avoiding-flood-limits/bd30b9aa7c12515496af55650205485d3455821f).
## 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. 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.
@ -82,13 +88,13 @@ if __name__ == '__main__':
testbot = MQBot(token, request=request, mqueue=q)
upd = telegram.ext.updater.Updater(bot=testbot)
def reply(bot, update):
def reply(update, context):
# tries to echo 10 msgs at once
chatid = update.message.chat_id
msgt = update.message.text
print(msgt, chatid)
for ix in range(10):
bot.send_message(chat_id=chatid, text='%s) %s' % (ix + 1, msgt))
context.bot.send_message(chat_id=chatid, text='%s) %s' % (ix + 1, msgt))
hdl = MessageHandler(Filters.text, reply)
upd.dispatcher.add_handler(hdl)

@ -1,3 +1,8 @@
## Version 12 beta note
This wiki page has been updated to work with the beta version 12 of the python-telegram-bot library.
This version has proven to be generally generally stable enough for most usecases. See [the v12 transistion guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-12.0) for more info.
If you're still using version 11.1.0, please see the [old version of this wiki page](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Code-snippets/d23093978b3c4a62bfc55e49b9ea80a4e568a73a).
This page can be read on its own to find the code snippet you need right now.
It is also a follow-up to the page [Introduction to the API](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API). If you come from there, you can leave your command line open and just try out a few of these snippets.
@ -56,22 +61,22 @@ To fetch messages sent to your Bot, you can use the [getUpdates](https://core.te
**Note:** You don't have to use `get_updates` if you are writing your bot with the `telegram.ext` submodule, since `telegram.ext.Updater` takes care of fetching all updates for you. Read more about that [here](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot).
```python
>>> updates = bot.get_updates()
>>> print([u.message.text for u in updates])
updates = bot.get_updates()
print([u.message.text for u in updates])
```
#### Fetch images sent to your Bot
```python
>>> updates = bot.get_updates()
>>> print([u.message.photo for u in updates if u.message.photo])
updates = bot.get_updates()
print([u.message.photo for u in updates if u.message.photo])
```
#### Reply to messages
You'll always need the `chat_id`
```python
>>> chat_id = bot.get_updates()[-1].message.chat_id
chat_id = bot.get_updates()[-1].message.chat_id
```
## General code snippets
@ -86,7 +91,7 @@ If the bot has a chat with the user, it will send the message to that chat.
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendmessage)
```python
>>> bot.send_message(chat_id=chat_id, text="I'm sorry Dave I'm afraid I can't do that.")
bot.send_message(chat_id=chat_id, text="I'm sorry Dave I'm afraid I can't do that.")
```
**Note:** `send_message` method (as any of `send_*` methods of `Bot` class) returns the instance of `Message` class, so it can be used in code later.
@ -96,7 +101,7 @@ If the bot has a chat with the user, it will send the message to that chat.
This is a shortcut to `bot.send_message` with sane defaults. Read more about it [in the docs](http://python-telegram-bot.readthedocs.io/en/latest/telegram.html#telegram.Message.reply_text).
```python
>>> update.message.reply_text("I'm sorry Dave I'm afraid I can't do that.")
update.message.reply_text("I'm sorry Dave I'm afraid I can't do that.")
```
**Note:** There are equivalents of this method for replying with photos, audio etc., and similar shortcuts exist throughout the library. Related PRs: [#362](https://github.com/python-telegram-bot/python-telegram-bot/pull/362), [#420](https://github.com/python-telegram-bot/python-telegram-bot/pull/420), [#423](https://github.com/python-telegram-bot/python-telegram-bot/pull/423)
@ -106,7 +111,7 @@ This is a shortcut to `bot.send_message` with sane defaults. Read more about it
Use this to tell the user that something is happening on the bot's side:
```python
>>> bot.send_chat_action(chat_id=chat_id, action=telegram.ChatAction.TYPING)
bot.send_chat_action(chat_id=chat_id, action=telegram.ChatAction.TYPING)
```
Alternatively, if you have several commands and don't want to repeat the above code snippet inside all commands, you can copy the snippet below and just decorate the callback functions with `@send_typing_action`.
@ -117,10 +122,9 @@ def send_typing_action(func):
"""Sends typing action while processing func command."""
@wraps(func)
def command_func(*args, **kwargs):
bot, update = args
bot.send_chat_action(chat_id=update.effective_message.chat_id, action=telegram.ChatAction.TYPING)
return func(bot, update, **kwargs)
def command_func(update, context, *args, **kwargs):
context.bot.send_chat_action(chat_id=update.effective_message.chat_id, action=ChatAction.TYPING)
return func(update, context, *args, **kwargs)
return command_func
@ -128,27 +132,15 @@ def send_typing_action(func):
def my_handler(bot, update):
pass # Will send 'typing' action while processing the request.
```
If you are using v12 that will not work as bot is no longer received as the first argument. Instead use:
```python
def send_typing_action(func):
"""Sends typing action while processing func command."""
@wraps(func)
def command_func(update, context, *args, **kwargs):
context.bot.send_chat_action(chat_id=update.effective_message.chat_id, action=ChatAction.TYPING)
return func(update, context, *args, **kwargs)
return command_func
```
#### Requesting location and contact from user
```python
>>> location_keyboard = telegram.KeyboardButton(text="send_location", request_location=True)
>>> contact_keyboard = telegram.KeyboardButton(text="send_contact", request_contact=True)
>>> custom_keyboard = [[ location_keyboard, contact_keyboard ]]
>>> reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
>>> bot.send_message(chat_id=chat_id,
location_keyboard = telegram.KeyboardButton(text="send_location", request_location=True)
contact_keyboard = telegram.KeyboardButton(text="send_contact", request_contact=True)
custom_keyboard = [[ location_keyboard, contact_keyboard ]]
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id,
... text="Would you mind sharing your location and contact with me?",
... reply_markup=reply_markup)
```
@ -159,18 +151,18 @@ def send_typing_action(func):
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendmessage)
```python
>>> bot.send_message(chat_id=chat_id,
... text="*bold* _italic_ `fixed width font` [link](http://google.com).",
... parse_mode=telegram.ParseMode.MARKDOWN)
bot.send_message(chat_id=chat_id,
text="*bold* _italic_ `fixed width font` [link](http://google.com).",
parse_mode=telegram.ParseMode.MARKDOWN)
```
#### Post a text message with HTML formatting
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendmessage)
```python
>>> bot.send_message(chat_id=chat_id,
... text='<b>bold</b> <i>italic</i> <a href="http://google.com">link</a>.',
... parse_mode=telegram.ParseMode.HTML)
bot.send_message(chat_id=chat_id,
text='<b>bold</b> <i>italic</i> <a href="http://google.com">link</a>.',
parse_mode=telegram.ParseMode.HTML)
```
#### Message entities
@ -180,7 +172,7 @@ To use MessageEntity, extract the entities and their respective text from a Mess
**Note:** This method should always be used instead of the ``entities`` attribute, since it calculates the correct substring from the message text based on UTF-16 codepoints - that is, it extracts the correct string even on when working with weird characters such as Emojis.
```python
>>> entities = message.parse_entities()
entities = message.parse_entities()
```
There are many more API methods. To read the full API documentation, visit the [Telegram API documentation](https://core.telegram.org/bots/api) or the [library documentation of telegram.Bot](http://python-telegram-bot.readthedocs.io/en/latest/telegram.bot.html)
@ -191,28 +183,28 @@ There are many more API methods. To read the full API documentation, visit the [
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendphoto)
```python
>>> bot.send_photo(chat_id=chat_id, photo=open('tests/test.png', 'rb'))
bot.send_photo(chat_id=chat_id, photo=open('tests/test.png', 'rb'))
```
#### Post a voice file from disk
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendvoice)
```python
>>> bot.send_voice(chat_id=chat_id, voice=open('tests/telegram.ogg', 'rb'))
bot.send_voice(chat_id=chat_id, voice=open('tests/telegram.ogg', 'rb'))
```
#### Post a photo from a URL
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendphoto)
```python
>>> bot.send_photo(chat_id=chat_id, photo='https://telegram.org/img/t_logo.png')
bot.send_photo(chat_id=chat_id, photo='https://telegram.org/img/t_logo.png')
```
#### Post a gif from a URL (send_animation)
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendanimation)
```python
>>> bot.send_animation(chat_id, animation, duration=None, width=None, height=None, thumb=None, caption=None, parse_mode=None, disable_notification=False, reply_to_message_id=None, reply_markup=None, timeout=20, **kwargs)
bot.send_animation(chat_id, animation, duration=None, width=None, height=None, thumb=None, caption=None, parse_mode=None, disable_notification=False, reply_to_message_id=None, reply_markup=None, timeout=20, **kwargs)
```
See the [online documentation](https://python-telegram-bot.readthedocs.io/en/latest/telegram.bot.html#telegram.Bot.send_animation)
@ -223,45 +215,45 @@ See the [online documentation](https://python-telegram-bot.readthedocs.io/en/lat
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#sendaudio)
```python
>>> bot.send_audio(chat_id=chat_id, audio=open('tests/test.mp3', 'rb'))
bot.send_audio(chat_id=chat_id, audio=open('tests/test.mp3', 'rb'))
```
#### Post a file from disk
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#senddocument)
```python
>>> bot.send_document(chat_id=chat_id, document=open('tests/test.zip', 'rb'))
bot.send_document(chat_id=chat_id, document=open('tests/test.zip', 'rb'))
```
#### Post an image from memory
In this example, `image` is a PIL (or Pillow) `Image` object, but it works the same with all media types.
```python
>>> from io import BytesIO
>>> bio = BytesIO()
>>> bio.name = 'image.jpeg'
>>> image.save(bio, 'JPEG')
>>> bio.seek(0)
>>> bot.send_photo(chat_id, photo=bio)
from io import BytesIO
bio = BytesIO()
bio.name = 'image.jpeg'
image.save(bio, 'JPEG')
bio.seek(0)
bot.send_photo(chat_id, photo=bio)
```
#### Get image with dimensions closest to a desired size
Where `photos` is a list of `PhotoSize` objects and `desired_size` is a tuple containing the desired size.
```python
>>> def get_closest(photos, desired_size):
>>> def diff(p): return p.width - desired_size[0], p.height - desired_size[1]
>>> def norm(t): return abs(t[0] + t[1] * 1j)
>>> return min(photos, key=lambda p: norm(diff(p)))
def get_closest(photos, desired_size):
def diff(p): return p.width - desired_size[0], p.height - desired_size[1]
def norm(t): return abs(t[0] + t[1] * 1j)
return min(photos, key=lambda p: norm(diff(p)))
```
#### Download a file
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots/api#getfile)
```python
>>> file_id = message.voice.file_id
>>> newFile = bot.get_file(file_id)
>>> newFile.download('voice.ogg')
file_id = message.voice.file_id
newFile = bot.get_file(file_id)
newFile.download('voice.ogg')
```
**Note:** For downloading photos, keep in mind that `update.message.photo` is an array of different photo sizes. Use `update.message.photo[-1]` to get the biggest size.
@ -272,12 +264,12 @@ Where `photos` is a list of `PhotoSize` objects and `desired_size` is a tuple co
[ᵀᴱᴸᴱᴳᴿᴬᴹ](https://core.telegram.org/bots#keyboards)
```python
>>> custom_keyboard = [['top-left', 'top-right'],
... ['bottom-left', 'bottom-right']]
>>> reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
>>> bot.send_message(chat_id=chat_id,
... text="Custom Keyboard Test",
... reply_markup=reply_markup)
custom_keyboard = [['top-left', 'top-right'],
['bottom-left', 'bottom-right']]
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id,
text="Custom Keyboard Test",
reply_markup=reply_markup)
```
See also: [Build a menu with Buttons](#build-a-menu-with-buttons)
@ -286,8 +278,8 @@ See also: [Build a menu with Buttons](#build-a-menu-with-buttons)
#### Remove a custom keyboard
```python
>>> reply_markup = telegram.ReplyKeyboardRemove()
>>> bot.send_message(chat_id=chat_id, text="I'm back.", reply_markup=reply_markup)
reply_markup = telegram.ReplyKeyboardRemove()
bot.send_message(chat_id=chat_id, text="I'm back.", reply_markup=reply_markup)
```
### Other useful stuff
@ -297,23 +289,22 @@ See also: [Build a menu with Buttons](#build-a-menu-with-buttons)
The Unicode flag emoji for any country can by definition be calculated from the countries [2 letter country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). The following snippet only works in Python 3.
```python
>>> OFFSET = 127462 - ord('A')
>>>
>>> def flag(code):
... code = code.upper()
... return chr(ord(code[0]) + OFFSET) + chr(ord(code[1]) + OFFSET)
...
OFFSET = 127462 - ord('A')
def flag(code):
code = code.upper()
return chr(ord(code[0]) + OFFSET) + chr(ord(code[1]) + OFFSET)
>>> flag('de')
'🇩🇪'
>>> flag('us')
'🇺🇸'
>>> flag('ru')
'🇷🇺'
>>>
```
#### Get the add group message
```
```python
class NewMember(BaseFilter):
def filter(self, message):
if not message.new_chat_members:
@ -343,12 +334,12 @@ LIST_OF_ADMINS = [12345678, 87654321]
def restricted(func):
@wraps(func)
def wrapped(bot, update, *args, **kwargs):
def wrapped(update, context, *args, **kwargs):
user_id = update.effective_user.id
if user_id not in LIST_OF_ADMINS:
print("Unauthorized access denied for {}.".format(user_id))
return
return func(bot, update, *args, **kwargs)
return func(update, context, *args, **kwargs)
return wrapped
```
@ -368,21 +359,6 @@ This parametrized decorator allows you to signal different actions depending on
```python
from functools import wraps
def send_action(action):
"""Sends `action` while processing func command."""
def decorator(func):
@wraps(func)
def command_func(*args, **kwargs):
bot, update = args
bot.send_chat_action(chat_id=update.effective_message.chat_id, action=action)
return func(bot, update, **kwargs)
return command_func
return decorator
```
If you are using telegram v12 the above snippet won't work, as the bot instance is not longer received as the first argument, instead we can access it through the context object.
```python
def send_action(action):
"""Sends `action` while processing func command."""
@ -394,7 +370,8 @@ def send_action(action):
return command_func
return decorator
```
```
##### Usage
![Result](https://i.imgur.com/ErBKSS4.png)
@ -518,7 +495,7 @@ def main():
updater.stop()
os.execl(sys.executable, sys.executable, *sys.argv)
def restart(bot, update):
def restart(update, context):
update.message.reply_text('Bot is restarting...')
Thread(target=stop_and_restart).start()
@ -538,59 +515,7 @@ if __name__ == '__main__':
#### Store ConversationHandler States
The following code allows you to store ConversationHandler States and UserData and reloading them when you restart the bot. Store procedure is executed every 60 seconds; to change this value, you can modify the `time.sleep(60)` instruction.
You should declare the two methods at the end of the main method to use python closure for accessing ConversationHandler and UserData.
```python
import time, threading, pickle
def main():
def loadData():
try:
f = open('backup/conversations', 'rb')
conv_handler.conversations = pickle.load(f)
f.close()
f = open('backup/userdata', 'rb')
dp.user_data = pickle.load(f)
f.close()
except FileNotFoundError:
utils.logging.error("Data file not found")
except:
utils.logging.error(sys.exc_info()[0])
def saveData():
while True:
time.sleep(60)
# Before pickling
resolved = dict()
for k, v in conv_handler.conversations.items():
if isinstance(v, tuple) and len(v) is 2 and isinstance(v[1], Promise):
try:
new_state = v[1].result() # Result of async function
except:
new_state = v[0] # In case async function raised an error, fallback to old state
resolved[k] = new_state
else:
resolved[k] = v
try:
f = open('backup/conversations', 'wb+')
pickle.dump(resolved, f)
f.close()
f = open('backup/userdata', 'wb+')
pickle.dump(dp.user_data, f)
f.close()
except:
utils.logging.error(sys.exc_info()[0])
```
##### Usage
```python
def main():
...
loadData()
threading.Thread(target=saveData).start()
```
Version 12 and up includes tools for [making your bot persistent](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Making-your-bot-persistent).
#### Save and load jobs using pickle
The following snippet pickles the jobs in the job queue periodically and on bot shutdown and unpickles and queues them again on startup. Since `pickle` doesn't support threading primitives, they are converted.
@ -662,8 +587,8 @@ def save_jobs(jq):
job._enabled = _enabled
def save_jobs_job(bot, job):
save_jobs(job.job_queue)
def save_jobs_job(context):
save_jobs(context.job_queue)
def main():

@ -1,3 +1,8 @@
## Version 12 beta note
This wiki page has been updated to work with the beta version 12 of the python-telegram-bot library.
This version has proven to be generally generally stable enough for most usecases. See [the v12 transistion guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-12.0) for more info.
If you're still using version 11.1.0, please see the [old version of this wiki page](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-JobQueue/0c79111ed68022f4936c2725f9827eac0a5240a0).
## Introduction
The extension class `telegram.ext.JobQueue` allows you to perform tasks with a delay or even periodically, at a set interval. Among many other things, you can use it to send regular updates to your subscribers.
@ -7,9 +12,9 @@ The `JobQueue` class is tightly integrated with other `telegram.ext` classes. Si
To use the `JobQueue`, you don't have to do much. When you instantiate the `Updater`, it will create a `JobQueue` for you:
```python
>>> from telegram.ext import Updater
>>> u = Updater('TOKEN')
>>> j = u.job_queue
from telegram.ext import Updater
u = Updater('TOKEN', use_context=True)
j = u.job_queue
```
This job queue is also linked to the dispatcher, which is discussed later in this article. Just know that unless you have a good reason to do so, you should not instantiate `JobQueue` yourself.
@ -19,11 +24,11 @@ Tasks in the job queue is encapsulated by the `Job` class. It takes a callback f
Add your first job to the queue by defining a callback function and adding it to the job queue. For this tutorial, you can replace `'@examplechannel'` with a channel where your bot is an admin, or by your user id (use [@userinfobot](https://telegram.me/userinfobot) to find out your user id):
```python
>>> def callback_minute(bot, job):
... bot.send_message(chat_id='@examplechannel',
... text='One message every minute')
...
>>> job_minute = j.run_repeating(callback_minute, interval=60, first=0)
def callback_minute(context):
context.bot.send_message(chat_id='@examplechannel',
text='One message every minute')
job_minute = j.run_repeating(callback_minute, interval=60, first=0)
```
The `callback_minute` function will be executed every `60.0` seconds, the first time being right now (because of `first=0`). The `interval` and `first` parameters are in seconds if they are `int` or `float`. They can also be `datetime` objects. See the [docs](http://python-telegram-bot.readthedocs.io/en/stable/telegram.ext.jobqueue.html) for detailed explanation.
@ -32,11 +37,11 @@ The return value of these functions are the `Job` objects being created. You can
You can also add a job that will be executed only once, with a delay:
```python
>>> def callback_30(bot, job):
... bot.send_message(chat_id='@examplechannel',
... text='A single message with 30s delay')
...
>>> j.run_once(callback_30, 30)
def callback_30(context):
context.bot.send_message(chat_id='@examplechannel',
text='A single message with 30s delay')
j.run_once(callback_30, 30)
```
In thirty seconds you should receive the message from `callback_30`.
@ -44,8 +49,8 @@ In thirty seconds you should receive the message from `callback_30`.
If you are tired of receiving a message every minute, you can temporarily disable a job or even completely remove it from the queue:
```python
>>> job_minute.enabled = False # Temporarily disable this job
>>> job_minute.schedule_removal() # Remove this job completely
job_minute.enabled = False # Temporarily disable this job
job_minute.schedule_removal() # Remove this job completely
```
**Note:** `schedule_removal` does not immediately remove the job from the queue. Instead, it is marked for removal and will be removed as soon as its current interval is over (it will not run again after being marked for removal).
@ -53,14 +58,15 @@ If you are tired of receiving a message every minute, you can temporarily disabl
A job can also change its own behavior, as it is passed to the callback function as the second argument:
```python
>>> def callback_increasing(bot, job):
... bot.send_message(chat_id='@examplechannel',
... text='Sending messages with increasing delay up to 10s, then stops.')
... job.interval += 1.0
... if job.interval > 10.0:
... job.schedule_removal()
...
>>> j.run_repeating(callback_increasing, 1)
def callback_increasing(context):
job = context.job
context.bot.send_message(chat_id='@examplechannel',
text='Sending messages with increasing delay up to 10s, then stops.')
job.interval += 1.0
if job.interval > 10.0:
job.schedule_removal()
j.run_repeating(callback_increasing, 1)
```
This job will send a first message after one second, a second message after two _more_ seconds, a third message after _three more_ seconds, and so on. After the ten messages, the job will terminate itself.
@ -68,18 +74,18 @@ This job will send a first message after one second, a second message after two
You might want to add jobs in response to certain user input, and there is a convenient way to do that. All `Handler` classes can pass the job queue into their callback functions, if you need them to. To do that, simply set `pass_job_queue=True` when instantiating the Handler. Another feature you can use here is the `context` keyword argument of `Job`. You can pass any object as a `context` parameter when you launch a Job and retrieve it at a later stage as long as the Job exists. Let's see how it looks in code:
```python
>>> from telegram.ext import CommandHandler
>>> def callback_alarm(bot, job):
... bot.send_message(chat_id=job.context, text='BEEP')
...
>>> def callback_timer(bot, update, job_queue):
... bot.send_message(chat_id=update.message.chat_id,
... text='Setting a timer for 1 minute!')
...
... job_queue.run_once(callback_alarm, 60, context=update.message.chat_id)
...
>>> timer_handler = CommandHandler('timer', callback_timer, pass_job_queue=True)
>>> u.dispatcher.add_handler(timer_handler)
from telegram.ext import CommandHandler
def callback_alarm(context):
context.bot.send_message(chat_id=context.job.context, text='BEEP')
def callback_timer(context, update):
context.bot.send_message(chat_id=update.message.chat_id,
text='Setting a timer for 1 minute!')
context.job_queue.run_once(callback_alarm, 60, context=update.message.chat_id)
timer_handler = CommandHandler('timer', callback_timer)
u.dispatcher.add_handler(timer_handler)
```
By placing the `chat_id` in the `Job` object, the callback function knows where it should send the message.
@ -87,11 +93,11 @@ By placing the `chat_id` in the `Job` object, the callback function knows where
All good things come to an end, so when you stop the Updater, the related job queue will be stopped as well:
```python
>>> u.stop()
u.stop()
```
Of course, you can instead also stop the job queue by itself:
```python
>>> j.stop()
j.stop()
```

@ -1 +0,0 @@
from telegram.ext import Updater

@ -1,3 +1,8 @@
## Version 12 beta note
This wiki page has been updated to work with the beta version 12 of the python-telegram-bot library.
This version has proven to be generally generally stable enough for most usecases. See [the v12 transistion guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-12.0) for more info.
If you're still using version 11.1.0, please see the [old version of this wiki page](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot/c8dd272e26b939168eaa5812de5bf2b066ff10d6).
## Introduction
The `telegram.ext` submodule is built on top of the pure API implementation. It provides an easy-to-use interface and takes some work off the programmer, so you [don't have to repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
@ -19,12 +24,14 @@ First, you have to create an `Updater` object. Replace `'TOKEN'` with your Bot's
```python
from telegram.ext import Updater
updater = Updater(token='TOKEN')
updater = Updater(token='TOKEN', use_context=True)
```
**Related docs:** [telegram.ext.Updater](http://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.updater.html#telegram.ext.updater.Updater)
For quicker access to the `Dispatcher` used by your `Updater`, you can introduce it locally:
**Note**: The `use_context=True` is a special argument only needed for version 12 of the library. It allows for better backwards compatibility with older versions of the library, and to give users some time to upgrade. From version 13 it `use_context=True` will be the default.
```python
dispatcher = updater.dispatcher
```
@ -42,10 +49,10 @@ logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s
Now, you can define a function that should process a specific type of update:
```python
def start(bot, update):
bot.send_message(chat_id=update.message.chat_id, text="I'm a bot, please talk to me!")
def start(update, context):
context.bot.send_message(chat_id=update.message.chat_id, text="I'm a bot, please talk to me!")
```
**Related docs:** [sendMessage](https://core.telegram.org/bots/api#sendmessage)
**Related docs:** [sendMessage](https://core.telegram.org/bots/api#sendmessage), [CallbackContext (the type of the context argument)](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.callbackcontext.html)
The goal is to have this function called every time the Bot receives a Telegram message that contains the `/start` command. To accomplish that, you can use a `CommandHandler` (one of the provided `Handler` subclasses) and register it in the dispatcher:
@ -68,8 +75,8 @@ Give it a try! Start a chat with your bot and issue the `/start` command - if al
But our Bot can now only answer to the `/start` command. Let's add another handler that listens for regular messages. Use the `MessageHandler`, another `Handler` subclass, to echo to all text messages:
```python
def echo(bot, update):
bot.send_message(chat_id=update.message.chat_id, text=update.message.text)
def echo(update, context):
context.bot.send_message(chat_id=update.message.chat_id, text=update.message.text)
from telegram.ext import MessageHandler, Filters
echo_handler = MessageHandler(Filters.text, echo)
@ -86,15 +93,15 @@ From now on, your bot should echo all non-command messages it receives.
Let's add some actual functionality to your bot. We want to implement a `/caps` command that will take some text as an argument and reply to it in CAPS. To make things easy, you can receive the arguments (as a `list`, split on spaces) that were passed to a command in the callback function:
```python
def caps(bot, update, args):
text_caps = ' '.join(args).upper()
bot.send_message(chat_id=update.message.chat_id, text=text_caps)
def caps(update, context):
text_caps = ' '.join(context.args).upper()
context.bot.send_message(chat_id=update.message.chat_id, text=text_caps)
caps_handler = CommandHandler('caps', caps, pass_args=True)
caps_handler = CommandHandler('caps', caps)
dispatcher.add_handler(caps_handler)
```
**Note:** Take a look at the `pass_args=True` in the `CommandHandler` initiation. This is required to let the handler know that you want it to pass the list of command arguments to the callback. All handler classes have keyword arguments like this. Some are the same among all handlers, some are specific to the handler class. If you use a new type of handler for the first time, look it up in the docs and see if one of them is useful to you.
**Note:** Take a look at the usage of `context.args`. The [CallbackContext)](https://python-telegram-bot.readthedocs.io/en/latest/telegram.ext.callbackcontext.html) will have many different attributes, depending on which handler is used.
Another cool feature of the Telegram Bot API is the [inline mode](https://core.telegram.org/bots/inline). If you want to implement inline functionality for your bot, please first talk to [@BotFather](https://telegram.me/botfather) and enable inline mode using `/setinline`. It sometimes takes a while until your Bot registers as an inline bot on your client. You might be able to speed up the process by restarting your Telegram App (or sometimes, you just have to wait for a while).
@ -102,7 +109,7 @@ As your bot is obviously a very loud one, let's continue with this theme for inl
```python
from telegram import InlineQueryResultArticle, InputTextMessageContent
def inline_caps(bot, update):
def inline_caps(update, context):
query = update.inline_query.query
if not query:
return
@ -114,7 +121,7 @@ def inline_caps(bot, update):
input_message_content=InputTextMessageContent(query.upper())
)
)
bot.answer_inline_query(update.inline_query.id, results)
context.bot.answer_inline_query(update.inline_query.id, results)
from telegram.ext import InlineQueryHandler
inline_caps_handler = InlineQueryHandler(inline_caps)
@ -127,8 +134,8 @@ Not bad! Your Bot can now yell on command (ha!) and via inline mode.
Some confused users might try to send commands to the bot that it doesn't understand, so you can use a `MessageHandler` with a `command` filter to reply to all commands that were not recognized by the previous handlers.
```python
def unknown(bot, update):
bot.send_message(chat_id=update.message.chat_id, text="Sorry, I didn't understand that command.")
def unknown(update, context):
context.bot.send_message(chat_id=update.message.chat_id, text="Sorry, I didn't understand that command.")
unknown_handler = MessageHandler(Filters.command, unknown)
dispatcher.add_handler(unknown_handler)

@ -17,7 +17,7 @@ If you want to create your own persistence class, please carefully read the docs
To make your bot persistent you need to know the following.
- Create a persistence object (e.g. `my_persistence = PicklePersistence(filename='my_file')`)
- Construct Updater with the persistence (`Updater('TOKEN', persistence=my_persistence)`)
- Construct Updater with the persistence (`Updater('TOKEN', persistence=my_persistence, use_context=True)`)
This is enough to make `user_data` and `chat_data` persistent.
To make a conversationhandler persistent (save states between bot restarts)

@ -1,3 +1,8 @@
## Version 12 beta note
This wiki page has been updated to work with the beta version 12 of the python-telegram-bot library.
This version has proven to be generally generally stable enough for most usecases. See [the v12 transistion guide](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Transition-guide-to-Version-12.0) for more info.
If you're still using version 11.1.0, please see the [old version of this wiki page](https://github.com/python-telegram-bot/python-telegram-bot/wiki/Performance-Optimizations/e804e4c8e8a4df1f67beacb17ea890bde57b34e8).
## Introduction
When your bot becomes popular, you will eventually want to improve response times. After all, Telegram places high priority on fast messaging. At the same time, responses become slower as more people are using your bot. This happens more quickly for inline bots, as they may receive multiple inline queries during one interaction.
@ -37,8 +42,8 @@ Then, use it as a decorator for the `echo` function:
```python
@run_async
def echo(bot, update):
bot.send_message(update.message.chat_id, text=update.message.text)
def echo(update, context):
context.bot.send_message(update.message.chat_id, text=update.message.text)
```
Simple and straightforward, right? So, why did I bore you with all that stuff before?
@ -120,7 +125,8 @@ I went through our bank example line by line and noted which of the criteria it
```python
@run_async
def transaction(bot, update):
def transaction(update, context):
bot = context.bot
chat_id = update.message.chat_id # 3
source_id, target_id, amount = parse_update(update) # 3
@ -153,7 +159,7 @@ def log_and_notify(action, amount, source_id, target_id, chat_id, message):
bank.log(action, amount, source_id, target_id)
bot.send_message(chat_id, message)
def transaction(bot, update):
def transaction(update, context):
chat_id = update.message.chat_id # 3
source_id, target_id, amount = parse_update(update) # 3