Revisit documentation, cross-references and unnecessary indents

This commit is contained in:
Lonami Exo 2018-06-20 11:05:33 +02:00
parent 1b7e7320a4
commit c85ba4accc
20 changed files with 651 additions and 522 deletions

View File

@ -11,11 +11,11 @@ Accessing the Full API
reason not to, like a method not existing or you wanting more control.
The `telethon.telegram_client.TelegramClient` 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.
The :ref:`TelegramClient <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.
.. note::
@ -30,7 +30,8 @@ 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.
Say `telethon.telegram_client.TelegramClient.send_message` didn't exist,
Say `client.send_message
<telethon.client.messages.MessageMethods.send_message>` didn't exist,
we could use the `search`__ to look for "message". There we would find
:tl:`SendMessageRequest`, which we can work with.
@ -39,13 +40,13 @@ 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:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import SendMessageRequest
If you're going to use a lot of these, you may do:
.. code-block:: python
.. code-block:: python
from telethon.tl import types, functions
# We now have access to 'functions.messages.SendMessageRequest'
@ -57,26 +58,28 @@ of type :tl:`InputPeer`, and a ``message`` which is just a Python
How can we retrieve this :tl:`InputPeer`? We have two options. We manually
construct one, for instance:
.. code-block:: python
.. code-block:: python
from telethon.tl.types import InputPeerUser
peer = InputPeerUser(user_id, user_hash)
Or we call `telethon.telegram_client.TelegramClient.get_input_entity()`:
Or we call `client.get_input_entity
<telethon.client.users.UserMethods.get_input_entity>`:
.. code-block:: python
.. code-block:: python
peer = client.get_input_entity('someone')
When you're going to invoke an API method, most require you to pass an
:tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
``.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 user, use
`telethon.telegram_client.TelegramClient.get_entity()` instead:
`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
user, use `client.get_entity <telethon.client.users.UserMethods.get_entity>`
instead:
.. code-block:: python
.. code-block:: python
entity = client.get_entity('someone')
@ -85,7 +88,7 @@ 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
every time its used, simply call `telethon.utils.get_input_peer`:
.. code-block:: python
.. code-block:: python
from telethon import utils
peer = utils.get_input_user(entity)
@ -94,15 +97,18 @@ every time its used, simply call `telethon.utils.get_input_peer`:
.. note::
Since ``v0.16.2`` this is further simplified. The ``Request`` itself
will call ``client.get_input_entity()`` for you when required, but
it's good to remember what's happening.
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 ``.get_entity`` versus
``.get_input_entity``, we have everything we need. To ``.invoke()`` our
After this small parenthesis about `client.get_entity
<telethon.client.users.UserMethods.get_entity>` versus
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`,
we have everything we need. To invoke our
request we do:
.. code-block:: python
.. code-block:: python
result = client(SendMessageRequest(peer, 'Hello there!'))
# __call__ is an alias for client.invoke(request). Both will work
@ -111,7 +117,7 @@ Message sent! Of course, this is only an example. There are nearly 250
methods available as of layer 73, and you can use every single of them
as you wish. Remember to use the right types! To sum up:
.. code-block:: python
.. code-block:: python
result = client(SendMessageRequest(
client.get_input_entity('username'), 'Hello there!'
@ -120,7 +126,7 @@ as you wish. Remember to use the right types! To sum up:
This can further be simplified to:
.. code-block:: python
.. code-block:: python
result = client(SendMessageRequest('username', 'Hello there!'))
# Or even

View File

@ -4,7 +4,8 @@
Session Files
==============
The first parameter you pass to the constructor of the ``TelegramClient`` is
The first parameter you pass to the constructor of the
:ref:`TelegramClient <telethon-client>` is
the ``session``, and defaults to be the session name (or full path). That is,
if you create a ``TelegramClient('anon')`` instance and connect, an
``anon.session`` file will be created in the working directory.
@ -42,7 +43,8 @@ If you don't want to use the default SQLite session storage, you can also use
one of the other implementations or implement your own storage.
To use a custom session storage, simply pass the custom session instance to
``TelegramClient`` instead of the session name.
:ref:`TelegramClient <telethon-client>` instead of
the session name.
Telethon contains two implementations of the abstract ``Session`` class:

View File

@ -24,7 +24,7 @@ Once that's ready, the next step is to create a ``TelegramClient``.
This class will be your main interface with Telegram's API, and creating
one is very simple:
.. code-block:: python
.. code-block:: python
from telethon import TelegramClient
@ -46,19 +46,37 @@ your disk. This is by default a database file using Python's ``sqlite3``.
creates the file in your working directory, but absolute paths work too.
.. important::
The process shown here shows how to sign in *manually*. You **should**
use `client.start() <telethon.client.auth.AuthMethods.start>` instead
unless you have a better reason not to (e.g. you need more control):
.. code-block:: python
client.start()
This is explained after going through the manual process.
Before using the client, you must be connected to Telegram.
Doing so is very easy:
``client.connect() # Must return True, otherwise, try again``
.. code-block:: python
client.connect() # Must return True, otherwise, try again
You may or may not be authorized yet. You must be authorized
before you're able to send any request:
``client.is_user_authorized() # Returns True if you can send requests``
.. code-block:: python
If you're not authorized, you need to ``.sign_in()``:
client.is_user_authorized() # Returns True if you can send requests
.. code-block:: python
If you're not authorized, you need to `.sign_in
<telethon.client.auth.AuthMethods.sign_in>`:
.. code-block:: python
phone_number = '+34600000000'
client.send_code_request(phone_number)
@ -82,7 +100,7 @@ mentioned ``.stringify()`` method, and printing these might prove useful.
As a full example:
.. code-block:: python
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
assert client.connect()
@ -91,15 +109,17 @@ As a full example:
me = client.sign_in(phone_number, input('Enter code: '))
All of this, however, can be done through a call to ``.start()``:
All of this, however, can be done through a call to `.start()
<telethon.client.auth.AuthMethods.start>`:
.. code-block:: python
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
client.start()
The code shown is just what ``.start()`` will be doing behind the scenes
The code shown is just what `.start()
<telethon.client.auth.AuthMethods.start>` will be doing behind the scenes
(with a few extra checks), so that you know how to sign in case you want
to avoid using ``input()`` (the default) for whatever reason. If no phone
or bot token is provided, you will be asked one through ``input()``. The
@ -108,13 +128,15 @@ method also accepts a ``phone=`` and ``bot_token`` parameters.
You can use either, as both will work. Determining which
is just a matter of taste, and how much control you need.
Remember that you can get yourself at any time with ``client.get_me()``.
Remember that you can get yourself at any time with `client.get_me()
<telethon.client.users.UserMethods.get_me>`.
.. warning::
Please note that if you fail to login around 5 times (or change the first
parameter of the ``TelegramClient``, which is the session name) you will
receive a ``FloodWaitError`` of around 22 hours, so be careful not to mess
this up! This shouldn't happen if you're doing things as explained, though.
parameter of the :ref:`TelegramClient <telethon-client>`, which is the session
name) you will receive a ``FloodWaitError`` of around 22 hours, so be
careful not to mess this up! This shouldn't happen if you're doing things
as explained, though.
.. note::
If you want to use a **proxy**, you have to `install PySocks`__
@ -137,11 +159,12 @@ Two Factor Authorization (2FA)
******************************
If you have Two Factor Authorization (from now on, 2FA) enabled on your
account, calling :meth:`telethon.TelegramClient.sign_in` will raise a
``SessionPasswordNeededError``. When this happens, just
:meth:`telethon.TelegramClient.sign_in` again with a ``password=``:
account, calling `.sign_in()
<telethon.client.auth.AuthMethods.sign_in>` will raise a
``SessionPasswordNeededError``. When this happens, just use the method
again with a ``password=``:
.. code-block:: python
.. code-block:: python
import getpass
from telethon.errors import SessionPasswordNeededError
@ -153,19 +176,23 @@ account, calling :meth:`telethon.TelegramClient.sign_in` will raise a
client.sign_in(password=getpass.getpass())
The mentioned ``.start()`` method will handle this for you as well, but
you must set the ``password=`` parameter beforehand (it won't be asked).
The mentioned `.start()
<telethon.client.auth.AuthMethods.start>` method will handle this for you as
well, but you must set the ``password=`` parameter beforehand (it won't be
asked).
If you don't have 2FA enabled, but you would like to do so through the
library, use `client.edit_2fa()
<telethon.client.auth.AuthMethods.edit_2fa>`.
If you don't have 2FA enabled, but you would like to do so through the library,
use ``client.edit_2fa()``.
Be sure to know what you're doing when using this function and
you won't run into any problems.
Take note that if you want to set only the email/hint and leave
the current password unchanged, you need to "redo" the 2fa.
you won't run into any problems. Take note that if you want to
set only the email/hint and leave the current password unchanged,
you need to "redo" the 2fa.
See the examples below:
.. code-block:: python
.. code-block:: python
from telethon.errors import EmailUnconfirmedError

View File

@ -22,9 +22,9 @@ in response to certain methods, such as :tl:`GetUsersRequest`.
To "encounter" an ID, you would have to "find it" like you would in the
normal app. If the peer is in your dialogs, you would need to
`client.get_dialogs() <telethon.telegram_client.TelegramClient.get_dialogs>`.
`client.get_dialogs() <telethon.client.dialogs.DialogMethods.get_dialogs>`.
If the peer is someone in a group, you would similarly
`client.get_participants(group) <telethon.telegram_client.TelegramClient.get_participants>`.
`client.get_participants(group) <telethon.client.chats.ChatMethods.get_participants>`.
Once you have encountered an ID, the library will (by default) have saved
their ``access_hash`` for you, which is needed to invoke most methods.
@ -69,9 +69,11 @@ you're able to just do this:
my_channel = client.get_entity(PeerChannel(some_id))
All methods in the :ref:`telegram-client` call ``.get_input_entity()`` prior
All methods in the :ref:`telegram-client` call `.get_input_entity()
<telethon.client.users.UserMethods.get_input_entity>` prior
to sending the requst to save you from the hassle of doing so manually.
That way, convenience calls such as ``client.send_message('lonami', 'hi!')``
That way, convenience calls such as `client.send_message('lonami', 'hi!')
<telethon.client.messages.MessageMethods.send_message>`
become possible.
Every entity the library encounters (in any response to any call) will by
@ -88,8 +90,10 @@ Entities vs. Input Entities
Don't worry if you don't understand this section, just remember some
of the details listed here are important. When you're calling a method,
don't call ``.get_entity()`` beforehand, just use the username or phone,
or the entity retrieved by other means like ``.get_dialogs()``.
don't call `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
beforehand, just use the username or phone, or the entity retrieved by
other means like `client.get_dialogs()
<telethon.client.dialogs.DialogMethods.get_dialogs>`.
On top of the normal types, the API also make use of what they call their
@ -108,21 +112,27 @@ before you can "use them".
As we just mentioned, API calls don't need to know the whole information
about the entities, only their ID and hash. For this reason, another method,
``.get_input_entity()`` is available. This will always use the cache while
possible, making zero API calls most of the time. When a request is made,
if you provided the full entity, e.g. an :tl:`User`, the library will convert
it to the required :tl:`InputPeer` automatically for you.
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
is available. This will always use the cache while possible, making zero API
calls most of the time. When a request is made, if you provided the full
entity, e.g. an :tl:`User`, the library will convert it to the required
:tl:`InputPeer` automatically for you.
**You should always favour** ``.get_input_entity()`` **over** ``.get_entity()``
**You should always favour**
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
**over**
`client.get_entity() <telethon.client.users.UserMethods.get_entity>`
for this reason! Calling the latter will always make an API call to get
the most recent information about said entity, but invoking requests don't
need this information, just the ``InputPeer``. Only use ``.get_entity()``
need this information, just the :tl:`InputPeer`. Only use
`client.get_entity() <telethon.client.users.UserMethods.get_entity>`
if you need to get actual information, like the username, name, title, etc.
of the entity.
To further simplify the workflow, since the version ``0.16.2`` of the
library, the raw requests you make to the API are also able to call
``.get_input_entity`` wherever needed, so you can even do things like:
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
wherever needed, so you can even do things like:
.. code-block:: python

