mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-03-03 19:00:21 +03:00
Document the magic sync module
This commit is contained in:
parent
551b0044ce
commit
d65f8ecc0d
23
README.rst
23
README.rst
|
@ -34,10 +34,7 @@ Creating a client
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
import asyncio
|
from telethon import TelegramClient, sync
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
|
|
||||||
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.
|
||||||
|
@ -45,7 +42,7 @@ Creating a client
|
||||||
api_hash = '0123456789abcdef0123456789abcdef'
|
api_hash = '0123456789abcdef0123456789abcdef'
|
||||||
|
|
||||||
client = TelegramClient('session_name', api_id, api_hash)
|
client = TelegramClient('session_name', api_id, api_hash)
|
||||||
loop.run_until_complete(client.start())
|
client.start()
|
||||||
|
|
||||||
|
|
||||||
Doing stuff
|
Doing stuff
|
||||||
|
@ -53,18 +50,14 @@ Doing stuff
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
async def main():
|
print(client.get_me().stringify())
|
||||||
me = await client.get_me()
|
|
||||||
print(me.stringify())
|
|
||||||
|
|
||||||
await client.send_message('username', 'Hello! Talking to you from Telethon')
|
client.send_message('username', 'Hello! Talking to you from Telethon')
|
||||||
await client.send_file('username', '/home/myself/Pictures/holidays.jpg')
|
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
|
||||||
|
|
||||||
await client.download_profile_photo('me')
|
client.download_profile_photo('me')
|
||||||
messages = await client.get_messages('username')
|
messages = client.get_messages('username')
|
||||||
await messages[0].download_media()
|
messages[0].download_media()
|
||||||
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
|
|
||||||
Next steps
|
Next steps
|
||||||
|
|
|
@ -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.
|
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
|
You should also refer to the documentation to see what the objects
|
||||||
(constructors) Telegram returns look like. Every constructor inherits
|
(constructors) Telegram returns look like. Every constructor inherits
|
||||||
from a common type, and that's the reason for this distinction.
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
import telethon.sync
|
||||||
loop = asyncio.get_event_loop()
|
peer = client.get_input_entity('someone')
|
||||||
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
|
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
|
||||||
|
@ -83,7 +92,7 @@ instead:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
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
|
||||||
|
@ -112,9 +121,7 @@ request we do:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
result = loop.run_until_complete(
|
result = client(SendMessageRequest(peer, 'Hello there!'))
|
||||||
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 over 250
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
result = loop.run_until_complete(client(SendMessageRequest(
|
result = client(SendMessageRequest(
|
||||||
client.get_input_entity('username'), 'Hello there!'
|
client.get_input_entity('username'), 'Hello there!'
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
This can further be simplified to:
|
This can further be simplified to:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
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!'))
|
|
||||||
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,8 @@ so the code above and the following are equivalent:
|
||||||
async def main():
|
async def main():
|
||||||
await client.disconnected
|
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
|
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
|
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
|
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.
|
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())
|
||||||
|
|
|
@ -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?
|
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 = asyncio.get_event_loop()
|
||||||
loop.run_until_complete(main())
|
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``.
|
methods in the :ref:`TelegramClient <telethon-client>` are ``async def``.
|
||||||
You must ``await`` all ``async def``, also known as a *coroutines*:
|
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.
|
but the loop must not be running before.
|
||||||
|
|
||||||
If you want to handle updates (and don't let the script die), you must
|
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
|
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
|
.. code-block:: python
|
||||||
|
@ -93,13 +207,18 @@ which is a property that you can wait on until you call
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await client.start()
|
await client.start()
|
||||||
await client.disconnected
|
await client.run_until_disconnected()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.run_until_complete(main())
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -110,8 +229,7 @@ This is the same as using the ``run_until_disconnected()`` method:
|
||||||
print(event)
|
print(event)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
loop = asyncio.get_event_loop()
|
client.start()
|
||||||
loop.run_until_complete(client.start())
|
|
||||||
client.run_until_disconnected()
|
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(asyncio.sleep(1))
|
||||||
rc(message.delete())
|
rc(message.delete())
|
||||||
|
|
||||||
The documentation will use all these three styles so you can get used
|
The documentation generally runs the loop until complete behind the
|
||||||
to them. Which one to use is up to you, but generally you should work
|
scenes if you've imported the magic ``sync`` module, but if you haven't,
|
||||||
inside an ``async def main()`` and just run the loop there.
|
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
|
More resources to learn asyncio
|
|
@ -26,15 +26,7 @@ one is very simple:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
from telethon import TelegramClient, sync
|
||||||
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
|
# Use your own values here
|
||||||
api_id = 12345
|
api_id = 12345
|
||||||
|
@ -62,7 +54,7 @@ your disk. This is by default a database file using Python's ``sqlite3``.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
rc(client.start())
|
client.start()
|
||||||
|
|
||||||
This is explained after going through the manual process.
|
This is explained after going through the manual process.
|
||||||
|
|
||||||
|
@ -72,14 +64,14 @@ Doing so is very easy:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
You may or may not be authorized yet. You must be authorized
|
||||||
before you're able to send any request:
|
before you're able to send any request:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
If you're not authorized, you need to `.sign_in
|
||||||
<telethon.client.auth.AuthMethods.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
|
.. code-block:: python
|
||||||
|
|
||||||
phone_number = '+34600000000'
|
phone_number = '+34600000000'
|
||||||
rc(client.send_code_request(phone_number))
|
client.send_code_request(phone_number)
|
||||||
myself = rc(client.sign_in(phone_number, input('Enter code: ')))
|
myself = client.sign_in(phone_number, input('Enter code: '))
|
||||||
# If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
|
# If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
|
||||||
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
|
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
|
||||||
# You can import both exceptions from telethon.errors.
|
# You can import both exceptions from telethon.errors.
|
||||||
|
@ -112,13 +104,10 @@ As a full example:
|
||||||
|
|
||||||
client = TelegramClient('anon', api_id, api_hash)
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
|
|
||||||
async def main():
|
client.connect()
|
||||||
assert await client.connect()
|
if not client.is_user_authorized():
|
||||||
if not await client.is_user_authorized():
|
client.send_code_request(phone_number)
|
||||||
await client.send_code_request(phone_number)
|
me = client.sign_in(phone_number, input('Enter code: '))
|
||||||
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()
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
client = TelegramClient('anon', api_id, api_hash)
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
loop.run_until_complete(client.start())
|
client.start()
|
||||||
|
|
||||||
|
|
||||||
The code shown is just what `.start()
|
The code shown is just what `.start()
|
||||||
|
@ -181,12 +170,11 @@ again with a ``password=``:
|
||||||
import getpass
|
import getpass
|
||||||
from telethon.errors import SessionPasswordNeededError
|
from telethon.errors import SessionPasswordNeededError
|
||||||
|
|
||||||
async def main():
|
client.sign_in(phone)
|
||||||
await client.sign_in(phone)
|
try:
|
||||||
try:
|
client.sign_in(code=input('Enter code: '))
|
||||||
await client.sign_in(code=input('Enter code: '))
|
except SessionPasswordNeededError:
|
||||||
except SessionPasswordNeededError:
|
client.sign_in(password=getpass.getpass())
|
||||||
await client.sign_in(password=getpass.getpass())
|
|
||||||
|
|
||||||
|
|
||||||
The mentioned `.start()
|
The mentioned `.start()
|
||||||
|
@ -209,33 +197,32 @@ See the examples below:
|
||||||
|
|
||||||
from telethon.errors import EmailUnconfirmedError
|
from telethon.errors import EmailUnconfirmedError
|
||||||
|
|
||||||
async def main():
|
# Sets 2FA password for first time:
|
||||||
# Sets 2FA password for first time:
|
client.edit_2fa(new_password='supersecurepassword')
|
||||||
await client.edit_2fa(new_password='supersecurepassword')
|
|
||||||
|
|
||||||
# Changes password:
|
# Changes password:
|
||||||
await client.edit_2fa(current_password='supersecurepassword',
|
client.edit_2fa(current_password='supersecurepassword',
|
||||||
new_password='changedmymind')
|
new_password='changedmymind')
|
||||||
|
|
||||||
# Clears current password (i.e. removes 2FA):
|
# 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:
|
# Sets new password with recovery email:
|
||||||
try:
|
try:
|
||||||
await client.edit_2fa(new_password='memes and dreams',
|
client.edit_2fa(new_password='memes and dreams',
|
||||||
email='JohnSmith@example.com')
|
email='JohnSmith@example.com')
|
||||||
# Raises error (you need to check your email to complete 2FA setup.)
|
# Raises error (you need to check your email to complete 2FA setup.)
|
||||||
except EmailUnconfirmedError:
|
except EmailUnconfirmedError:
|
||||||
# You can put email checking code here if desired.
|
# You can put email checking code here if desired.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Also take note that unless you remove 2FA or explicitly
|
# Also take note that unless you remove 2FA or explicitly
|
||||||
# give email parameter again it will keep the last used setting
|
# give email parameter again it will keep the last used setting
|
||||||
|
|
||||||
# Set hint after already setting password:
|
# 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',
|
new_password='memes and dreams',
|
||||||
hint='It keeps you alive')
|
hint='It keeps you alive')
|
||||||
|
|
||||||
__ https://github.com/Anorov/PySocks#installation
|
__ https://github.com/Anorov/PySocks#installation
|
||||||
__ https://github.com/Anorov/PySocks#usage-1
|
__ https://github.com/Anorov/PySocks#usage-1
|
||||||
|
|
|
@ -42,32 +42,31 @@ you're able to just do this:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# Dialogs are the "conversations you have open".
|
||||||
# Dialogs are the "conversations you have open".
|
# This method returns a list of Dialog, which
|
||||||
# This method returns a list of Dialog, which
|
# has the .entity attribute and other information.
|
||||||
# has the .entity attribute and other information.
|
dialogs = client.get_dialogs()
|
||||||
dialogs = await client.get_dialogs()
|
|
||||||
|
|
||||||
# All of these work and do the same.
|
# All of these work and do the same.
|
||||||
lonami = await client.get_entity('lonami')
|
lonami = client.get_entity('lonami')
|
||||||
lonami = await client.get_entity('t.me/lonami')
|
lonami = client.get_entity('t.me/lonami')
|
||||||
lonami = await client.get_entity('https://telegram.dog/lonami')
|
lonami = client.get_entity('https://telegram.dog/lonami')
|
||||||
|
|
||||||
# Other kind of entities.
|
# Other kind of entities.
|
||||||
channel = await client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
|
channel = client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
|
||||||
contact = await client.get_entity('+34xxxxxxxxx')
|
contact = client.get_entity('+34xxxxxxxxx')
|
||||||
friend = await client.get_entity(friend_id)
|
friend = client.get_entity(friend_id)
|
||||||
|
|
||||||
# Getting entities through their ID (User, Chat or Channel)
|
# 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
|
# You can be more explicit about the type for said ID by wrapping
|
||||||
# it inside a Peer instance. This is recommended but not necessary.
|
# it inside a Peer instance. This is recommended but not necessary.
|
||||||
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
||||||
|
|
||||||
my_user = await client.get_entity(PeerUser(some_id))
|
my_user = client.get_entity(PeerUser(some_id))
|
||||||
my_chat = await client.get_entity(PeerChat(some_id))
|
my_chat = client.get_entity(PeerChat(some_id))
|
||||||
my_channel = await client.get_entity(PeerChannel(some_id))
|
my_channel = client.get_entity(PeerChannel(some_id))
|
||||||
|
|
||||||
|
|
||||||
All methods in the :ref:`telegram-client` call `.get_input_entity()
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
client(SendMessageRequest('username', 'hello'))
|
||||||
await client(SendMessageRequest('username', 'hello'))
|
|
||||||
|
|
||||||
The library will call the ``.resolve()`` method of the request, which will
|
The library will call the ``.resolve()`` method of the request, which will
|
||||||
resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if
|
resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if
|
||||||
|
|
|
@ -21,18 +21,14 @@ Creating a client
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
from telethon import TelegramClient, sync
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
|
|
||||||
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).start()
|
||||||
loop.run_until_complete(client.start())
|
|
||||||
|
|
||||||
**More details**: :ref:`creating-a-client`
|
**More details**: :ref:`creating-a-client`
|
||||||
|
|
||||||
|
@ -42,36 +38,33 @@ Basic Usage
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# Getting information about yourself
|
||||||
# Getting information about yourself
|
me = client.get_me()
|
||||||
me = await client.get_me()
|
print(me.stringify())
|
||||||
print(me.stringify())
|
|
||||||
|
|
||||||
# Sending a message (you can use 'me' or 'self' to message yourself)
|
# 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
|
# 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
|
# Retrieving messages from a chat
|
||||||
from telethon import utils
|
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)
|
print(utils.get_display_name(message.sender), message.message)
|
||||||
|
|
||||||
# Listing all the dialogs (conversations you have open)
|
# 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)
|
print(dialog.name, dialog.draft.text)
|
||||||
|
|
||||||
# Downloading profile photos (default path is the working directory)
|
# 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)
|
# Once you have a message with .media (if message.media)
|
||||||
# you can download it using client.download_media(),
|
# you can download it using client.download_media(),
|
||||||
# or even using message.download_media():
|
# or even using message.download_media():
|
||||||
messages = await client.get_messages('username')
|
messages = client.get_messages('username')
|
||||||
await messages[0].download_media()
|
messages[0].download_media()
|
||||||
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
**More details**: :ref:`telegram-client`
|
**More details**: :ref:`telegram-client`
|
||||||
|
|
||||||
|
@ -86,8 +79,8 @@ Handling Updates
|
||||||
from telethon import events
|
from telethon import events
|
||||||
|
|
||||||
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
|
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
|
||||||
async def handler(event):
|
def handler(event):
|
||||||
await event.reply('Hello!')
|
event.reply('Hello!')
|
||||||
|
|
||||||
client.run_until_disconnected()
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
|
@ -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.
|
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
|
(assuming you have ``from telethon import sync`` or ``import telethon.sync``):
|
||||||
needs to be done once for your entire program):
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
myself = client.get_me()
|
||||||
|
|
||||||
async def main():
|
|
||||||
myself = await client.get_me() # <- a single line!
|
|
||||||
|
|
||||||
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
|
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
|
||||||
|
@ -55,11 +47,10 @@ how the library refers to either of these:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# The method will infer that you've passed an username
|
||||||
# The method will infer that you've passed an username
|
# It also accepts phone numbers, and will get the user
|
||||||
# It also accepts phone numbers, and will get the user
|
# from your contact list.
|
||||||
# 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,
|
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
|
||||||
|
@ -69,31 +60,30 @@ Many other common methods for quick scripts are also available:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# Note that you can use 'me' or 'self' to message yourself
|
||||||
# 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
|
# .send_message's parse mode defaults to markdown, so you
|
||||||
# can use **bold**, __italics__, [links](https://example.com), `code`,
|
# can use **bold**, __italics__, [links](https://example.com), `code`,
|
||||||
# and even [mentions](@username)/[mentions](tg://user?id=123456789)
|
# 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()
|
# The utils package has some goodies, like .get_display_name()
|
||||||
from telethon import utils
|
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)
|
print(utils.get_display_name(message.sender), message.message)
|
||||||
|
|
||||||
# Dialogs are the conversations you have open
|
# 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)
|
print(dialog.name, dialog.draft.text)
|
||||||
|
|
||||||
# Default path is the working directory
|
# Default path is the working directory
|
||||||
await client.download_profile_photo('username')
|
client.download_profile_photo('username')
|
||||||
|
|
||||||
# Call .disconnect() when you're done
|
# Call .disconnect() when you're done
|
||||||
await client.disconnect()
|
client.disconnect()
|
||||||
|
|
||||||
Remember that you can call ``.stringify()`` to any object Telegram returns
|
Remember that you can call ``.stringify()`` to any object Telegram returns
|
||||||
to pretty print it. Calling ``str(result)`` does the same operation, but on
|
to pretty print it. Calling ``str(result)`` does the same operation, but on
|
||||||
|
|
|
@ -4,6 +4,16 @@
|
||||||
Working with Updates
|
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
|
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
|
over what Telegram calls `updates`__, and are meant to ease simple and common
|
||||||
|
@ -36,7 +46,6 @@ Getting Started
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from telethon import TelegramClient, events
|
from telethon import TelegramClient, events
|
||||||
|
|
||||||
client = TelegramClient('name', api_id, api_hash)
|
client = TelegramClient('name', api_id, api_hash)
|
||||||
|
@ -46,7 +55,7 @@ Getting Started
|
||||||
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_until_complete(client.start())
|
client.start()
|
||||||
client.run_until_disconnected()
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from telethon import TelegramClient, events
|
from telethon import TelegramClient, events
|
||||||
|
|
||||||
client = TelegramClient('name', api_id, api_hash)
|
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
|
<telethon.tl.custom.message.Message.reply>` to the event
|
||||||
with a ``'hi!'`` message.
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
asyncio.get_event_loop().run_until_complete(client.start())
|
client.start()
|
||||||
client.run_until_disconnected()
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
Finally, this tells the client that we're done with our code. We run the
|
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
|
``asyncio`` loop until the client starts (this is done behind the scenes,
|
||||||
we are disconnected. Of course, you can do other things instead of running
|
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`.
|
until disconnected. For this refer to :ref:`update-modes`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ not *interact* with a voting message), by making use of the
|
||||||
|
|
||||||
from telethon.tl.functions.messages import GetInlineBotResultsRequest
|
from telethon.tl.functions.messages import GetInlineBotResultsRequest
|
||||||
|
|
||||||
bot_results = loop.run_until_complete(client(GetInlineBotResultsRequest(
|
bot_results = client(GetInlineBotResultsRequest(
|
||||||
bot, user_or_chat, 'query', ''
|
bot, user_or_chat, 'query', ''
|
||||||
)))
|
))
|
||||||
|
|
||||||
And you can select any of their results by using
|
And you can select any of their results by using
|
||||||
:tl:`SendInlineBotResultRequest`:
|
:tl:`SendInlineBotResultRequest`:
|
||||||
|
@ -30,11 +30,11 @@ And you can select any of their results by using
|
||||||
|
|
||||||
from telethon.tl.functions.messages import SendInlineBotResultRequest
|
from telethon.tl.functions.messages import SendInlineBotResultRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(SendInlineBotResultRequest(
|
client(SendInlineBotResultRequest(
|
||||||
get_input_peer(user_or_chat),
|
get_input_peer(user_or_chat),
|
||||||
obtained_query_id,
|
obtained_query_id,
|
||||||
obtained_str_id
|
obtained_str_id
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
Talking to Bots with special reply markup
|
Talking to Bots with special reply markup
|
||||||
|
@ -45,9 +45,8 @@ Generally, you just use the `message.click()
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
messages = client.get_messages('somebot')
|
||||||
messages = await client.get_messages('somebot')
|
messages[0].click(0)
|
||||||
await messages[0].click(0)
|
|
||||||
|
|
||||||
You can also do it manually.
|
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
|
from telethon.tl.functions.messages import GetBotCallbackAnswerRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(GetBotCallbackAnswerRequest(
|
client(GetBotCallbackAnswerRequest(
|
||||||
user_or_chat,
|
user_or_chat,
|
||||||
msg.id,
|
msg.id,
|
||||||
data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data
|
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
|
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
|
show it visually (button rows, and buttons within each row, each with
|
||||||
|
|
|
@ -25,11 +25,11 @@ to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from telethon.tl.functions.channels import JoinChannelRequest
|
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
|
# In the same way, you can also leave such channel
|
||||||
from telethon.tl.functions.channels import LeaveChannelRequest
|
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`__.
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
from telethon.tl.functions.messages import ImportChatInviteRequest
|
from telethon.tl.functions.messages import ImportChatInviteRequest
|
||||||
updates = loop.run_until_complete(
|
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
|
||||||
client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
Adding someone else to such chat or channel
|
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.
|
# 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``).
|
# It's the user you want to add (``user_id=user_to_add``).
|
||||||
loop.run_until_complete(client(AddChatUserRequest(
|
client(AddChatUserRequest(
|
||||||
chat_id,
|
chat_id,
|
||||||
user_to_add,
|
user_to_add,
|
||||||
fwd_limit=10 # Allow the user to see the 10 last messages
|
fwd_limit=10 # Allow the user to see the 10 last messages
|
||||||
)))
|
))
|
||||||
|
|
||||||
# For channels (which includes megagroups)
|
# For channels (which includes megagroups)
|
||||||
from telethon.tl.functions.channels import InviteToChannelRequest
|
from telethon.tl.functions.channels import InviteToChannelRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(InviteToChannelRequest(
|
client(InviteToChannelRequest(
|
||||||
channel,
|
channel,
|
||||||
[users_to_add]
|
[users_to_add]
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
Checking a link without joining
|
Checking a link without joining
|
||||||
|
@ -108,7 +106,7 @@ Here is the easy way to do it:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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.
|
Now we will show how the method works internally.
|
||||||
|
|
||||||
|
@ -133,9 +131,9 @@ a fixed limit:
|
||||||
all_participants = []
|
all_participants = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
participants = loop.run_until_complete(client(GetParticipantsRequest(
|
participants = client(GetParticipantsRequest(
|
||||||
channel, ChannelParticipantsSearch(''), offset, limit, hash=0
|
channel, ChannelParticipantsSearch(''), offset, limit, hash=0
|
||||||
)))
|
))
|
||||||
if not participants.users:
|
if not participants.users:
|
||||||
break
|
break
|
||||||
all_participants.extend(participants.users)
|
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
|
# 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
|
# User will now be able to change group info, delete other people's
|
||||||
# messages and pin messages.
|
# messages and pin messages.
|
||||||
|
@ -261,7 +259,7 @@ banned rights of an user through :tl:`EditBannedRequest` and its parameter
|
||||||
embed_links=True
|
embed_links=True
|
||||||
)
|
)
|
||||||
|
|
||||||
loop.run_until_complete(client(EditBannedRequest(channel, user, rights)))
|
client(EditBannedRequest(channel, user, rights))
|
||||||
|
|
||||||
|
|
||||||
Kicking a member
|
Kicking a member
|
||||||
|
@ -276,12 +274,12 @@ is enough:
|
||||||
from telethon.tl.functions.channels import EditBannedRequest
|
from telethon.tl.functions.channels import EditBannedRequest
|
||||||
from telethon.tl.types import ChannelBannedRights
|
from telethon.tl.types import ChannelBannedRights
|
||||||
|
|
||||||
loop.run_until_complete(client(EditBannedRequest(
|
client(EditBannedRequest(
|
||||||
channel, user, ChannelBannedRights(
|
channel, user, ChannelBannedRights(
|
||||||
until_date=None,
|
until_date=None,
|
||||||
view_messages=True
|
view_messages=True
|
||||||
)
|
)
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
__ https://github.com/Kyle2142
|
__ 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 `channel' through dialogs or through client.get_entity() or anyhow.
|
||||||
# Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list.
|
# Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list.
|
||||||
|
|
||||||
loop.run_until_complete(client(GetMessagesViewsRequest(
|
client(GetMessagesViewsRequest(
|
||||||
peer=channel,
|
peer=channel,
|
||||||
id=msg_ids,
|
id=msg_ids,
|
||||||
increment=True
|
increment=True
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
Note that you can only do this **once or twice a day** per account,
|
Note that you can only do this **once or twice a day** per account,
|
||||||
|
|
|
@ -19,12 +19,11 @@ you should use :tl:`GetFullUser`:
|
||||||
|
|
||||||
from telethon.tl.functions.users import GetFullUserRequest
|
from telethon.tl.functions.users import GetFullUserRequest
|
||||||
|
|
||||||
async def main():
|
full = client(GetFullUserRequest(user))
|
||||||
full = await client(GetFullUserRequest(user))
|
# or even
|
||||||
# or even
|
full = client(GetFullUserRequest('username'))
|
||||||
full = await client(GetFullUserRequest('username'))
|
|
||||||
|
|
||||||
bio = full.about
|
bio = full.about
|
||||||
|
|
||||||
|
|
||||||
See :tl:`UserFull` to know what other fields you can access.
|
See :tl:`UserFull` to know what other fields you can access.
|
||||||
|
@ -40,9 +39,9 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
|
||||||
|
|
||||||
from telethon.tl.functions.account import UpdateProfileRequest
|
from telethon.tl.functions.account import UpdateProfileRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(UpdateProfileRequest(a
|
client(UpdateProfileRequest(a
|
||||||
bout='This is a test from Telethon'
|
bout='This is a test from Telethon'
|
||||||
)))
|
))
|
||||||
|
|
||||||
|
|
||||||
Updating your username
|
Updating your username
|
||||||
|
@ -54,7 +53,7 @@ You need to use :tl:`account.UpdateUsername`:
|
||||||
|
|
||||||
from telethon.tl.functions.account import UpdateUsernameRequest
|
from telethon.tl.functions.account import UpdateUsernameRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(UpdateUsernameRequest('new_username')))
|
client(UpdateUsernameRequest('new_username'))
|
||||||
|
|
||||||
|
|
||||||
Updating your profile photo
|
Updating your profile photo
|
||||||
|
@ -68,6 +67,6 @@ through :tl:`UploadProfilePhoto`:
|
||||||
|
|
||||||
from telethon.tl.functions.photos import UploadProfilePhotoRequest
|
from telethon.tl.functions.photos import UploadProfilePhotoRequest
|
||||||
|
|
||||||
loop.run_until_complete(client(UploadProfilePhotoRequest(
|
client(UploadProfilePhotoRequest(
|
||||||
client.upload_file('/path/to/some/file')
|
client.upload_file('/path/to/some/file')
|
||||||
)))
|
)))
|
||||||
|
|
|
@ -20,32 +20,31 @@ Forwarding messages
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# If you only have the message IDs
|
||||||
# If you only have the message IDs
|
client.forward_messages(
|
||||||
await client.forward_messages(
|
entity, # to which entity you are forwarding the messages
|
||||||
entity, # to which entity you are forwarding the messages
|
message_ids, # the IDs of the messages (or message) to forward
|
||||||
message_ids, # the IDs of the messages (or message) to forward
|
from_entity # who sent the messages?
|
||||||
from_entity # who sent the messages?
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# If you have ``Message`` objects
|
# If you have ``Message`` objects
|
||||||
await client.forward_messages(
|
client.forward_messages(
|
||||||
entity, # to which entity you are forwarding the messages
|
entity, # to which entity you are forwarding the messages
|
||||||
messages # the messages (or message) to forward
|
messages # the messages (or message) to forward
|
||||||
)
|
)
|
||||||
|
|
||||||
# You can also do it manually if you prefer
|
# You can also do it manually if you prefer
|
||||||
from telethon.tl.functions.messages import ForwardMessagesRequest
|
from telethon.tl.functions.messages import ForwardMessagesRequest
|
||||||
|
|
||||||
messages = foo() # retrieve a few messages (or even one, in a list)
|
messages = foo() # retrieve a few messages (or even one, in a list)
|
||||||
from_entity = bar()
|
from_entity = bar()
|
||||||
to_entity = baz()
|
to_entity = baz()
|
||||||
|
|
||||||
await client(ForwardMessagesRequest(
|
client(ForwardMessagesRequest(
|
||||||
from_peer=from_entity, # who sent these messages?
|
from_peer=from_entity, # who sent these messages?
|
||||||
id=[msg.id for msg in messages], # which are the messages?
|
id=[msg.id for msg in messages], # which are the messages?
|
||||||
to_peer=to_entity # who are we forwarding them to?
|
to_peer=to_entity # who are we forwarding them to?
|
||||||
))
|
))
|
||||||
|
|
||||||
The named arguments are there for clarity, although they're not needed because
|
The named arguments are there for clarity, although they're not needed because
|
||||||
they appear in order. You can obviously just wrap a single message on the list
|
they appear in order. You can obviously just wrap a single message on the list
|
||||||
|
@ -72,7 +71,7 @@ into issues_. A valid example would be:
|
||||||
from telethon.tl.types import InputMessagesFilterEmpty
|
from telethon.tl.types import InputMessagesFilterEmpty
|
||||||
|
|
||||||
filter = InputMessagesFilterEmpty()
|
filter = InputMessagesFilterEmpty()
|
||||||
result = loop.run_until_complete(client(SearchRequest(
|
result = client(SearchRequest(
|
||||||
peer=peer, # On which chat/conversation
|
peer=peer, # On which chat/conversation
|
||||||
q='query', # What to search for
|
q='query', # What to search for
|
||||||
filter=filter, # Filter to use (maybe filter for media)
|
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
|
min_id=0, # Minimum message ID
|
||||||
from_id=None, # Who must have sent the message (peer)
|
from_id=None, # Who must have sent the message (peer)
|
||||||
hash=0 # Special number to return nothing on no-change
|
hash=0 # Special number to return nothing on no-change
|
||||||
)))
|
))
|
||||||
|
|
||||||
It's important to note that the optional parameter ``from_id`` could have
|
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
|
been omitted (defaulting to ``None``). Changing it to :tl:`InputUserEmpty`, as one
|
||||||
|
@ -116,25 +115,24 @@ send yourself the very first sticker you have:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
async def main():
|
# Get all the sticker sets this user has
|
||||||
# Get all the sticker sets this user has
|
from telethon.tl.functions.messages import GetAllStickersRequest
|
||||||
from telethon.tl.functions.messages import GetAllStickersRequest
|
sticker_sets = client(GetAllStickersRequest(0))
|
||||||
sticker_sets = await client(GetAllStickersRequest(0))
|
|
||||||
|
|
||||||
# Choose a sticker set
|
# Choose a sticker set
|
||||||
from telethon.tl.functions.messages import GetStickerSetRequest
|
from telethon.tl.functions.messages import GetStickerSetRequest
|
||||||
from telethon.tl.types import InputStickerSetID
|
from telethon.tl.types import InputStickerSetID
|
||||||
sticker_set = sticker_sets.sets[0]
|
sticker_set = sticker_sets.sets[0]
|
||||||
|
|
||||||
# Get the stickers for this sticker set
|
# Get the stickers for this sticker set
|
||||||
stickers = await client(GetStickerSetRequest(
|
stickers = client(GetStickerSetRequest(
|
||||||
stickerset=InputStickerSetID(
|
stickerset=InputStickerSetID(
|
||||||
id=sticker_set.id, access_hash=sticker_set.access_hash
|
id=sticker_set.id, access_hash=sticker_set.access_hash
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
# Stickers are nothing more than files, so send that
|
# 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
|
.. _issues: https://github.com/LonamiWebs/Telethon/issues/215
|
||||||
|
|
|
@ -15,22 +15,25 @@ or use the menu on the left. Remember to read the :ref:`changelog`
|
||||||
when you upgrade!
|
when you upgrade!
|
||||||
|
|
||||||
.. important::
|
.. important::
|
||||||
If you're new here, you want to read :ref:`getting-started`. If you're
|
If you're new here, you want to read :ref:`getting-started`. If you're
|
||||||
looking for the method reference, you should check :ref:`telethon-client`.
|
looking for the method reference, you should check :ref:`telethon-client`.
|
||||||
|
|
||||||
The mentioned :ref:`telethon-client` is an important section and it
|
The mentioned :ref:`telethon-client` is an important section and it
|
||||||
contains the friendly methods that **you should use** most of the time.
|
contains the friendly methods that **you should use** most of the time.
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The library uses `asyncio <https://docs.python.org/3/library/asyncio.html>`_
|
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
|
||||||
`a simpler version <https://github.com/LonamiWebs/Telethon/tree/sync>`_
|
going to work with updates! If you're an user of Telethon pre-1.0 and you
|
||||||
(select the "sync" version in ``readthedocs``' bottom left corner).
|
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
|
If you used Telethon pre-1.0 but your scripts don't use updates or threads,
|
||||||
faster and more powerful. :ref:`asyncio-crash-course` will teach you why
|
running ``import telethon.sync`` should make them Just Work. Otherwise,
|
||||||
``asyncio`` is good and how to use it.
|
we have :ref:`asyncio-magic` to teach you why ``asyncio`` is good and
|
||||||
|
how to use it.
|
||||||
|
|
||||||
|
|
||||||
What is this?
|
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/getting-started
|
||||||
extra/basic/installation
|
extra/basic/installation
|
||||||
extra/basic/asyncio-crash-course
|
|
||||||
extra/basic/creating-a-client
|
extra/basic/creating-a-client
|
||||||
extra/basic/telegram-client
|
extra/basic/telegram-client
|
||||||
extra/basic/entities
|
extra/basic/entities
|
||||||
|
extra/basic/asyncio-magic
|
||||||
extra/basic/working-with-updates
|
extra/basic/working-with-updates
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user