Rewrite the first part of the docs for asyncio

This commit is contained in:
Lonami Exo 2018-06-21 21:54:54 +02:00
parent 5e322a6ca9
commit f733f8e565
11 changed files with 389 additions and 302 deletions

View File

@ -4,8 +4,11 @@ Telethon
⭐️ Thanks **everyone** who has starred the project, it means a lot!
**Telethon** is Telegram client implementation in **Python 3** which uses
the latest available API of Telegram.
**Telethon** is an `asyncio <https://docs.python.org/3/library/asyncio.html>`_
**Python 3** library to interact with Telegram's API.
If you don't like ``asyncio``, you can still use `a simpler version
<https://github.com/LonamiWebs/Telethon/tree/sync>`_ that uses threads instead.
What is this?
@ -22,7 +25,7 @@ Installing
.. code:: sh
pip3 install telethon
pip3 install telethon-aio
Creating a client
@ -30,6 +33,9 @@ Creating a client
.. code:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient
# These example values won't work. You must get your own api_id and
@ -38,7 +44,7 @@ Creating a client
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash)
client.start()
loop.run_until_complete(client.start())
Doing stuff
@ -46,20 +52,23 @@ Doing stuff
.. code:: python
print(client.get_me().stringify())
async def main():
me = await client.get_me()
print(me.stringify())
client.send_message('username', 'Hello! Talking to you from Telethon')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
await client.send_message('username', 'Hello! Talking to you from Telethon')
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.download_profile_photo('me')
messages = client.get_messages('username')
client.download_media(messages[0])
await client.download_profile_photo('me')
messages = await client.get_messages('username')
await messages[0].download_media()
loop.run_until_complete(main())
Next steps
----------
Do you like how Telethon looks? Check out
`Read The Docs <http://telethon.rtfd.io/>`_
for a more in-depth explanation, with examples,
troubleshooting issues, and more useful information.
Do you like how Telethon looks? Check out `Read The Docs
<http://telethon.rtfd.io/>`_ for a more in-depth explanation,
with examples, troubleshooting issues, and more useful information.

View File