View File

@ -9,15 +9,17 @@ Getting Started
Simple Installation
*******************
``pip3 install telethon``
.. code-block:: sh
**More details**: :ref:`installation`
pip3 install telethon
**More details**: :ref:`installation`
Creating a client
*****************
.. code-block:: python
.. code-block:: python
from telethon import TelegramClient
@ -29,13 +31,13 @@ Creating a client
client = TelegramClient('session_name', api_id, api_hash)
client.start()
**More details**: :ref:`creating-a-client`
**More details**: :ref:`creating-a-client`
Basic Usage
***********
.. code-block:: python
.. code-block:: python
# Getting information about yourself
print(client.get_me().stringify())
@ -63,15 +65,15 @@ Basic Usage
messages = client.get_messages('username')
client.download_media(messages[0])
**More details**: :ref:`telegram-client`
**More details**: :ref:`telegram-client`
See :ref:`telethon-client` for all available friendly methods.
See :ref:`telethon-client` for all available friendly methods.
Handling Updates
****************
.. code-block:: python
.. code-block:: python
from telethon import events
@ -85,7 +87,7 @@ Handling Updates
# If you want to handle updates you can't let the script end.
input('Press enter to exit.')
**More details**: :ref:`working-with-updates`
**More details**: :ref:`working-with-updates`
----------

