Telethon/readthedocs/concepts/full-api.rst

230 lines
7.6 KiB
ReStructuredText
Raw Normal View History

2019-05-09 13:24:37 +03:00
.. _full-api:
2017-11-20 07:19:53 +03:00
2019-05-09 13:24:37 +03:00
============
The Full API
============
2017-11-20 07:12:31 +03:00
2018-05-17 13:00:22 +03:00
.. important::
While you have access to this, you should always use the friendly
2019-05-09 13:24:37 +03:00
methods listed on :ref:`client-ref` unless you have a better reason
not to, like a method not existing or you wanting more control.
2018-05-17 13:00:22 +03:00
2019-05-09 13:24:37 +03:00
The :ref:`telethon-client` doesn't offer a method for every single request
the Telegram API supports. However, it's very simple to *call* or *invoke*
any request. Whenever you need something, don't forget to `check the documentation`_
and look for the `method you need`_. There you can go through a sorted list
of everything you can do.
2017-11-20 07:12:31 +03:00
.. note::
2019-05-22 12:29:46 +03:00
The reason to keep both https://tl.telethon.dev and this
documentation alive is that the former allows instant search results
as you type, and a "Copy import" button. If you like namespaces, you
can also do ``from telethon.tl import types, functions``. Both work.
2017-11-20 07:12:31 +03:00
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.
2017-11-20 07:12:31 +03:00
2019-05-09 13:24:37 +03:00
Say `client.send_message()
<telethon.client.messages.MessageMethods.send_message>` didn't exist,
2019-05-09 13:24:37 +03:00
we could `use the search`_ to look for "message". There we would find
2018-05-30 19:55:01 +03:00
:tl:`SendMessageRequest`, which we can work with.
2017-11-20 07:12:31 +03:00
Every request is a Python class, and has the parameters needed for you
to invoke it. You can also call ``help(request)`` for information on
what input parameters it takes. Remember to "Copy import to the
clipboard", or your script won't be aware of this class! Now we have:
2017-11-20 07:12:31 +03:00
.. code-block:: python
from telethon.tl.functions.messages import SendMessageRequest
2017-11-20 07:12:31 +03:00
If you're going to use a lot of these, you may do:
2017-11-20 07:12:31 +03:00
.. code-block:: python
from telethon.tl import types, functions
# We now have access to 'functions.messages.SendMessageRequest'
2017-11-20 07:12:31 +03:00
We see that this request must take at least two parameters, a ``peer``
of type :tl:`InputPeer`, and a ``message`` which is just a Python
`str`\ ing.
2017-11-20 07:12:31 +03:00
How can we retrieve this :tl:`InputPeer`? We have two options. We manually
construct one, for instance:
2017-11-20 07:12:31 +03:00
.. code-block:: python
2017-11-20 07:12:31 +03:00
from telethon.tl.types import InputPeerUser
2017-11-20 07:12:31 +03:00
peer = InputPeerUser(user_id, user_hash)
2017-11-20 07:12:31 +03:00
2019-05-09 13:24:37 +03:00
Or we call `client.get_input_entity()
<telethon.client.users.UserMethods.get_input_entity>`:
2017-11-20 07:12:31 +03:00
.. code-block:: python
2017-11-20 07:12:31 +03:00
import telethon
async def main():
peer = await client.get_input_entity('someone')
asyncio.run(main())
.. note::
Remember that ``await`` must occur inside an ``async def``.
Every full API example assumes you already know and do this.
2018-06-25 22:14:58 +03:00
2017-11-20 07:12:31 +03:00
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
2019-05-09 13:24:37 +03:00
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
is more straightforward (and often immediate, if you've seen the user before,
know their ID, etc.). If you also **need** to have information about the whole
2019-05-09 13:24:37 +03:00
user, use `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
instead:
2017-11-20 07:12:31 +03:00
.. code-block:: python
2017-11-20 07:12:31 +03:00
entity = await client.get_entity('someone')
2017-11-20 07:12:31 +03:00
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
want to cache its input version so the library doesn't have to do this
2018-05-30 19:55:01 +03:00
every time its used, simply call `telethon.utils.get_input_peer`:
2017-11-20 07:12:31 +03:00
.. code-block:: python
2017-11-20 07:12:31 +03:00
from telethon import utils
2018-06-22 15:44:59 +03:00
peer = utils.get_input_peer(entity)
2017-11-20 07:12:31 +03:00
.. note::
Since ``v0.16.2`` this is further simplified. The ``Request`` itself
2018-10-06 21:20:11 +03:00
will call `client.get_input_entity
<telethon.client.users.UserMethods.get_input_entity>` for you when
required, but it's good to remember what's happening.
After this small parenthesis about `client.get_entity
<telethon.client.users.UserMethods.get_entity>` versus
2019-05-09 13:24:37 +03:00
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`,
we have everything we need. To invoke our
2017-11-20 07:12:31 +03:00
request we do:
.. code-block:: python
2017-11-20 07:12:31 +03:00
result = await client(SendMessageRequest(peer, 'Hello there!'))
2017-11-20 07:12:31 +03:00
2018-06-22 15:44:59 +03:00
Message sent! Of course, this is only an example. There are over 250
methods available as of layer 80, and you can use every single of them
as you wish. Remember to use the right types! To sum up:
2017-11-20 07:12:31 +03:00
.. code-block:: python
2017-11-20 07:12:31 +03:00
result = await client(SendMessageRequest(
await client.get_input_entity('username'), 'Hello there!'
2018-06-25 22:14:58 +03:00
))
2017-11-20 07:12:31 +03:00
This can further be simplified to:
.. code-block:: python
result = await client(SendMessageRequest('username', 'Hello there!'))
2018-06-25 22:14:58 +03:00
# Or even
result = await client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
2017-11-20 07:12:31 +03:00
.. note::
Note that some requests have a "hash" parameter. This is **not**
your ``api_hash``! It likely isn't your self-user ``.access_hash`` either.
2017-11-20 07:12:31 +03:00
It's a special hash used by Telegram to only send a difference of new data
that you don't already have with that request, so you can leave it to 0,
and it should work (which means no hash is known yet).
2017-11-20 07:12:31 +03:00
For those requests having a "limit" parameter, you can often set it to
zero to signify "return default amount". This won't work for all of them
though, for instance, in "messages.search" it will actually return 0 items.
2017-11-20 07:12:31 +03:00
Requests in Parallel
2019-05-09 13:24:37 +03:00
====================
The library will automatically merge outgoing requests into a single
*container*. Telegram's API supports sending multiple requests in a
single container, which is faster because it has less overhead and
the server can run them without waiting for others. You can also
force using a container manually:
.. code-block:: python
async def main():
# Letting the library do it behind the scenes
await asyncio.wait([
client.send_message('me', 'Hello'),
client.send_message('me', ','),
client.send_message('me', 'World'),
client.send_message('me', '.')
])
# Manually invoking many requests at once
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ', '),
SendMessageRequest('me', 'World'),
SendMessageRequest('me', '.')
])
Note that you cannot guarantee the order in which they are run.
Try running the above code more than one time. You will see the
order in which the messages arrive is different.
If you use the raw API (the first option), you can use ``ordered``
to tell the server that it should run the requests sequentially.
This will still be faster than going one by one, since the server
knows all requests directly:
.. code-block:: python
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ', '),
SendMessageRequest('me', 'World'),
SendMessageRequest('me', '.')
], ordered=True)
If any of the requests fails with a Telegram error (not connection
errors or any other unexpected events), the library will raise
`telethon.errors.common.MultiError`. You can ``except`` this
and still access the successful results:
.. code-block:: python
from telethon.errors import MultiError
try:
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ''),
SendMessageRequest('me', 'World')
], ordered=True)
except MultiError as e:
# The first and third requests worked.
first = e.results[0]
third = e.results[2]
# The second request failed.
second = e.exceptions[1]
2019-05-22 12:29:46 +03:00
.. _check the documentation: https://tl.telethon.dev
.. _method you need: https://tl.telethon.dev/methods/index.html
.. _use the search: https://tl.telethon.dev/?q=message&redirect=no