@ -69,7 +69,9 @@ Or we call `client.get_input_entity
.. code-block:: python
peer = client.get_input_entity('someone')
import asyncio
loop = asyncio.get_event_loop()
peer = loop.run_until_complete(client.get_input_entity('someone'))
When you're going to invoke an API method, most require you to pass an
:tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
@ -81,7 +83,7 @@ instead:
.. code-block:: python
entity = client.get_entity('someone')
entity = loop.run_until_complete(client.get_entity('someone'))
In the later case, when you use the entity, the library will cast it to
its "input" version for you. If you already have the complete user and
@ -110,7 +112,9 @@ request we do:
.. code-block:: python
result = client(SendMessageRequest(peer, 'Hello there!'))
result = loop.run_until_complete(
client(SendMessageRequest(peer, 'Hello there!'))
)
# __call__ is an alias for client.invoke(request). Both will work
Message sent! Of course, this is only an example. There are nearly 250
@ -119,19 +123,21 @@ as you wish. Remember to use the right types! To sum up:
.. code-block:: python
result = client(SendMessageRequest(
result = loop.run_until_complete(client(SendMessageRequest(
client.get_input_entity('username'), 'Hello there!'
))
)))
This can further be simplified to:
.. code-block:: python
result = client(SendMessageRequest('username', 'Hello there!'))
async def main():
result = await client(SendMessageRequest('username', 'Hello there!'))
# Or even
result = client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
result = await client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
loop.run_until_complete(main())
.. note::

View File

@ -4,141 +4,46 @@
Update Modes
============
With ``asyncio``, the library has several tasks running in the background.
One task is used for sending requests, another task is used to receive them,
and a third one is used to handle updates.
The library can run in four distinguishable modes:
- With no extra threads at all.
- With an extra thread that receives everything as soon as possible (default).
- With several worker threads that run your update handlers.
- A mix of the above.
Since this section is about updates, we'll describe the simplest way to
work with them.
Using multiple workers
**********************
When you create your client, simply pass a number to the
``update_workers`` parameter:
``client = TelegramClient('session', api_id, api_hash, update_workers=2)``
You can set any amount of workers you want. The more you put, the more
update handlers that can be called "at the same time". One or two should
suffice most of the time, since setting more will not make things run
faster most of the times (actually, it could slow things down).
The next thing you want to do is to add a method that will be called when
an `Update`__ arrives:
To handle updates, you must keep your script running. You can do this in
several ways. For instance, if you are *not* running ``asyncio``'s event
loop, you should use `client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>`:
.. code-block:: python
def callback(update):
print('I received', update)
import asyncio
from telethon import TelegramClient
client.add_event_handler(callback)
# do more work here, or simply sleep!
That's it! This is the old way to listen for raw updates, with no further
processing. If this feels annoying for you, remember that you can always
use :ref:`working-with-updates` but maybe use this for some other cases.
Now let's do something more interesting. Every time an user talks to us,
let's reply to them with the same text reversed:
.. code-block:: python
from telethon.tl.types import UpdateShortMessage, PeerUser
def replier(update):
if isinstance(update, UpdateShortMessage) and not update.out:
client.send_message(PeerUser(update.user_id), update.message[::-1])
client.add_event_handler(replier)
input('Press enter to stop this!')
client.disconnect()
We only ask you one thing: don't keep this running for too long, or your
contacts will go mad.
Spawning no worker at all
*************************
All the workers do is loop forever and poll updates from a queue that is
filled from the ``ReadThread``, responsible for reading every item off
the network. If you only need a worker and the ``MainThread`` would be
doing no other job, this is the preferred way. You can easily do the same
as the workers like so:
.. code-block:: python
while True:
try:
update = client.updates.poll()
if not update:
continue
print('I received', update)
except KeyboardInterrupt:
break
client.disconnect()
Note that ``poll`` accepts a ``timeout=`` parameter, and it will return
``None`` if other thread got the update before you could or if the timeout
expired, so it's important to check ``if not update``.
This can coexist with the rest of ``N`` workers, or you can set it to ``0``
additional workers:
``client = TelegramClient('session', api_id, api_hash, update_workers=0)``
You **must** set it to ``0`` (or higher), as it defaults to ``None`` and that
has a different meaning. ``None`` workers means updates won't be processed
*at all*, so you must set it to some integer value if you want
``client.updates.poll()`` to work.
Using the main thread instead the ``ReadThread``
************************************************
If you have no work to do on the ``MainThread`` and you were planning to have
a ``while True: sleep(1)``, don't do that. Instead, don't spawn the secondary
``ReadThread`` at all like so:
.. code-block:: python
client = TelegramClient(
client = TelegramClient(...)
...
spawn_read_thread=False
)
client.run_until_disconnected()
And then ``.idle()`` from the ``MainThread``:
``client.idle()``
Behind the scenes, this method is ``await``'ing on the `client.disconnected
<telethon.client.telegrambaseclient.disconnected>` property, so the code above
and the following are equivalent:
You can stop it with :kbd:`Control+C`, and you can configure the signals
to be used in a similar fashion to `Python Telegram Bot`__.
As a complete example:
.. code-block:: python
def callback(update):
print('I received', update)
import asyncio
from telethon import TelegramClient
client = TelegramClient('session', api_id, api_hash,
update_workers=1, spawn_read_thread=False)
client = TelegramClient(...)
client.connect()
client.add_event_handler(callback)
client.idle() # ends with Ctrl+C
async def main():
await client.disconnected
asyncio.get_event_loop().run_until_complete(main())
This is the preferred way to use if you're simply going to listen for updates.
You could also run `client.disconnected
<telethon.client.telegrambaseclient.disconnected>` until it completed.
__ https://lonamiwebs.github.io/Telethon/types/update.html
__ https://github.com/python-telegram-bot/python-telegram-bot/blob/4b3315db6feebafb94edcaa803df52bb49999ced/telegram/ext/updater.py#L460
But if you don't want to ``await``, then you should know what you want
to be doing instead! What matters is that you shouldn't let your script
die. If you don't care about updates, you don't need any of this.

View File

@ -0,0 +1,123 @@
.. _asyncio-crash-course:
===========================
A Crash Course into asyncio
===========================
Why asyncio?
************
Python's `asyncio <https://docs.python.org/3/library/asyncio.html>`_ is the
standard way to run asynchronous code from within Python. Since Python 3.5,
using ``async def`` and ``await`` became possible, and Python 3.6 further
improves what you can do with asynchronous code, although it's not the only
way (other projects like `Trio <https://github.com/python-trio>`_ also exist).
Telegram is a service where all API calls are executed in an asynchronous
way. You send your request, and eventually, Telegram will process it and
respond to it. It feels natural to make a library that also behaves this
way: you send a request, and you can ``await`` for its result.
Having understood that Telegram's API follows an asynchronous model and
developing a library that does the same greatly simplifies the internal
code and eases working with the API.
Using ``asyncio`` keeps a cleaner library that will be easier to understand,
develop, and that will be faster than using threads, which are harder to get
right and can cause issues. It also enables to use the powerful ``asyncio``
system such as futures, timeouts, cancellation, etc. in a natural way.
If you're still not convinced or you're just not ready for using ``asyncio``,
the library offers a synchronous interface without the need for all the
``async`` and ``await`` you would otherwise see. `Follow this link
<https://github.com/LonamiWebs/Telethon/tree/sync>`_ to find out more.
How do I get started?
*********************
To get started with ``asyncio``, all you need is to setup your main
``async def`` like so:
.. code-block:: python
import asyncio
async def main():
pass # Your code goes here
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Inside ``async def main():``, you can use the ``await`` keyword. Most
methods in the :ref:`TelegramClient <telethon-client>` are ``async def``.
You must ``await`` all ``async def``, also known as a coroutine:
.. code-block:: python
async def main():
client = TelegramClient(...)
# client.start() is a coroutine (async def), it needs an await
await client.start()
# Sending a message also interacts with the API, and needs an await
await client.send_message('me', 'Hello myself!')
If you don't know anything else about ``asyncio``, this will be enough
to get you started. Once you're ready to learn more about it, you will
be able to use that power and everything you've learnt with Telethon.
Just remember that if you use ``await``, you need to be inside of an
``async def``.
Another way to use ``async def`` is to use ``loop.run_until_complete(f())``,
but the loop must not be running before.
If you want to handle updates (and don't let the script die), you must
`await client.disconnected <telethon.client.telegrambaseclient.disconnected>`
which is a property that you can wait on until you call
`await client.disconnect() <telethon.client.telegrambaseclient.disconnect>`:
.. code-block:: python
client = TelegramClient(...)
@client.on(events.NewMessage)
async def handler(event):
print(event)
async def main():
await client.start()
await client.disconnected
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
This is the same as using the ``run_until_disconnected()`` method:
.. code-block:: python
client = TelegramClient(...)
@client.on(events.NewMessage)
async def handler(event):
print(event)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(client.start())
client.run_until_disconnected()
More resources to learn asyncio
*******************************
If you would like to learn a bit more about why ``asyncio`` is something
you should learn, `check out my blog post
<https://lonamiwebs.github.io/blog/asyncio/>`_ that goes into more detail.

View File

@ -26,6 +26,14 @@ one is very simple:
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
# Rename loop.run_until_complete(...) as rc(...), we will use it a lot.
# This basically lets us run the event loop (necessary in asyncio) to
# execute all the requests we need.
rc = loop.run_until_complete
from telethon import TelegramClient
# Use your own values here
@ -54,7 +62,7 @@ your disk. This is by default a database file using Python's ``sqlite3``.
.. code-block:: python
client.start()
rc(client.start())
This is explained after going through the manual process.
@ -64,14 +72,14 @@ Doing so is very easy:
.. code-block:: python
client.connect() # Must return True, otherwise, try again
rc(client.connect()) # Must return True, otherwise, try again
You may or may not be authorized yet. You must be authorized
before you're able to send any request:
.. code-block:: python
client.is_user_authorized() # Returns True if you can send requests
rc(client.is_user_authorized()) # Returns True if you can send requests
If you're not authorized, you need to `.sign_in
<telethon.client.auth.AuthMethods.sign_in>`:
@ -79,8 +87,8 @@ If you're not authorized, you need to `.sign_in
.. code-block:: python
phone_number = '+34600000000'
client.send_code_request(phone_number)
myself = client.sign_in(phone_number, input('Enter code: '))
rc(client.send_code_request(phone_number))
myself = rc(client.sign_in(phone_number, input('Enter code: ')))
# If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
# You can import both exceptions from telethon.errors.
@ -103,10 +111,14 @@ As a full example:
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
assert client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number)
me = client.sign_in(phone_number, input('Enter code: '))
async def main():
assert await client.connect()
if not await client.is_user_authorized():
await client.send_code_request(phone_number)
me = await client.sign_in(phone_number, input('Enter code: '))
loop.run_until_complete(main())
All of this, however, can be done through a call to `.start()
@ -115,7 +127,7 @@ All of this, however, can be done through a call to `.start()
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
client.start()
loop.run_until_complete(client.start())
The code shown is just what `.start()
@ -169,11 +181,12 @@ again with a ``password=``:
import getpass
from telethon.errors import SessionPasswordNeededError
client.sign_in(phone)
async def main():
await client.sign_in(phone)
try:
client.sign_in(code=input('Enter code: '))
await client.sign_in(code=input('Enter code: '))
except SessionPasswordNeededError:
client.sign_in(password=getpass.getpass())
await client.sign_in(password=getpass.getpass())
The mentioned `.start()
@ -196,19 +209,20 @@ See the examples below:
from telethon.errors import EmailUnconfirmedError
async def main():
# Sets 2FA password for first time:
client.edit_2fa(new_password='supersecurepassword')
await client.edit_2fa(new_password='supersecurepassword')
# Changes password:
client.edit_2fa(current_password='supersecurepassword',
await client.edit_2fa(current_password='supersecurepassword',
new_password='changedmymind')
# Clears current password (i.e. removes 2FA):
client.edit_2fa(current_password='changedmymind', new_password=None)
await client.edit_2fa(current_password='changedmymind', new_password=None)
# Sets new password with recovery email:
try:
client.edit_2fa(new_password='memes and dreams',
await client.edit_2fa(new_password='memes and dreams',
email='JohnSmith@example.com')
# Raises error (you need to check your email to complete 2FA setup.)
except EmailUnconfirmedError:
@ -219,7 +233,7 @@ See the examples below:
# give email parameter again it will keep the last used setting
# Set hint after already setting password:
client.edit_2fa(current_password='memes and dreams',
await client.edit_2fa(current_password='memes and dreams',
new_password='memes and dreams',
hint='It keeps you alive')

View File

@ -42,31 +42,32 @@ you're able to just do this:
.. code-block:: python
async def main():
# Dialogs are the "conversations you have open".
# This method returns a list of Dialog, which
# has the .entity attribute and other information.
dialogs = client.get_dialogs()
dialogs = await client.get_dialogs()
# All of these work and do the same.
lonami = client.get_entity('lonami')
lonami = client.get_entity('t.me/lonami')
lonami = client.get_entity('https://telegram.dog/lonami')
lonami = await client.get_entity('lonami')
lonami = await client.get_entity('t.me/lonami')
lonami = await client.get_entity('https://telegram.dog/lonami')
# Other kind of entities.
channel = client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
contact = client.get_entity('+34xxxxxxxxx')
friend = client.get_entity(friend_id)
channel = await client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
contact = await client.get_entity('+34xxxxxxxxx')
friend = await client.get_entity(friend_id)
# Getting entities through their ID (User, Chat or Channel)
entity = client.get_entity(some_id)
entity = await client.get_entity(some_id)
# You can be more explicit about the type for said ID by wrapping
# it inside a Peer instance. This is recommended but not necessary.
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
my_user = client.get_entity(PeerUser(some_id))
my_chat = client.get_entity(PeerChat(some_id))
my_channel = client.get_entity(PeerChannel(some_id))
my_user = await client.get_entity(PeerUser(some_id))
my_chat = await client.get_entity(PeerChat(some_id))
my_channel = await client.get_entity(PeerChannel(some_id))
All methods in the :ref:`telegram-client` call `.get_input_entity()
@ -136,7 +137,8 @@ wherever needed, so you can even do things like:
.. code-block:: python
client(SendMessageRequest('username', 'hello'))
async def main():
await client(SendMessageRequest('username', 'hello'))
The library will call the ``.resolve()`` method of the request, which will
resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if

View File

@ -21,6 +21,9 @@ Creating a client
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient
# These example values won't work. You must get your own api_id and
@ -29,7 +32,7 @@ Creating a client
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash)
client.start()
loop.run_until_complete(client.start())
**More details**: :ref:`creating-a-client`
@ -39,31 +42,36 @@ Basic Usage
.. code-block:: python
async def main():
# Getting information about yourself
print(client.get_me().stringify())
me = await client.get_me()
print(me.stringify())
# Sending a message (you can use 'me' or 'self' to message yourself)
client.send_message('username', 'Hello World from Telethon!')
await client.send_message('username', 'Hello World from Telethon!')
# Sending a file
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# Retrieving messages from a chat
from telethon import utils
for message in client.iter_messages('username', limit=10):
async for message in client.iter_messages('username', limit=10):
print(utils.get_display_name(message.sender), message.message)
# Listing all the dialogs (conversations you have open)
for dialog in client.get_dialogs(limit=10):
print(utils.get_display_name(dialog.entity), dialog.draft.text)
async for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Downloading profile photos (default path is the working directory)
client.download_profile_photo('username')
await client.download_profile_photo('username')
# Once you have a message with .media (if message.media)
# you can download it using client.download_media():
messages = client.get_messages('username')
client.download_media(messages[0])
# you can download it using client.download_media(),
# or even using message.download_media():
messages = await client.get_messages('username')
await messages[0].download_media()
loop.run_until_complete(main())
**More details**: :ref:`telegram-client`
@ -77,15 +85,11 @@ Handling Updates
from telethon import events
# We need to have some worker running
client.updates.workers = 1
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
def handler(event):
event.reply('Hello!')
async def handler(event):
await event.reply('Hello!')
# If you want to handle updates you can't let the script end.
input('Press enter to exit.')
client.run_until_disconnected()
**More details**: :ref:`working-with-updates`

View File

@ -34,7 +34,14 @@ For instance, retrieving your own user can be done in a single line:
.. code-block:: python
myself = client.get_me()
import asyncio
async def main():
myself = await client.get_me()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Internally, this method has sent a request to Telegram, who replied with
the information about your own user, and then the desired information
@ -46,10 +53,11 @@ how the library refers to either of these:
.. code-block:: python
async def main():
# The method will infer that you've passed an username
# It also accepts phone numbers, and will get the user
# from your contact list.
lonami = client.get_entity('lonami')
lonami = await client.get_entity('lonami')
The so called "entities" are another important whole concept on its own,
but for now you don't need to worry about it. Simply know that they are
@ -59,30 +67,31 @@ Many other common methods for quick scripts are also available:
.. code-block:: python
async def main():
# Note that you can use 'me' or 'self' to message yourself
client.send_message('username', 'Hello World from Telethon!')
await client.send_message('username', 'Hello World from Telethon!')
# .send_message's parse mode defaults to markdown, so you
# can use **bold**, __italics__, [links](https://example.com), `code`,
# and even [mentions](@username)/[mentions](tg://user?id=123456789)
client.send_message('username', '**Using** __markdown__ `too`!')
await client.send_message('username', '**Using** __markdown__ `too`!')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# The utils package has some goodies, like .get_display_name()
from telethon import utils
for message in client.iter_messages('username', limit=10):
async for message in client.iter_messages('username', limit=10):
print(utils.get_display_name(message.sender), message.message)
# Dialogs are the conversations you have open
for dialog in client.get_dialogs(limit=10):
print(utils.get_display_name(dialog.entity), dialog.draft.text)
async for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Default path is the working directory
client.download_profile_photo('username')
await client.download_profile_photo('username')
# Call .disconnect() when you're done
client.disconnect()
await client.disconnect()
Remember that you can call ``.stringify()`` to any object Telegram returns
to pretty print it. Calling ``str(result)`` does the same operation, but on

View File

@ -36,30 +36,31 @@ Getting Started
.. code-block:: python
import asyncio
from telethon import TelegramClient, events
client = TelegramClient(..., update_workers=1, spawn_read_thread=False)
client.start()
client = TelegramClient('name', api_id, api_hash)
@client.on(events.NewMessage)
def my_event_handler(event):
async def my_event_handler(event):
if 'hello' in event.raw_text:
event.reply('hi!')
await event.reply('hi!')
client.idle()
asyncio.get_event_loop().run_until_complete(client.start())
client.run_until_disconnected()
Not much, but there might be some things unclear. What does this code do?
.. code-block:: python
import asyncio
from telethon import TelegramClient, events
client = TelegramClient(..., update_workers=1, spawn_read_thread=False)
client.start()
client = TelegramClient('name', api_id, api_hash)
This is normal initialization (of course, pass session name, API ID and hash).
This is normal creation (of course, pass session name, API ID and hash).
Nothing we don't know already.
.. code-block:: python
@ -74,9 +75,9 @@ the callback function you're about to define will be called:
.. code-block:: python
def my_event_handler(event):
async def my_event_handler(event):
if 'hello' in event.raw_text:
event.reply('hi!')
await event.reply('hi!')
If a `NewMessage
@ -86,12 +87,14 @@ with a ``'hi!'`` message.
.. code-block:: python
client.idle()
asyncio.get_event_loop().run_until_complete(client.start())
client.run_until_disconnected()
Finally, this tells the client that we're done with our code, and want
to listen for all these events to occur. Of course, you might want to
do other things instead idling. For this refer to :ref:`update-modes`.
Finally, this tells the client that we're done with our code. We run the
``asyncio`` loop until the client starts, and then we run it again until
we are disconnected. Of course, you can do other things instead of running
until disconnected. For this refer to :ref:`update-modes`.
More on events
@ -130,17 +133,17 @@ for example:
# Either a single item or a list of them will work for the chats.
# You can also use the IDs, Peers, or even User/Chat/Channel objects.
@client.on(events.NewMessage(chats=('TelethonChat', 'TelethonOffTopic')))
def normal_handler(event):
async def normal_handler(event):
if 'roll' in event.raw_text:
event.reply(str(random.randint(1, 6)))
await event.reply(str(random.randint(1, 6)))
# Similarly, you can use incoming=True for messages that you receive
@client.on(events.NewMessage(chats='TelethonOffTopic', outgoing=True))
def admin_handler(event):
if event.raw_text.startswith('eval'):
expression = event.raw_text.replace('eval', '').strip()
event.reply(str(ast.literal_eval(expression)))
@client.on(events.NewMessage(chats='TelethonOffTopic', outgoing=True,
pattern='eval (.+)'))
async def admin_handler(event):
expression = event.pattern_match.group(1)
await event.reply(str(ast.literal_eval(expression)))
You can pass one or more chats to the ``chats`` parameter (as a list or tuple),
@ -183,15 +186,15 @@ will cause the propagation of the update through your handlers to stop:
from telethon.events import StopPropagation
@client.on(events.NewMessage)
def _(event):
async def _(event):
# ... some conditions
event.delete()
await event.delete()
# Other handlers won't have an event to work with
raise StopPropagation
@client.on(events.NewMessage)
def _(event):
async def _(event):
# Will never be reached, because it is the second handler
# in the chain.
pass

View File

@ -22,6 +22,17 @@ when you upgrade!
contains the friendly methods that **you should use** most of the time.
.. note::
The library uses `asyncio <https://docs.python.org/3/library/asyncio.html>`_
by default, but you if you don't know how to use ``asyncio`` you can use
`a simpler version <https://github.com/LonamiWebs/Telethon/tree/sync>`_
(select the "sync" version in ``readthedocs``' bottom left corner).
However, **you are encouraged to use asyncio**, it will make your scripts
faster and more powerful. :ref:`asyncio-crash-course` will teach you why
``asyncio`` is good and how to use it.
What is this?
*************
@ -39,6 +50,7 @@ heavy job for you, so you can focus on developing an application.
extra/basic/getting-started
extra/basic/installation
extra/basic/asyncio-crash-course
extra/basic/creating-a-client
extra/basic/telegram-client
extra/basic/entities

View File

@ -174,8 +174,8 @@ class NewMessage(EventBuilder):
>>> from telethon import TelegramClient, events
>>> client = TelegramClient(...)
>>>
>>> @client.on(events.NewMessage(pattern=r'hi (\w+)!'))
... def handler(event):
>>> @client.on(events.NewMessage(pattern=r'hi (\\w+)!'))
... async def handler(event):
... # In this case, the result is a ``Match`` object
... # since the ``str`` pattern was converted into
... # the ``re.compile(pattern).match`` function.