View File

@ -10,18 +10,22 @@ Automatic Installation
To install Telethon, simply do:
``pip3 install telethon``
.. code-block:: sh
pip3 install telethon
Needless to say, you must have Python 3 and PyPi installed in your system.
See https://python.org and https://pypi.python.org/pypi/pip for more.
If you already have the library installed, upgrade with:
``pip3 install --upgrade telethon``
.. code-block:: sh
pip3 install --upgrade telethon
You can also install the library directly from GitHub or a fork:
.. code-block:: sh
.. code-block:: sh
# pip3 install git+https://github.com/LonamiWebs/Telethon.git
or
@ -38,7 +42,9 @@ which can be really slow when uploading or downloading files. If you don't
mind using a C extension, install `cryptg <https://github.com/Lonami/cryptg>`__
via ``pip`` or as an extra:
``pip3 install telethon[cryptg]``
.. code-block:: sh
pip3 install telethon[cryptg]
Manual Installation
@ -47,14 +53,27 @@ Manual Installation
1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and
``rsa`` (`GitHub`__ | `PyPi`__) modules:
``sudo -H pip3 install pyaes rsa``
.. code-block:: sh
pip3 install pyaes rsa
2. Clone Telethon's GitHub repository:
``git clone https://github.com/LonamiWebs/Telethon.git``
3. Enter the cloned repository: ``cd Telethon``
.. code-block:: sh
4. Run the code generator: ``python3 setup.py gen tl errors``
git clone https://github.com/LonamiWebs/Telethon.git
3. Enter the cloned repository:
.. code-block:: sh
cd Telethon
4. Run the code generator:
.. code-block:: sh
python3 setup.py gen
5. Done!

