Fix asyncio docs

This commit is contained in:
Lonami Exo 2018-05-30 18:36:37 +02:00
parent aba478789c
commit 85089353f2
8 changed files with 61 additions and 140 deletions

View File

@ -67,7 +67,7 @@ Or we call ``.get_input_entity()``:
.. code-block:: python .. code-block:: python
peer = client.get_input_entity('someone') peer = await client.get_input_entity('someone')
When you're going to invoke an API method, most require you to pass an 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 :tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
@ -78,7 +78,7 @@ If you also need to have information about the whole user, use
.. code-block:: python .. code-block:: python
entity = client.get_entity('someone') entity = await client.get_entity('someone')
In the later case, when you use the entity, the library will cast it to 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 its "input" version for you. If you already have the complete user and
@ -104,7 +104,7 @@ request we do:
.. code-block:: python .. code-block:: python
result = client(SendMessageRequest(peer, 'Hello there!')) result = await client(SendMessageRequest(peer, 'Hello there!'))
# __call__ is an alias for client.invoke(request). Both will work # __call__ is an alias for client.invoke(request). Both will work
Message sent! Of course, this is only an example. There are nearly 250 Message sent! Of course, this is only an example. There are nearly 250
@ -113,7 +113,8 @@ as you wish. Remember to use the right types! To sum up:
.. code-block:: python .. code-block:: python
result = client(SendMessageRequest( async def method():
result = await client(SendMessageRequest(
client.get_input_entity('username'), 'Hello there!' client.get_input_entity('username'), 'Hello there!'
)) ))
@ -122,9 +123,9 @@ This can further be simplified to:
.. code-block:: python .. code-block:: python
result = client(SendMessageRequest('username', 'Hello there!')) result = await client(SendMessageRequest('username', 'Hello there!'))
# Or even # Or even
result = client(SendMessageRequest(PeerChannel(id), 'Hello there!')) result = await client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
.. note:: .. note::

View File

@ -4,41 +4,23 @@
Update Modes Update Modes
============ ============
Using ``asyncio`` simplifies the way you can work with updates. The library
will always ensure the future of a loop that will poll updates for you, so
you can do other things in the mean time.
The library can run in four distinguishable modes: Once you have your client ready, the next thing you want to do is to add a
method that will be called when an `Update`__ arrives:
- 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:
.. code-block:: python .. code-block:: python
def callback(update): import asyncio
loop = asyncio.get_event_loop()
async def callback(update):
print('I received', update) print('I received', update)
client.add_event_handler(callback) loop.run_until_complete(client.add_event_handler(callback))
# do more work here, or simply sleep! loop.run_forever() # this blocks forever, don't let the script end!
That's it! This is the old way to listen for raw updates, with no further 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 processing. If this feels annoying for you, remember that you can always
@ -51,94 +33,18 @@ let's reply to them with the same text reversed:
from telethon.tl.types import UpdateShortMessage, PeerUser from telethon.tl.types import UpdateShortMessage, PeerUser
def replier(update): async def replier(update):
if isinstance(update, UpdateShortMessage) and not update.out: if isinstance(update, UpdateShortMessage) and not update.out:
client.send_message(PeerUser(update.user_id), update.message[::-1]) await client.send_message(PeerUser(update.user_id), update.message[::-1])
client.add_event_handler(replier) loop.run_until_complete(client.add_event_handler(replier))
input('Press enter to stop this!') loop.run_forever()
client.disconnect()
We only ask you one thing: don't keep this running for too long, or your We only ask you one thing: don't keep this running for too long, or your
contacts will go mad. 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(
...
spawn_read_thread=False
)
And then ``.idle()`` from the ``MainThread``:
``client.idle()``
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)
client = TelegramClient('session', api_id, api_hash,
update_workers=1, spawn_read_thread=False)
client.connect()
client.add_event_handler(callback)
client.idle() # ends with Ctrl+C
This is the preferred way to use if you're simply going to listen for updates. This is the preferred way to use if you're simply going to listen for updates.
__ https://lonamiwebs.github.io/Telethon/types/update.html __ https://lonamiwebs.github.io/Telethon/types/update.html
__ https://github.com/python-telegram-bot/python-telegram-bot/blob/4b3315db6feebafb94edcaa803df52bb49999ced/telegram/ext/updater.py#L460

View File

@ -84,6 +84,7 @@ As a full example:
.. code-block:: python .. code-block:: python
async def main():
client = TelegramClient('anon', api_id, api_hash) client = TelegramClient('anon', api_id, api_hash)
assert await client.connect() assert await client.connect()
if not client.is_user_authorized(): if not client.is_user_authorized():
@ -95,6 +96,7 @@ All of this, however, can be done through a call to ``.start()``:
.. code-block:: python .. code-block:: python
async def main():
client = TelegramClient('anon', api_id, api_hash) client = TelegramClient('anon', api_id, api_hash)
await client.start() await client.start()
@ -159,7 +161,7 @@ account, calling :meth:`telethon.TelegramClient.sign_in` will raise a
import getpass import getpass
from telethon.errors import SessionPasswordNeededError from telethon.errors import SessionPasswordNeededError
client.sign_in(phone) await client.sign_in(phone)
try: try:
await client.sign_in(code=input('Enter code: ')) await client.sign_in(code=input('Enter code: '))
except SessionPasswordNeededError: except SessionPasswordNeededError:

