mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-09 05:19:41 +00:00
Finish up asyncio docs
This commit is contained in:
@@ -19,9 +19,9 @@ 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.
|
||||
Now that we know that Telegram's API follows an asynchronous model, you
|
||||
should understand the benefits of developing a library that does the same,
|
||||
it 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
|
||||
@@ -54,7 +54,7 @@ To get started with ``asyncio``, all you need is to setup your 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:
|
||||
You must ``await`` all ``async def``, also known as a *coroutines*:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -78,9 +78,9 @@ 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>`
|
||||
`await client.disconnected <telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
|
||||
which is a property that you can wait on until you call
|
||||
`await client.disconnect() <telethon.client.telegrambaseclient.disconnect>`:
|
||||
`await client.disconnect() <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -115,6 +115,68 @@ This is the same as using the ``run_until_disconnected()`` method:
|
||||
client.run_until_disconnected()
|
||||
|
||||
|
||||
Which methods should I use and when?
|
||||
************************************
|
||||
|
||||
Something to note is that you must always get an event loop if you
|
||||
want to be able to make any API calls. This is done as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
The loop must be running, or things will never get sent.
|
||||
Normally, you use ``run_until_complete``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def coroutine():
|
||||
await asyncio.sleep(1)
|
||||
|
||||
loop.run_until_complete(coroutine())
|
||||
|
||||
Note that ``asyncio.sleep`` is in itself a coroutine, so this will
|
||||
work too:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
loop.run_until_complete(asyncio.sleep(1))
|
||||
|
||||
Generally, you make an ``async def main()`` if you need to ``await``
|
||||
a lot of things, instead of typing ``run_until_complete`` all the time:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def main():
|
||||
message = await client.send_message('me', 'Hi')
|
||||
await asyncio.sleep(1)
|
||||
await message.delete()
|
||||
|
||||
loop.run_until_complete(main())
|
||||
|
||||
# vs
|
||||
|
||||
message = loop.run_until_complete(client.send_message('me', 'Hi'))
|
||||
loop.run_until_complete(asyncio.sleep(1))
|
||||
loop.run_until_complete(message.delete())
|
||||
|
||||
You can see that the first version has more lines, but you had to type
|
||||
a lot less. You can also rename the run method to something shorter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Note no parenthesis (), we're not running it, just copying the method
|
||||
rc = loop.run_until_complete
|
||||
message = rc(client.send_message('me', 'Hi'))
|
||||
rc(asyncio.sleep(1))
|
||||
rc(message.delete())
|
||||
|
||||
The documentation will use all these three styles so you can get used
|
||||
to them. Which one to use is up to you, but generally you should work
|
||||
inside an ``async def main()`` and just run the loop there.
|
||||
|
||||
|
||||
More resources to learn asyncio
|
||||
*******************************
|
||||
|
||||
|
@@ -30,14 +30,16 @@ this is, any "method" listed on the API. There are a few methods (and
|
||||
growing!) on the :ref:`TelegramClient <telethon-client>` class that abstract
|
||||
you from the need of manually importing the requests you need.
|
||||
|
||||
For instance, retrieving your own user can be done in a single line:
|
||||
For instance, retrieving your own user can be done in a single line
|
||||
(if we ignore the boilerplate needed to setup ``asyncio``, which only
|
||||
needs to be done once for your entire program):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
|
||||
async def main():
|
||||
myself = await client.get_me()
|
||||
myself = await client.get_me() # <- a single line!
|
||||
|
||||
if __name__ == '__main__':
|
||||
loop = asyncio.get_event_loop()
|
||||
|
@@ -82,7 +82,8 @@ the callback function you're about to define will be called:
|
||||
|
||||
If a `NewMessage
|
||||
<telethon.events.newmessage.NewMessage>` event occurs,
|
||||
and ``'hello'`` is in the text of the message, we ``reply`` to the event
|
||||
and ``'hello'`` is in the text of the message, we `.reply()
|
||||
<telethon.tl.custom.message.Message.reply>` to the event
|
||||
with a ``'hi!'`` message.
|
||||
|
||||
.. code-block:: python
|
||||
@@ -101,23 +102,35 @@ More on events
|
||||
**************
|
||||
|
||||
The `NewMessage <telethon.events.newmessage.NewMessage>` event has much
|
||||
more than what was shown. You can access the ``.sender`` of the message
|
||||
through that member, or even see if the message had ``.media``, a ``.photo``
|
||||
or a ``.document`` (which you could download with for example
|
||||
`client.download_media(event.photo) <telethon.client.downloads.DownloadMethods.download_media>`.
|
||||
more than what was shown. You can access the `.sender
|
||||
<telethon.tl.custom.message.Message.sender>` of the message
|
||||
through that member, or even see if the message had `.media
|
||||
<telethon.tl.custom.message.Message.media>`, a `.photo
|
||||
<telethon.tl.custom.message.Message.photo>` or a `.document
|
||||
<telethon.tl.custom.message.Message.document>` (which you
|
||||
could download with for example `client.download_media(event.photo)
|
||||
<telethon.client.downloads.DownloadMethods.download_media>`.
|
||||
|
||||
If you don't want to ``.reply`` as a reply, you can use the ``.respond()``
|
||||
method instead. Of course, there are more events such as ``ChatAction`` or
|
||||
``UserUpdate``, and they're all used in the same way. Simply add the
|
||||
``@client.on(events.XYZ)`` decorator on the top of your handler and you're
|
||||
done! The event that will be passed always is of type ``XYZ.Event`` (for
|
||||
instance, ``NewMessage.Event``), except for the ``Raw`` event which just
|
||||
passes the ``Update`` object.
|
||||
If you don't want to `.reply()
|
||||
<telethon.tl.custom.message.Message.reply>` as a reply,
|
||||
you can use the `.respond() <telethon.tl.custom.message.Message.respond>`
|
||||
method instead. Of course, there are more events such as `ChatAction
|
||||
<telethon.events.chataction.ChatAction>` or `UserUpdate
|
||||
<telethon.events.userupdate.UserUpdate>`, and they're all
|
||||
used in the same way. Simply add the `@client.on(events.XYZ)
|
||||
<telethon.client.updates.UpdateMethods.on>` decorator on the top
|
||||
of your handler and you're done! The event that will be passed always
|
||||
is of type ``XYZ.Event`` (for instance, `NewMessage.Event
|
||||
<telethon.events.newmessage.NewMessage.Event>`), except for the `Raw
|
||||
<telethon.events.raw.Raw>` event which just passes the :tl:`Update` object.
|
||||
|
||||
Note that ``.reply()`` and ``.respond()`` are just wrappers around the
|
||||
Note that `.reply()
|
||||
<telethon.tl.custom.message.Message.reply>` and `.respond()
|
||||
<telethon.tl.custom.message.Message.respond>` are just wrappers around the
|
||||
`client.send_message() <telethon.client.messages.MessageMethods.send_message>`
|
||||
method which supports the ``file=`` parameter.
|
||||
This means you can reply with a photo if you do ``event.reply(file=photo)``.
|
||||
This means you can reply with a photo if you do `event.reply(file=photo)
|
||||
<telethon.tl.custom.message.Message.reply>`.
|
||||
|
||||
You can put the same event on many handlers, and even different events on
|
||||
the same handler. You can also have a handler work on only specific chats,
|
||||
@@ -154,6 +167,45 @@ random number, while if you say ``'eval 4+4'``, you will reply with the
|
||||
solution. Try it!
|
||||
|
||||
|
||||
Properties vs. methods
|
||||
**********************
|
||||
|
||||
The event shown above acts just like a `custom.Message
|
||||
<telethon.tl.custom.message.Message>`, which means you
|
||||
can access all the properties it has, like ``.sender``.
|
||||
|
||||
**However** events are different to other methods in the client, like
|
||||
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
|
||||
Events *may not* send information about the sender or chat, which means it
|
||||
can be ``None``, but all the methods defined in the client always have this
|
||||
information so it doesn't need to be re-fetched. For this reason, you have
|
||||
``get_`` methods, which will make a network call if necessary.
|
||||
|
||||
In short, you should do this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@client.on(events.NewMessage)
|
||||
async def handler(event):
|
||||
# event.input_chat may be None, use event.get_input_chat()
|
||||
chat = await event.get_input_chat()
|
||||
sender = await event.get_sender()
|
||||
buttons = await event.get_buttons()
|
||||
|
||||
async def main():
|
||||
async for message in client.iter_messages('me', 10):
|
||||
# Methods from the client always have these properties ready
|
||||
chat = message.input_chat
|
||||
sender = message.sender
|
||||
buttons = message.buttons
|
||||
|
||||
Notice, properties (`message.sender
|
||||
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
|
||||
methods (`message.get_sender
|
||||
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
|
||||
and you should use methods in events for these properties that may need network.
|
||||
|
||||
|
||||
Events without decorators
|
||||
*************************
|
||||
|
||||
|
Reference in New Issue
Block a user