View File

@ -15,9 +15,9 @@ Introduction
available methods are in the :ref:`telethon-client` reference, including
detailed descriptions to what they do.
The ``TelegramClient`` is the central class of the library, the one
you will be using most of the time. For this reason, it's important
to know what it offers.
The :ref:`TelegramClient <telethon-client>` is the
central class of the library, the one you will be using most of the time. For
this reason, it's important to know what it offers.
Since we're working with Python, one must not forget that we can do
``help(client)`` or ``help(TelegramClient)`` at any time for a more
@ -27,12 +27,14 @@ methods for any object, even yours!
Interacting with the Telegram API is done through sending **requests**,
this is, any "method" listed on the API. There are a few methods (and
growing!) on the ``TelegramClient`` class that abstract you from the
need of manually importing the requests you need.
growing!) on the :ref:`TelegramClient <telethon-client>` class that abstract
you from the need of manually importing the requests you need.
For instance, retrieving your own user can be done in a single line:
``myself = client.get_me()``
.. code-block:: python
myself = client.get_me()
Internally, this method has sent a request to Telegram, who replied with
the information about your own user, and then the desired information
@ -42,7 +44,7 @@ If you want to retrieve any other user, chat or channel (channels are a
special subset of chats), you want to retrieve their "entity". This is
how the library refers to either of these:
.. code-block:: python
.. code-block:: python
# The method will infer that you've passed an username
# It also accepts phone numbers, and will get the user
@ -55,7 +57,7 @@ a good way to get information about an user, chat or channel.
Many other common methods for quick scripts are also available:
.. code-block:: python
.. code-block:: python
# Note that you can use 'me' or 'self' to message yourself
client.send_message('username', 'Hello World from Telethon!')
@ -91,9 +93,9 @@ Available methods
*****************
The :ref:`reference <telethon-package>` lists all the "handy" methods
available for you to use in the ``TelegramClient`` class. These are simply
wrappers around the "raw" Telegram API, making it much more manageable and
easier to work with.
available for you to use in the :ref:`TelegramClient <telethon-client>` class.
These are simply wrappers around the "raw" Telegram API, making it much more
manageable and easier to work with.
Please refer to :ref:`accessing-the-full-api` if these aren't enough,
and don't be afraid to read the source code of the InteractiveTelegramClient_

