Document the magic sync module

This commit is contained in:
Lonami Exo 2018-06-25 21:14:58 +02:00
parent 551b0044ce
commit d65f8ecc0d
15 changed files with 389 additions and 278 deletions

View File

@ -34,10 +34,7 @@ Creating a client
.. code:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient
from telethon import TelegramClient, sync
# These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
@ -45,7 +42,7 @@ Creating a client
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash)
loop.run_until_complete(client.start())
client.start()
Doing stuff
@ -53,18 +50,14 @@ Doing stuff
.. code:: python
async def main():
me = await client.get_me()
print(me.stringify())
print(client.get_me().stringify())
await client.send_message('username', 'Hello! Talking to you from Telethon')
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.send_message('username', 'Hello! Talking to you from Telethon')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
await client.download_profile_photo('me')
messages = await client.get_messages('username')
await messages[0].download_media()
loop.run_until_complete(main())
client.download_profile_photo('me')
messages = client.get_messages('username')
messages[0].download_media()
Next steps

View File

@ -26,6 +26,15 @@ can go through a sorted list of everything you can do.
can also do ``from telethon.tl import types, functions``. Both work.
.. important::
All the examples in this documentation assume that you have
``from telethon import sync`` or ``import telethon.sync``
for the sake of simplicity and that you understand what
it does (see :ref:`asyncio-magic` for more). Simply add
either line at the beginning of your project and it will work.
You should also refer to the documentation to see what the objects
(constructors) Telegram returns look like. Every constructor inherits
from a common type, and that's the reason for this distinction.
@ -69,9 +78,9 @@ Or we call `client.get_input_entity
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
peer = loop.run_until_complete(client.get_input_entity('someone'))
import telethon.sync
peer = 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
@ -83,7 +92,7 @@ instead:
.. code-block:: python
entity = loop.run_until_complete(client.get_entity('someone'))
entity = 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
@ -112,9 +121,7 @@ request we do:
.. code-block:: python
result = loop.run_until_complete(
client(SendMessageRequest(peer, 'Hello there!'))
)
result = 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 over 250
@ -123,21 +130,18 @@ as you wish. Remember to use the right types! To sum up:
.. code-block:: python
result = loop.run_until_complete(client(SendMessageRequest(
result = client(SendMessageRequest(
client.get_input_entity('username'), 'Hello there!'
)))
))
This can further be simplified to:
.. code-block:: python
async def main():
result = await client(SendMessageRequest('username', 'Hello there!'))
result = client(SendMessageRequest('username', 'Hello there!'))
# Or even
result = await client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
loop.run_until_complete(main())
result = client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
.. note::

View File

@ -38,7 +38,8 @@ so the code above and the following are equivalent:
async def main():
await client.disconnected
asyncio.get_event_loop().run_until_complete(main())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You could also run `client.disconnected
@ -48,3 +49,17 @@ until it completed.
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.
Notice that unlike `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`,
`client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>` will
handle ``KeyboardInterrupt`` with you. This method is special and can
also be ran while the loop is running, so you can do this:
.. code-block:: python
async def main():
await client.run_until_disconnected()
loop.run_until_complete(main())

View File

@ -1,8 +1,117 @@
.. _asyncio-crash-course:
.. _asyncio-magic:
===========================
A Crash Course into asyncio
===========================
==================
Magic with asyncio
==================
The sync module
***************
It's time to tell you the truth. The library has been doing magic behind
the scenes. We're sorry to tell you this, but at least it wasn't dark magic!
You may have noticed one of these lines across the documentation:
.. code-block:: python
from telethon import sync
# or
import telethon.sync
Either of these lines will import the *magic* ``sync`` module. When you
import this module, you can suddenly use all the methods defined in the
:ref:`TelegramClient <telethon-client>` like so:
.. code-block:: python
client.send_message('me', 'Hello!')
for dialog in client.iter_dialogs():
print(dialog.title)
What happened behind the scenes is that all those methods, called *coroutines*,
were rewritten to be normal methods that will block (with some exceptions).
This means you can use the library without worrying about ``asyncio`` and
event loops.
However, this only works until you run the event loop yourself explicitly:
.. code-block:: python
import asyncio
async def coro():
client.send_message('me', 'Hello!') # <- no longer works!
loop = asyncio.get_event_loop()
loop.run_until_complete(coro())
What things will work and when?
*******************************
You can use all the methods in the :ref:`TelegramClient <telethon-client>`
in a synchronous, blocking way without trouble, as long as you're not running
the loop as we saw above (the ``loop.run_until_complete(...)`` line runs "the
loop"). If you're running the loop, then *you* are the one responsible to
``await`` everything. So to fix the code above:
.. code-block:: python
import asyncio
async def coro():
await client.send_message('me', 'Hello!')
# ^ notice this new await
loop = asyncio.get_event_loop()
loop.run_until_complete(coro())
The library can only run the loop until the method completes if the loop
isn't already running, which is why the magic can't work if you run the
loop yourself.
**When you work with updates or events**, the loop needs to be
running one way or another (using `client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` runs the loop),
so your event handlers must be ``async def``.
.. important::
Turning your event handlers into ``async def`` is the biggest change
between Telethon pre-1.0 and 1.0, but updating will likely cause a
noticeable speed-up in your programs. Keep reading!
So in short, you can use **all** methods in the client with ``await`` or
without it if the loop isn't running:
.. code-block:: python
client.send_message('me', 'Hello!') # works
async def main():
await client.send_message('me', 'Hello!') # also works
loop.run_until_complete(main())
When you work with updates, you should stick using the ``async def main``
way, since your event handlers will be ``async def`` too.
.. note::
There are two exceptions. Both `client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` and
`client.start() <telethon.client.updates.UpdateMethods.start>` work in
and outside of ``async def`` for convenience without importing the
magic module. The rest of methods remain ``async`` unless you import it.
You can skip the rest if you already know how ``asyncio`` works and you
already understand what the magic does and how it works. Just remember
to ``await`` all your methods if you're inside an ``async def`` or are
using updates and you will be good.
Why asyncio?
@ -51,8 +160,11 @@ To get started with ``asyncio``, all you need is to setup your main
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You don't need to ``import telethon.sync`` if you're going to work this
way. This is the best way to work in real programs since the loop won't
be starting and ending all the time, but is a bit more annoying to setup.
Inside ``async def main():``, you can use the ``await`` keyword. Most
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 *coroutines*:
@ -78,9 +190,11 @@ 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.TelegramBaseClient.disconnected>`
`await client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>`
which is a property that you can wait on until you call
`await client.disconnect() <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`:
`await client.disconnect()
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`:
.. code-block:: python
@ -93,13 +207,18 @@ which is a property that you can wait on until you call
async def main():
await client.start()
await client.disconnected
await client.run_until_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:
`client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` and
`client.start()
<telethon.client.auth.AuthMethods.start>` are special-cased and work
inside or outside ``async def`` for convenience, even without importing
the ``sync`` module, so you can also do this:
.. code-block:: python
@ -110,8 +229,7 @@ This is the same as using the ``run_until_disconnected()`` method:
print(event)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(client.start())
client.start()
client.run_until_disconnected()
@ -172,9 +290,11 @@ a lot less. You can also rename the run method to something shorter:
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.
The documentation generally runs the loop until complete behind the
scenes if you've imported the magic ``sync`` module, but if you haven't,
you need to run the loop yourself. We recommend that you use the
``async def main()`` method to do all your work with ``await``.
It's the easiest and most performant thing to do.
More resources to learn asyncio

View File

@ -26,15 +26,7 @@ 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
from telethon import TelegramClient, sync
# Use your own values here
api_id = 12345
@ -62,7 +54,7 @@ your disk. This is by default a database file using Python's ``sqlite3``.
.. code-block:: python
rc(client.start())
client.start()
This is explained after going through the manual process.
@ -72,14 +64,14 @@ Doing so is very easy:
.. code-block:: python
rc(client.connect()) # Must return True, otherwise, try again
client.connect()
You may or may not be authorized yet. You must be authorized
before you're able to send any request:
.. code-block:: python
rc(client.is_user_authorized()) # Returns True if you can send requests
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>`:
@ -87,8 +79,8 @@ If you're not authorized, you need to `.sign_in
.. code-block:: python
phone_number = '+34600000000'
rc(client.send_code_request(phone_number))
myself = rc(client.sign_in(phone_number, input('Enter code: ')))
client.send_code_request(phone_number)
myself = 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.
@ -112,13 +104,10 @@ As a full example:
client = TelegramClient('anon', api_id, api_hash)
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())
client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number)
me = client.sign_in(phone_number, input('Enter code: '))
All of this, however, can be done through a call to `.start()
@ -127,7 +116,7 @@ All of this, however, can be done through a call to `.start()
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
loop.run_until_complete(client.start())
client.start()
The code shown is just what `.start()
@ -181,12 +170,11 @@ again with a ``password=``:
import getpass
from telethon.errors import SessionPasswordNeededError
async def main():
await client.sign_in(phone)
client.sign_in(phone)
try:
await client.sign_in(code=input('Enter code: '))
client.sign_in(code=input('Enter code: '))
except SessionPasswordNeededError:
await client.sign_in(password=getpass.getpass())
client.sign_in(password=getpass.getpass())
The mentioned `.start()
@ -209,20 +197,19 @@ See the examples below:
from telethon.errors import EmailUnconfirmedError
async def main():
# Sets 2FA password for first time:
await client.edit_2fa(new_password='supersecurepassword')
client.edit_2fa(new_password='supersecurepassword')
# Changes password:
await client.edit_2fa(current_password='supersecurepassword',
client.edit_2fa(current_password='supersecurepassword',
new_password='changedmymind')
# Clears current password (i.e. removes 2FA):
await client.edit_2fa(current_password='changedmymind', new_password=None)
client.edit_2fa(current_password='changedmymind', new_password=None)
# Sets new password with recovery email:
try:
await client.edit_2fa(new_password='memes and dreams',
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:
@ -233,7 +220,7 @@ See the examples below:
# give email parameter again it will keep the last used setting
# Set hint after already setting password:
await client.edit_2fa(current_password='memes and dreams',
client.edit_2fa(current_password='memes and dreams',
new_password='memes and dreams',
hint='It keeps you alive')

View File

@ -42,32 +42,31 @@ 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 = await client.get_dialogs()
dialogs = client.get_dialogs()
# All of these work and do the same.
lonami = await client.get_entity('lonami')
lonami = await client.get_entity('t.me/lonami')
lonami = await client.get_entity('https://telegram.dog/lonami')
lonami = client.get_entity('lonami')
lonami = client.get_entity('t.me/lonami')
lonami = client.get_entity('https://telegram.dog/lonami')
# Other kind of entities.
channel = await client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
contact = await client.get_entity('+34xxxxxxxxx')
friend = await client.get_entity(friend_id)
channel = client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
contact = client.get_entity('+34xxxxxxxxx')
friend = client.get_entity(friend_id)
# Getting entities through their ID (User, Chat or Channel)
entity = await client.get_entity(some_id)
entity = 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 = 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))
my_user = client.get_entity(PeerUser(some_id))
my_chat = client.get_entity(PeerChat(some_id))
my_channel = client.get_entity(PeerChannel(some_id))
All methods in the :ref:`telegram-client` call `.get_input_entity()
@ -137,8 +136,7 @@ wherever needed, so you can even do things like:
.. code-block:: python
async def main():
await client(SendMessageRequest('username', 'hello'))
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,18 +21,14 @@ Creating a client
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
from telethon import TelegramClient
from telethon import TelegramClient, sync
# 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_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash)
loop.run_until_complete(client.start())
client = TelegramClient('session_name', api_id, api_hash).start()
**More details**: :ref:`creating-a-client`
@ -42,36 +38,33 @@ Basic Usage
.. code-block:: python
async def main():
# Getting information about yourself
me = await client.get_me()
me = client.get_me()
print(me.stringify())
# Sending a message (you can use 'me' or 'self' to message yourself)
await client.send_message('username', 'Hello World from Telethon!')
client.send_message('username', 'Hello World from Telethon!')
# Sending a file
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# Retrieving messages from a chat
from telethon import utils
async for message in client.iter_messages('username', limit=10):
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)
async for dialog in client.get_dialogs(limit=10):
for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Downloading profile photos (default path is the working directory)
await client.download_profile_photo('username')
client.download_profile_photo('username')
# Once you have a message with .media (if message.media)
# 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())
messages = client.get_messages('username')
messages[0].download_media()
**More details**: :ref:`telegram-client`
@ -86,8 +79,8 @@ Handling Updates
from telethon import events
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
async def handler(event):
await event.reply('Hello!')
def handler(event):
event.reply('Hello!')
client.run_until_disconnected()

View File

@ -31,19 +31,11 @@ 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
(if we ignore the boilerplate needed to setup ``asyncio``, which only
needs to be done once for your entire program):
(assuming you have ``from telethon import sync`` or ``import telethon.sync``):
.. code-block:: python
import asyncio
async def main():
myself = await client.get_me() # <- a single line!
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
myself = client.get_me()
Internally, this method has sent a request to Telegram, who replied with
the information about your own user, and then the desired information
@ -55,11 +47,10 @@ 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 = await client.get_entity('lonami')
lonami = 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
@ -69,31 +60,30 @@ 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
await client.send_message('username', 'Hello World from Telethon!')
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)
await client.send_message('username', '**Using** __markdown__ `too`!')
client.send_message('username', '**Using** __markdown__ `too`!')
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# The utils package has some goodies, like .get_display_name()
from telethon import utils
async for message in client.iter_messages('username', limit=10):
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
async for dialog in client.get_dialogs(limit=10):
for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Default path is the working directory
await client.download_profile_photo('username')
client.download_profile_photo('username')
# Call .disconnect() when you're done
await client.disconnect()
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

@ -4,6 +4,16 @@
Working with Updates
====================
.. important::
Make sure you have read at least the first part of :ref:`asyncio-magic`
before working with updates. **This is a big change from Telethon pre-1.0
and 1.0, and your old handlers won't work with this version**.
To port your code to the new version, you should just prefix all your
event handlers with ``async`` and ``await`` everything that makes an
API call, such as replying, deleting messages, etc.
The library comes with the `telethon.events` module. *Events* are an abstraction
over what Telegram calls `updates`__, and are meant to ease simple and common
@ -36,7 +46,6 @@ Getting Started
.. code-block:: python
import asyncio
from telethon import TelegramClient, events
client = TelegramClient('name', api_id, api_hash)
@ -46,7 +55,7 @@ Getting Started
if 'hello' in event.raw_text:
await event.reply('hi!')
asyncio.get_event_loop().run_until_complete(client.start())
client.start()
client.run_until_disconnected()
@ -54,7 +63,6 @@ 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('name', api_id, api_hash)
@ -86,15 +94,21 @@ and ``'hello'`` is in the text of the message, we `.reply()
<telethon.tl.custom.message.Message.reply>` to the event
with a ``'hi!'`` message.
Do you notice anything different? Yes! Event handlers **must** be ``async``
for them to work, and **every method using the network** needs to have an
``await``, otherwise, Python's ``asyncio`` will tell you that you forgot
to do so, so you can easily add it.
.. code-block:: python
asyncio.get_event_loop().run_until_complete(client.start())
client.start()
client.run_until_disconnected()
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
``asyncio`` loop until the client starts (this is done behind the scenes,
since the method is so common), 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`.

View File

@ -19,9 +19,9 @@ not *interact* with a voting message), by making use of the
from telethon.tl.functions.messages import GetInlineBotResultsRequest
bot_results = loop.run_until_complete(client(GetInlineBotResultsRequest(
bot_results = client(GetInlineBotResultsRequest(
bot, user_or_chat, 'query', ''
)))
))
And you can select any of their results by using
:tl:`SendInlineBotResultRequest`:
@ -30,11 +30,11 @@ And you can select any of their results by using
from telethon.tl.functions.messages import SendInlineBotResultRequest
loop.run_until_complete(client(SendInlineBotResultRequest(
client(SendInlineBotResultRequest(
get_input_peer(user_or_chat),
obtained_query_id,
obtained_str_id
)))
))
Talking to Bots with special reply markup
@ -45,9 +45,8 @@ Generally, you just use the `message.click()
.. code-block:: python
async def main():
messages = await client.get_messages('somebot')
await messages[0].click(0)
messages = client.get_messages('somebot')
messages[0].click(0)
You can also do it manually.
@ -58,11 +57,11 @@ To interact with a message that has a special reply markup, such as
from telethon.tl.functions.messages import GetBotCallbackAnswerRequest
loop.run_until_complete(client(GetBotCallbackAnswerRequest(
client(GetBotCallbackAnswerRequest(
user_or_chat,
msg.id,
data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data
)))
))
It's a bit verbose, but it has all the information you would need to
show it visually (button rows, and buttons within each row, each with

View File

@ -25,11 +25,11 @@ to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
.. code-block:: python
from telethon.tl.functions.channels import JoinChannelRequest
loop.run_until_complete(client(JoinChannelRequest(channel)))
client(JoinChannelRequest(channel))
# In the same way, you can also leave such channel
from telethon.tl.functions.channels import LeaveChannelRequest
loop.run_until_complete(client(LeaveChannelRequest(input_channel)))
client(LeaveChannelRequest(input_channel))
For more on channels, check the `channels namespace`__.
@ -51,9 +51,7 @@ example, is the ``hash`` of the chat or channel. Now you can use
.. code-block:: python
from telethon.tl.functions.messages import ImportChatInviteRequest
updates = loop.run_until_complete(
client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
)
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
Adding someone else to such chat or channel
@ -70,19 +68,19 @@ use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
# Note that ``user_to_add`` is NOT the name of the parameter.
# It's the user you want to add (``user_id=user_to_add``).
loop.run_until_complete(client(AddChatUserRequest(
client(AddChatUserRequest(
chat_id,
user_to_add,
fwd_limit=10 # Allow the user to see the 10 last messages
)))
))
# For channels (which includes megagroups)
from telethon.tl.functions.channels import InviteToChannelRequest
loop.run_until_complete(client(InviteToChannelRequest(
client(InviteToChannelRequest(
channel,
[users_to_add]
)))
))
Checking a link without joining
@ -108,7 +106,7 @@ Here is the easy way to do it:
.. code-block:: python
participants = loop.run_until_complete(client.get_participants(group))
participants = client.get_participants(group)
Now we will show how the method works internally.
@ -133,9 +131,9 @@ a fixed limit:
all_participants = []
while True:
participants = loop.run_until_complete(client(GetParticipantsRequest(
participants = client(GetParticipantsRequest(
channel, ChannelParticipantsSearch(''), offset, limit, hash=0
)))
))
if not participants.users:
break
all_participants.extend(participants.users)
@ -202,7 +200,7 @@ Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`
# )
# Once you have a ChannelAdminRights, invoke it
loop.run_until_complete(client(EditAdminRequest(channel, user, rights)))
client(EditAdminRequest(channel, user, rights))
# User will now be able to change group info, delete other people's
# messages and pin messages.
@ -261,7 +259,7 @@ banned rights of an user through :tl:`EditBannedRequest` and its parameter
embed_links=True
)
loop.run_until_complete(client(EditBannedRequest(channel, user, rights)))
client(EditBannedRequest(channel, user, rights))
Kicking a member
@ -276,12 +274,12 @@ is enough:
from telethon.tl.functions.channels import EditBannedRequest
from telethon.tl.types import ChannelBannedRights
loop.run_until_complete(client(EditBannedRequest(
client(EditBannedRequest(
channel, user, ChannelBannedRights(
until_date=None,
view_messages=True
)
)))
))
__ https://github.com/Kyle2142
@ -302,11 +300,11 @@ use :tl:`GetMessagesViewsRequest`, setting ``increment=True``:
# Obtain `channel' through dialogs or through client.get_entity() or anyhow.
# Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list.
loop.run_until_complete(client(GetMessagesViewsRequest(
client(GetMessagesViewsRequest(
peer=channel,
id=msg_ids,
increment=True
)))
))
Note that you can only do this **once or twice a day** per account,

View File

@ -19,10 +19,9 @@ you should use :tl:`GetFullUser`:
from telethon.tl.functions.users import GetFullUserRequest
async def main():
full = await client(GetFullUserRequest(user))
full = client(GetFullUserRequest(user))
# or even
full = await client(GetFullUserRequest('username'))
full = client(GetFullUserRequest('username'))
bio = full.about
@ -40,9 +39,9 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
from telethon.tl.functions.account import UpdateProfileRequest
loop.run_until_complete(client(UpdateProfileRequest(a
client(UpdateProfileRequest(a
bout='This is a test from Telethon'
)))
))
Updating your username
@ -54,7 +53,7 @@ You need to use :tl:`account.UpdateUsername`:
from telethon.tl.functions.account import UpdateUsernameRequest
loop.run_until_complete(client(UpdateUsernameRequest('new_username')))
client(UpdateUsernameRequest('new_username'))
Updating your profile photo
@ -68,6 +67,6 @@ through :tl:`UploadProfilePhoto`:
from telethon.tl.functions.photos import UploadProfilePhotoRequest
loop.run_until_complete(client(UploadProfilePhotoRequest(
client(UploadProfilePhotoRequest(
client.upload_file('/path/to/some/file')
)))

View File

@ -20,16 +20,15 @@ Forwarding messages
.. code-block:: python
async def main():
# If you only have the message IDs
await client.forward_messages(
client.forward_messages(
entity, # to which entity you are forwarding the messages
message_ids, # the IDs of the messages (or message) to forward
from_entity # who sent the messages?
)
# If you have ``Message`` objects
await client.forward_messages(
client.forward_messages(
entity, # to which entity you are forwarding the messages
messages # the messages (or message) to forward
)
@ -41,7 +40,7 @@ Forwarding messages
from_entity = bar()
to_entity = baz()
await client(ForwardMessagesRequest(
client(ForwardMessagesRequest(
from_peer=from_entity, # who sent these messages?
id=[msg.id for msg in messages], # which are the messages?
to_peer=to_entity # who are we forwarding them to?
@ -72,7 +71,7 @@ into issues_. A valid example would be:
from telethon.tl.types import InputMessagesFilterEmpty
filter = InputMessagesFilterEmpty()
result = loop.run_until_complete(client(SearchRequest(
result = client(SearchRequest(
peer=peer, # On which chat/conversation
q='query', # What to search for
filter=filter, # Filter to use (maybe filter for media)
@ -85,7 +84,7 @@ into issues_. A valid example would be:
min_id=0, # Minimum message ID
from_id=None, # Who must have sent the message (peer)
hash=0 # Special number to return nothing on no-change
)))
))
It's important to note that the optional parameter ``from_id`` could have
been omitted (defaulting to ``None``). Changing it to :tl:`InputUserEmpty`, as one
@ -116,10 +115,9 @@ send yourself the very first sticker you have:
.. code-block:: python
async def main():
# Get all the sticker sets this user has
from telethon.tl.functions.messages import GetAllStickersRequest
sticker_sets = await client(GetAllStickersRequest(0))
sticker_sets = client(GetAllStickersRequest(0))
# Choose a sticker set
from telethon.tl.functions.messages import GetStickerSetRequest
@ -127,14 +125,14 @@ send yourself the very first sticker you have:
sticker_set = sticker_sets.sets[0]
# Get the stickers for this sticker set
stickers = await client(GetStickerSetRequest(
stickers = client(GetStickerSetRequest(
stickerset=InputStickerSetID(
id=sticker_set.id, access_hash=sticker_set.access_hash
)
))
# Stickers are nothing more than files, so send that
await client.send_file('me', stickers.documents[0])
client.send_file('me', stickers.documents[0])
.. _issues: https://github.com/LonamiWebs/Telethon/issues/215

View File

@ -24,13 +24,16 @@ when you upgrade!
.. 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
under the hood, but you don't need to know anything about it unless you're
going to work with updates! If you're an user of Telethon pre-1.0 and you
aren't ready to convert your event handlers into ``async``, 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.
If you used Telethon pre-1.0 but your scripts don't use updates or threads,
running ``import telethon.sync`` should make them Just Work. Otherwise,
we have :ref:`asyncio-magic` to teach you why ``asyncio`` is good and
how to use it.
What is this?
@ -50,10 +53,10 @@ 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
extra/basic/asyncio-magic
extra/basic/working-with-updates