View File

@ -38,7 +38,7 @@ Getting entities
Through the use of the :ref:`sessions`, the library will automatically Through the use of the :ref:`sessions`, the library will automatically
remember the ID and hash pair, along with some extra information, so remember the ID and hash pair, along with some extra information, so
you're able to just do this: you're able to just do this (inside an ``async def``):
.. code-block:: python .. code-block:: python

View File

@ -19,15 +19,19 @@ Creating a client
.. code-block:: python .. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient from telethon import TelegramClient
# These example values won't work. You must get your own api_id and # These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development. # api_hash from https://my.telegram.org, under API Development.
api_id = 12345 api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef' api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash) client = TelegramClient('session_name', api_id, api_hash)
await client.start() loop.run_until_complete(client.start())
**More details**: :ref:`creating-a-client` **More details**: :ref:`creating-a-client`
@ -37,6 +41,8 @@ Basic Usage
.. code-block:: python .. code-block:: python
# You should write all this inside of an async def.
#
# Getting information about yourself # Getting information about yourself
print((await client.get_me()).stringify()) print((await client.get_me()).stringify())
@ -76,9 +82,6 @@ Handling Updates
import asyncio import asyncio
from telethon import events from telethon import events
# We need to have some worker running
client.updates.workers = 1
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi')) @client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
async def handler(event): async def handler(event):
await event.reply('Hello!') await event.reply('Hello!')

View File

@ -32,7 +32,7 @@ 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:
``myself = client.get_me()`` ``myself = await client.get_me()``
Internally, this method has sent a request to Telegram, who replied with Internally, this method has sent a request to Telegram, who replied with
the information about your own user, and then the desired information the information about your own user, and then the desired information
@ -53,7 +53,8 @@ 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 but for now you don't need to worry about it. Simply know that they are
a good way to get information about an user, chat or channel. a good way to get information about an user, chat or channel.
Many other common methods for quick scripts are also available: Many other common methods for quick scripts are also available.
Note that you should be writing this inside of an ``async def``:
.. code-block:: python .. code-block:: python

View File

@ -31,27 +31,32 @@ Getting Started
.. code-block:: python .. code-block:: python
import asyncio import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient, events from telethon import TelegramClient, events
client = TelegramClient(..., update_workers=1, spawn_read_thread=False) client = TelegramClient(...)
await client.start() loop.run_until_complete(client.start())
@client.on(events.NewMessage) @client.on(events.NewMessage)
async def my_event_handler(event): async def my_event_handler(event):
if 'hello' in event.raw_text: if 'hello' in event.raw_text:
await event.reply('hi!') await event.reply('hi!')
asyncio.get_event_loop().run_forever() loop.run_forever()
Not much, but there might be some things unclear. What does this code do? Not much, but there might be some things unclear. What does this code do?
.. code-block:: python .. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient, events from telethon import TelegramClient, events
client = TelegramClient(..., update_workers=1, spawn_read_thread=False) client = TelegramClient(...)
await client.start() loop.run_until_complete(client.start())
This is normal initialization (of course, pass session name, API ID and hash). This is normal initialization (of course, pass session name, API ID and hash).
@ -78,7 +83,7 @@ message, we ``reply`` to the event with a ``'hi!'`` message.
.. code-block:: python .. code-block:: python
asyncio.get_event_loop().run_forever() loop.run_forever()
Finally, this tells the script that we're done with our code, and want Finally, this tells the script that we're done with our code, and want

View File

@ -256,7 +256,9 @@ class TelegramClient(TelegramBareClient):
also taking into consideration that 2FA may be enabled in the account. also taking into consideration that 2FA may be enabled in the account.
Example usage: Example usage:
>>> client = await TelegramClient(session, api_id, api_hash).start(phone) >>> import asyncio
>>> rc = asyncio.get_event_loop().run_until_complete
>>> client = rc(TelegramClient(session, api_id, api_hash).start(phone))
Please enter the code you received: 12345 Please enter the code you received: 12345
Please enter your password: ******* Please enter your password: *******
(You are now logged in) (You are now logged in)
@ -945,6 +947,7 @@ class TelegramClient(TelegramBareClient):
Examples: Examples:
>>> import asyncio
>>> async def main(): >>> async def main():
... client = await TelegramClient(...).start() ... client = await TelegramClient(...).start()
... message = await client.send_message('username', 'hello') ... message = await client.send_message('username', 'hello')
@ -955,7 +958,7 @@ class TelegramClient(TelegramBareClient):
... # or ... # or
... await client.edit_message(message, 'Hello!') ... await client.edit_message(message, 'Hello!')
... ...
>>> loop = ... >>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(main()) >>> loop.run_until_complete(main())
Raises: Raises: