From 1f79f063a28b40d251cee8821fae0f2771f890bf Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sat, 11 Mar 2023 12:45:06 +0100 Subject: [PATCH] Expand documentation on using the raw API --- readthedocs/concepts/full-api.rst | 207 ++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 8 deletions(-) diff --git a/readthedocs/concepts/full-api.rst b/readthedocs/concepts/full-api.rst index cce026f1..ba5755d0 100644 --- a/readthedocs/concepts/full-api.rst +++ b/readthedocs/concepts/full-api.rst @@ -10,13 +10,20 @@ The Full API methods listed on :ref:`client-ref` unless you have a better reason not to, like a method not existing or you wanting more control. +.. contents:: + + +Introduction +============ 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. +any request defined in Telegram's API. +This section will teach you how to use what Telethon calls the `TL reference`_. +The linked page contains a list and a way to search through *all* types +generated from the definition of Telegram's API (in ``.tl`` file format, +hence the name). These types include requests and constructors. .. note:: @@ -25,10 +32,193 @@ of everything you can do. as you type, and a "Copy import" button. If you like namespaces, you can also do ``from telethon.tl import types, functions``. Both work. +Telegram makes these ``.tl`` files public, which other implementations, such +as Telethon, can also use to generate code. These files are versioned under +what's called "layers". ``.tl`` files consist of thousands of definitions, +and newer layers often add, change, or remove them. Each definition refers +to either a Remote Procedure Call (RPC) function, or a type (which the +`TL reference`_ calls "constructors", as they construct particular type +instances). -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. +As such, the `TL reference`_ is a good place to go to learn about all possible +requests, types, and what they look like. If you're curious about what's been +changed between layers, you can refer to the `TL diff`_ site. + + +Navigating the TL reference +=========================== + +Functions +--------- + +"Functions" is the term used for the Remote Procedure Calls (RPC) that can be +sent to Telegram to ask it to perform something (e.g. "send message"). These +requests have an associated return type. These can be invoked ("called"): + +.. code-block:: python + + client = TelegramClient(...) + function_instance = SomeRequest(...) + + # Invoke the request + returned_type = await client(function_instance) + +Whenever you find the type for a function in the `TL reference`_, the page +will contain the following information: + +* What type of account can use the method. This information is regenerated + from time to time (by attempting to invoke the function under both account + types and finding out where it fails). Some requests can only be used by + bot accounts, others by user accounts, and others by both. +* The TL definition. This helps you get a feel for the what the function + looks like. This is not Python code. It just contains the definition in + a concise manner. +* "Copy import" button. Does what it says: it will copy the necessary Python + code to import the function to your system's clipboard for easy access. +* Returns. The returned type. When you invoke the function, this is what the + result will be. It also includes which of the constructors can be returned + inline, to save you a click. +* Parameters. The parameters accepted by the function, including their type, + whether they expect a list, and whether they're optional. +* Known RPC errors. A best-effort list of known errors the request may cause. + This list is not complete and may be out of date, but should provide an + overview of what could go wrong. +* Example. Autogenerated example, showcasing how you may want to call it. + Bear in mind that this is *autogenerated*. It may be spitting out non-sense. + The goal of this example is not to show you everything you can do with the + request, only to give you a feel for what it looks like to use it. + +It is very important to click through the links and navigate to get the full +picture. A specific page will show you what the specific function returns and +needs as input parameters. But it may reference other types, so you need to +navigate to those to learn what those contain or need. + +Types +----- + +"Types" as understood by TL are not actually generated in Telethon. +They would be the "abstract base class" of the constructors, but since Python +is duck-typed, there is hardly any need to generate mostly unnecessary code. +The page for a type contains: + +* Constructors. Every type will have one or more constructors. These + constructors *are* generated and can be immported and used. +* Requests returning this type. A helpful way to find out "what requests can + return this?". This is how you may learn what request you need to use to + obtain a particular instance of a type. +* Requests accepting this type as input. A helpful way to find out "what + requests can use this type as one of their input parameters?". This is how + you may learn where a type is used. +* Other types containing this type. A helpful way to find out "where else + does this type appear?". This is how you can walk back through nested + objects. + +Constructors +------------ + +Constructors are used to create instances of a particular type, and are also +returned when invoking requests. You will have to create instances yourself +when invoking requests that need a particular type as input. +The page for a constructor contains: + +* Belongs to. The parent type. This is a link back to the types page for the + specific constructor. It also contains the sibling constructors inline, to + save you a click. +* Members. Both the input parameters *and* fields the constructor contains. + + +Using the TL reference +====================== + +After you've found a request you want to send, a good start would be to simply +copy and paste the autogenerated example into your script. Then you can simply +tweak it to your needs. + +If you want to do it from scratch, first, make sure to import the request into +your code (either using the "Copy import" button near the top, or by manually +spelling out the package under ``telethon.tl.functions.*``). + +Then, start reading the parameters one by one. If the parameter cannot be +omitted, you **will** need to specify it, so make sure to spell it out as +an input parameter when constructing the request instance. Let's look at +`PingRequest`_ for example. First, we copy the import: + +.. code-block:: python + + from telethon.tl.functions import PingRequest + +Then, we look at the parameters: + + ping_id - long + +A single parameter, and it's a long (a integer number with a large range of +values). It doesn't say it can be omitted, so we must provide it, like so: + +.. code-block:: python + + PingRequest( + ping_id=48641868471 + ) + +(In this case, the ping ID is a random number. You often have to guess what +the parameter needs just by looking at the name.) + +Now that we have our request, we can invoke it: + +.. code-block:: python + + response = await client(PingRequest( + ping_id=48641868471 + )) + +To find out what ``response`` looks like, we can do as the autogenerated +example suggests and "stringify" the result as a pretty-printed string: + +.. code-block:: python + + print(result.stringify()) + +This will print out the following: + +.. code-block:: python + + Pong( + msg_id=781875678118, + ping_id=48641868471 + ) + +Which is a very easy way to get a feel for a response. You should nearly +always print the stringified result, at least once, when trying out requests, +to get a feel for what the response may look like. + +But of course, you don't need to do that. Without writing any code, you could +have navigated through the "Returns" link to learn ``PingRequest`` returns a +``Pong``, which only has one constructor, and the constructor has two members, +``msg_id`` and ``ping_id``. + +If you wanted to create your own ``Pong``, you would use both members as input +parameters: + +.. code-block:: python + + my_pong = Pong( + msg_id=781875678118, + ping_id=48641868471 + ) + +(Yes, constructing object instances can use the same code that ``.stringify`` +would return!) + +And if you wanted to access the ``msg_id`` member, you would simply access it +like any other attribute access in Python: + +.. code-block:: python + + print(response.msg_id) + + +Example walkthrough +=================== Say `client.send_message() ` didn't exist, @@ -224,6 +414,7 @@ and still access the successful results: # The second request failed. second = e.exceptions[1] -.. _check the documentation: https://tl.telethon.dev -.. _method you need: https://tl.telethon.dev/methods/index.html +.. _TL reference: https://tl.telethon.dev +.. _TL diff: https://diff.telethon.dev +.. _PingRequest: https://tl.telethon.dev/methods/ping.html .. _use the search: https://tl.telethon.dev/?q=message&redirect=no