View File

@ -5,21 +5,27 @@ Working with Updates
====================
The library comes with the :mod:`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
usage when dealing with them, since there are many updates. If you're looking
for the method reference, check :ref:`telethon-events-package`, otherwise,
let's dive in!
.. note::
.. important::
The library logs by default no output, and any exception that occurs
inside your handlers will be "hidden" from you to prevent the thread
from terminating (so it can still deliver events). You should enable
logging (``import logging; logging.basicConfig(level=logging.ERROR)``)
when working with events, at least the error level, to see if this is
happening so you can debug the error.
logging when working with events, at least the error level, to see if
this is happening so you can debug the error.
**When using updates, please enable logging:**
.. code-block:: python
import logging
logging.basicConfig(level=logging.ERROR)
.. contents::
@ -62,7 +68,8 @@ Nothing we don't know already.
This Python decorator will attach itself to the ``my_event_handler``
definition, and basically means that *on* a ``NewMessage`` *event*,
definition, and basically means that *on* a `NewMessage
<telethon.events.newmessage.NewMessage>` *event*,
the callback function you're about to define will be called:
.. code-block:: python
@ -72,8 +79,10 @@ the callback function you're about to define will be called:
event.reply('hi!')
If a ``NewMessage`` event occurs, and ``'hello'`` is in the text of the
message, we ``reply`` to the event with a ``'hi!'`` message.
If a `NewMessage
<telethon.events.newmessage.NewMessage>` event occurs,
and ``'hello'`` is in the text of the message, we ``reply`` to the event
with a ``'hi!'`` message.
.. code-block:: python
@ -88,10 +97,11 @@ do other things instead idling. For this refer to :ref:`update-modes`.
More on events
**************
The ``NewMessage`` event has much more than what was shown. You can access
the ``.sender`` of the message through that member, or even see if the message
had ``.media``, a ``.photo`` or a ``.document`` (which you could download with
for example ``client.download_media(event.photo)``.
The `NewMessage <telethon.events.newmessage.NewMessage>` event has much
more than what was shown. You can access the ``.sender`` of the message
through that member, or even see if the message had ``.media``, a ``.photo``
or a ``.document`` (which you could download with for example
`client.download_media(event.photo) <telethon.client.downloads.DownloadMethods.download_media>`.
If you don't want to ``.reply`` as a reply, you can use the ``.respond()``
method instead. Of course, there are more events such as ``ChatAction`` or
@ -102,15 +112,16 @@ instance, ``NewMessage.Event``), except for the ``Raw`` event which just
passes the ``Update`` object.
Note that ``.reply()`` and ``.respond()`` are just wrappers around the
``client.send_message()`` method which supports the ``file=`` parameter.
This means you can reply with a photo if you do ``client.reply(file=photo)``.
`client.send_message() <telethon.client.messages.MessageMethods.send_message>`
method which supports the ``file=`` parameter.
This means you can reply with a photo if you do ``event.reply(file=photo)``.
You can put the same event on many handlers, and even different events on
the same handler. You can also have a handler work on only specific chats,
for example:
.. code-block:: python
.. code-block:: python
import ast
import random
@ -143,15 +154,20 @@ solution. Try it!
Events without decorators
*************************
If for any reason you can't use the ``@client.on`` syntax, don't worry.
You can call ``client.add_event_handler(callback, event)`` to achieve
If for any reason you can't use the `@client.on
<telethon.client.updates.UpdateMethods.on>` syntax, don't worry.
You can call `client.add_event_handler(callback, event)
<telethon.client.updates.UpdateMethods.add_event_handler>` to achieve
the same effect.
Similar to that method, you also have :meth:`client.remove_event_handler`
and :meth:`client.list_event_handlers` which do as they names indicate.
Similarly, you also have `client.remove_event_handler
<telethon.client.updates.UpdateMethods.remove_event_handler>`
and `client.list_event_handlers
<telethon.client.updates.UpdateMethods.list_event_handlers>`.
The ``event`` type is optional in all methods and defaults to ``events.Raw``
for adding, and ``None`` when removing (so all callbacks would be removed).
The ``event`` type is optional in all methods and defaults to
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
removing (so all callbacks would be removed).
Stopping propagation of Updates
@ -159,8 +175,8 @@ Stopping propagation of Updates
There might be cases when an event handler is supposed to be used solitary and
it makes no sense to process any other handlers in the chain. For this case,
it is possible to raise a ``StopPropagation`` exception which will cause the
propagation of the update through your handlers to stop:
it is possible to raise a `telethon.events.StopPropagation` exception which
will cause the propagation of the update through your handlers to stop:
.. code-block:: python

View File

@ -12,27 +12,32 @@ that servers as a nice interface with the most commonly used methods on
Telegram such as sending messages, retrieving the message history,
handling updates, etc.
The ``TelegramClient`` inherits the ``TelegramBareClient``. The later is
basically a pruned version of the ``TelegramClient``, which knows basic
stuff like ``.invoke()``\ 'ing requests, downloading files, or switching
between data centers. This is primary to keep the method count per class
and file low and manageable.
The ``TelegramClient`` inherits from several mixing ``Method`` classes,
since there are so many methods that having them in a single file would
make maintenance painful (it was three thousand lines before this separation
happened!). It's a "god object", but there is only a way to interact with
Telegram really.
Both clients make use of the ``network/mtproto_sender.py``. The
``MtProtoSender`` class handles packing requests with the ``salt``,
``id``, ``sequence``, etc., and also handles how to process responses
(i.e. pong, RPC errors). This class communicates through Telegram via
its ``.connection`` member.
The ``TelegramBaseClient`` is an ABC which will support all of these mixins
so they can work together nicely. It doesn't even know how to invoke things
because they need to be resolved with user information first (to work with
input entities comfortably).
The ``Connection`` class uses a ``extensions/tcp_client``, a C#-like
``TcpClient`` to ease working with sockets in Python. All the
The client makes use of the ``network/mtprotosender.py``. The
``MTProtoSender`` is responsible for connecting, reconnecting,
packing, unpacking, sending and receiving items from the network.
Basically, the low-level communication with Telegram, and handling
MTProto-related functions and types such as ``BadSalt``.
The sender makes use of a ``Connection`` class which knows the format in
which outgoing messages should be sent (how to encode their length and
their body, if they're further encrypted).
For now, all connection modes make use of the ``extensions/tcpclient``,
a C#-like ``TcpClient`` to ease working with sockets in Python. All the
``TcpClient`` know is how to connect through TCP and writing/reading
from the socket with optional cancel.
The ``Connection`` class bundles up all the connections modes and sends
and receives the messages accordingly (TCP full, obfuscated,
intermediate…).
Auto-generated code
*******************

View File

@ -5,7 +5,7 @@ Test Servers
To run Telethon on a test server, use the following code:
.. code-block:: python
.. code-block:: python
client = TelegramClient(None, api_id, api_hash)
client.session.set_dc(dc_id, '149.154.167.40', 80)
@ -28,7 +28,7 @@ Valid phone numbers are ``99966XYYYY``, where ``X`` is the ``dc_id`` and
be ``9996621234``. The code sent by Telegram will be ``dc_id`` repeated five
times, in this case, ``22222`` so we can hardcode that:
.. code-block:: python
.. code-block:: python
client = TelegramClient(None, api_id, api_hash)
client.session.set_dc(2, '149.154.167.40', 80)

View File

@ -8,7 +8,7 @@ be kind and don't forget to mention it helped you!
You should start by reading the source code on the `first
release <https://github.com/LonamiWebs/Telethon/releases/tag/v0.1>`__ of
the project, and start creating a ``MtProtoSender``. Once this is made,
the project, and start creating a ``MTProtoSender``. Once this is made,
you should write by hand the code to authenticate on the Telegram's
server, which are some steps required to get the key required to talk to
them. Save it somewhere! Then, simply mimic, or reinvent other parts of

