mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-03 21:24:35 +03:00
Add documentation
This commit is contained in:
parent
e36c35c805
commit
b62327308b
|
@ -8,13 +8,15 @@ python tools/codegen.py
|
||||||
Formatting, type-checking and testing:
|
Formatting, type-checking and testing:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pip install isort black mypy pytest pytest-asyncio
|
pip install -e client/[dev]
|
||||||
python tools/check.py
|
python tools/check.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Documentation:
|
Documentation (requires [sphinx](https://www.sphinx-doc.org) and [graphviz](https://www.graphviz.org)'s `dot`):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pip install sphinx_rtd_theme
|
pip install -e client/[doc]
|
||||||
python tools/docgen.py
|
python tools/docgen.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that multiple optional dependency sets can be specified by separating them with a comma (`[dev,doc]`).
|
||||||
|
|
59
client/doc/basic/installation.rst
Normal file
59
client/doc/basic/installation.rst
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Telethon is a Python 3 library, which means you need to download and install Python to use it.
|
||||||
|
Installing Python, using virtual environments, and the basics of the language, are outside of the scope of this guide.
|
||||||
|
|
||||||
|
You can find the official resources to `download Python <https://www.python.org/downloads/>`_,
|
||||||
|
learn about the `Python Setup and Usage <https://docs.python.org/3/using/index.html>`_ for different platforms,
|
||||||
|
or follow the `The Python Tutorial <https://docs.python.org/3/tutorial/index.html>`_ to learn the basics.
|
||||||
|
These are not necessarily the best resources to learn, but they are official.
|
||||||
|
Be sure to search online if you prefer learning in video form or otherwise.
|
||||||
|
|
||||||
|
You can confirm that you have Python installed with:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
python --version
|
||||||
|
|
||||||
|
Which should print something similar to ``Python 3.11.5`` (or newer).
|
||||||
|
|
||||||
|
|
||||||
|
Installing the latest stable version
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Once you have a working Python 3 installation, you can install or upgrade the ``telethon`` package with ``pip``:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
python -m pip install --upgrade telethon
|
||||||
|
|
||||||
|
Be sure to use lock-files if your project depends on a specific, older version of the library!
|
||||||
|
|
||||||
|
|
||||||
|
Installing development versions
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
If you want the *latest* unreleased changes, you can run the following command instead:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
python -m pip install --upgrade https://github.com/LonamiWebs/Telethon/archive/v2.zip
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The development version may have bugs and is not recommended for production use.
|
||||||
|
However, when you are `reporting a library bug <https://github.com/LonamiWebs/Telethon/issues/>`,
|
||||||
|
you must reproduce the issue in this version before reporting the problem.
|
||||||
|
|
||||||
|
|
||||||
|
Verifying the installation
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
To verify that the library is installed correctly, run the following command:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
python -c "import telethon; print(telethon.__version__)"
|
||||||
|
|
||||||
|
The version number of the library should show in the output.
|
32
client/doc/basic/next-steps.rst
Normal file
32
client/doc/basic/next-steps.rst
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
Next steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
By now, you should have successfully gone through both the :doc:`installation` and :doc:`signing-in` processes.
|
||||||
|
|
||||||
|
With a :class:`Client` instance connected and authorized, you can send any request to Telegram.
|
||||||
|
Some requests are bot-specific, and some are user-specific, but most can be used by any account.
|
||||||
|
You will need to have the correct permissions and pass valid parameters, but after that, your imagination is the limit.
|
||||||
|
|
||||||
|
Telethon features extensive documentation for every public item offered by the library.
|
||||||
|
All methods within the :class:`Client` also contain one or more examples on how to use them.
|
||||||
|
|
||||||
|
Whatever you build, remember to comply with both `Telegram's Terms of Service <https://telegram.org/tos>`_
|
||||||
|
and `Telegram's API ToS <https://core.telegram.org/api/terms>`_.
|
||||||
|
There are `several requests that applications must make <https://core.telegram.org/api/config#terms-of-service>`_:
|
||||||
|
|
||||||
|
.. epigraph::
|
||||||
|
|
||||||
|
[…] when logging in as an existing user, apps are supposed to call :tl:`help.getTermsOfServiceUpdate`
|
||||||
|
to check for any updates to the Terms of Service;
|
||||||
|
this call should be repeated after ``expires`` seconds have elapsed.
|
||||||
|
If an update to the Terms Of Service is available, clients are supposed to show a consent popup;
|
||||||
|
if accepted, clients should call :tl:`help.acceptTermsOfService`,
|
||||||
|
providing the ``termsOfService id`` JSON object;
|
||||||
|
in case of denial, clients are to delete the account using :tl:`account.deleteAccount`,
|
||||||
|
providing Decline ToS update as deletion reason.
|
||||||
|
|
||||||
|
The library will not make these calls for you, as it cannot know how users interact with the application being developed.
|
||||||
|
If you use an official client alongside the application you are developing,
|
||||||
|
it should be safe to rely on that client making the requests instead.
|
211
client/doc/basic/signing-in.rst
Normal file
211
client/doc/basic/signing-in.rst
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
Signing in
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
Most of Telegram's API methods are gated behind an account login.
|
||||||
|
But before you can interact with the API at all, you will need to obtain an API ID and hash pair for your application.
|
||||||
|
|
||||||
|
|
||||||
|
Registering your Telegram application
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Before working with Telegram's API, you (as the application developer) need to get an API ID and hash:
|
||||||
|
|
||||||
|
1. `Login to your Telegram account <https://my.telegram.org/>`_ with the phone number of the developer account to use.
|
||||||
|
|
||||||
|
2. Click under *API Development tools*.
|
||||||
|
|
||||||
|
3. A *Create new application* window will appear. Fill in your application details.
|
||||||
|
There is no need to enter any *URL*, and only the first two fields (*App title* and *Short name*) can currently be changed later.
|
||||||
|
|
||||||
|
4. Click on *Create application* at the end.
|
||||||
|
Remember that your **API hash is secret** and Telegram won't let you revoke it.
|
||||||
|
Don't post it anywhere!
|
||||||
|
|
||||||
|
This API ID and hash can now be used to develop an application using Telegram's API.
|
||||||
|
Telethon consumes this API ID and hash in order to make the requests to Telegram.
|
||||||
|
|
||||||
|
It is important to note that this API ID and hash is attached to a developer account,
|
||||||
|
and can be used to develop applications or otherwise using libraries such as Telethon.
|
||||||
|
|
||||||
|
The *users* of the application you develop do *not* need to provide their own API ID and hash.
|
||||||
|
The API ID and hash values are meant to be hardcoded in the application.
|
||||||
|
Any user is then able to login with just their phone number or bot token, even if they have not registered an application themselves.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
The API ID and hash are meant to be *secret*, but Python is often distributed in source-code form.
|
||||||
|
These two things conflict with eachother!
|
||||||
|
You can opt to obfuscate the values somehow, or perhaps distribute an executable binary file instead.
|
||||||
|
Depending on what you are developing, it might be reasonable to expect users to provide their own API ID and hash instead.
|
||||||
|
|
||||||
|
Official applications *also* must embed the API ID and hash, but these are often distributed as binary files.
|
||||||
|
Whatever you do, **do not use other people's API ID and hash!**
|
||||||
|
Telegram may detect this as suspicious and ban the accounts.
|
||||||
|
|
||||||
|
If you receive an error, Telegram is likely blocking the registration of a new applications.
|
||||||
|
The best you can do is wait and try again later.
|
||||||
|
If the issue persists, you may try contacting them, using a proxy or using a VPN.
|
||||||
|
Be aware that some phone numbers are not eligible to register applications with.
|
||||||
|
|
||||||
|
|
||||||
|
Interactive login
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The library offers a method for "quick and dirty" scripts known as :meth:`~Client.interactive_login`.
|
||||||
|
This method will first check whether the account was previously logged-in, and if not, ask for a phone number to be input.
|
||||||
|
|
||||||
|
You can write the code in a file (such as ``hello.py``) and then run it, or use the built-in ``asyncio``-enabled REPL.
|
||||||
|
For this tutorial, we'll be using the ``asyncio`` REPL:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
python -m asyncio
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
If you opt to write your code in a file, do **not** call your script ``telethon.py``!
|
||||||
|
Python will try to import from there and it will fail with an error such as "ImportError: cannot import name ...".
|
||||||
|
|
||||||
|
The first thing we need to do is import the :class:`Client` class and create an instance of it:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import Client
|
||||||
|
|
||||||
|
client = Client('name', 12345, '0123456789abcdef0123456789abcdef')
|
||||||
|
|
||||||
|
The second and third parameters must be the API ID and hash, respectively.
|
||||||
|
We have a client instance now, but we can't send requests to Telegram until we connect!
|
||||||
|
So the next step is to :meth:`~Client.connect`:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
await client.connect()
|
||||||
|
|
||||||
|
If all went well, you will have connected to one of Telegram's servers.
|
||||||
|
If you run into issues, you might need to try a different hosting provider or use some sort of proxy.
|
||||||
|
|
||||||
|
Once you're connected, we can begin the :meth:`~Client.interactive_login`:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
await client.interactive_login()
|
||||||
|
|
||||||
|
Do as the prompts say on the terminal, and you will have successfully logged-in!
|
||||||
|
|
||||||
|
Once you're done, make sure to :meth:`~Client.disconnect` for a graceful shutdown.
|
||||||
|
|
||||||
|
|
||||||
|
Manual login
|
||||||
|
------------
|
||||||
|
|
||||||
|
We've talked about the second and third parameters of the :class:`Client` constructor, but not the first:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client = Client('name', 12345, '0123456789abcdef0123456789abcdef')
|
||||||
|
|
||||||
|
The first parameter is the "session".
|
||||||
|
When using a string or a :class:`~pathlib.Path`, the library will create a SQLite database in that path.
|
||||||
|
The session path can contain directory separators and live anywhere in the file system.
|
||||||
|
Telethon will automatically append the ``.session`` extension if you don't provide any.
|
||||||
|
|
||||||
|
Briefly, the session contains some of the information needed to connect to Telegram.
|
||||||
|
This includes the datacenter belonging to the account logged-in, and the authorization key used for encryption, among other things.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
**Do not leak the session file!**
|
||||||
|
Anyone with that file can login to the account stored in it.
|
||||||
|
If you believe someone else has obtained this file, immediately revoke all active sessions from an official client.
|
||||||
|
|
||||||
|
Let's take a look at what :meth:`~Client.interactive_login` does under the hood.
|
||||||
|
|
||||||
|
1. First, it's using an equivalent of :meth:`~Client.is_authorized` to check whether the session was logged-in previously.
|
||||||
|
2. Then, it will either :meth:`~Client.bot_sign_in` with a bot token or :meth:`~Client.request_login_code` with a phone number.
|
||||||
|
|
||||||
|
* If it logged-in as a bot account, a :class:`~types.User` is returned and we're done.
|
||||||
|
* Otherwise, a login code was sent. Go to step 3.
|
||||||
|
|
||||||
|
3. Attempt to complete the user sign-in with :meth:`~Client.sign_in`, by entering the login code.
|
||||||
|
|
||||||
|
* If a :class:`~types.User` is returned, we're done.
|
||||||
|
* Otherwise, a 2FA password is required. Go to step 4.
|
||||||
|
|
||||||
|
4. Use :meth:`Client.check_password` to check that the password is correct.
|
||||||
|
|
||||||
|
* If the password is correct, :class:`~types.User` is returned and we're done.
|
||||||
|
|
||||||
|
Put into code, a user can thus login as follows:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import Client
|
||||||
|
from telethon.types import User
|
||||||
|
|
||||||
|
# SESSION, API_ID, API_HASH should be previously defined in your code
|
||||||
|
async with Client(SESSION, API_ID, API_HASH) as client:
|
||||||
|
if not await client.is_authorized():
|
||||||
|
phone = input('phone: ')
|
||||||
|
login_token = await client.request_login_code(phone_or_token)
|
||||||
|
|
||||||
|
code = input('code: ')
|
||||||
|
user_or_token = await client.sign_in(login_token, code)
|
||||||
|
|
||||||
|
if isinstance(user_or_token, User):
|
||||||
|
return user_or_token
|
||||||
|
|
||||||
|
# user_or_token is PasswordToken
|
||||||
|
password_token = user_or_token
|
||||||
|
|
||||||
|
import getpass
|
||||||
|
password = getpass.getpass("password: ")
|
||||||
|
user = await client.check_password(password_token, password)
|
||||||
|
return user
|
||||||
|
|
||||||
|
A bot account does not need to request login code and cannot have passwords, so the login flow is much simpler:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import Client
|
||||||
|
|
||||||
|
# SESSION, API_ID, API_HASH should be previously defined in your code
|
||||||
|
async with Client(SESSION, API_ID, API_HASH) as client:
|
||||||
|
bot_token = input('token: ')
|
||||||
|
bot_user = await client.bot_sign_in(bot_token)
|
||||||
|
return bot_user
|
||||||
|
|
||||||
|
To get a bot account, you need to talk with `@BotFather <https://t.me/BotFather>`_.
|
||||||
|
|
||||||
|
You may have noticed the ``async with`` keywords.
|
||||||
|
The :class:`Client` can be used in a context-manager.
|
||||||
|
This will automatically call :meth:`Client.connect` and :meth:`Client.disconnect` for you.
|
||||||
|
|
||||||
|
A good way to structure your code is as follows:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from telethon import Client
|
||||||
|
|
||||||
|
SESSION = ...
|
||||||
|
API_ID = ...
|
||||||
|
API_HASH = ...
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with Client(SESSION, API_ID, API_HASH) as client:
|
||||||
|
... # use client to your heart's content
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
|
|
||||||
|
This way, both the :mod:`asyncio` event loop and the :class:`Client` will exit cleanly.
|
||||||
|
Otherwise, you might run into errors such as tasks being destroyed while pending.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Once a :class:`Client` instance has been connected, you cannot change the :mod:`asyncio` event loop.
|
||||||
|
Methods like :func:`asyncio.run` setup and tear-down a new event loop every time.
|
||||||
|
If the loop changes, the client is likely to be "stuck" because its loop cannot advance.
|
117
client/doc/concepts/botapi-vs-mtproto.rst
Normal file
117
client/doc/concepts/botapi-vs-mtproto.rst
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
HTTP Bot API vs MTProto
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
Telethon is more than capable to develop bots for Telegram.
|
||||||
|
If you haven't decided which wrapper library for bots to use yet,
|
||||||
|
using Telethon from the beginning may save you some headaches later.
|
||||||
|
|
||||||
|
|
||||||
|
What is Bot API?
|
||||||
|
----------------
|
||||||
|
|
||||||
|
`Telegram's HTTP Bot API <https://core.telegram.org/bots/api>`_,
|
||||||
|
from now on referred to as simply "Bot API", is Telegram's official way for developers to control their own Telegram bots.
|
||||||
|
Quoting their main page:
|
||||||
|
|
||||||
|
.. epigraph::
|
||||||
|
|
||||||
|
The Bot API is an HTTP-based interface created for developers keen on building bots for Telegram.
|
||||||
|
|
||||||
|
To learn how to create and set up a bot, please consult our
|
||||||
|
`Introduction to Bots <https://core.telegram.org/bots>`_
|
||||||
|
and `Bot FAQ <https://core.telegram.org/bots/faq>`_.
|
||||||
|
|
||||||
|
Bot API is simply an HTTP endpoint offering a custom HTTP API.
|
||||||
|
Underneath, it uses `tdlib <https://core.telegram.org/tdlib>`_ to talk to Telegram's servers.
|
||||||
|
|
||||||
|
You can configure your bot details via `@BotFather <https://t.me/BotFather>`_.
|
||||||
|
This includes name, commands, and auto-completion.
|
||||||
|
|
||||||
|
|
||||||
|
What is MTProto?
|
||||||
|
----------------
|
||||||
|
|
||||||
|
`MTProto <https://core.telegram.org/mtproto>`_ stands for "Mobile Transport Protocol".
|
||||||
|
It is the language that the Telegram servers "speak".
|
||||||
|
You can think of it as an alternative to HTTP.
|
||||||
|
|
||||||
|
Telegram offers multiple APIs.
|
||||||
|
All user accounts must use the API offered via MTProto.
|
||||||
|
We will call this API the "MTProto API".
|
||||||
|
This is the canonical Telegram API.
|
||||||
|
|
||||||
|
The MTProto API is different from Bot API, but bot accounts can use either in the same way.
|
||||||
|
In fact, the Bot API is implemented to use the MTProto API to map the requests and responses.
|
||||||
|
|
||||||
|
Telethon implements the MTProto and offers classes and methods that can be called to send requests.
|
||||||
|
In Telethon, all the methods and types generated from Telegram's API definitions are also known as :term:`Raw API`.
|
||||||
|
This name was chosen because it gives you "raw" access to the MTProto API.
|
||||||
|
Telethon's :class:`Client` and other custom types are implemented using the :term:`Raw API`.
|
||||||
|
|
||||||
|
|
||||||
|
Advantages of MTProto over Bot API
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
MTProto clients (like Telethon) connect directly to Telegram's servers via TCP or UDP.
|
||||||
|
There is no HTTP connection, no "polling", and no "web hooks".
|
||||||
|
We can compare the two visually:
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
:caption: Communication between a Client and the Bot API
|
||||||
|
|
||||||
|
digraph botapi {
|
||||||
|
rankdir=LR;
|
||||||
|
"Client" -> "HTTP API";
|
||||||
|
"HTTP API" -> "MTProto API";
|
||||||
|
"MTProto API" -> "Telegram Servers";
|
||||||
|
|
||||||
|
"Telegram Servers" -> "MTProto API" [label="IPC"];
|
||||||
|
"MTProto API" -> "HTTP API" [label="MTProto"];
|
||||||
|
"HTTP API" -> "Client" [label="JSON"];
|
||||||
|
}
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
:caption: Communication between a Client and the MTProto API
|
||||||
|
|
||||||
|
digraph botapi {
|
||||||
|
rankdir=LR;
|
||||||
|
"Client" -> "MTProto API";
|
||||||
|
"MTProto API" -> "Telegram Servers";
|
||||||
|
|
||||||
|
"Telegram Servers" -> "MTProto API" [label="IPC"];
|
||||||
|
"MTProto API" -> "Client" [label="MTProto"];
|
||||||
|
}
|
||||||
|
|
||||||
|
When interacting with the MTProto API directly, we can cut down one intermediary (the HTTP API).
|
||||||
|
This is less theoretical overhead and latency.
|
||||||
|
It also means that, even if the Bot API endpoint is down, talking to the MTProto API could still work.
|
||||||
|
|
||||||
|
The methods offered by the Bot API map to some of the methods in the MTProto API, but not all.
|
||||||
|
The Bot API is its own abstraction, and chooses to expose less details.
|
||||||
|
By talking to the MTProto API directly, you unlock the `full potential <https://github.com/LonamiWebs/Telethon/wiki/MTProto-vs-HTTP-Bot-API>`_.
|
||||||
|
|
||||||
|
The serialization format used by MTProto is more compact than JSON and can still be compressed.
|
||||||
|
|
||||||
|
Another benefit of avoiding the Bot API is the ease to switch to user accounts instead of bots.
|
||||||
|
The MTProto API is the same for users and bots, so by using Telethon, you don't need to learn to use a second library.
|
||||||
|
|
||||||
|
|
||||||
|
Migrating from Bot API to Telethon
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
If the above points convinced you to switch to Telethon, the following short guides should help you make the switch!
|
||||||
|
|
||||||
|
It doesn't matter if you wrote your bot with `requests <https://pypi.org/project/requests/>`_
|
||||||
|
and you were making API requests manually, or if you used a wrapper library like
|
||||||
|
`python-telegram-bot <https://python-telegram-bot.readthedocs.io>`_
|
||||||
|
or `pyTelegramBotAPI <https://pytba.readthedocs.io/en/latest/index.html>`.
|
||||||
|
You will surely be pleased with Telethon!
|
||||||
|
|
||||||
|
If you were using an asynchronous library like `aiohttp <https://docs.aiohttp.org/en/stable>`_
|
||||||
|
or a wrapper like `aiogram <https://docs.aiohttp.org/en/stable>`_, the switch will be even easier.
|
||||||
|
|
||||||
|
|
||||||
|
Migrating from TODO
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
108
client/doc/concepts/chats.rst
Normal file
108
client/doc/concepts/chats.rst
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
Chats
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
The term :term:`chat` is extremely overloaded, so it's no surprise many are confused by what it means.
|
||||||
|
This section should hopefully clear that up.
|
||||||
|
|
||||||
|
|
||||||
|
Telethon Chat
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The word :term:`chat` in Telethon is used to refer a place where messages are sent to.
|
||||||
|
Therefore, a Telethon :term:`chat` can be another user, a bot, a group, or a broadcast channel.
|
||||||
|
All of those are places where messages can be sent.
|
||||||
|
|
||||||
|
Of course, chats do more things than contain messages.
|
||||||
|
They often have a name, username, photo, description, and other information.
|
||||||
|
|
||||||
|
When a :term:`chat` appears in a parameter or as a property,
|
||||||
|
it means that it will be either a :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||||
|
|
||||||
|
When a parameter must be "chat-like", it means Telethon will accept anything that can be "converted" to a :term:`chat`.
|
||||||
|
The following types are chat-like:
|
||||||
|
|
||||||
|
* The ``'me'`` literal string. This represents the account that is logged in ("yourself").
|
||||||
|
* An ``'@username'``. The at-sign ``@`` is optional. Note that links are not supported.
|
||||||
|
* An ``'+1 23'`` phone number string. It must be an ``str`` and start with the plus-sign ``+`` character.
|
||||||
|
* An ``123`` integer identifier. It must be an ``int`` and cannot be negative.
|
||||||
|
* An existing :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||||
|
* A :class:`~types.PackedChat`.
|
||||||
|
|
||||||
|
Previous versions of Telethon referred to this term as "entity" or "entities" instead.
|
||||||
|
|
||||||
|
|
||||||
|
Telegram Chat
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The Telegram API is very confusing when it comes to the word "chat".
|
||||||
|
You only need to know about this if you plan to use the :term:`Raw API`.
|
||||||
|
|
||||||
|
In the schema definitions, there are two boxed types, :tl:`User` and :tl:`Chat`.
|
||||||
|
A boxed :tl:`User` can only be the bare :tl:`user`, but the boxed :tl:`Chat` can be either a bare :tl:`chat` or a bare :tl:`channel`.
|
||||||
|
|
||||||
|
A bare :tl:`chat` always refers to small groups.
|
||||||
|
A bare :tl:`channel` can have either the ``broadcast`` or the ``megagroup`` flag set to ``True``.
|
||||||
|
|
||||||
|
A bare :tl:`channel` with the ``broadcast`` flag set to ``True`` is known as a broadcast channel.
|
||||||
|
A bare :tl:`channel` with the ``megagroup`` flag set to ``True`` is known as a supergroup.
|
||||||
|
|
||||||
|
A bare :tl:`chat` with has less features than a bare :tl:`channel` ``megagroup``.
|
||||||
|
Official clients are very good at hiding this difference.
|
||||||
|
They will implicitly convert bare :tl:`chat` to bare :tl:`channel` ``megagroup`` when doing certain operations.
|
||||||
|
Doing things like setting a username is actually a two-step process (migration followed by updating the username).
|
||||||
|
Official clients transparently merge the history of migrated :tl:`channel` with their old :tl:`chat`.
|
||||||
|
|
||||||
|
In Telethon:
|
||||||
|
|
||||||
|
* A :class:`~types.User` always corresponds to :tl:`user`.
|
||||||
|
* A :class:`~types.Group` represents either a :tl:`chat` or a :tl:`channel` ``megagroup``.
|
||||||
|
* A :class:`~types.Channel` represents a :tl:`channel` ``broadcast``.
|
||||||
|
|
||||||
|
Telethon classes aim to map to similar concepts in official applications.
|
||||||
|
|
||||||
|
|
||||||
|
Bot API chat
|
||||||
|
------------
|
||||||
|
|
||||||
|
The Bot API follows a certain convention when it comes to identifiers:
|
||||||
|
|
||||||
|
* User IDs are positive.
|
||||||
|
* Chat IDs are negative.
|
||||||
|
* Channel IDs are prefixed with ``-100``.
|
||||||
|
|
||||||
|
Telethon encourages the use of :class:`~types.PackedChat` instead of naked identifiers.
|
||||||
|
As a reminder, negative identifiers are not supported in Telethon's chat-like parameters.
|
||||||
|
|
||||||
|
|
||||||
|
Encountering chats
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The way you encounter chats in Telethon is no different from official clients.
|
||||||
|
If you:
|
||||||
|
|
||||||
|
* …have joined a group or channel, or have sent private messages to some user, you can :meth:`~Client.get_dialogs`.
|
||||||
|
* …know the user is in your contact list, you can :meth:`~Client.get_contacts`.
|
||||||
|
* …know the user has a common chat with you, you can :meth:`~Client.get_participants` of the chat in common.
|
||||||
|
* …know the username of the user, group, or channel, you can :meth:`~Client.resolve_username`.
|
||||||
|
* …are a bot responding to users, you will be able to access the :attr:`types.Message.sender`.
|
||||||
|
|
||||||
|
Chats access hash
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Users, supergroups and channels all need an :term:`access hash`.
|
||||||
|
|
||||||
|
In Telethon, the :class:`~types.PackedChat` is the recommended way to deal with the identifier-hash pairs.
|
||||||
|
This compact type can be used anywhere a chat is expected.
|
||||||
|
It's designed to be easy to store and cache in any way your application chooses.
|
||||||
|
|
||||||
|
Bot accounts can get away with an invalid :term:`access hash` for certain operations under certain conditions.
|
||||||
|
The same is true for user accounts, although to a lesser extent.
|
||||||
|
|
||||||
|
When using just the identifier to refer to a chat, Telethon will attempt to retrieve its hash from its in-memory cache.
|
||||||
|
If this fails, an invalid hash will be used. This may or may not make the API call succeed.
|
||||||
|
For this reason, it is recommended that you always use :class:`~types.PackedChat` instead.
|
||||||
|
|
||||||
|
Remember that an :term:`access hash` is account-bound.
|
||||||
|
You cannot obtain an :term:`access hash` in Account-A and use it in Account-B.
|
40
client/doc/concepts/errors.rst
Normal file
40
client/doc/concepts/errors.rst
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
RPC Errors
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
:term:`RPC` stands for Remote Procedure Call.
|
||||||
|
By extension, RPC Errors occur when a RPC fails to execute in the server.
|
||||||
|
In Telethon, a :term:`RPC error` corresponds to the :class:`RpcError` class.
|
||||||
|
|
||||||
|
Telethon will only ever raise :class:`RpcError` when the result to a :term:`RPC` is an error.
|
||||||
|
If the error is raised, you know it comes from Telegram.
|
||||||
|
Consequently, when using :term:`Raw API`, if a :class:`RpcError` occurs, it is never a bug in the library.
|
||||||
|
|
||||||
|
:term:`RPC error` consist of an integer :attr:`~RpcError.code` and a string :attr:`~RpcError.name`.
|
||||||
|
The :attr:`RpcError.code` is roughly the same as `HTTP status codes <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status>`_.
|
||||||
|
The :attr:`RpcError.name` is often a string in ``SCREAMING_CASE`` and refers to what went wrong.
|
||||||
|
|
||||||
|
Certain error names also contain an integer value.
|
||||||
|
This value is removed from the :attr:`~RpcError.name` and put into :attr:`RpcError.value`.
|
||||||
|
If Telegram responds with ``FLOOD_WAIT_60``, the name would be ``'FLOOD_WAIT'`` and the value ``60``.
|
||||||
|
|
||||||
|
A very common error is ``FLOOD_WAIT``.
|
||||||
|
It occurs when you have attempted to use a request too many times during a certain window of time:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from telethon import RpcError
|
||||||
|
|
||||||
|
try:
|
||||||
|
await client.send_message('me', 'Spam')
|
||||||
|
except RpcError as e:
|
||||||
|
# If we get a flood error, sleep. Else, propagate the error.
|
||||||
|
if e.name == 'FLOOD_WAIT':
|
||||||
|
await asyncio.sleep(e.value)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
Note that the library can automatically handle and retry on ``FLOOD_WAIT`` for you.
|
||||||
|
Refer to the ``flood_sleep_threshold`` of the :class:`Client` to learn how.
|
66
client/doc/concepts/full-api.rst
Normal file
66
client/doc/concepts/full-api.rst
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
The Full API
|
||||||
|
============
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
The API surface offered by Telethon is not exhaustive.
|
||||||
|
Telegram is constantly adding new features, and both implementing and documenting custom methods would an exhausting, never-ending job.
|
||||||
|
|
||||||
|
Telethon concedes to this fact and implements only commonly-used features to keep a lean API.
|
||||||
|
Access to the entirity of Telegram's API via Telethon's :term:`Raw API` is a necessary evil.
|
||||||
|
|
||||||
|
The ``telethon._tl`` module has a leading underscore to signal that it is private.
|
||||||
|
It is not covered by the semver guarantees of the library, but you may need to use it regardless.
|
||||||
|
If the :class:`Client` doesn't offer a method for what you need, using the :term:`Raw API` is inevitable.
|
||||||
|
|
||||||
|
|
||||||
|
Invoking Raw API methods
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The :term:`Raw API` can be *invoked* in a very similar way to other client methods:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import _tl as tl
|
||||||
|
|
||||||
|
was_reset = await client(tl.functions.account.reset_wall_papers())
|
||||||
|
|
||||||
|
Inside ``telethon._tl.functions`` you will find a function for every single :term:`RPC` supported by Telegram.
|
||||||
|
The parameters are keyword-only and do not have defaults.
|
||||||
|
Whatever arguments you pass is exactly what Telegram will receive.
|
||||||
|
Whatever is returned is exactly what Telegram responded with.
|
||||||
|
|
||||||
|
All functions inside ``telethon._tl.functions`` will return the serialized request.
|
||||||
|
When calling a :class:`Client` instance with this request as input, it will be sent to Telegram and wait for a response.
|
||||||
|
|
||||||
|
Multiple requests may be in-flight at the same time, specially when using :mod:`asyncio`.
|
||||||
|
Telethon will attempt to combine these into a single "container" when possible as an optimization.
|
||||||
|
|
||||||
|
|
||||||
|
Exploring the Raw API
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Everything under ``telethon._tl.types`` implements :func:`repr`.
|
||||||
|
This means you can print any response and get the Python representation of that object.
|
||||||
|
|
||||||
|
All types are proper classes with attributes.
|
||||||
|
You do not need to use a regular expression on the string representation to access the field you want.
|
||||||
|
|
||||||
|
Most :term:`RPC` return an abstract class from ``telethon._tl.abcs``.
|
||||||
|
To check for a concrete type, you can use :func:`isinstance`:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
invite = await client(tl.functions.messages.check_chat_invite(hash='aBcDeF'))
|
||||||
|
if isinstance(invite, tl.types.ChatInviteAlready):
|
||||||
|
print(invite.chat)
|
||||||
|
|
||||||
|
The ``telethon._tl`` module is not documented here because it would result in tens of megabytes.
|
||||||
|
Instead, there are multiple alternatives:
|
||||||
|
|
||||||
|
* Use Telethon's separate site to search in the `Telethon Raw API <https://tl.telethon.dev/>`_.
|
||||||
|
This is the recommended way. It also features auto-generated examples.
|
||||||
|
* Use Python's built-in :func:`help` and :func:`dir` to help you navigate the module.
|
||||||
|
* Use an editor with autocompletion support.
|
||||||
|
* Choose the right layer from `Telegram's official API Layers <https://core.telegram.org/api/layers>`_.
|
||||||
|
Note that the `TL Schema <https://core.telegram.org/schema>`_ might not be up-to-date.
|
42
client/doc/concepts/glossary.rst
Normal file
42
client/doc/concepts/glossary.rst
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
Glossary
|
||||||
|
========
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
:sorted:
|
||||||
|
|
||||||
|
chat
|
||||||
|
A :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||||
|
|
||||||
|
.. seealso:: The :doc:`../concepts/chats` concept.
|
||||||
|
|
||||||
|
Raw API
|
||||||
|
Functions and types under ``telethon._tl`` that enable access to all of Telegram's API.
|
||||||
|
|
||||||
|
.. seealso:: The :doc:`../concepts/full-api` concept.
|
||||||
|
|
||||||
|
access hash
|
||||||
|
Account-bound integer tied to a specific resource.
|
||||||
|
Users, channels, photos and documents are all resources with an access hash.
|
||||||
|
The access hash doesn't change, but every account will see a different value for the same resource.
|
||||||
|
|
||||||
|
RPC
|
||||||
|
Remote Procedure Call.
|
||||||
|
Invoked when calling a :class:`Client` with a function from ``telethon._tl.functions``.
|
||||||
|
|
||||||
|
RPC Error
|
||||||
|
Error type returned by Telegram.
|
||||||
|
:class:`RpcError` contains an integer code similar to HTTP status codes and a name.
|
||||||
|
|
||||||
|
.. seealso:: The :doc:`../concepts/errors` concept.
|
||||||
|
|
||||||
|
session
|
||||||
|
Data used to securely connect to Telegram and other state related to the logged-in account.
|
||||||
|
|
||||||
|
.. seealso:: The :doc:`../concepts/sessions` concept.
|
||||||
|
|
||||||
|
MTProto
|
||||||
|
Mobile Transport Protocol used to interact with Telegram's API.
|
||||||
|
|
||||||
|
.. seealso:: The :doc:`../concepts/botapi-vs-mtproto` concept.
|
55
client/doc/concepts/sessions.rst
Normal file
55
client/doc/concepts/sessions.rst
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
Sessions
|
||||||
|
========
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
In Telethon, the word :term:`session` is used to refer to the set of data needed to connect to Telegram.
|
||||||
|
This includes the server address of your home datacenter, as well as the authorization key bound to an account.
|
||||||
|
When you first connect to Telegram, an authorization key is generated to encrypt all communication.
|
||||||
|
After login, Telegram remembers this authorization key as logged-in, so you don't need to login again.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
**Do not leak the session file!**
|
||||||
|
Anyone with that file can login to the account stored in it.
|
||||||
|
If you believe someone else has obtained this file, immediately revoke all active sessions from an official client.
|
||||||
|
|
||||||
|
Some auxiliary information such as the user ID of the logged-in user is also kept.
|
||||||
|
|
||||||
|
The update state, which can change every time an update is received from Telegram, is also stored in the session.
|
||||||
|
Telethon needs this information to catch up on all missed updates while your code was not running.
|
||||||
|
This is why it's important to call :meth:`Client.disconnect`.
|
||||||
|
Doing so flushes all the update state to the session and saves it.
|
||||||
|
|
||||||
|
|
||||||
|
Session files
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Telethon defaults to using SQLite to store the session state.
|
||||||
|
The session state is written to ``.session`` files, so make sure your VCS ignores them!
|
||||||
|
To make sure the ``.session`` file is saved, you should call :meth:`Client.disconnect` before exiting the program.
|
||||||
|
|
||||||
|
The first parameter in the :class:`Client` constructor is the session to use.
|
||||||
|
You can use a `str`, a :class:`pathlib.Path` or a :class:`session.Storage`.
|
||||||
|
The string or path are relative to the Current Working Directory.
|
||||||
|
You can use absolute paths or relative paths to folders elsewhere.
|
||||||
|
The ``.session`` extension is automatically added if the path has no extension.
|
||||||
|
|
||||||
|
|
||||||
|
Session storages
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The :class:`session.Storage` abstract base class defines the required methods to create custom storages.
|
||||||
|
Telethon comes with two built-in storages:
|
||||||
|
|
||||||
|
* :class:`~session.SqliteSession`. This is used by default when a string or path is used.
|
||||||
|
* :class:`~session.MemorySession`. This is used by default when the path is ``None``.
|
||||||
|
You can also use it directly when you have a :class:`~session.Session` instance.
|
||||||
|
It's useful when you don't have file-system access.
|
||||||
|
|
||||||
|
If you would like to store the session state in a different way, you can subclass :class:`session.Storage`.
|
||||||
|
|
||||||
|
Some Python installations do not have the ``sqlite3`` module.
|
||||||
|
In this case, attempting to use the default :class:`~session.SqliteSession` will fail.
|
||||||
|
If this happens, you can try reinstalling Python.
|
||||||
|
If you still don't have the ``sqlite3`` module, you should use a different storage.
|
75
client/doc/concepts/updates.rst
Normal file
75
client/doc/concepts/updates.rst
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
Updates
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
Updates are an important topic in a messaging platform like Telegram.
|
||||||
|
After all, you want to be notified as soon as certain events happen, such as new message arrives.
|
||||||
|
|
||||||
|
Telethon abstracts away Telegram updates with :mod:`~telethon.events`.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
It is strongly advised to configure logging when working with events:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(
|
||||||
|
format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
|
||||||
|
level=logging.WARNING
|
||||||
|
)
|
||||||
|
|
||||||
|
With the above, you will see all warnings and errors and when they happened.
|
||||||
|
|
||||||
|
|
||||||
|
Filtering events
|
||||||
|
----------------
|
||||||
|
|
||||||
|
There is no way to tell Telegram to only send certain updates.
|
||||||
|
Telethon must be received and process all updates to ensure correct ordering.
|
||||||
|
|
||||||
|
Filters are not magic.
|
||||||
|
They work all the same as ``if`` conditions inside your event handlers.
|
||||||
|
However, they offer a more convenient and consistent way to check for certain conditions.
|
||||||
|
|
||||||
|
All built-in filters can be found in :mod:`telethon.events.filters`.
|
||||||
|
|
||||||
|
When registering an event handler, you can optionally define the filter to use.
|
||||||
|
You can retrieve a handler's filter with :meth:`~Client.get_handler_filter`.
|
||||||
|
You can set (and overwrite) a handler's filter with :meth:`~Client.set_handler_filter`.
|
||||||
|
|
||||||
|
Filters are meant to be fast and never raise exceptions.
|
||||||
|
For this reason, filters cannot be asynchronous.
|
||||||
|
This reduces the chance a filter will do slow IO and potentially fail.
|
||||||
|
|
||||||
|
A filter is simply a callable function that takes an event as input and returns a boolean.
|
||||||
|
If the filter returns ``True``, the handler will be called.
|
||||||
|
Using this knowledge, you can create custom filters too.
|
||||||
|
If you need state, you can use a class with a ``__call__`` method defined:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def only_odd_messages(event):
|
||||||
|
"A filter that only handles messages when their ID is divisible by 2"
|
||||||
|
return event.id % 2 == 0
|
||||||
|
|
||||||
|
client.add_event_handler(handler, events.NewMessage, only_odd_messages)
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
class OnlyDivisibleMessages:
|
||||||
|
"A filter that only handles messages when their ID is divisible by some amount"
|
||||||
|
def __init__(self, divisible_by):
|
||||||
|
self.divisible_by = divisible_by
|
||||||
|
|
||||||
|
def __call__(self, event):
|
||||||
|
return event.id % self.divisible_by == 0
|
||||||
|
|
||||||
|
client.add_event_handler(handler, events.NewMessage, OnlyDivisibleMessages(7))
|
||||||
|
|
||||||
|
Custom filters should accept any :class:`~events.Event`.
|
||||||
|
You can use :func:`isinstance` if your filter can only deal with certain types of events.
|
||||||
|
|
||||||
|
If you need to perform asynchronous operations, you can't use a filter.
|
||||||
|
Instead, manually check for those conditions inside your handler.
|
|
@ -3,6 +3,11 @@
|
||||||
# For the full list of built-in configuration values, see the documentation:
|
# For the full list of built-in configuration values, see the documentation:
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.curdir)) # for custom extensions
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
@ -14,11 +19,21 @@ release = "2.0.0a0"
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
# extensions = []
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
templates_path = ["_templates"]
|
"sphinx.ext.intersphinx",
|
||||||
# exclude_patterns = []
|
"sphinx.ext.graphviz",
|
||||||
|
"roles.tl",
|
||||||
|
]
|
||||||
|
|
||||||
|
intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)}
|
||||||
|
tl_ref_url = "https://tl.telethon.dev"
|
||||||
|
autodoc_default_options = {
|
||||||
|
"members": True,
|
||||||
|
"undoc-members": True,
|
||||||
|
}
|
||||||
|
modindex_common_prefix = ["telethon."]
|
||||||
|
graphviz_output_format = "svg"
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
8
client/doc/developing/changelog.rst
Normal file
8
client/doc/developing/changelog.rst
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Changelog (Version History)
|
||||||
|
===========================
|
||||||
|
|
||||||
|
|
||||||
|
v2 alpha
|
||||||
|
--------
|
||||||
|
|
||||||
|
WIP!
|
17
client/doc/developing/coding-style.rst
Normal file
17
client/doc/developing/coding-style.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Coding style
|
||||||
|
============
|
||||||
|
|
||||||
|
Knowledge of Python is a obviously a must to develop a Python library.
|
||||||
|
A good online resource is `Dive Into Python 3 <http://www.diveintopython3.net/>`_.
|
||||||
|
|
||||||
|
Telethon uses multiple tools to automatically format the code and check for linting rules.
|
||||||
|
This means you can simply ignore formatting and let the tools handle it for you.
|
||||||
|
You can find these tools under the ``tools/`` folder.
|
||||||
|
|
||||||
|
The documentation is written with mostly a newline after every period.
|
||||||
|
This is not a hard rule.
|
||||||
|
Lines can be cut earlier if they become too long to be comfortable.
|
||||||
|
|
||||||
|
Commit messages should be short and descriptive.
|
||||||
|
They should start with an action in the present ("Fix" and not "Fixed").
|
||||||
|
This saves a few characters and represents what the commit will "do" after applied.
|
4
client/doc/developing/migration-guide.rst
Normal file
4
client/doc/developing/migration-guide.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Migrating from v1 to v2
|
||||||
|
=======================
|
||||||
|
|
||||||
|
WIP!
|
10
client/doc/developing/philosophy.rst
Normal file
10
client/doc/developing/philosophy.rst
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Philosophy
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Dependencies should only be added when absolutely necessary.
|
||||||
|
* Dependencies written in anything other than Python cannot be mandatory.
|
||||||
|
* The library must work correctly with no system dependencies other than Python 3.
|
||||||
|
* Strict type-checking is required to pass everywhere in the library to make upgrades easier.
|
||||||
|
* The code structure must make use of hard and clear boundaries to keep the different parts decoupled.
|
||||||
|
* The API should cover only the most commonly used features to avoid bloat and reduce maintenance costs.
|
||||||
|
* Documentation must be a pleasure to use and contain plenty of code examples.
|
95
client/doc/developing/project-structure.rst
Normal file
95
client/doc/developing/project-structure.rst
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
Project Structure
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. currentmodule:: telethon
|
||||||
|
|
||||||
|
The repository contains several folders, each with their own "package".
|
||||||
|
|
||||||
|
|
||||||
|
benches/
|
||||||
|
--------
|
||||||
|
|
||||||
|
This folder contains different benchmarks.
|
||||||
|
Pretty straightforward.
|
||||||
|
|
||||||
|
|
||||||
|
stubs/
|
||||||
|
------
|
||||||
|
|
||||||
|
If a dependency doesn't support typing, files here must work around that.
|
||||||
|
|
||||||
|
|
||||||
|
tools/
|
||||||
|
------
|
||||||
|
|
||||||
|
Various utility scripts.
|
||||||
|
Each script should have a "comment" at the top explaining what they are for.
|
||||||
|
|
||||||
|
See ``DEVELOPING.md`` in the repository root to learn how to use some of the tools.
|
||||||
|
|
||||||
|
|
||||||
|
generator/
|
||||||
|
----------
|
||||||
|
|
||||||
|
A package that should not be published and is only used when developing the library.
|
||||||
|
The implementation is private and exists under the ``src/*/_impl/`` folder.
|
||||||
|
Only select parts are exported under public modules.
|
||||||
|
Tests live under ``tests/``.
|
||||||
|
|
||||||
|
The implementation consists of a parser and a code generator.
|
||||||
|
|
||||||
|
The parser is able to read parse ``.tl`` files (Type-Language definition files).
|
||||||
|
It doesn't do anything with the files other than to represent the content as Python objects.
|
||||||
|
|
||||||
|
The code generator uses the parsed definitions to generate Python code.
|
||||||
|
Most of the code to serialize and deserialize objects lives under ``serde/``.
|
||||||
|
|
||||||
|
An in-memory "filesystem" structure is kept before writing all files to disk.
|
||||||
|
This makes it possible to execute most of the process in a sans-io manner.
|
||||||
|
Once the code generation finishes, all files are written to disk at once.
|
||||||
|
|
||||||
|
See ``DEVELOPING.md`` in the repository root to learn how to generate code.
|
||||||
|
|
||||||
|
|
||||||
|
client/
|
||||||
|
-------
|
||||||
|
|
||||||
|
The Telethon client library and documentation lives here.
|
||||||
|
This is the package that gets published.
|
||||||
|
The implementation is private and exists under the ``src/*/_impl/`` folder.
|
||||||
|
Only select parts are exported under public modules.
|
||||||
|
Tests live under ``tests/``.
|
||||||
|
|
||||||
|
The client implementation consists of several subpackages.
|
||||||
|
|
||||||
|
The ``tl`` package sits at the bottom.
|
||||||
|
It is where the generated code is placed.
|
||||||
|
It also contains some of the definitions needed for the generated code to work.
|
||||||
|
Even though all the :term:`RPC` live here, this package can't do anything by itself.
|
||||||
|
|
||||||
|
The ``crypto`` package implements all the encryption and decryption rules used by Telegram.
|
||||||
|
Details concerning the :term:`MTProto` are mostly avoided, so the package can be generally useful.
|
||||||
|
|
||||||
|
The ``mtproto`` package implements the logic required to talk to Telegram.
|
||||||
|
It is implemented in a sans-io manner.
|
||||||
|
This package is responsible for generating an authorization key and serializing packets.
|
||||||
|
It also contains some optimizations which are not strictly necessary when implementing the library.
|
||||||
|
|
||||||
|
The ``mtsender`` package simply adds IO to ``mtproto``.
|
||||||
|
It is responsible for driving the network, enqueuing requests, and waiting for results.
|
||||||
|
|
||||||
|
The ``session`` crate implements what's needed to manage the :term:`session` state.
|
||||||
|
The logic to handle and correctly order updates also lives here, in a sans-io manner.
|
||||||
|
|
||||||
|
The ``client`` ties everything together.
|
||||||
|
This is what defines the Pythonic API to interact with Telegram.
|
||||||
|
Custom object and event types also live here.
|
||||||
|
|
||||||
|
Even though only common methods are implemented, the code is still huge.
|
||||||
|
For this reason, the :class:`Client` implementation is separated from the class definition.
|
||||||
|
The class definition only contains documentation and calls functions defined in other files.
|
||||||
|
A tool under ``tools/`` exists to make it easy to keep these two in sync.
|
||||||
|
|
||||||
|
If you plan to port the library to a different language, good luck!
|
||||||
|
You will need a code generator, the ``crypto``, ``mtproto`` and ``mtsender`` packages to have an initial working version.
|
||||||
|
The tests are your friend, write them too!
|
|
@ -1,15 +1,126 @@
|
||||||
Telethon's documentation
|
.. |svglogo| image:: ../../logo.svg
|
||||||
========================
|
:width: 24pt
|
||||||
|
:height: 24pt
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. highlights:: |svglogo| **Welcome to Telethon's documentation!**
|
||||||
|
|
||||||
|
.. only:: not html
|
||||||
|
|
||||||
|
.. highlights:: **Welcome to Telethon's documentation!**
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from telethon import Client, events
|
||||||
|
from telethon.events import filters
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with Client('name', api_id, api_hash) as client:
|
||||||
|
me = await client.interactive_login()
|
||||||
|
await client.send_message(me, f'Hello, {me.full_name}!')
|
||||||
|
|
||||||
|
@client.on(events.NewMessage, filters.Text(r'(?i)hello'))
|
||||||
|
async def handler(event):
|
||||||
|
await event.reply('Hey!')
|
||||||
|
|
||||||
|
await client.run_until_disconnected()
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
|
|
||||||
|
* Are you new here? Jump straight into :doc:`basic/installation`!
|
||||||
|
* Looking for the Client API reference? See :doc:`modules/client`.
|
||||||
|
* Did you upgrade the library? Please read :doc:`developing/changelog`.
|
||||||
|
* Coming from Bot API or want to create new bots? See :doc:`concepts/botapi-vs-mtproto`.
|
||||||
|
* Used Telethon before v2.0? See :doc:`developing/migration-guide`.
|
||||||
|
* Want to hack away with the raw API? Search in `Telethon Raw API <https://tl.telethon.dev/>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Preface
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. rubric:: What is this?
|
||||||
|
|
||||||
|
Telegram is a popular messaging application.
|
||||||
|
This library is meant to make it easy for you to write Python programs that can interact with Telegram.
|
||||||
|
Think of it as a wrapper that has already done the hard work for you, so you can focus on developing an application.
|
||||||
|
|
||||||
|
|
||||||
|
.. rubric:: How should I use the documentation?
|
||||||
|
|
||||||
|
This documentation is divided in multiple sections. The first few sections are a guide, while others contain the API reference or a glossary of terms.
|
||||||
|
The documentation assumes some familiarity with Python.
|
||||||
|
|
||||||
|
If you are getting started with the library, you should follow the documentation in order by pressing the "Next" button at the bottom-right of every page.
|
||||||
|
|
||||||
|
You can also use the menu on the left to quickly skip over sections if you're looking for something in particular or want to continue where you left off.
|
||||||
|
|
||||||
|
|
||||||
|
First steps
|
||||||
|
===========
|
||||||
|
|
||||||
|
In this section you will learn how to install the library and login to your Telegram account.
|
||||||
|
|
||||||
|
:doc:`‣ Start reading Installation <basic/installation>`
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Contents:
|
:caption: First steps
|
||||||
|
|
||||||
|
basic/installation
|
||||||
|
basic/signing-in
|
||||||
|
basic/next-steps
|
||||||
|
|
||||||
|
|
||||||
|
API reference
|
||||||
|
=============
|
||||||
|
|
||||||
Indices and tables
|
This section contains all the functions and types offered by the library.
|
||||||
==================
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
:doc:`‣ Start reading Client API <modules/client>`
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
:caption: API reference
|
||||||
|
|
||||||
|
modules/client
|
||||||
|
modules/events
|
||||||
|
modules/types
|
||||||
|
modules/sessions
|
||||||
|
|
||||||
|
Concepts
|
||||||
|
========
|
||||||
|
|
||||||
|
A more in-depth explanation of some of the concepts and words used in Telethon.
|
||||||
|
|
||||||
|
:doc:`‣ Start reading Chat concept <concepts/chats>`
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
:caption: Concepts
|
||||||
|
|
||||||
|
concepts/chats
|
||||||
|
concepts/updates
|
||||||
|
concepts/sessions
|
||||||
|
concepts/errors
|
||||||
|
concepts/botapi-vs-mtproto
|
||||||
|
concepts/full-api
|
||||||
|
concepts/glossary
|
||||||
|
|
||||||
|
Developing
|
||||||
|
==========
|
||||||
|
|
||||||
|
Tips and tricks to develop both with the library and for the library.
|
||||||
|
|
||||||
|
:doc:`‣ Start reading Changelog <developing/changelog>`
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
:caption: Developing
|
||||||
|
|
||||||
|
developing/changelog
|
||||||
|
developing/migration-guide
|
||||||
|
developing/philosophy.rst
|
||||||
|
developing/coding-style.rst
|
||||||
|
developing/project-structure.rst
|
||||||
|
|
4
client/doc/modules/client.rst
Normal file
4
client/doc/modules/client.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Client
|
||||||
|
======
|
||||||
|
|
||||||
|
.. autoclass:: telethon.Client
|
12
client/doc/modules/events.rst
Normal file
12
client/doc/modules/events.rst
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Events and filters
|
||||||
|
==================
|
||||||
|
|
||||||
|
Events
|
||||||
|
------
|
||||||
|
|
||||||
|
.. automodule:: telethon.events
|
||||||
|
|
||||||
|
Filters
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. automodule:: telethon.events.filters
|
4
client/doc/modules/sessions.rst
Normal file
4
client/doc/modules/sessions.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Session storages
|
||||||
|
================
|
||||||
|
|
||||||
|
.. automodule:: telethon.session
|
6
client/doc/modules/types.rst
Normal file
6
client/doc/modules/types.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Types
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. automodule:: telethon.types
|
||||||
|
|
||||||
|
.. autoclass:: telethon.RpcError
|
34
client/doc/roles/tl.py
Normal file
34
client/doc/roles/tl.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from docutils import nodes, utils
|
||||||
|
from docutils.parsers.rst.roles import set_classes
|
||||||
|
|
||||||
|
|
||||||
|
def make_link_node(rawtext, app, name, options):
|
||||||
|
try:
|
||||||
|
base = app.config.tl_ref_url
|
||||||
|
if not base:
|
||||||
|
raise AttributeError
|
||||||
|
except AttributeError as e:
|
||||||
|
raise ValueError("tl_ref_url config value is not set") from e
|
||||||
|
|
||||||
|
if base[-1] != "/":
|
||||||
|
base += "/"
|
||||||
|
|
||||||
|
set_classes(options)
|
||||||
|
node = nodes.reference(
|
||||||
|
rawtext, utils.unescape(name), refuri="{}?q={}".format(base, name), **options
|
||||||
|
)
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def tl_role(name, rawtext, text, lineno, inliner, options=None, content=None):
|
||||||
|
if options is None:
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
app = inliner.document.settings.env.app
|
||||||
|
node = make_link_node(rawtext, app, text, options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_role("tl", tl_role)
|
||||||
|
app.add_config_value("tl_ref_url", None, "env")
|
|
@ -28,9 +28,16 @@ dynamic = ["version"]
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
cryptg = ["cryptg~=0.4"]
|
cryptg = ["cryptg~=0.4"]
|
||||||
dev = [
|
dev = [
|
||||||
|
"isort~=5.12",
|
||||||
|
"black~=23.3.0",
|
||||||
|
"mypy~=1.3",
|
||||||
"pytest~=7.3",
|
"pytest~=7.3",
|
||||||
"pytest-asyncio~=0.21",
|
"pytest-asyncio~=0.21",
|
||||||
]
|
]
|
||||||
|
doc = [
|
||||||
|
"sphinx_rtd_theme~=1.2",
|
||||||
|
"types-docutils~=0.20",
|
||||||
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
"Homepage" = "https://telethon.dev/"
|
"Homepage" = "https://telethon.dev/"
|
||||||
|
@ -43,4 +50,4 @@ requires = ["setuptools>=61.0"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[tool.setuptools.dynamic]
|
[tool.setuptools.dynamic]
|
||||||
version = {attr = "telethon.__version__"}
|
version = {attr = "telethon.version.__version__"}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user