View File

@ -15,7 +15,7 @@ You can query an inline bot, such as `@VoteBot`__ (note, *query*,
not *interact* with a voting message), by making use of the
:tl:`GetInlineBotResultsRequest` request:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import GetInlineBotResultsRequest
@ -26,7 +26,7 @@ not *interact* with a voting message), by making use of the
And you can select any of their results by using
:tl:`SendInlineBotResultRequest`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import SendInlineBotResultRequest
@ -43,7 +43,7 @@ Talking to Bots with special reply markup
To interact with a message that has a special reply markup, such as
`@VoteBot`__ polls, you would use :tl:`GetBotCallbackAnswerRequest`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import GetBotCallbackAnswerRequest

View File

@ -22,7 +22,7 @@ Joining a public channel
Once you have the :ref:`entity <entities>` of the channel you want to join
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
client(JoinChannelRequest(channel))
@ -48,7 +48,7 @@ enough information to join! The part after the
example, is the ``hash`` of the chat or channel. Now you can use
:tl:`ImportChatInviteRequest` as follows:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import ImportChatInviteRequest
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
@ -61,7 +61,7 @@ If you don't want to add yourself, maybe because you're already in,
you can always add someone else with the :tl:`AddChatUserRequest`, which
use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
.. code-block:: python
.. code-block:: python
# For normal chats
from telethon.tl.functions.messages import AddChatUserRequest
@ -112,7 +112,7 @@ closest thing to "no filter" is to simply use
If we want to get *all* the members, we need to use a moving offset and
a fixed limit:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
@ -164,7 +164,7 @@ Admin Permissions
Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.channels import EditAdminRequest
from telethon.tl.types import ChannelAdminRights
@ -218,7 +218,7 @@ Similar to how you give or revoke admin permissions, you can edit the
banned rights of an user through :tl:`EditBannedRequest` and its parameter
:tl:`ChannelBannedRights`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.channels import EditBannedRequest
from telethon.tl.types import ChannelBannedRights
@ -262,7 +262,7 @@ Telegram doesn't actually have a request to kick an user from a group.
Instead, you need to restrict them so they can't see messages. Any date
is enough:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.channels import EditBannedRequest
from telethon.tl.types import ChannelBannedRights
@ -285,7 +285,7 @@ It has been asked `quite`__ `a few`__ `times`__ (really, `many`__), and
while I don't understand why so many people ask this, the solution is to
use :tl:`GetMessagesViewsRequest`, setting ``increment=True``:
.. code-block:: python
.. code-block:: python
# Obtain `channel' through dialogs or through client.get_entity() or anyhow.

View File

@ -15,7 +15,7 @@ If you need to retrieve the bio, biography or about information for an user
you should use :tl:`GetFullUser`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.users import GetFullUserRequest
@ -35,7 +35,7 @@ Updating your name and/or bio
The first name, last name and bio (about) can all be changed with the same
request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.account import UpdateProfileRequest
@ -47,7 +47,7 @@ Updating your username
You need to use :tl:`account.UpdateUsername`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.account import UpdateUsernameRequest
@ -61,7 +61,7 @@ The easiest way is to upload a new file and use that as the profile photo
through :tl:`UploadProfilePhoto`:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.photos import UploadProfilePhotoRequest

View File

@ -65,7 +65,7 @@ Searching Messages
Messages are searched through the obvious :tl:`SearchRequest`, but you may run
into issues_. A valid example would be:
.. code-block:: python
.. code-block:: python
from telethon.tl.functions.messages import SearchRequest
from telethon.tl.types import InputMessagesFilterEmpty
@ -113,7 +113,7 @@ referenced through this pair of ID/hash (unique per user), and you need to
use this handle when sending a "document" message. This working example will
send yourself the very first sticker you have:
.. code-block:: python
.. code-block:: python
# Get all the sticker sets this user has
sticker_sets = client(GetAllStickersRequest(0))

View File

@ -14,7 +14,7 @@ will be printed unless you explicitly enable it.
You can also `use the module`__ on your own project very easily:
.. code-block:: python
.. code-block:: python
import logging
logger = logging.getLogger(__name__)
@ -27,7 +27,7 @@ You can also `use the module`__ on your own project very easily:
If you want to enable ``logging`` for your project *but* use a different
log level for the library:
.. code-block:: python
.. code-block:: python
import logging
logging.basicConfig(level=logging.DEBUG)

View File

@ -50,14 +50,14 @@ The current winner is `issue
**Issue:**
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
:alt: Winner issue
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
:alt: Winner issue
Winner issue
Winner issue
**Answer:**
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
:alt: Winner issue answer
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
:alt: Winner issue answer
Winner issue answer
Winner issue answer

View File

@ -31,7 +31,16 @@ class UpdateMethods(UserMethods):
def on(self, event):
"""
Decorator helper method around add_event_handler().
Decorator helper method around `add_event_handler`. Example:
>>> from telethon import TelegramClient, events
>>> client = TelegramClient(...)
>>>
>>> @client.on(events.NewMessage)
... async def handler(event):
... ...
...
>>>
Args:
event (`_EventBuilder` | `type`):

View File

@ -82,7 +82,29 @@ class EventBuilder(abc.ABC):
class EventCommon(abc.ABC):
"""Intermediate class with common things to all events"""
"""
Intermediate class with common things to all events.
Attributes:
pattern_match (`obj`):
The resulting object from calling the passed ``pattern`` function.
Here's an example using a string (defaults to regex match):
>>> from telethon import TelegramClient, events
>>> client = TelegramClient(...)
>>>
>>> @client.on(events.NewMessage(pattern=r'hi (\w+)!'))
... def handler(event):
... # In this case, the result is a ``Match`` object
... # since the ``str`` pattern was converted into
... # the ``re.compile(pattern).match`` function.
... print('Welcomed', event.pattern_match.group(1))
...
>>>
original_update (:tl:`Update`):
The original Telegram update object that caused this event.
"""
_event_name = 'Event'
def __init__(self, chat_peer=None, msg_id=None, broadcast=False):
@ -146,6 +168,9 @@ class EventCommon(abc.ABC):
@property
def client(self):
"""
The `telethon.TelegramClient` that created this event.
"""
return self._client
@property

View File

@ -177,6 +177,12 @@ class Message:
@property
async def chat(self):
"""
The (:tl:`User` | :tl:`Chat` | :tl:`Channel`, optional) on which
the event occurred. This property may make an API call the first time
to get the most up to date version of the chat (mostly when the event
doesn't belong to a channel), so keep that in mind.
"""
if self._chat is None:
try:
self._chat =\