Completely overhaul the documentation

This commit is contained in:
Lonami Exo 2019-05-09 12:24:37 +02:00
parent 10251f9782
commit 0a3d6106f0
75 changed files with 2410 additions and 2895 deletions

View File

@ -0,0 +1,77 @@
.. _installation:
============
Installation
============
Telethon is a Python library, which means you need to download and install
Python from https://www.python.org/downloads/ if you haven't already. Once
you have Python installed, run:
.. code-block:: sh
pip3 install -U telethon --user
To install or upgrade the library to the latest version.
Installing Development Versions
===============================
If you want the *latest* unreleased changes,
you can run the following command instead:
.. code-block:: sh
pip3 install -U https://github.com/LonamiWebs/Telethon/archive/master.zip --user
.. note::
The development version may have bugs and is not recommended for production
use. However, when you are `reporting a library bug`__, you should try if the
bug still occurs in this version.
.. __: https://github.com/LonamiWebs/Telethon/issues/
Verification
============
To verify that the library is installed correctly, run the following command:
.. code-block:: sh
python3 -c 'import telethon; print(telethon.__version__)'
The version number of the library should show in the output.
Optional Dependencies
=====================
If cryptg_ is installed, **the library will work a lot faster**, since
encryption and decryption will be made in C instead of Python. If your
code deals with a lot of updates or you are downloading/uploading a lot
of files, you will notice a considerable speed-up (from a hundred kilobytes
per second to several megabytes per second, if your connection allows it).
If it's not installed, pyaes_ will be used (which is pure Python, so it's
much slower).
If pillow_ is installed, large images will be automatically resized when
sending photos to prevent Telegram from failing with "invalid image".
Official clients also do this.
If aiohttp_ is installed, the library will be able to download
:tl:`WebDocument` media files (otherwise you will get an error).
If hachoir_ is installed, it will be used to extract metadata from files
when sending documents. Telegram uses this information to show the song's
performer, artist, title, duration, and for videos too (including size).
Otherwise, they will default to empty values, and you can set the attributes
manually.
.. _cryptg: https://github.com/Lonami/cryptg
.. _pyaes: https://github.com/ricmoo/pyaes
.. _pillow: https://python-pillow.org
.. _aiohttp: https://docs.aiohttp.org
.. _hachoir: https://hachoir.readthedocs.io

View File

@ -0,0 +1,22 @@
==========
Next Steps
==========
These basic first steps should have gotten you started with the library.
By now, you should know how to call friendly methods and how to work with
the returned objects, how things work inside event handlers, etc.
Next, we will see a quick reference summary of *all* the methods and
properties that you will need when using the library. If you follow
the links there, you will expand the documentation for the method
and property, with more examples on how to use them.
Therefore, **you can find an example on every method** of the client
to learn how to use it, as well as a description of all the arguments.
After that, we will go in-depth with some other important concepts
that are worth learning and understanding.
From now on, you can keep pressing the "Next" button if you want,
or use the menu on the left, since some pages are quite lengthy.

View File

@ -0,0 +1,79 @@
===========
Quick-Start
===========
Let's see a longer example to learn some of the methods that the library
has to offer. These are known as "friendly methods", and you should always
use these if possible.
.. code-block:: python
from telethon.sync import TelegramClient
# Remember to use your own values from my.telegram.org!
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
with TelegramClient('anon', api_id, api_hash) as client:
# Getting information about yourself
me = client.get_me()
# "me" is an User object. You can pretty-print
# any Telegram object with the "stringify" method:
print(me.stringify())
# When you print something, you see a representation of it.
# You can access all attributes of Telegram objects with
# the dot operator. For example, to get the username:
username = me.username
print(username)
print(me.phone)
# You can print all the dialogs/conversations that you are part of:
for dialog in client.iter_dialogs():
print(dialog.name, 'has ID', dialog.id)
# You can send messages to yourself...
client.send_message('me', 'Hello, myself!')
# ...to some chat ID
client.send_message(-100123456, 'Hello, group!')
# ...to your contacts
client.send_message('+34600123123', 'Hello, friend!')
# ...or even to any username
client.send_message('TelethonChat', 'Hello, Telethon!')
# You can, of course, use markdown in your messages:
message = client.send_message(
'me',
'This message has **bold**, `code`, __italics__ and '
'a [nice website](https://lonamiwebs.github.io)!',
link_preview=False
)
# Sending a message returns the sent message object, which you can use
print(message.raw_text)
# You can reply to messages directly if you have a message object
message.reply('Cool!')
# Or send files, songs, documents, albums...
client.send_file('me', '/home/me/Pictures/holidays.jpg')
# You can print the message history of any chat:
for message in client.iter_messages('me'):
print(message.id, message.text)
# You can download media from messages, too!
# The method will return the path where the file was saved.
if message.photo:
path = message.download_media()
print('File saved to', path)
Here, we show how to sign in, get information about yourself, send
messages, files, getting chats, printing messages, and downloading
files.
You should make sure that you understand what the code shown here
does, take note on how methods are called and used and so on before
proceeding. We will see all the available methods later on.

View File

@ -0,0 +1,128 @@
.. _signing-in:
==========
Signing In
==========
Before working with Telegram's API, you need to get your own 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!
.. note::
This API ID and hash is the one used by *your application*, not your
phone number. You can use this API ID and hash with *any* phone number
or even for bot accounts.
Editing the Code
================
This is a little introduction for those new to Python programming in general.
We will write our code inside ``hello.py``, so you can use any text
editor that you like. To run the code, use ``python3 hello.py`` from
the terminal.
.. important::
Don't call your script ``telethon.py``! Python will try to import
the client from there and it will fail with an error such as
"ImportError: cannot import name 'TelegramClient' ...".
Signing In
==========
We can finally write some code to log into our account!
.. code-block:: python
from telethon.sync import TelegramClient
# Use your own values from my.telegram.org
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
# The first parameter is the .session file name (absolute paths allowed)
with TelegramClient('anon', api_id, api_hash) as client:
client.send_message('me', 'Hello, myself!')
In the first line, we import the class name so we can create an instance
of the client. Then, we define variables to store our API ID and hash
conveniently.
At last, we create a new `TelegramClient <telethon.client.telegramclient.TelegramClient>`
instance and call it ``client``. We can now use the client variable
for anything that we want, such as sending a message to ourselves.
Using a ``with`` block is the preferred way to use the library. It will
automatically `start() <telethon.client.auth.AuthMethods.start>` the client,
logging or signing up if necessary.
If the ``.session`` file already existed, it will not login
again, so be aware of this if you move or rename the file!
Signing In as a Bot Account
===========================
You can also use Telethon for your bots (normal bot accounts, not users).
You will still need an API ID and hash, but the process is very similar:
.. code-block:: python
from telethon.sync import TelegramClient
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
bot_token = '12345:0123456789abcdef0123456789abcdef
# We have to manually call "start" if we want a explicit bot token
bot = TelegramClient('bot', api_id, api_hash).start(bot_token=bot_token)
# But then we can use the client instance as usual
with bot:
...
To get a bot account, you need to talk
with `@BotFather <https://t.me/BotFather>`_.
Signing In behind a Proxy
=========================
If you need to use a proxy to access Telegram,
you will need to `install PySocks`__ and then change:
.. code-block:: python
TelegramClient('anon', api_id, api_hash)
with
.. code-block:: python
TelegramClient('anon', api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 4444))
(of course, replacing the IP and port with the IP and port of the proxye).
The ``proxy=`` argument should be a tuple, a list or a dict,
consisting of parameters described `in PySocks usage`__.
.. __: https://github.com/Anorov/PySocks#installation
.. __: https://github.com/Anorov/PySocks#usage-1

View File

@ -0,0 +1,161 @@
=======
Updates
=======
Updates are an important topic in a messaging platform like Telegram.
After all, you want to be notified when a new message arrives, when
a member joins, when someone starts typing, etc.
For that, you can use **events**.
.. important::
It is strongly advised to enable logging when working with events,
since exceptions in event handlers are hidden by default. Please
add the following snippet to the very top of your file:
.. code-block:: python
import logging
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
level=logging.WARNING)
Getting Started
===============
Let's start things with an example to automate replies:
.. code-block:: python
from telethon import TelegramClient, events
client = TelegramClient('anon', api_id, api_hash)
@client.on(events.NewMessage)
async def my_event_handler(event):
if 'hello' in event.raw_text:
await event.reply('hi!')
client.start()
client.run_until_disconnected()
This code isn't much, but there might be some things unclear.
Let's break it down:
.. code-block:: python
from telethon import TelegramClient, events
client = TelegramClient('anon', api_id, api_hash)
This is normal creation (of course, pass session name, API ID and hash).
Nothing we don't know already.
.. code-block:: python
@client.on(events.NewMessage)
This Python decorator will attach itself to the ``my_event_handler``
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
async def my_event_handler(event):
if 'hello' in event.raw_text:
await event.reply('hi!')
If a `NewMessage
<telethon.events.newmessage.NewMessage>` event occurs,
and ``'hello'`` is in the text of the message, we `reply()
<telethon.tl.custom.message.Message.reply>` to the event
with a ``'hi!'`` message.
.. note::
Event handlers **must** be ``async def``. After all,
Telethon is an asynchronous library based on asyncio_,
which is a safer and often faster approach to threads.
You **must** ``await`` all method calls that use
network requests, which is most of them.
More Examples
=============
Replying to messages with hello is fun, but, can we do more?
.. code-block:: python
@client.on(events.NewMessage(outgoing=True, pattern=r'\.save'))
async def handler(event):
if event.is_reply:
replied = await event.get_reply_message()
sender = replied.sender
await client.download_profile_photo(sender)
await event.respond('Saved your photo {}'.format(sender.username))
We could also get replies. This event filters outgoing messages
(only those that we send will trigger the method), then we filter
by the regex ``r'\.save'``, which will match messages starting
with ``".save"``.
Inside the method, we check whether the event is replying to another message
or not. If it is, we get the reply message and the sender of that message,
and download their profile photo.
Let's delete messages which contain "heck". We don't allow swearing here.
.. code-block:: python
@client.on(events.NewMessage(pattern=r'(?i).*heck'))
async def handler(event):
await event.delete()
With the ``r'(?i).*heck'`` regex, we match case-insensitive
"heck" anywhere in the message. Regex is very powerful and you
can learn more at https://regexone.com/.
So far, we have only seen the `NewMessage
<telethon.events.newmessage.NewMessage>`, but there are many more
which will be covered later. This is only a small introduction to updates.
Entities
========
When you need the user or chat where an event occurred, you **must** use
the following methods:
.. code-block::
async def handler(event):
# Good
chat = await event.get_chat()
sender = await event.get_sender()
chat_id = event.chat_id
sender_id = event.sender_id
# BAD. Don't do this
chat = event.chat
sender = event.sender
chat_id = event.chat.id
sender_id = event.sender.id
Events are like messages, but don't have all the information a message has!
When you manually get a message, it will have all the information it needs.
When you receive an update about a message, it **won't** have all the
information, so you have to **use the methods**, not the properties.
Make sure you understand the code seen here before continuing!
As a rule of thumb, remember that new message events behave just
like message objects, so you can do with them everything you can
do with a message object.
.. _asyncio: https://docs.python.org/3/library/asyncio.html

View File

@ -8,7 +8,7 @@ Mastering asyncio
What's asyncio?
***************
===============
asyncio_ is a Python 3's built-in library. This means it's already installed if
you have Python 3. Since Python 3.5, it is convenient to work with asynchronous
@ -20,7 +20,7 @@ APIs such as Telegram's makes a lot of sense this way.
Why asyncio?
************
============
Asynchronous IO makes a lot of sense in a library like Telethon.
You send a request to the server (such as "get some message"), and
@ -38,7 +38,7 @@ because tasks are smaller than threads, which are smaller than processes.
What are asyncio basics?
************************
========================
.. code-block:: python
@ -59,7 +59,7 @@ What are asyncio basics?
What does telethon.sync do?
***************************
===========================
The moment you import any of these:
@ -133,7 +133,7 @@ running, and if the loop is running, you must ``await`` things yourself:
What are async, await and coroutines?
*************************************
=====================================
The ``async`` keyword lets you define asynchronous functions,
also known as coroutines, and also iterate over asynchronous
@ -212,7 +212,7 @@ The same example, but without the comment noise:
Can I use threads?
******************
==================
Yes, you can, but you must understand that the loops themselves are
not thread safe. and you must be sure to know what is happening. You
@ -250,7 +250,7 @@ which only works in the main thread.
client.run_until_disconnected() blocks!
***************************************
=======================================
All of what `client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` does is
@ -282,7 +282,7 @@ Of course, there are better tools to run code hourly or daily, see below.
What else can asyncio do?
*************************
=========================
Asynchronous IO is a really powerful tool, as we've seen. There are plenty
of other useful libraries that also use asyncio_ and that you can integrate
@ -339,7 +339,7 @@ combine all the libraries you want. People seem to forget this simple fact!
Why does client.start() work outside async?
*******************************************
===========================================
Because it's so common that it's really convenient to offer said
functionality by default. This means you can set up all your event
@ -352,7 +352,7 @@ Using the client in a ``with`` block, `start
all support this.
Where can I read more?
**********************
======================
`Check out my blog post
<https://lonamiwebs.github.io/blog/asyncio/>`_ about asyncio_, which

View File

@ -1,46 +1,8 @@
.. _entities:
=========================
Users, Chats and Channels
=========================
.. important::
TL;DR; If you're here because of *"Could not find the input entity for"*,
you must ask yourself "how did I find this entity through official
applications"? Now do the same with the library. Use what applies:
.. code-block:: python
with client:
# Does it have an username? Use it!
entity = client.get_entity(username)
# Do you have a conversation open with them? Get dialogs.
client.get_dialogs()
# Are they participant of some group? Get them.
client.get_participants('TelethonChat')
# Is the entity the original sender of a forwarded message? Get it.
client.get_messages('TelethonChat', 100)
# NOW you can use the ID, anywhere!
entity = client.get_entity(123456)
client.send_message(123456, 'Hi!')
Once the library has "seen" the entity, you can use their **integer** ID.
You can't use entities from IDs the library hasn't seen. You must make the
library see them *at least once* and disconnect properly. You know where
the entities are and you must tell the library. It won't guess for you.
.. contents::
Introduction
************
========
Entities
========
The library widely uses the concept of "entities". An entity will refer
to any :tl:`User`, :tl:`Chat` or :tl:`Channel` object that the API may return
@ -67,8 +29,72 @@ in response to certain methods, such as :tl:`GetUsersRequest`.
should work to find the entity.
Getting entities
****************
.. contents::
What is an Entity?
==================
A lot of methods and requests require *entities* to work. For example,
you send a message to an *entity*, get the username of an *entity*, and
so on.
There are a lot of things that work as entities: usernames, phone numbers,
chat links, invite links, IDs, and the types themselves. That is, you can
use any of those when you see an "entity" is needed.
.. note::
Remember that the phone number must be in your contact list before you
can use it.
You should use, **from better to worse**:
1. Input entities. For example, `event.input_chat
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`,
`message.input_sender
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`,
or caching an entity you will use a lot with
``entity = await client.get_input_entity(...)``.
2. Entities. For example, if you had to get someone's
username, you can just use ``user`` or ``channel``.
It will work. Only use this option if you already have the entity!
3. IDs. This will always look the entity up from the
cache (the ``*.session`` file caches seen entities).
4. Usernames, phone numbers and links. The cache will be
used too (unless you force a `client.get_entity()
<telethon.client.users.UserMethods.get_entity>`),
but may make a request if the username, phone or link
has not been found yet.
In recent versions of the library, the following two are equivalent:
.. code-block:: python
async def handler(event):
await client.send_message(event.sender_id, 'Hi')
await client.send_message(event.input_sender, 'Hi')
If you need to be 99% sure that the code will work (sometimes it's
simply impossible for the library to find the input entity), or if
you will reuse the chat a lot, consider using the following instead:
.. code-block:: python
async def handler(event):
# This method may make a network request to find the input sender.
# Properties can't make network requests, so we need a method.
sender = await event.get_input_sender()
await client.send_message(sender, 'Hi')
await client.send_message(sender, 'Hi')
Getting Entities
================
Through the use of the :ref:`sessions`, the library will automatically
remember the ID and hash pair, along with some extra information, so
@ -79,6 +105,8 @@ you're able to just do this:
# Dialogs are the "conversations you have open".
# This method returns a list of Dialog, which
# has the .entity attribute and other information.
#
# This part is IMPORTANT, because it feels the entity cache.
dialogs = client.get_dialogs()
# All of these work and do the same.
@ -109,7 +137,7 @@ you're able to just do this:
library do its job. Use a phone from your contacts, username, ID or
input entity (preferred but not necessary), whatever you already have.
All methods in the :ref:`telegram-client` call `.get_input_entity()
All methods in the :ref:`telethon-client` call `.get_input_entity()
<telethon.client.users.UserMethods.get_input_entity>` prior
to sending the request to save you from the hassle of doing so manually.
That way, convenience calls such as `client.send_message('lonami', 'hi!')
@ -124,16 +152,12 @@ made to obtain the required information.
Entities vs. Input Entities
***************************
===========================
.. note::
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 `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
beforehand, just use the username, a phone from your contacts, or the entity
retrieved by other means like `client.get_dialogs()
<telethon.client.dialogs.DialogMethods.get_dialogs>`.
This section is informative, but worth reading. The library
will transparently handle all of these details for you.
On top of the normal types, the API also make use of what they call their
``Input*`` versions of objects. The input version of an entity (e.g.
@ -195,8 +219,8 @@ resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if
you don't get this yet, but remember some of the details here are important.
Full entities
*************
Full Entities
=============
In addition to :tl:`PeerUser`, :tl:`InputPeerUser`, :tl:`User` (and its
variants for chats and channels), there is also the concept of :tl:`UserFull`.
@ -211,3 +235,74 @@ suggest commands to use).
You can get both of these by invoking :tl:`GetFullUser`, :tl:`GetFullChat`
and :tl:`GetFullChannel` respectively.
Accessing Entities
==================
Although it's explicitly noted in the documentation that messages
*subclass* `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
and `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>`,
some people still don't get inheritance.
When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
it means that the class you're looking at, *also* can act as the class it
bases. In this case, `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
knows how to get the *chat* where a thing belongs to.
So, a `Message <telethon.tl.custom.message.Message>` is a
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`.
That means you can do this:
.. code-block:: python
message.is_private
message.chat_id
message.get_chat()
# ...etc
`SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
.. code-block:: python
message.user_id
message.get_input_user()
message.user
# ...etc
Quite a few things implement them, so it makes sense to reuse the code.
For example, all events (except raw updates) implement `ChatGetter
<telethon.tl.custom.chatgetter.ChatGetter>` since all events occur
in some chat.
Summary
=======
TL;DR; If you're here because of *"Could not find the input entity for"*,
you must ask yourself "how did I find this entity through official
applications"? Now do the same with the library. Use what applies:
.. code-block:: python
with client:
# Does it have an username? Use it!
entity = client.get_entity(username)
# Do you have a conversation open with them? Get dialogs.
client.get_dialogs()
# Are they participant of some group? Get them.
client.get_participants('TelethonChat')
# Is the entity the original sender of a forwarded message? Get it.
client.get_messages('TelethonChat', 100)
# NOW you can use the ID, anywhere!
entity = client.get_entity(123456)
client.send_message(123456, 'Hi!')
Once the library has "seen" the entity, you can use their **integer** ID.
You can't use entities from IDs the library hasn't seen. You must make the
library see them *at least once* and disconnect properly. You know where
the entities are and you must tell the library. It won't guess for you.

View File

@ -1,3 +1,5 @@
.. _rpc-errors:
==========
RPC Errors
==========
@ -6,7 +8,7 @@ RPC stands for Remote Procedure Call, and when the library raises
a ``RPCError``, it's because you have invoked some of the API
methods incorrectly (wrong parameters, wrong permissions, or even
something went wrong on Telegram's server). All the errors are
available in :ref:`telethon-errors-package`, but some examples are:
available in :ref:`telethon-errors`, but some examples are:
- ``FloodWaitError`` (420), the same request was repeated many times.
Must wait ``.seconds`` (you can access this attribute). For example:
@ -43,3 +45,33 @@ If the error is not recognised, it will only be an ``RPCError``.
You can refer to all errors from Python through the ``telethon.errors``
module. If you don't know what attributes they have, try printing their
dir (like ``print(dir(e))``).
Avoiding Limits
===============
Don't spam. You won't get ``FloodWaitError`` or your account banned or
deleted if you use the library *for legit use cases*. Make cool tools.
Don't spam! Nobody knows the exact limits for all requests since they
depend on a lot of factors, so don't bother asking.
Still, if you do have a legit use case and still get those errors, the
library will automatically sleep when they are smaller than 60 seconds
by default. You can set different "auto-sleep" thresholds:
.. code-block:: python
client.flood_sleep_threshold = 0 # Don't auto-sleep
client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
You can also except it and act as you prefer:
.. code-block:: python
from telethon.errors import FloodWaitError
try:
...
except FloodWaitError as e:
print('Flood waited for', e.seconds)
quit(1)
VoIP numbers are very limited, and some countries are more limited too.

View File

@ -1,21 +1,21 @@
.. _accessing-the-full-api:
.. _full-api:
======================
Accessing the Full API
======================
============
The Full API
============
.. important::
While you have access to this, you should always use the friendly
methods listed on :ref:`telethon-client` unless you have a better
reason not to, like a method not existing or you wanting more control.
methods listed on :ref:`client-ref` unless you have a better reason
not to, like a method not existing or you wanting more control.
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.
The :ref:`telethon-client` doesn't offer a method for every single request
the Telegram API supports. However, it's very simple to *call* or *invoke*
any request. Whenever you need something, don't forget to `check the documentation`_
and look for the `method you need`_. There you can go through a sorted list
of everything you can do.
.. note::
@ -39,9 +39,9 @@ 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 `client.send_message
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
we could `use the search`_ to look for "message". There we would find
:tl:`SendMessageRequest`, which we can work with.
Every request is a Python class, and has the parameters needed for you
@ -73,7 +73,7 @@ construct one, for instance:
peer = InputPeerUser(user_id, user_hash)
Or we call `client.get_input_entity
Or we call `client.get_input_entity()
<telethon.client.users.UserMethods.get_input_entity>`:
.. code-block:: python
@ -84,10 +84,10 @@ Or we call `client.get_input_entity
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
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`
`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>`
user, use `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
instead:
.. code-block:: python
@ -114,7 +114,7 @@ every time its used, simply call `telethon.utils.get_input_peer`:
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>`,
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`,
we have everything we need. To invoke our
request we do:
@ -156,7 +156,7 @@ This can further be simplified to:
Requests in Parallel
********************
====================
The library will automatically merge outgoing requests into a single
*container*. Telegram's API supports sending multiple requests in a
@ -224,6 +224,6 @@ and still access the successful results:
# The second request failed.
second = e.exceptions[1]
__ https://lonamiwebs.github.io/Telethon
__ https://lonamiwebs.github.io/Telethon/methods/index.html
__ https://lonamiwebs.github.io/Telethon/?q=message&redirect=no
.. _check the documentation: https://lonamiwebs.github.io/Telethon
.. _method you need: https://lonamiwebs.github.io/Telethon/methods/index.html
.. _use the search: https://lonamiwebs.github.io/Telethon/?q=message&redirect=no

View File

@ -6,8 +6,11 @@ Session Files
.. contents::
What are sessions?
******************
They are an important part for the library to be efficient, such as caching
and handling your authorization key (or you would have to login every time!).
What are Sessions?
==================
The first parameter you pass to the constructor of the
:ref:`TelegramClient <telethon-client>` is
@ -43,7 +46,7 @@ by setting ``client.session.save_entities = False``.
Different Session Storage
*************************
=========================
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.
@ -54,13 +57,15 @@ the session name.
Telethon contains three implementations of the abstract ``Session`` class:
* ``MemorySession``: stores session data within memory.
* ``SQLiteSession``: stores sessions within on-disk SQLite databases. Default.
* ``StringSession``: stores session data within memory,
.. currentmodule:: telethon.sessions
* `MemorySession <memory.MemorySession>`: stores session data within memory.
* `SQLiteSession <sqlite.SQLiteSession>`: stores sessions within on-disk SQLite databases. Default.
* `StringSession <string.StringSession>`: stores session data within memory,
but can be saved as a string.
You can import these ``from telethon.sessions``. For example, using the
``StringSession`` is done as follows:
`StringSession <string.StringSession>` is done as follows:
.. code-block:: python
@ -91,25 +96,27 @@ There are other community-maintained implementations available:
* `Redis <https://github.com/ezdev128/telethon-session-redis>`_:
stores all sessions in a single Redis data store.
Creating your Own Storage
*************************
=========================
The easiest way to create your own storage implementation is to use
``MemorySession`` as the base and check out how ``SQLiteSession`` or
one of the community-maintained implementations work. You can find the
relevant Python files under the ``sessions`` directory in Telethon.
`MemorySession <memory.MemorySession>` as the base and check out how
`SQLiteSession <sqlite.SQLiteSession>` or one of the community-maintained
implementations work. You can find the relevant Python files under the
``sessions/`` directory in the Telethon's repository.
After you have made your own implementation, you can add it to the
community-maintained session implementation list above with a pull request.
String Sessions
***************
===============
``StringSession`` are a convenient way to embed your login credentials
directly into your code for extremely easy portability, since all they
take is a string to be able to login without asking for your phone and
code (or faster start if you're using a bot token).
`StringSession <string.StringSession>` are a convenient way to embed your
login credentials directly into your code for extremely easy portability,
since all they take is a string to be able to login without asking for your
phone and code (or faster start if you're using a bot token).
The easiest way to generate a string session is as follows:

View File

@ -0,0 +1,100 @@
======================
String-based Debugging
======================
Debugging is *really* important. Telegram's API is really big and there
is a lot of things that you should know. Such as, what attributes or fields
does a result have? Well, the easiest thing to do is printing it:
.. code-block:: python
user = client.get_entity('Lonami')
print(user)
That will show a huge **string** similar to the following:
.. code-block:: python
User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
That's a lot of text. But as you can see, all the properties are there.
So if you want the username you **don't use regex** or anything like
splitting ``str(user)`` to get what you want. You just access the
attribute you need:
.. code-block:: python
username = user.username
Can we get better than the shown string, though? Yes!
.. code-block:: python
print(user.stringify())
Will show a much better:
.. code-block:: python
User(
id=10885151,
is_self=False,
contact=False,
mutual_contact=False,
deleted=False,
bot=False,
bot_chat_history=False,
bot_nochats=False,
verified=False,
restricted=False,
min=False,
bot_inline_geo=False,
access_hash=123456789012345678,
first_name='Lonami',
last_name=None,
username='Lonami',
phone=None,
photo=UserProfilePhoto(
photo_id=123456789012345678,
photo_small=FileLocation(
dc_id=4,
volume_id=123456789,
local_id=123456789,
secret=-123456789012345678
),
photo_big=FileLocation(
dc_id=4,
volume_id=123456789,
local_id=123456789,
secret=123456789012345678
)
),
status=UserStatusOffline(
was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
),
bot_info_version=None,
restriction_reason=None,
bot_inline_placeholder=None,
lang_code=None
)
Now it's easy to see how we could get, for example,
the ``was_online`` time. It's inside ``status``:
.. code-block:: python
online_at = user.status.was_online
You don't need to print everything to see what all the possible values
can be. You can just search in http://lonamiwebs.github.io/Telethon/.
Remember that you can use Python's `isinstance
<https://docs.python.org/3/library/functions.html#isinstance>`_
to check the type of something. For example:
.. code-block:: python
from telethon import types
if isinstance(user.status, types.UserStatusOffline):
print(user.status.was_online)

View File

@ -0,0 +1,229 @@
================
Updates in Depth
================
Properties vs. Methods
======================
The event shown above acts just like a `custom.Message
<telethon.tl.custom.message.Message>`, which means you
can access all the properties it has, like ``.sender``.
**However** events are different to other methods in the client, like
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
Events *may not* send information about the sender or chat, which means it
can be ``None``, but all the methods defined in the client always have this
information so it doesn't need to be re-fetched. For this reason, you have
``get_`` methods, which will make a network call if necessary.
In short, you should do this:
.. code-block:: python
@client.on(events.NewMessage)
async def handler(event):
# event.input_chat may be None, use event.get_input_chat()
chat = await event.get_input_chat()
sender = await event.get_sender()
buttons = await event.get_buttons()
async def main():
async for message in client.iter_messages('me', 10):
# Methods from the client always have these properties ready
chat = message.input_chat
sender = message.sender
buttons = message.buttons
Notice, properties (`message.sender
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
methods (`message.get_sender
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
and you should use methods in events for these properties that may need network.
Events Without the client
=========================
The code of your application starts getting big, so you decide to
separate the handlers into different files. But how can you access
the client from these files? You don't need to! Just `events.register
<telethon.events.register>` them:
.. code-block:: python
# handlers/welcome.py
from telethon import events
@events.register(events.NewMessage('(?i)hello'))
async def handler(event):
client = event.client
await event.respond('Hey!')
await client.send_message('me', 'I said hello to someone')
Registering events is a way of saying "this method is an event handler".
You can use `telethon.events.is_handler` to check if any method is a handler.
You can think of them as a different approach to Flask's blueprints.
It's important to note that this does **not** add the handler to any client!
You never specified the client on which the handler should be used. You only
declared that it is a handler, and its type.
To actually use the handler, you need to `client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>` to the
client (or clients) where they should be added to:
.. code-block:: python
# main.py
from telethon import TelegramClient
import handlers.welcome
with TelegramClient(...) as client:
client.add_event_handler(handlers.welcome.handler)
client.run_until_disconnected()
This also means that you can register an event handler once and
then add it to many clients without re-declaring the event.
Events Without Decorators
=========================
If for any reason you don't want to use `telethon.events.register`,
you can explicitly pass the event handler to use to the mentioned
`client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>`:
.. code-block:: python
from telethon import TelegramClient, events
async def handler(event):
...
with TelegramClient(...) as client:
client.add_event_handler(handler, events.NewMessage)
client.run_until_disconnected()
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`` argument is optional in all three methods and defaults to
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
removing (so all callbacks would be removed).
.. note::
The ``event`` type is ignored in `client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>`
if you have used `telethon.events.register` on the ``callback``
before, since that's the point of using such method at all.
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 `telethon.events.StopPropagation` exception which
will cause the propagation of the update through your handlers to stop:
.. code-block:: python
from telethon.events import StopPropagation
@client.on(events.NewMessage)
async def _(event):
# ... some conditions
await event.delete()
# Other handlers won't have an event to work with
raise StopPropagation
@client.on(events.NewMessage)
async def _(event):
# Will never be reached, because it is the second handler
# in the chain.
pass
Remember to check :ref:`telethon-events` if you're looking for
the methods reference.
Understanding asyncio
=====================
With ``asyncio``, the library has several tasks running in the background.
One task is used for sending requests, another task is used to receive them,
and a third one is used to handle updates.
To handle updates, you must keep your script running. You can do this in
several ways. For instance, if you are *not* running ``asyncio``'s event
loop, you should use `client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>`:
.. code-block:: python
import asyncio
from telethon import TelegramClient
client = TelegramClient(...)
...
client.run_until_disconnected()
Behind the scenes, this method is ``await``'ing on the `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>` property,
so the code above and the following are equivalent:
.. code-block:: python
import asyncio
from telethon import TelegramClient
client = TelegramClient(...)
async def main():
await client.disconnected
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You could also run `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
until it completed.
But if you don't want to ``await``, then you should know what you want
to be doing instead! What matters is that you shouldn't let your script
die. If you don't care about updates, you don't need any of this.
Notice that unlike `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`,
`client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>` will
handle ``KeyboardInterrupt`` with you. This method is special and can
also be ran while the loop is running, so you can do this:
.. code-block:: python
async def main():
await client.run_until_disconnected()
loop.run_until_complete(main())
Sequential Updates
==================
If you need to process updates sequentially (i.e. not in parallel),
you should set ``sequential_updates=True`` when creating the client:
.. code-block:: python
with TelegramClient(..., sequential_updates=True) as client:
...

View File

@ -61,7 +61,7 @@ master_doc = 'index'
# General information about the project.
project = 'Telethon'
copyright = '2017, Lonami'
copyright = '2017 - 2019, Lonami'
author = 'Lonami'
# The version info for the project you're documenting, acts as replacement for

View File

@ -4,7 +4,7 @@ Project Structure
Main interface
**************
==============
The library itself is under the ``telethon/`` directory. The
``__init__.py`` file there exposes the main ``TelegramClient``, a class
@ -34,7 +34,7 @@ which outgoing messages should be sent (how to encode their length and
their body, if they're further encrypted).
Auto-generated code
*******************
===================
The files under ``telethon_generator/`` are used to generate the code
that gets placed under ``telethon/tl/``. The parsers take in files in

View File

@ -19,7 +19,7 @@ there by `@vysheng <https://github.com/vysheng>`__,
has been moved to `BitBucket <https://bitbucket.org/vysheng/tdcli>`__.
C++
***
===
The newest (and official) library, written from scratch, is called
`tdlib <https://github.com/tdlib/td>`__ and is what the Telegram X
@ -27,7 +27,7 @@ uses. You can find more information in the official documentation,
published `here <https://core.telegram.org/tdlib/docs/>`__.
JavaScript
**********
==========
`@zerobias <https://github.com/zerobias>`__ is working on
`telegram-mtproto <https://github.com/zerobias/telegram-mtproto>`__,
@ -35,7 +35,7 @@ a work-in-progress JavaScript library installable via
`npm <https://www.npmjs.com/>`__.
Kotlin
******
======
`Kotlogram <https://github.com/badoualy/kotlogram>`__ is a Telegram
implementation written in Kotlin (one of the
@ -46,7 +46,7 @@ languages for
yet working.
PHP
***
===
A PHP implementation is also available thanks to
`@danog <https://github.com/danog>`__ and his
@ -55,7 +55,7 @@ a very nice `online
documentation <https://daniil.it/MadelineProto/API_docs/>`__ too.
Python
******
======
A fairly new (as of the end of 2017) Telegram library written from the
ground up in Python by
@ -66,7 +66,7 @@ sad to see you go, but it would be nice to know what you miss from each
other library in either one so both can improve.
Rust
****
====
Yet another work-in-progress implementation, this time for Rust thanks
to `@JuanPotato <https://github.com/JuanPotato>`__ under the fancy

View File

@ -5,13 +5,13 @@ Working with Chats and Channels
.. note::
These examples assume you have read :ref:`accessing-the-full-api`.
These examples assume you have read :ref:`full-api`.
.. contents::
Joining a chat or channel
*************************
=========================
Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a
special form of :tl:`Chat`, which can also be super-groups if
@ -19,7 +19,7 @@ their ``megagroup`` member is ``True``.
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:
@ -41,7 +41,7 @@ __ https://lonamiwebs.github.io/Telethon/methods/channels/index.html
Joining a private chat or channel
*********************************
=================================
If all you have is a link like this one:
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
@ -57,7 +57,7 @@ example, is the ``hash`` of the chat or channel. Now you can use
Adding someone else to such chat or channel
*******************************************
===========================================
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
@ -86,7 +86,7 @@ use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
Checking a link without joining
*******************************
===============================
If you don't need to join but rather check whether it's a group or a
channel, you can use the :tl:`CheckChatInviteRequest`, which takes in
@ -94,7 +94,7 @@ the hash of said channel or group.
Admin Permissions
*****************
=================
Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`:
@ -152,7 +152,7 @@ Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`
Restricting Users
*****************
=================
Similar to how you give or revoke admin permissions, you can edit the
banned rights of a user through :tl:`EditBannedRequest` and its parameter
@ -203,7 +203,7 @@ https://core.telegram.org/bots/api#restrictchatmember.
Kicking a member
****************
================
Telegram doesn't actually have a request to kick a user from a group.
Instead, you need to restrict them so they can't see messages. Any date
@ -228,7 +228,7 @@ __ https://lonamiwebs.github.io/Telethon/constructors/channel_admin_rights.html
Increasing View Count in a Channel
**********************************
==================================
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

View File

@ -1,3 +1,5 @@
.. _telethon_projects:
=======================
Projects using Telethon
=======================
@ -15,10 +17,10 @@ the library.
.. _projects-telegram-export:
telethon_examples/
******************
==================
`Link <https://github.com/LonamiWebs/Telethon/tree/master/telethon_examples>`_ /
`Author's website <https://lonamiwebs.github.io>`_
`telethon_examples <https://github.com/LonamiWebs/Telethon/tree/master/telethon_examples>`_ /
`LonamiWebs' site <https://lonamiwebs.github.io>`_
This documentation is not the only place where you can find useful code
snippets using the library. The main repository also has a folder with
@ -26,10 +28,10 @@ some cool examples (even a Tkinter GUI!) which you can download, edit
and run to learn and play with them.
telegram-export
***************
===============
`Link <https://github.com/expectocode/telegram-export>`_ /
`Author's website <https://github.com/expectocode>`_
`telegram-export <https://github.com/expectocode/telegram-export>`_ /
`expectocode's GitHub <https://github.com/expectocode>`_
A tool to download Telegram data (users, chats, messages, and media)
into a database (and display the saved data).
@ -37,28 +39,28 @@ into a database (and display the saved data).
.. _projects-mautrix-telegram:
mautrix-telegram
****************
================
`Link <https://github.com/tulir/mautrix-telegram>`_ /
`Author's website <https://maunium.net/>`_
`mautrix-telegram <https://github.com/tulir/mautrix-telegram>`_ /
`maunium's site <https://maunium.net/>`_
A Matrix-Telegram hybrid puppeting/relaybot bridge.
.. _projects-telegramtui:
TelegramTUI
***********
===========
`Link <https://github.com/bad-day/TelegramTUI>`_ /
`Author's website <https://github.com/bad-day>`_
`TelegramTUI <https://github.com/bad-day/TelegramTUI>`_ /
`bad-day's GitHub <https://github.com/bad-day>`_
A Telegram client on your terminal.
spotify_telegram_bio_updater
****************************
============================
`Link <https://github.com/Poolitzer/spotify_telegram_bio_updater>`_ /
`Author's website <https://t.me/pooltalks>`_
`spotify_telegram_bio_updater <https://github.com/Poolitzer/spotify_telegram_bio_updater>`_ /
`pooltalks' Telegram <https://t.me/pooltalks>`_
Small project that updates the biography of a telegram user according
to their current Spotify playback, or revert it if no playback is active.

View File

@ -5,13 +5,13 @@ Users
.. note::
These examples assume you have read :ref:`accessing-the-full-api`.
These examples assume you have read :ref:`full-api`.
.. contents::
Retrieving full information
***************************
===========================
If you need to retrieve the bio, biography or about information for a user
you should use :tl:`GetFullUser`:
@ -32,7 +32,7 @@ See :tl:`UserFull` to know what other fields you can access.
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`:
@ -47,7 +47,7 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
Updating your username
**********************
======================
You need to use :tl:`account.UpdateUsername`:
@ -59,7 +59,7 @@ You need to use :tl:`account.UpdateUsername`:
Updating your profile photo
***************************
===========================
The easiest way is to upload a new file and use that as the profile photo
through :tl:`UploadProfilePhoto`:

View File

@ -0,0 +1,16 @@
=================
A Word of Warning
=================
Full API is **not** how you are intended to use the library. You **should**
always prefer the :ref:`client-ref`. However, not everything is implemented
as a friendly method, so full API is your last resort.
If you select a method in :ref:`client-ref`, you will most likely find an
example for that method. This is how you are intended to use the library.
Full API **will** break between different minor versions of the library,
since Telegram changes very often. The friendly methods will be kept
compatible between major versions.
If you need to see real-world examples, please refer to :ref:`telethon_projects`.

View File

@ -5,13 +5,13 @@ Working with messages
.. note::
These examples assume you have read :ref:`accessing-the-full-api`.
These examples assume you have read :ref:`full-api`.
.. contents::
Sending stickers
****************
================
Stickers are nothing else than ``files``, and when you successfully retrieve
the stickers for a certain sticker set, all you will have are ``handles`` to

View File

@ -1,343 +0,0 @@
.. _mastering-telethon:
==================
Mastering Telethon
==================
You've come far! In this section you will learn best practices, as well
as how to fix some silly (yet common) errors you may have found. Let's
start with a simple one.
Asyncio madness
***************
We promise ``asyncio`` is worth learning. Take your time to learn it.
It's a powerful tool that enables you to use this powerful library.
You need to be comfortable with it if you want to master Telethon.
.. code-block:: text
AttributeError: 'coroutine' object has no attribute 'id'
You probably had a previous version, upgraded, and expected everything
to work. Remember, just add this line:
.. code-block:: python
import telethon.sync
If you're inside an event handler you need to ``await`` **everything** that
*makes a network request*. Getting users, sending messages, and nearly
everything in the library needs access to the network, so they need to
be awaited:
.. code-block:: python
@client.on(events.NewMessage)
async def handler(event):
print((await event.get_sender()).username)
You may want to read https://lonamiwebs.github.io/blog/asyncio/ to help
you understand ``asyncio`` better. I'm open for `feedback
<https://t.me/LonamiWebs>`_ regarding that blog post
Entities
********
A lot of methods and requests require *entities* to work. For example,
you send a message to an *entity*, get the username of an *entity*, and
so on. There is an entire section on this at :ref:`entities` due to their
importance.
There are a lot of things that work as entities: usernames, phone numbers,
chat links, invite links, IDs, and the types themselves. That is, you can
use any of those when you see an "entity" is needed.
.. note::
Remember that the phone number must be in your contact list before you
can use it.
You should use, **from better to worse**:
1. Input entities. For example, `event.input_chat
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`,
`message.input_sender
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`,
or caching an entity you will use a lot with
``entity = await client.get_input_entity(...)``.
2. Entities. For example, if you had to get someone's
username, you can just use ``user`` or ``channel``.
It will work. Only use this option if you already have the entity!
3. IDs. This will always look the entity up from the
cache (the ``*.session`` file caches seen entities).
4. Usernames, phone numbers and links. The cache will be
used too (unless you force a `client.get_entity()
<telethon.client.users.UserMethods.get_entity>`),
but may make a request if the username, phone or link
has not been found yet.
In short, unlike in most bot API libraries where you use the ID, you
**should not** use the ID *if* you have the input entity. This is OK:
.. code-block:: python
async def handler(event):
await client.send_message(event.sender_id, 'Hi')
However, **this is better**:
.. code-block:: python
async def handler(event):
await client.send_message(event.input_sender, 'Hi')
Note that this also works for `message <telethon.tl.custom.message.Message>`
instead of ``event``. Telegram may not send the sender information, so if you
want to be 99% confident that the above will work you should do this:
.. code-block:: python
async def handler(event):
await client.send_message(await event.get_input_sender(), 'Hi')
Methods are able to make network requests to get information that
could be missing. Properties will never make a network request.
Of course, it is convenient to IDs or usernames for most purposes. It will
be fast enough and caching with `client.get_input_entity(...)
<telethon.client.users.UserMethods.get_input_entity>` will
be a micro-optimization. However it's worth knowing, and it
will also let you know if the entity cannot be found beforehand.
.. note::
Sometimes Telegram doesn't send the access hash inside entities,
so using `chat <telethon.tl.custom.chatgetter.ChatGetter.chat>`
or `sender <telethon.tl.custom.sendergetter.SenderGetter.sender>`
may not work, but `input_chat
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`
and `input_sender
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`
while making requests definitely will since that's what they exist
for. If Telegram did not send information about the access hash,
you will get something like "Invalid channel object" or
"Invalid user object".
Debugging
*********
**Please enable logging**:
.. code-block:: python
import logging
logging.basicConfig(level=logging.WARNING)
Change it for ``logging.DEBUG`` if you are asked for logs. It will save you
a lot of headaches and time when you work with events. This is for errors.
Debugging is *really* important. Telegram's API is really big and there
is a lot of things that you should know. Such as, what attributes or fields
does a result have? Well, the easiest thing to do is printing it:
.. code-block:: python
user = client.get_entity('Lonami')
print(user)
That will show a huge line similar to the following:
.. code-block:: python
User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
That's a lot of text. But as you can see, all the properties are there.
So if you want the username you **don't use regex** or anything like
splitting ``str(user)`` to get what you want. You just access the
attribute you need:
.. code-block:: python
username = user.username
Can we get better than the shown string, though? Yes!
.. code-block:: python
print(user.stringify())
Will show a much better:
.. code-block:: python
User(
id=10885151,
is_self=False,
contact=False,
mutual_contact=False,
deleted=False,
bot=False,
bot_chat_history=False,
bot_nochats=False,
verified=False,
restricted=False,
min=False,
bot_inline_geo=False,
access_hash=123456789012345678,
first_name='Lonami',
last_name=None,
username='Lonami',
phone=None,
photo=UserProfilePhoto(
photo_id=123456789012345678,
photo_small=FileLocation(
dc_id=4,
volume_id=123456789,
local_id=123456789,
secret=-123456789012345678
),
photo_big=FileLocation(
dc_id=4,
volume_id=123456789,
local_id=123456789,
secret=123456789012345678
)
),
status=UserStatusOffline(
was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
),
bot_info_version=None,
restriction_reason=None,
bot_inline_placeholder=None,
lang_code=None
)
Now it's easy to see how we could get, for example,
the ``was_online`` time. It's inside ``status``:
.. code-block:: python
online_at = user.status.was_online
You don't need to print everything to see what all the possible values
can be. You can just search in http://lonamiwebs.github.io/Telethon/.
Remember that you can use Python's `isinstance
<https://docs.python.org/3/library/functions.html#isinstance>`_
to check the type of something. For example:
.. code-block:: python
from telethon import types
if isinstance(user.status, types.UserStatusOffline):
print(user.status.was_online)
Avoiding Limits
***************
Don't spam. You won't get ``FloodWaitError`` or your account banned or
deleted if you use the library *for legit use cases*. Make cool tools.
Don't spam! Nobody knows the exact limits for all requests since they
depend on a lot of factors, so don't bother asking.
Still, if you do have a legit use case and still get those errors, the
library will automatically sleep when they are smaller than 60 seconds
by default. You can set different "auto-sleep" thresholds:
.. code-block:: python
client.flood_sleep_threshold = 0 # Don't auto-sleep
client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
You can also except it and act as you prefer:
.. code-block:: python
from telethon.errors import FloodWaitError
try:
...
except FloodWaitError as e:
print('Flood waited for', e.seconds)
quit(1)
VoIP numbers are very limited, and some countries are more limited too.
Chat or User From Messages
**************************
Although it's explicitly noted in the documentation that messages
*subclass* `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
and `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>`,
some people still don't get inheritance.
When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
it means that the class you're looking at, *also* can act as the class it
bases. In this case, `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
knows how to get the *chat* where a thing belongs to.
So, a `Message <telethon.tl.custom.message.Message>` is a
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`.
That means you can do this:
.. code-block:: python
message.is_private
message.chat_id
message.get_chat()
# ...etc
`SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
.. code-block:: python
message.user_id
message.get_input_user()
message.user
# ...etc
Quite a few things implement them, so it makes sense to reuse the code.
For example, all events (except raw updates) implement `ChatGetter
<telethon.tl.custom.chatgetter.ChatGetter>` since all events occur
in some chat.
Session Files
*************
They are an important part for the library to be efficient, such as caching
and handling your authorization key (or you would have to login every time!).
However, some people have a lot of trouble with SQLite, especially in Windows:
.. code-block:: text
...some lines of traceback
'insert or replace into entities values (?,?,?,?,?)', rows)
sqlite3.OperationalError: database is locked
This error occurs when **two or more clients use the same session**,
that is, when you write the same session name to be used in the client:
* You have two scripts running (interactive sessions count too).
* You have two clients in the same script running at the same time.
The solution is, if you need two clients, use two sessions. If the
problem persists and you're on Linux, you can use ``fuser my.session``
to find out the process locking the file. As a last resort, you can
reboot your system.
If you really dislike SQLite, use a different session storage. There
is an entire section covering that at :ref:`sessions`.
Final Words
***********
Now you are aware of some common errors and use cases, this should help
you master your Telethon skills to get the most out of the library. Have
fun developing awesome things!

View File

@ -1,73 +0,0 @@
.. _update-modes:
============
Update Modes
============
With ``asyncio``, the library has several tasks running in the background.
One task is used for sending requests, another task is used to receive them,
and a third one is used to handle updates.
To handle updates, you must keep your script running. You can do this in
several ways. For instance, if you are *not* running ``asyncio``'s event
loop, you should use `client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>`:
.. code-block:: python
import asyncio
from telethon import TelegramClient
client = TelegramClient(...)
...
client.run_until_disconnected()
Behind the scenes, this method is ``await``'ing on the `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>` property,
so the code above and the following are equivalent:
.. code-block:: python
import asyncio
from telethon import TelegramClient
client = TelegramClient(...)
async def main():
await client.disconnected
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You could also run `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
until it completed.
But if you don't want to ``await``, then you should know what you want
to be doing instead! What matters is that you shouldn't let your script
die. If you don't care about updates, you don't need any of this.
Notice that unlike `client.disconnected
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`,
`client.run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>` will
handle ``KeyboardInterrupt`` with you. This method is special and can
also be ran while the loop is running, so you can do this:
.. code-block:: python
async def main():
await client.run_until_disconnected()
loop.run_until_complete(main())
If you need to process updates sequentially (i.e. not in parallel),
you should set ``sequential_updates=True`` when creating the client:
.. code-block:: python
with TelegramClient(..., sequential_updates=True) as client:
...

View File

@ -1,263 +0,0 @@
.. _creating-a-client:
=================
Creating a Client
=================
Before working with Telegram's API, you need to get your own API ID and hash:
1. Follow `this link <https://my.telegram.org/>`_ and login with your
phone number.
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!
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
from telethon import TelegramClient, sync
# Use your own values here
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('some_name', api_id, api_hash)
Note that ``'some_name'`` will be used to save your session (persistent
information such as access key and others) as ``'some_name.session'`` in
your disk. This is by default a database file using Python's ``sqlite3``.
.. note::
It's important that the library always accesses the same session file so
that you don't need to re-send the code over and over again. By default it
creates the file in your working directory, but absolute paths work too.
Once you have a client ready, simply `.start()
<telethon.client.auth.AuthMethods.start>` it:
.. code-block:: python
client.start()
This line connects to Telegram, checks whether the current user is
authorized or not, and if it's not, it begins the login or sign up process.
When you're done with your code, you should always disconnect:
.. code-block:: python
client = TelegramClient(...)
try:
client.start()
... # your code here
finally:
client.disconnect()
You can also use a ``with`` block to achieve the same effect:
.. code-block:: python
client = TelegramClient(...)
with client:
... # your code here
# or
with TelegramClient(...) as client:
... # your code here
Wrapping it all together:
.. code-block:: python
from telethon import TelegramClient, sync
with TelegramClient('session_name', api_id, api_hash) as client:
... # your code
Just two setup lines.
.. warning::
Please note that if you fail to login around 5 times (or change the first
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`__
(via pip or manual) and then set the appropriated parameters:
.. code-block:: python
import socks
client = TelegramClient('session_id',
api_id=12345, api_hash='0123456789abcdef0123456789abcdef',
proxy=(socks.SOCKS5, 'localhost', 4444)
)
The ``proxy=`` argument should be a tuple, a list or a dict,
consisting of parameters described `here`__.
Manually Signing In
*******************
.. note::
Skip this unless you need more control when connecting.
If you need more control, you can replicate what `client.start()
<telethon.client.auth.AuthMethods.start>` is doing behind the scenes
for your convenience. The first step is to connect to the servers:
.. code-block:: python
client.connect()
You may or may not be authorized yet. You must be authorized
before you're able to send any request:
.. code-block:: python
client.is_user_authorized() # Returns True if you can send requests
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)
myself = client.sign_in(phone_number, input('Enter code: '))
# If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
# You can import both exceptions from telethon.errors.
.. note::
If you send the code that Telegram sent you over the app through the
app itself, it will expire immediately. You can still send the code
through the app by "obfuscating" it (maybe add a magic constant, like
``12345``, and then subtract it to get the real code back) or any other
technique.
``myself`` is your Telegram user. You can view all the information about
yourself by doing ``print(myself.stringify())``. You're now ready to use
the client as you wish! Remember that any object returned by the API has
mentioned ``.stringify()`` method, and printing these might prove useful.
As a full example:
.. code-block:: python
from telethon import TelegramClient, sync
client = TelegramClient('session_name', api_id, api_hash)
client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number)
me = client.sign_in(phone_number, input('Enter code: '))
Remember that this is the manual process and it's so much easier
to use the code snippets shown at the beginning of the page.
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
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()
<telethon.client.users.UserMethods.get_me>`.
Two Factor Authorization (2FA)
------------------------------
If you have Two Factor Authorization (from now on, 2FA) enabled on your
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
import getpass
from telethon.errors import SessionPasswordNeededError
client.sign_in(phone)
try:
client.sign_in(code=input('Enter code: '))
except SessionPasswordNeededError:
client.sign_in(password=getpass.getpass())
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>`.
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.
See the examples below:
.. code-block:: python
from telethon.errors import EmailUnconfirmedError
# Sets 2FA password for first time:
client.edit_2fa(new_password='supersecurepassword')
# Changes password:
client.edit_2fa(current_password='supersecurepassword',
new_password='changedmymind')
# Clears current password (i.e. removes 2FA):
client.edit_2fa(current_password='changedmymind', new_password=None)
# Sets new password with recovery email:
try:
client.edit_2fa(new_password='memes and dreams',
email='JohnSmith@example.com')
# Raises error (you need to check your email to complete 2FA setup.)
except EmailUnconfirmedError:
# You can put email checking code here if desired.
pass
# Also take note that unless you remove 2FA or explicitly
# give email parameter again it will keep the last used setting
# Set hint after already setting password:
client.edit_2fa(current_password='memes and dreams',
new_password='memes and dreams',
hint='It keeps you alive')
__ https://github.com/Anorov/PySocks#installation
__ https://github.com/Anorov/PySocks#usage-1

View File

@ -1,95 +0,0 @@
.. _getting-started:
===============
Getting Started
===============
.. contents::
Simple Installation
*******************
.. code-block:: sh
pip3 install telethon
**More details**: :ref:`installation`
Creating a client
*****************
.. code-block:: python
from telethon import TelegramClient, sync
# These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash).start()
**More details**: :ref:`creating-a-client`
Basic Usage
***********
.. code-block:: python
# Getting information about yourself
me = client.get_me()
print(me.stringify())
# Sending a message (you can use 'me' or 'self' to message yourself)
client.send_message('username', 'Hello World from Telethon!')
# Sending a file
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# Retrieving messages from a chat
from telethon import utils
for message in client.iter_messages('username', limit=10):
print(utils.get_display_name(message.sender), message.message)
# Listing all the dialogs (conversations you have open)
for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Downloading profile photos (default path is the working directory)
client.download_profile_photo('username')
# Once you have a message with .media (if message.media)
# you can download it using client.download_media(),
# or even using message.download_media():
messages = client.get_messages('username')
messages[0].download_media()
**More details**: :ref:`telegram-client`
See :ref:`telethon-client` for all available friendly methods.
Handling Updates
****************
.. code-block:: python
from telethon import events
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
async def handler(event):
await event.reply('Hello!')
client.run_until_disconnected()
**More details**: :ref:`working-with-updates`
----------
You can continue by clicking on the "More details" link below each
snippet of code or the "Next" button at the bottom of the page.

View File

@ -1,119 +0,0 @@
.. _installation:
============
Installation
============
.. contents::
Automatic Installation
**********************
To install Telethon, simply do:
.. 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:
.. code-block:: sh
pip3 install --upgrade telethon
You can also install the library directly from GitHub or a fork:
.. code-block:: sh
# pip3 install git+https://github.com/LonamiWebs/Telethon.git
or
$ git clone https://github.com/LonamiWebs/Telethon.git
$ cd Telethon/
# pip install -Ue .
If you don't have root access, simply pass the ``--user`` flag to the pip
command. If you want to install a specific branch, append ``@branch`` to
the end of the first install command.
By default the library will use a pure Python implementation for encryption,
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:
.. code-block:: sh
pip3 install telethon[cryptg]
Manual Installation
*******************
1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and
``rsa`` (`GitHub`__ | `PyPi`__) modules:
.. code-block:: sh
pip3 install pyaes rsa
2. Clone Telethon's GitHub repository:
.. code-block:: sh
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!
To generate the `method documentation`__, ``python3 setup.py gen docs``.
Optional dependencies
*********************
If pillow_ is installed, large images will be automatically resized when
sending photos to prevent Telegram from failing with "invalid image".
Official clients also do this.
If aiohttp_ is installed, the library will be able to download
:tl:`WebDocument` media files (otherwise you will get an error).
If hachoir_ is installed, it will be used to extract metadata from files
when sending documents. Telegram uses this information to show the song's
performer, artist, title, duration, and for videos too (including size).
Otherwise, they will default to empty values, and you can set the attributes
manually.
If cryptg_ is installed, encryption and decryption will be made in C instead
of Python which will be a lot faster. If your code deals with a lot of
updates or you are downloading/uploading a lot of files, you will notice
a considerable speed-up (from a hundred kilobytes per second to several
megabytes per second, if your connection allows it). If it's not installed,
pyaes_ will be used (which is pure Python, so it's much slower).
__ https://github.com/ricmoo/pyaes
__ https://pypi.python.org/pypi/pyaes
__ https://github.com/sybrenstuvel/python-rsa
__ https://pypi.python.org/pypi/rsa/3.4.2
__ https://lonamiwebs.github.io/Telethon
.. _pillow: https://python-pillow.org
.. _aiohttp: https://docs.aiohttp.org
.. _hachoir: https://hachoir.readthedocs.io
.. _cryptg: https://github.com/Lonami/cryptg
.. _pyaes: https://github.com/ricmoo/pyaes

View File

@ -1,104 +0,0 @@
.. _telegram-client:
==============
TelegramClient
==============
.. note::
Make sure to use the friendly methods described in :ref:`telethon-client`!
This section is just an introduction to using the client, but all the
available methods are in the :ref:`telethon-client` reference, including
detailed descriptions to what they do.
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
detailed description and a list of all the available methods. Calling
``help()`` from an interactive Python session will always list all the
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 :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
(assuming you have ``from telethon import sync`` or ``import telethon.sync``):
.. 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
was extracted from their response.
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
# The method will infer that you've passed a username
# It also accepts phone numbers, and will get the user
# from your contact list.
lonami = client.get_entity('lonami')
The so called "entities" are another important whole concept on its own,
but for now you don't need to worry about it. Simply know that they are
a good way to get information about a user, chat or channel.
Many other common methods for quick scripts are also available:
.. code-block:: python
# Note that you can use 'me' or 'self' to message yourself
client.send_message('username', 'Hello World from Telethon!')
# .send_message's parse mode defaults to markdown, so you
# can use **bold**, __italics__, [links](https://example.com), `code`,
# and even [mentions](@username)/[mentions](tg://user?id=123456789)
client.send_message('username', '**Using** __markdown__ `too`!')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
# The utils package has some goodies, like .get_display_name()
from telethon import utils
for message in client.iter_messages('username', limit=10):
print(utils.get_display_name(message.sender), message.message)
# Dialogs are the conversations you have open
for dialog in client.get_dialogs(limit=10):
print(dialog.name, dialog.draft.text)
# Default path is the working directory
client.download_profile_photo('username')
# Call .disconnect() when you're done
client.disconnect()
Remember that you can call ``.stringify()`` to any object Telegram returns
to pretty print it. Calling ``str(result)`` does the same operation, but on
a single line.
Available methods
*****************
The :ref:`reference <telethon-package>` lists all the "handy" methods
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_
or even the TelegramClient_ itself to learn how it works.
See the mentioned :ref:`telethon-client` to find the available methods.
.. _InteractiveTelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/interactive_telegram_client.py
.. _TelegramClient: https://github.com/LonamiWebs/Telethon/tree/master/telethon/client

View File

@ -1,333 +0,0 @@
.. _working-with-updates:
====================
Working with Updates
====================
.. important::
Coming from Telethon before it reached its version 1.0?
Make sure to read :ref:`compatibility-and-convenience`!
Otherwise, you can ignore this note and just follow along.
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!
.. 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 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::
Getting Started
***************
.. code-block:: python
from telethon import TelegramClient, events
client = TelegramClient('name', api_id, api_hash)
@client.on(events.NewMessage)
async def my_event_handler(event):
if 'hello' in event.raw_text:
await event.reply('hi!')
client.start()
client.run_until_disconnected()
Not much, but there might be some things unclear. What does this code do?
.. code-block:: python
from telethon import TelegramClient, events
client = TelegramClient('name', api_id, api_hash)
This is normal creation (of course, pass session name, API ID and hash).
Nothing we don't know already.
.. code-block:: python
@client.on(events.NewMessage)
This Python decorator will attach itself to the ``my_event_handler``
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
async def my_event_handler(event):
if 'hello' in event.raw_text:
await event.reply('hi!')
If a `NewMessage
<telethon.events.newmessage.NewMessage>` event occurs,
and ``'hello'`` is in the text of the message, we `.reply()
<telethon.tl.custom.message.Message.reply>` to the event
with a ``'hi!'`` message.
Do you notice anything different? Yes! Event handlers **must** be ``async``
for them to work, and **every method using the network** needs to have an
``await``, otherwise, Python's ``asyncio`` will tell you that you forgot
to do so, so you can easily add it.
.. code-block:: python
client.start()
client.run_until_disconnected()
Finally, this tells the client that we're done with our code. We run the
``asyncio`` loop until the client starts (this is done behind the scenes,
since the method is so common), and then we run it again until we are
disconnected. Of course, you can do other things instead of running
until disconnected. For this refer to :ref:`update-modes`.
More on events
**************
The `NewMessage <telethon.events.newmessage.NewMessage>` event has much
more than what was shown. You can access the `.sender
<telethon.tl.custom.message.Message.sender>` of the message
through that member, or even see if the message had `.media
<telethon.tl.custom.message.Message.media>`, a `.photo
<telethon.tl.custom.message.Message.photo>` or a `.document
<telethon.tl.custom.message.Message.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()
<telethon.tl.custom.message.Message.reply>` as a reply,
you can use the `.respond() <telethon.tl.custom.message.Message.respond>`
method instead. Of course, there are more events such as `ChatAction
<telethon.events.chataction.ChatAction>` or `UserUpdate
<telethon.events.userupdate.UserUpdate>`, and they're all
used in the same way. Simply add the `@client.on(events.XYZ)
<telethon.client.updates.UpdateMethods.on>` decorator on the top
of your handler and you're done! The event that will be passed always
is of type ``XYZ.Event`` (for instance, `NewMessage.Event
<telethon.events.newmessage.NewMessage.Event>`), except for the `Raw
<telethon.events.raw.Raw>` event which just passes the :tl:`Update` object.
Note that `.reply()
<telethon.tl.custom.message.Message.reply>` and `.respond()
<telethon.tl.custom.message.Message.respond>` are just wrappers around the
`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)
<telethon.tl.custom.message.Message.reply>`.
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
import ast
import random
# Either a single item or a list of them will work for the chats.
# You can also use the IDs, Peers, or even User/Chat/Channel objects.
@client.on(events.NewMessage(chats=('TelethonChat', 'TelethonOffTopic')))
async def normal_handler(event):
if 'roll' in event.raw_text:
await event.reply(str(random.randint(1, 6)))
# Similarly, you can use incoming=True for messages that you receive
@client.on(events.NewMessage(chats='TelethonOffTopic', outgoing=True,
pattern='eval (.+)'))
async def admin_handler(event):
expression = event.pattern_match.group(1)
await event.reply(str(ast.literal_eval(expression)))
You can pass one or more chats to the ``chats`` parameter (as a list or tuple),
and only events from there will be processed. You can also specify whether you
want to handle incoming or outgoing messages (those you receive or those you
send). In this example, people can say ``'roll'`` and you will reply with a
random number, while if you say ``'eval 4+4'``, you will reply with the
solution. Try it!
Properties vs. Methods
**********************
The event shown above acts just like a `custom.Message
<telethon.tl.custom.message.Message>`, which means you
can access all the properties it has, like ``.sender``.
**However** events are different to other methods in the client, like
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
Events *may not* send information about the sender or chat, which means it
can be ``None``, but all the methods defined in the client always have this
information so it doesn't need to be re-fetched. For this reason, you have
``get_`` methods, which will make a network call if necessary.
In short, you should do this:
.. code-block:: python
@client.on(events.NewMessage)
async def handler(event):
# event.input_chat may be None, use event.get_input_chat()
chat = await event.get_input_chat()
sender = await event.get_sender()
buttons = await event.get_buttons()
async def main():
async for message in client.iter_messages('me', 10):
# Methods from the client always have these properties ready
chat = message.input_chat
sender = message.sender
buttons = message.buttons
Notice, properties (`message.sender
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
methods (`message.get_sender
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
and you should use methods in events for these properties that may need network.
Events Without the client
*************************
The code of your application starts getting big, so you decide to
separate the handlers into different files. But how can you access
the client from these files? You don't need to! Just `events.register
<telethon.events.register>` them:
.. code-block:: python
# handlers/welcome.py
from telethon import events
@events.register(events.NewMessage('(?i)hello'))
async def handler(event):
client = event.client
await event.respond('Hey!')
await client.send_message('me', 'I said hello to someone')
Registering events is a way of saying "this method is an event handler".
You can use `telethon.events.is_handler` to check if any method is a handler.
You can think of them as a different approach to Flask's blueprints.
It's important to note that this does **not** add the handler to any client!
You never specified the client on which the handler should be used. You only
declared that it is a handler, and its type.
To actually use the handler, you need to `client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>` to the
client (or clients) where they should be added to:
.. code-block:: python
# main.py
from telethon import TelegramClient
import handlers.welcome
with TelegramClient(...) as client:
client.add_event_handler(handlers.welcome.handler)
client.run_until_disconnected()
This also means that you can register an event handler once and
then add it to many clients without re-declaring the event.
Events Without Decorators
*************************
If for any reason you don't want to use `telethon.events.register`,
you can explicitly pass the event handler to use to the mentioned
`client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>`:
.. code-block:: python
from telethon import TelegramClient, events
async def handler(event):
...
with TelegramClient(...) as client:
client.add_event_handler(handler, events.NewMessage)
client.run_until_disconnected()
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`` argument is optional in all three methods and defaults to
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
removing (so all callbacks would be removed).
.. note::
The ``event`` type is ignored in `client.add_event_handler
<telethon.client.updates.UpdateMethods.add_event_handler>`
if you have used `telethon.events.register` on the ``callback``
before, since that's the point of using such method at all.
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 `telethon.events.StopPropagation` exception which
will cause the propagation of the update through your handlers to stop:
.. code-block:: python
from telethon.events import StopPropagation
@client.on(events.NewMessage)
async def _(event):
# ... some conditions
await event.delete()
# Other handlers won't have an event to work with
raise StopPropagation
@client.on(events.NewMessage)
async def _(event):
# Will never be reached, because it is the second handler
# in the chain.
pass
Remember to check :ref:`telethon-events-package` if you're looking for
the methods reference.
__ https://lonamiwebs.github.io/Telethon/types/update.html

View File

@ -1,751 +0,0 @@
.. _telegram-client-example:
========================
Examples with the Client
========================
This section explores the methods defined in the :ref:`telegram-client`
with some practical examples. The section assumes that you have imported
the ``telethon.sync`` package and that you have a client ready to use.
.. note::
There are some very common errors (such as forgetting to add
``import telethon.sync``) for newcomers to ``asyncio``:
.. code-block:: python
# AttributeError: 'coroutine' object has no attribute 'first_name'
print(client.get_me().first_name)
# TypeError: 'AsyncGenerator' object is not iterable
for message in client.iter_messages('me'):
...
# RuntimeError: This event loop is already running
with client.conversation('me') as conv:
...
That error means you're probably inside an ``async def`` so you
need to use:
.. code-block:: python
print((await client.get_me()).first_name)
async for message in client.iter_messages('me'):
...
async with client.conversation('me') as conv:
...
You can of course call other ``def`` functions from your ``async def``
event handlers, but if they need making API calls, make your own
functions ``async def`` so you can ``await`` things:
.. code-block:: python
async def helper(client):
await client.send_message('me', 'Hi')
If you're not inside an ``async def`` you can enter one like so:
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
loop.run_until_complete(my_async_def())
.. contents::
Authorization
*************
Starting the client is as easy as calling `client.start()
<telethon.client.auth.AuthMethods.start>`:
.. code-block:: python
client.start()
... # code using the client
client.disconnect()
And you can even use a ``with`` block:
.. code-block:: python
with client:
... # code using the client
.. note::
Remember we assume you have ``import telethon.sync``. You can of course
use the library without importing it. The code would be rewritten as:
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
async def main():
await client.start()
...
await client.disconnect()
# or
async with client:
...
loop.run_until_complete(main())
All methods that need access to the network (e.g. to make an API call)
**must** be awaited (or their equivalent such as ``async for`` and
``async with``). You can do this yourself or you can let the library
do it for you by using ``import telethon.sync``. With event handlers,
you must do this yourself.
The cleanest way to delete your ``*.session`` file is `client.log_out
<telethon.client.auth.AuthMethods.log_out>`. Note that you will obviously
need to login again if you use this:
.. code-block:: python
# Logs out and deletes the session file; you will need to sign in again
client.log_out()
# You often simply want to disconnect. You will not need to sign in again
client.disconnect()
Group Chats
***********
You can easily iterate over all the :tl:`User` in a chat and
do anything you want with them by using `client.iter_participants
<telethon.client.chats.ChatMethods.iter_participants>`:
.. code-block:: python
for user in client.iter_participants(chat):
... # do something with the user
You can also search by their name:
.. code-block:: python
for user in client.iter_participants(chat, search='name'):
...
Or by their type (e.g. if they are admin) with :tl:`ChannelParticipantsFilter`:
.. code-block:: python
from telethon.tl.types import ChannelParticipantsAdmins
for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
...
Open Conversations and Joined Channels
**************************************
The conversations you have open and the channels you have joined
are in your "dialogs", so to get them you need to `client.get_dialogs
<telethon.client.dialogs.DialogMethods.get_dialogs>`:
.. code-block:: python
dialogs = client.get_dialogs()
first = dialogs[0]
print(first.title)
You can then use the dialog as if it were a peer:
.. code-block:: python
client.send_message(first, 'hi')
You can access `dialog.draft <telethon.tl.custom.draft.Draft>` or you can
get them all at once without getting the dialogs:
.. code-block:: python
drafts = client.get_drafts()
Downloading Media
*****************
It's easy to `download_profile_photo
<telethon.client.downloads.DownloadMethods.download_profile_photo>`:
.. code-block:: python
client.download_profile_photo(user)
Or `download_media <telethon.client.downloads.DownloadMethods.download_media>`
from a message:
.. code-block:: python
client.download_media(message)
client.download_media(message, filename)
# or
message.download_media()
message.download_media(filename)
Remember that these methods return the final filename where the
media was downloaded (e.g. it may add the extension automatically).
Getting Messages
****************
You can easily iterate over all the `messages
<telethon.tl.custom.message.Message>` of a chat with `iter_messages
<telethon.client.messages.MessageMethods.iter_messages>`:
.. code-block:: python
for message in client.iter_messages(chat):
... # do something with the message from recent to older
for message in client.iter_messages(chat, reverse=True):
... # going from the oldest to the most recent
You can also use it to search for messages from a specific person:
.. code-block:: python
for message in client.iter_messages(chat, from_user='me'):
...
Or you can search by text:
.. code-block:: python
for message in client.iter_messages(chat, search='hello'):
...
Or you can search by media with a :tl:`MessagesFilter`:
.. code-block:: python
from telethon.tl.types import InputMessagesFilterPhotos
for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
...
If you want a list instead, use the get variant. The second
argument is the limit, and ``None`` means "get them all":
.. code-block:: python
from telethon.tl.types import InputMessagesFilterPhotos
# Get 0 photos and print the total
photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
print(photos.total)
# Get all the photos
photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
Or just some IDs:
.. code-block:: python
message_1337 = client.get_messages(chats, ids=1337)
Exporting Messages
******************
If you plan on exporting data from your Telegram account, such as the entire
message history from your private conversations, chats or channels, or if you
plan to download a lot of media, you may prefer to do this within a *takeout*
session. Takeout sessions let you export data from your account with lower
flood wait limits.
To start a takeout session, simply call `client.takeout()
<telethon.client.account.AccountMethods.takeout>`:
.. code-block:: python
from telethon import errors
try:
with client.takeout() as takeout:
for message in takeout.iter_messages(chat, wait_time=0):
... # Do something with the message
except errors.TakeoutInitDelayError as e:
print('Must wait', e.seconds, 'before takeout')
Depending on the condition of the session (for example, when it's very
young and the method has not been called before), you may or not need
to ``except errors.TakeoutInitDelayError``. However, it is good practice.
Sending Messages
****************
Just use `send_message <telethon.client.messages.MessageMethods.send_message>`:
.. code-block:: python
client.send_message('lonami', 'Thanks for the Telethon library!')
The function returns the `custom.Message <telethon.tl.custom.message.Message>`
that was sent so you can do more things with it if you want.
You can also `reply <telethon.tl.custom.message.Message.reply>` or
`respond <telethon.tl.custom.message.Message.respond>` to messages:
.. code-block:: python
message.reply('Hello')
message.respond('World')
Sending Markdown or HTML messages
*********************************
Markdown (``'md'`` or ``'markdown'``) is the default `parse_mode
<telethon.client.messageparse.MessageParseMethods.parse_mode>`
for the client. You can change the default parse mode like so:
.. code-block:: python
client.parse_mode = 'html'
Now all messages will be formatted as HTML by default:
.. code-block:: python
client.send_message('me', 'Some <b>bold</b> and <i>italic</i> text')
client.send_message('me', 'An <a href="https://example.com">URL</a>')
client.send_message('me', '<code>code</code> and <pre>pre\nblocks</pre>')
client.send_message('me', '<a href="tg://user?id=me">Mentions</a>')
You can override the default parse mode to use for special cases:
.. code-block:: python
# No parse mode by default
client.parse_mode = None
# ...but here I want markdown
client.send_message('me', 'Hello, **world**!', parse_mode='md')
# ...and here I need HTML
client.send_message('me', 'Hello, <i>world</i>!', parse_mode='html')
The rules are the same as for Bot API, so please refer to
https://core.telegram.org/bots/api#formatting-options.
Sending Messages with Media
***************************
Sending media can be done with `send_file
<telethon.client.uploads.UploadMethods.send_file>`:
.. code-block:: python
client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
# or
client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
You can send voice notes or round videos by setting the right arguments:
.. code-block:: python
client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
client.send_file(chat, '/my/videos/video.mp4', video_note=True)
You can set a JPG thumbnail for any document:
.. code-block:: python
client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
You can force sending images as documents:
.. code-block:: python
client.send_file(chat, '/my/photos/photo.png', force_document=True)
You can send albums if you pass more than one file:
.. code-block:: python
client.send_file(chat, [
'/my/photos/holiday1.jpg',
'/my/photos/holiday2.jpg',
'/my/drawings/portrait.png'
])
The caption can also be a list to match the different photos.
Reusing Uploaded Files
**********************
All files you send are automatically cached, so if you do:
.. code-block:: python
client.send_file(first_chat, 'document.txt')
client.send_file(second_chat, 'document.txt')
The ``'document.txt'`` file will only be uploaded once. You
can disable this behaviour by settings ``allow_cache=False``:
.. code-block:: python
client.send_file(first_chat, 'document.txt', allow_cache=False)
client.send_file(second_chat, 'document.txt', allow_cache=False)
Disabling cache is the only way to send the same document with different
attributes (for example, you send an ``.ogg`` as a song but now you want
it to show as a voice note; you probably need to disable the cache).
However, you can *upload* the file once (not sending it yet!), and *then*
you can send it with different attributes. This means you can send an image
as a photo and a document:
.. code-block:: python
file = client.upload_file('photo.jpg')
client.send_file(chat, file) # sends as photo
client.send_file(chat, file, force_document=True) # sends as document
file.name = 'not a photo.jpg'
client.send_file(chat, file, force_document=True) # document, new name
Or, the example described before:
.. code-block:: python
file = client.upload_file('song.ogg')
client.send_file(chat, file) # sends as song
client.send_file(chat, file, voice_note=True) # sends as voice note
The ``file`` returned by `client.upload_file
<telethon.client.uploads.UploadMethods.upload_file>` represents the uploaded
file, not an immutable document (that's why the attributes can change, because
they are set later). This handle can be used only for a limited amount of time
(somewhere within a day). Telegram decides this limit and it is not public.
However, a day is often more than enough.
Sending Messages with Buttons
*****************************
**You must sign in as a bot** in order to add inline buttons (or normal
keyboards) to your messages. Once you have signed in as a bot specify
the `Button <telethon.tl.custom.button.Button>` or buttons to use:
.. code-block:: python
from telethon import events
from telethon.tl.custom import Button
@client.on(events.CallbackQuery)
async def callback(event):
await event.edit('Thank you for clicking {}!'.format(event.data))
client.send_message(chat, 'A single button, with "clk1" as data',
buttons=Button.inline('Click me', b'clk1'))
client.send_message(chat, 'Pick one from this grid', buttons=[
[Button.inline('Left'), Button.inline('Right')],
[Button.url('Check this site!', 'https://lonamiwebs.github.io')]
])
You can also use normal buttons (not inline) to request the user's
location, phone number, or simply for them to easily send a message:
.. code-block:: python
client.send_message(chat, 'Welcome', buttons=[
Button.text('Thanks!', resize=True, single_use=True),
Button.request_phone('Send phone'),
Button.request_location('Send location')
])
Forcing a reply or removing the keyboard can also be done:
.. code-block:: python
client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
Remember to check `Button <telethon.tl.custom.button.Button>` for more.
Making Inline Queries
*********************
You can send messages ``via @bot`` by first making an inline query:
.. code-block:: python
results = client.inline_query('like', 'Do you like Telethon?')
Then access the result you want and `click
<telethon.tl.custom.inlineresult.InlineResult.click>` it in the chat
where you want to send it to:
.. code-block:: python
message = results[0].click('TelethonOffTopic')
Sending messages through inline bots lets you use buttons as a normal user.
It can look a bit strange at first, but you can make inline queries in no
chat in particular, and then click a *result* to send it to some chat.
Clicking Buttons
****************
Let's `click <telethon.tl.custom.message.Message.click>`
the message we sent in the example above!
.. code-block:: python
message.click(0)
This will click the first button in the message. You could also
``click(row, column)``, using some text such as ``click(text='👍')``
or even the data directly ``click(data=b'payload')``.
Answering Inline Queries
************************
As a bot, you can answer to inline queries with `events.InlineQuery
<telethon.events.inlinequery.InlineQuery>`. You should make use of the
`builder <telethon.tl.custom.inlinebuilder.InlineBuilder>` property
to conveniently build the list of results to show to the user. Remember
to check the properties of the `InlineQuery.Event
<telethon.events.inlinequery.InlineQuery.Event>`:
.. code-block:: python
@bot.on(events.InlineQuery)
async def handler(event):
builder = event.builder
rev_text = event.text[::-1]
await event.answer([
builder.article('Reverse text', text=rev_text),
builder.photo('/path/to/photo.jpg')
])
Conversations: Waiting for Messages or Replies
**********************************************
This one is really useful for unit testing your bots, which you can
even write within Telethon itself! You can open a `Conversation
<telethon.tl.custom.conversation.Conversation>` in any chat as:
.. code-block:: python
with client.conversation(chat) as conv:
...
Conversations let you program a finite state machine with the
higher-level constructs we are all used to, such as ``while``
and ``if`` conditionals instead setting the state and jumping
from one place to another which is less clean.
For instance, let's imagine ``you`` are the bot talking to ``usr``:
.. code-block:: text
<you> Hi!
<usr> Hello!
<you> Please tell me your name
<usr> ?
<you> Your name didn't have any letters! Try again
<usr> Lonami
<you> Thanks Lonami!
This can be programmed as follows:
.. code-block:: python
with bot.conversation(chat) as conv:
conv.send_message('Hi!')
hello = conv.get_response()
conv.send_message('Please tell me your name')
name = conv.get_response().raw_text
while not any(x.isalpha() for x in name):
conv.send_message("Your name didn't have any letters! Try again")
name = conv.get_response().raw_text
conv.send_message('Thanks {}!'.format(name))
Note how we sent a message **with the conversation**, not with the client.
This is important so the conversation remembers what messages you sent.
The method reference for getting a response, getting a reply or marking
the conversation as read can be found by clicking here: `Conversation
<telethon.tl.custom.conversation.Conversation>`.
Sending a message or getting a response returns a `Message
<telethon.tl.custom.message.Message>`. Reading its documentation
will also be really useful!
If a reply never arrives or too many messages come in, getting
responses will raise ``asyncio.TimeoutError`` or ``ValueError``
respectively. You may want to ``except`` these and tell the user
they were too slow, or simply drop the conversation.
Forwarding Messages
*******************
You can forward up to 100 messages with `forward_messages
<telethon.client.messages.MessageMethods.forward_messages>`,
or a single one if you have the message with `forward_to
<telethon.tl.custom.message.Message.forward_to>`:
.. code-block:: python
# a single one
client.forward_messages(chat, message)
# or
client.forward_messages(chat, message_id, from_chat)
# or
message.forward_to(chat)
# multiple
client.forward_messages(chat, messages)
# or
client.forward_messages(chat, message_ids, from_chat)
You can also "forward" messages without showing "Forwarded from" by
re-sending the message:
.. code-block:: python
client.send_message(chat, message)
Editing Messages
****************
With `edit_message <telethon.client.messages.MessageMethods.edit_message>`
or `message.edit <telethon.tl.custom.message.Message.edit>`:
.. code-block:: python
client.edit_message(message, 'New text')
# or
message.edit('New text')
# or
client.edit_message(chat, message_id, 'New text')
Deleting Messages
*****************
With `delete_messages <telethon.client.messages.MessageMethods.delete_messages>`
or `message.delete <telethon.tl.custom.message.Message.delete>`. Note that the
first one supports deleting entire chats at once!:
.. code-block:: python
client.delete_messages(chat, messages)
# or
message.delete()
Marking Messages as Read
************************
Marking messages up to a certain point as read with `send_read_acknowledge
<telethon.client.messages.MessageMethods.send_read_acknowledge>`:
.. code-block:: python
client.send_read_acknowledge(last_message)
# or
client.send_read_acknowledge(last_message_id)
# or
client.send_read_acknowledge(messages)
Getting Entities
****************
Entities are users, chats, or channels. You can get them by their ID if
you have seen them before (e.g. you probably need to get all dialogs or
all the members from a chat first):
.. code-block:: python
from telethon import utils
me = client.get_entity('me')
print(utils.get_display_name(me))
chat = client.get_input_entity('username')
for message in client.iter_messages(chat):
...
# Note that you could have used the username directly, but it's
# good to use get_input_entity if you will reuse it a lot.
for message in client.iter_messages('username'):
...
# Note that for this to work the phone number must be in your contacts
some_id = client.get_peer_id('+34123456789')
The documentation for shown methods are `get_entity
<telethon.client.users.UserMethods.get_entity>`, `get_input_entity
<telethon.client.users.UserMethods.get_input_entity>` and `get_peer_id
<telethon.client.users.UserMethods.get_peer_id>`.
Note that the utils package also has a `get_peer_id
<telethon.utils.get_peer_id>` but it won't work with things
that need access to the network such as usernames or phones,
which need to be in your contact list.
Getting the Admin Log
*********************
If you're an administrator in a channel or megagroup, then you have access
to the admin log. This is a list of events within the last 48 hours of
different actions, such as joining or leaving members, edited or deleted
messages, new promotions, bans or restrictions.
You can iterate over all the available actions like so:
.. code-block:: python
for event in client.iter_admin_log(channel):
if event.changed_title:
print('The title changed from', event.old, 'to', event.new)
You can also filter to only show some text or actions.
Let's find people who swear to ban them:
.. code-block:: python
# Get a list of deleted message events which said "heck"
events = client.get_admin_log(channel, search='heck', delete=True)
# Print the old message before it was deleted
print(events[0].old)
You can find here the documentation for `client.iter_admin_log
<telethon.client.chats.ChatMethods.iter_admin_log>`, and be sure
to also check the properties of the returned `AdminLogEvent
<telethon.tl.custom.adminlogevent.AdminLogEvent>` to know what
you can access.

View File

@ -1,27 +0,0 @@
========================================
Deleted, Limited or Deactivated Accounts
========================================
If you're from Iran or Russia, we have bad news for you. Telegram is much more
likely to ban these numbers, as they are often used to spam other accounts,
likely through the use of libraries like this one. The best advice we can
give you is to not abuse the API, like calling many requests really quickly,
and to sign up with these phones through an official application.
We have also had reports from Kazakhstan and China, where connecting
would fail. To solve these connection problems, you should use a proxy.
Telegram may also ban virtual (VoIP) phone numbers,
as again, they're likely to be used for spam.
If you want to check if your account has been limited,
simply send a private message to `@SpamBot`__ through Telegram itself.
You should notice this by getting errors like ``PeerFloodError``,
which means you're limited, for instance,
when sending a message to some accounts but not others.
For more discussion, please see `issue 297`__.
__ https://t.me/SpamBot
__ https://github.com/LonamiWebs/Telethon/issues/297

View File

@ -1,40 +0,0 @@
================
Enabling Logging
================
Telethon makes use of the `logging`__ module, and you can enable it as follows:
.. code:: python
import logging
logging.basicConfig(level=logging.DEBUG)
The library has the `NullHandler`__ added by default so that no log calls
will be printed unless you explicitly enable it.
You can also `use the module`__ on your own project very easily:
.. code-block:: python
import logging
logger = logging.getLogger(__name__)
logger.debug('Debug messages')
logger.info('Useful information')
logger.warning('This is a warning!')
If you want to enable ``logging`` for your project *but* use a different
log level for the library:
.. code-block:: python
import logging
logging.basicConfig(level=logging.DEBUG)
# For instance, show only warnings and above
logging.getLogger('telethon').setLevel(level=logging.WARNING)
__ https://docs.python.org/3/library/logging.html
__ https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
__ https://docs.python.org/3/howto/logging.html

View File

@ -1,29 +1,31 @@
.. Telethon documentation master file, created by
sphinx-quickstart on Fri Nov 17 15:36:11 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
========================
Telethon's Documentation
========================
====================================
Welcome to Telethon's documentation!
====================================
.. code-block:: python
from telethon.sync import TelegramClient, events
with TelegramClient('name', api_id, api_hash) as client:
client.send_message('me', 'Hello, myself!')
print(client.download_profile_photo('me'))
@client.on(events.NewMessage(pattern='(?i).*Hello'))
async def handler(event):
await event.reply('Hey!')
client.run_until_disconnected()
Pure Python 3 Telegram client library.
Official Site `here <https://lonamiwebs.github.io/Telethon>`_.
Please follow the links on the index below to navigate from here,
or use the menu on the left. Remember to read the :ref:`changelog`
when you upgrade!
.. important::
* Are you new here? Jump straight into :ref:`getting-started`!
* Looking for available friendly methods? See :ref:`ref-summary`.
* Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
* Need the full API reference? https://lonamiwebs.github.io/Telethon/.
* Are you new here? Jump straight into :ref:`installation`!
* Looking for the method reference? See :ref:`client-ref`.
* Did you upgrade the library? Please read :ref:`changelog`.
* Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
* Need the full API reference? https://lonamiwebs.github.io/Telethon/.
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
@ -31,93 +33,84 @@ with Telegram. Think of it as a wrapper that has already done the
heavy job for you, so you can focus on developing an application.
.. _installation-and-usage:
How should I use the documentation?
-----------------------------------
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.
.. toctree::
:maxdepth: 2
:caption: Installation and Simple Usage
:hidden:
:caption: First Steps
extra/basic/getting-started
extra/basic/installation
extra/basic/creating-a-client
extra/basic/telegram-client
extra/reference
extra/basic/entities
extra/basic/working-with-updates
extra/basic/compatibility-and-convenience
.. _Advanced-usage:
basic/installation
basic/signing-in
basic/quick-start
basic/updates
basic/next-steps
.. toctree::
:maxdepth: 2
:caption: Advanced Usage
:hidden:
:caption: Quick References
extra/advanced-usage/accessing-the-full-api
extra/advanced-usage/sessions
extra/advanced-usage/update-modes
extra/advanced-usage/mastering-telethon
extra/advanced-usage/mastering-asyncio
.. _Examples:
quick-references/faq
quick-references/client-reference
quick-references/events-reference
quick-references/objects-reference
.. toctree::
:maxdepth: 2
:caption: Examples
:hidden:
:caption: Concepts
extra/examples/telegram-client
extra/examples/working-with-messages
extra/examples/chats-and-channels
extra/examples/users
extra/examples/projects-using-telethon
.. _Troubleshooting:
concepts/strings
concepts/entities
concepts/updates
concepts/sessions
concepts/full-api
concepts/errors
concepts/asyncio
.. toctree::
:maxdepth: 2
:caption: Troubleshooting
:hidden:
:caption: Full API Examples
extra/troubleshooting/enable-logging
extra/troubleshooting/deleted-limited-or-deactivated-accounts
extra/troubleshooting/rpc-errors
.. _Developing:
examples/word-of-warning
examples/chats-and-channels
examples/users
examples/working-with-messages
examples/projects-using-telethon
.. toctree::
:maxdepth: 2
:caption: Developing
:hidden:
:caption: Developing
extra/developing/philosophy.rst
extra/developing/test-servers.rst
extra/developing/project-structure.rst
extra/developing/coding-style.rst
extra/developing/understanding-the-type-language.rst
extra/developing/tips-for-porting-the-project.rst
extra/developing/telegram-api-in-other-languages.rst
.. _More:
developing/philosophy.rst
developing/test-servers.rst
developing/project-structure.rst
developing/coding-style.rst
developing/understanding-the-type-language.rst
developing/tips-for-porting-the-project.rst
developing/telegram-api-in-other-languages.rst
.. toctree::
:maxdepth: 2
:caption: More
extra/changelog
extra/wall-of-shame.rst
:hidden:
:caption: Miscellaneous
misc/changelog
misc/wall-of-shame.rst
misc/compatibility-and-convenience
.. toctree::
:caption: Telethon modules
:hidden:
:caption: Telethon Modules
modules
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
modules/client
modules/events
modules/custom
modules/utils
modules/errors
modules/sessions
modules/network

View File

@ -867,7 +867,7 @@ Additions
<telethon.events.callbackquery.CallbackQuery>`.
- New ``silent`` parameter when sending messages, usable in broadcast channels.
- Documentation now has an entire section dedicate to how to use
the client's friendly methods at :ref:`telegram-client-example`.
the client's friendly methods at *(removed broken link)*.
Bug fixes
~~~~~~~~~
@ -924,7 +924,7 @@ Additions
~~~~~~~~~
- ``add_mark=`` is now back on ``utils.get_input_peer`` and also on
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`.
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`.
- New `client.get_peer_id <telethon.client.users.UserMethods.get_peer_id>`
convenience for ``utils.get_peer_id(await client.get_input_entity(peer))``.
@ -1776,7 +1776,7 @@ Of course there was more work to be done regarding updates, and it's here!
The library comes with a new ``events`` module (which you will often import
as ``from telethon import TelegramClient, events``). This are pretty much
all the additions that come with this version change, but they are a nice
addition. Refer to :ref:`working-with-updates` to get started with events.
addition. Refer to *(removed broken link)* to get started with events.
Trust the Server with Updates (v0.17)

View File

@ -12,7 +12,7 @@ is there to tell you when these important changes happen.
Compatibility
*************
=============
Some decisions when developing will inevitable be proven wrong in the future.
One of these decisions was using threads. Now that Python 3.4 is reaching EOL
@ -76,7 +76,7 @@ the chat or sender. If you don't use updates, you're done!
Convenience
***********
===========
.. note::
@ -134,7 +134,7 @@ This keeps the best of both worlds as a sane default.
them too. Otherwise, there is no need to do so with this mode.
Speed
*****
=====
When you're ready to micro-optimize your application, or if you simply
don't need to call any non-basic methods from a synchronous context,
@ -176,7 +176,7 @@ So that you don't have to write it yourself every time. That's the
overhead you pay if you import it, and what you save if you don't.
Learning
********
========
You know the library uses ``asyncio`` everywhere, and you want to learn
how to do things right. Even though ``asyncio`` is its own topic, the

View File

@ -1,7 +0,0 @@
telethon
========
.. toctree::
:maxdepth: 3
telethon

View File

@ -1,12 +1,14 @@
.. _telethon-client:
==============
TelegramClient
==============
telethon\.client package
========================
.. currentmodule:: telethon.client
The `telethon.TelegramClient` aggregates several mixin classes to provide
all the common functionality in a nice, Pythonic interface. Each mixin has
its own methods, which you all can use.
The `TelegramClient <telegramclient.TelegramClient>` aggregates several mixin
classes to provide all the common functionality in a nice, Pythonic interface.
Each mixin has its own methods, which you all can use.
**In short, to create a client you must run:**
@ -24,8 +26,15 @@ its own methods, which you all can use.
You **don't** need to import these `AuthMethods`, `MessageMethods`, etc.
Together they are the `telethon.TelegramClient` and you can access all of
their methods.
Together they are the `TelegramClient <telegramclient.TelegramClient>` and
you can access all of their methods.
See :ref:`client-ref` for a short summary.
.. automodule:: telethon.client.telegramclient
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.client.telegrambaseclient
:members:

View File

@ -1,115 +1,145 @@
telethon\.tl\.custom package
============================
==============
Custom package
==============
The `telethon.tl.custom` package contains custom classes that the library
uses in order to make working with Telegram easier. Only those that you
are supposed to use will be documented here. You can use undocumented ones
at your own risk.
telethon\.tl\.custom\.draft module
----------------------------------
More often than not, you don't need to import these (unless you want
type hinting), nor do you need to manually create instances of these
classes. They are returned by client methods.
.. automodule:: telethon.tl.custom.draft
.. contents::
.. automodule:: telethon.tl.custom
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.dialog module
-----------------------------------
.. automodule:: telethon.tl.custom.dialog
AdminLogEvent
=============
.. automodule:: telethon.tl.custom.adminlogevent
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.file module
---------------------------------
.. automodule:: telethon.tl.custom.file
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.message module
------------------------------------
.. automodule:: telethon.tl.custom.message
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.messagebutton module
------------------------------------------
.. automodule:: telethon.tl.custom.messagebutton
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.forward module
------------------------------------
.. automodule:: telethon.tl.custom.forward
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.button module
-----------------------------------
Button
======
.. automodule:: telethon.tl.custom.button
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.inlinebuilder module
------------------------------------------
.. automodule:: telethon.tl.custom.inlinebuilder
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.inlineresult module
-----------------------------------------
.. automodule:: telethon.tl.custom.inlineresult
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.inlineresults module
------------------------------------------
.. automodule:: telethon.tl.custom.inlineresults
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.chatgetter module
---------------------------------------
ChatGetter
==========
.. automodule:: telethon.tl.custom.chatgetter
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.sendergetter module
-----------------------------------------
.. automodule:: telethon.tl.custom.sendergetter
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.conversation module
-----------------------------------------
Conversation
============
.. automodule:: telethon.tl.custom.conversation
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.adminlogevent module
------------------------------------------
.. automodule:: telethon.tl.custom.adminlogevent
Dialog
======
.. automodule:: telethon.tl.custom.dialog
:members:
:undoc-members:
:show-inheritance:
Draft
=====
.. automodule:: telethon.tl.custom.draft
:members:
:undoc-members:
:show-inheritance:
File
====
.. automodule:: telethon.tl.custom.file
:members:
:undoc-members:
:show-inheritance:
Forward
=======
.. automodule:: telethon.tl.custom.forward
:members:
:undoc-members:
:show-inheritance:
InlineBuilder
=============
.. automodule:: telethon.tl.custom.inlinebuilder
:members:
:undoc-members:
:show-inheritance:
InlineResult
============
.. automodule:: telethon.tl.custom.inlineresult
:members:
:undoc-members:
:show-inheritance:
InlineResults
=============
.. automodule:: telethon.tl.custom.inlineresults
:members:
:undoc-members:
:show-inheritance:
Message
=======
.. automodule:: telethon.tl.custom.message
:members:
:undoc-members:
:show-inheritance:
MessageButton
=============
.. automodule:: telethon.tl.custom.messagebutton
:members:
:undoc-members:
:show-inheritance:
SenderGetter
============
.. automodule:: telethon.tl.custom.sendergetter
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,19 @@
.. _telethon-errors:
==========
API Errors
==========
These are the base errors that Telegram's API may raise.
See :ref:`rpc-errors` for a more friendly explanation.
.. automodule:: telethon.errors.common
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.errors.rpcbaseerrors
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,9 +1,12 @@
.. _telethon-events-package:
.. _telethon-events:
telethon\.events package
========================
=============
Update Events
=============
Every event (builder) subclasses `telethon.events.common.EventBuilder`,
.. currentmodule:: telethon.events
Every event (builder) subclasses `common.EventBuilder`,
so all the methods in it can be used from any event builder/event instance.
.. automodule:: telethon.events.common
@ -11,62 +14,51 @@ so all the methods in it can be used from any event builder/event instance.
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.newmessage
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.chataction
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.userupdate
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.messageedited
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.messagedeleted
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.messageread
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.callbackquery
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.inlinequery
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events.raw
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.events
:members:
:undoc-members:

View File

@ -0,0 +1,8 @@
=======
Helpers
=======
.. automodule:: telethon.helpers
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,33 @@
.. _telethon-network:
================
Connection Modes
================
The only part about network that you should worry about are
the different connection modes, which are the following:
.. automodule:: telethon.network.connection.tcpfull
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.network.connection.tcpabridged
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.network.connection.tcpintermediate
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.network.connection.tcpobfuscated
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.network.connection.http
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,27 @@
.. _telethon-sessions:
========
Sessions
========
These are the different built-in session storage that you may subclass.
.. automodule:: telethon.sessions.abstract
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.sessions.memory
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.sessions.sqlite
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.sessions.string
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,12 @@
.. _telethon-utils:
=========
Utilities
=========
These are the utilities that the library has to offer.
.. automodule:: telethon.utils
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,188 @@
.. _client-ref:
================
Client Reference
================
This page contains a summary of all the important methods and properties that
you may need when using Telethon. They are sorted by relevance and are not in
alphabetical order.
You should use this page to learn about which methods are available, and
if you need an usage example or further description of the arguments, be
sure to follow the links.
.. contents::
TelegramClient
==============
This is a summary of the methods and
properties you will find at :ref:`telethon-client`.
Auth
----
.. currentmodule:: telethon.client.auth.AuthMethods
.. autosummary::
:nosignatures:
start
send_code_request
sign_in
sign_up
log_out
edit_2fa
Base
----
.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
.. autosummary::
:nosignatures:
connect
disconnect
is_connected
disconnected
loop
Messages
--------
.. py:currentmodule:: telethon.client.messages.MessageMethods
.. autosummary::
:nosignatures:
send_message
edit_message
delete_messages
forward_messages
iter_messages
get_messages
send_read_acknowledge
Uploads
-------
.. py:currentmodule:: telethon.client.uploads.UploadMethods
.. autosummary::
:nosignatures:
send_file
upload_file
Downloads
---------
.. currentmodule:: telethon.client.downloads.DownloadMethods
.. autosummary::
:nosignatures:
download_media
download_profile_photo
download_file
Dialogs
-------
.. py:currentmodule:: telethon.client.dialogs.DialogMethods
.. autosummary::
:nosignatures:
iter_dialogs
get_dialogs
iter_drafts
get_drafts
conversation
Users
-----
.. py:currentmodule:: telethon.client.users.UserMethods
.. autosummary::
:nosignatures:
get_me
is_bot
is_user_authorized
get_entity
get_input_entity
get_peer_id
Chats
-----
.. currentmodule:: telethon.client.chats.ChatMethods
.. autosummary::
:nosignatures:
iter_participants
get_participants
iter_admin_log
get_admin_log
action
Parse Mode
----------
.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
.. autosummary::
:nosignatures:
parse_mode
Updates
-------
.. py:currentmodule:: telethon.client.updates.UpdateMethods
.. autosummary::
:nosignatures:
on
run_until_disconnected
add_event_handler
remove_event_handler
list_event_handlers
catch_up
Bots
----
.. currentmodule:: telethon.client.bots.BotMethods
.. autosummary::
:nosignatures:
inline_query
Buttons
-------
.. currentmodule:: telethon.client.buttons.ButtonMethods
.. autosummary::
:nosignatures:
build_reply_markup
Account
-------
.. currentmodule:: telethon.client.account.AccountMethods
.. autosummary::
:nosignatures:
takeout
end_takeout

View File

@ -0,0 +1,203 @@
================
Events Reference
================
Here you will find a quick summary of all the methods
and properties that you can access when working with events.
You can access the client that creates this event by doing
``event.client``, and you should view the description of the
events to find out what arguments it allows on creation and
its **attributes** (the properties will be shown here).
It is important to remember that **all events subclass**
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`!
.. contents::
ChatGetter
==========
All events subclass `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`,
which means all events have (and you can access to):
.. currentmodule:: telethon.tl.custom.chatgetter.ChatGetter
.. autosummary::
:nosignatures:
chat
input_chat
chat_id
is_private
is_group
is_channel
get_chat
get_input_chat
CallbackQuery
=============
Full documentation for the `CallbackQuery
<telethon.events.callbackquery.CallbackQuery>`.
.. currentmodule:: telethon.events.callbackquery.CallbackQuery.Event
.. autosummary::
:nosignatures:
id
message_id
data
chat_instance
via_inline
respond
reply
edit
delete
answer
get_message
ChatAction
==========
Full documentation for the `ChatAction
<telethon.events.chataction.ChatAction>`.
.. currentmodule:: telethon.events.chataction.ChatAction.Event
.. autosummary::
:nosignatures:
added_by
kicked_by
user
input_user
user_id
users
input_users
user_ids
respond
reply
delete
get_pinned_message
get_added_by
get_kicked_by
get_user
get_input_user
get_users
get_input_users
InlineQuery
===========
Full documentation for the `InlineQuery
<telethon.events.inlinequery.InlineQuery>`.
.. currentmodule:: telethon.events.inlinequery.InlineQuery.Event
.. autosummary::
:nosignatures:
id
text
offset
geo
builder
answer
MessageDeleted
==============
Full documentation for the `MessageDeleted
<telethon.events.messagedeleted.MessageDeleted>`.
It only has the ``deleted_id`` and ``deleted_ids`` attributes
(in addition to the chat if the deletion happened in a channel).
MessageEdited
=============
Full documentation for the `MessageEdited
<telethon.events.messageedited.MessageEdited>`.
This event is the same as `NewMessage
<telethon.events.newmessage.NewMessage>`,
but occurs only when an edit happens.
MessageRead
===========
Full documentation for the `MessageRead
<telethon.events.messageread.MessageRead>`.
.. currentmodule:: telethon.events.messageread.MessageRead.Event
.. autosummary::
:nosignatures:
inbox
message_ids
get_messages
is_read
NewMessage
==========
Full documentation for the `NewMessage
<telethon.events.newmessage.NewMessage>`.
Note that the new message event **should be treated as** a
normal `Message <telethon.tl.custom.message.Message>`, with
the following exceptions:
* ``pattern_match`` is the match object returned by ``pattern=``.
* ``message`` is **not** the message string. It's the `Message
<telethon.tl.custom.message.Message>` object.
Remember, this event is just a proxy over the message, so while
you won't see its attributes and properties, you can still access
them.
Raw
===
Raw events are not actual events. Instead, they are the raw
:tl:`Update` object that Telegram sends. You normally shouldn't
need these.
UserUpdate
==========
Full documentation for the `UserUpdate
<telethon.events.userupdate.UserUpdate>`.
A lot of fields are attributes and not properties, so they
are not shown here.
.. currentmodule:: telethon.events.userupdate.UserUpdate.Event
.. autosummary::
:nosignatures:
user
input_user
user_id
get_user
get_input_user

View File

@ -0,0 +1,190 @@
===
FAQ
===
Let's start the quick references section with some useful tips to keep in
mind, with the hope that you will understand why certain things work the
way that they do.
.. contents::
Code without errors doesn't work
================================
Then it probably has errors, but you haven't enabled logging yet.
To enable logging, at the following code to the top of your main file:
.. code-block:: python
import logging
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
level=logging.WARNING)
You can change the logging level to be something different, from less to more information:
.. code-block:: python
level=logging.CRITICAL # won't show errors (same as disabled)
level=logging.ERROR # will only show errors that you didn't handle
level=logging.WARNING # will also show messages with medium severity, such as internal Telegram issues
level=logging.INFO # will also show informational messages, such as connection or disconnections
level=logging.DEBUG # will show a lot of output to help debugging issues in the library
See the official Python documentation for more information on logging_.
How can I except FloodWaitError?
================================
You can use all errors from the API by importing:
.. code-block:: python
from telethon import errors
And except them as such:
.. code-block:: python
import time
try:
client.send_message(chat, 'Hi')
except FloodWaitError as e:
print('Flood for', e.seconds)
time.sleep(e.seconds)
My account was deleted/limited when using the library
=====================================================
The library will only do things that you tell it to do. If you use
the library with bad intentions, Telegram will hopefully ban you.
However, you may also be part of a limited country, such as Iran or Russia.
In that case, we have bad news for you. Telegram is much more likely to ban
these numbers, as they are often used to spam other accounts, likely through
the use of libraries like this one. The best advice we can give you is to not
abuse the API, like calling many requests really quickly, and to sign up with
these phones through an official application.
We have also had reports from Kazakhstan and China, where connecting
would fail. To solve these connection problems, you should use a proxy.
Telegram may also ban virtual (VoIP) phone numbers,
as again, they're likely to be used for spam.
If you want to check if your account has been limited,
simply send a private message to `@SpamBot`_ through Telegram itself.
You should notice this by getting errors like ``PeerFloodError``,
which means you're limited, for instance,
when sending a message to some accounts but not others.
For more discussion, please see `issue 297`_.
How can I use a proxy?
======================
This was one of the first things described in :ref:`signing-in`.
How do I access a field?
========================
This is basic Python knowledge. You should use the dot operator:
.. code-block:: python
me = client.get_me()
print(me.username)
# ^ we used the dot operator to access the username attribute
result = client(functions.photos.GetUserPhotosRequest(
user_id='me',
offset=0,
max_id=0,
limit=100
))
# Working with list is also pretty basic
print(result.photos[0].sizes[-1].type)
# ^ ^ ^ ^ ^
# | | | | \ type
# | | | \ last size
# | | \ list of sizes
# access | \ first photo from the list
# the... \ list of photos
#
# To print all, you could do (or mix-and-match):
for photo in result.photos:
for size in photo.sizes:
print(size.type)
AttributeError: 'coroutine' object has no attribute 'id'
========================================================
You either forgot to:
.. code-block:: python
import telethon.sync
# ^^^^^ import sync
Or:
.. code-block:: python
async def handler(event):
me = await client.get_me()
# ^^^^^ note the await
print(me.username)
sqlite3.OperationalError: database is locked
============================================
An older process is still running and is using the same ``'session'`` file.
This error occurs when **two or more clients use the same session**,
that is, when you write the same session name to be used in the client:
* You have an older process using the same session file.
* You have two different scripts running (interactive sessions count too).
* You have two clients in the same script running at the same time.
The solution is, if you need two clients, use two sessions. If the
problem persists and you're on Linux, you can use ``fuser my.session``
to find out the process locking the file. As a last resort, you can
reboot your system.
If you really dislike SQLite, use a different session storage. There
is an entire section covering that at :ref:`sessions`.
event.chat or event.sender is None
==================================
Telegram doesn't always send this information in order to save bandwidth.
If you need the information, you should fetch it yourself, since the library
won't do unnecessary work unless you need to:
.. code-block:: python
async def handler(event):
chat = await event.get_chat()
sender = await event.get_sender()
Can I use Flask with the library?
=================================
Yes, if you know what you are doing. However, you will probably have a
lot of headaches to get threads and asyncio to work together. Instead,
consider using `Quart <https://pgjones.gitlab.io/quart/>`_, an asyncio-based
alternative to `Flask <flask.pocoo.org/>`_.
.. _logging: https://docs.python.org/3/library/logging.html
.. _@SpamBot: https://t.me/SpamBot
.. _issue 297: https://github.com/LonamiWebs/Telethon/issues/297

View File

@ -1,191 +1,16 @@
.. _ref-summary:
=================
Reference Summary
Objects Reference
=================
This page contains a summary of all the important methods and properties that
you may need when using Telethon. They are sorted by relevance and are not in
alphabetical order.
This is the quick reference for those objects returned by client methods
or other useful modules that the library has to offer. They are kept in
a separate page to help finding and discovering them.
The way you should use this page is by looking up the type you need in the
table of contents (method index below) and searching for the method or
property that you are interested in.
Remember that this page only shows properties and methods,
**not attributes**. Make sure to open the full documentation
to find out about the attributes.
.. contents:: Method Index
TelegramClient
==============
This is a summary of the methods and
properties you will find at :ref:`telethon-client`.
Auth
----
.. currentmodule:: telethon.client.auth.AuthMethods
.. autosummary::
:nosignatures:
start
send_code_request
sign_in
sign_up
log_out
edit_2fa
Base
----
.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
.. autosummary::
:nosignatures:
connect
disconnect
is_connected
disconnected
loop
Messages
--------
.. py:currentmodule:: telethon.client.messages.MessageMethods
.. autosummary::
:nosignatures:
send_message
edit_message
delete_messages
forward_messages
iter_messages
get_messages
send_read_acknowledge
Uploads
-------
.. py:currentmodule:: telethon.client.uploads.UploadMethods
.. autosummary::
:nosignatures:
send_file
upload_file
Downloads
---------
.. currentmodule:: telethon.client.downloads.DownloadMethods
.. autosummary::
:nosignatures:
download_media
download_profile_photo
download_file
Dialogs
-------
.. py:currentmodule:: telethon.client.dialogs.DialogMethods
.. autosummary::
:nosignatures:
iter_dialogs
get_dialogs
iter_drafts
get_drafts
conversation
Users
-----
.. py:currentmodule:: telethon.client.users.UserMethods
.. autosummary::
:nosignatures:
get_me
is_bot
is_user_authorized
get_entity
get_input_entity
get_peer_id
Chats
-----
.. currentmodule:: telethon.client.chats.ChatMethods
.. autosummary::
:nosignatures:
iter_participants
get_participants
iter_admin_log
get_admin_log
action
Parse Mode
----------
.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
.. autosummary::
:nosignatures:
parse_mode
Updates
-------
.. py:currentmodule:: telethon.client.updates.UpdateMethods
.. autosummary::
:nosignatures:
on
run_until_disconnected
add_event_handler
remove_event_handler
list_event_handlers
catch_up
Bots
----
.. currentmodule:: telethon.client.bots.BotMethods
.. autosummary::
:nosignatures:
inline_query
Buttons
-------
.. currentmodule:: telethon.client.buttons.ButtonMethods
.. autosummary::
:nosignatures:
build_reply_markup
Account
-------
.. currentmodule:: telethon.client.account.AccountMethods
.. autosummary::
:nosignatures:
takeout
end_takeout
.. contents::
Message

View File

@ -1,22 +0,0 @@
.. _telethon-errors-package:
telethon\.errors package
========================
telethon\.errors\.common module
-------------------------------
.. automodule:: telethon.errors.common
:members:
:undoc-members:
:show-inheritance:
telethon\.errors\.rpcbaseerrors module
--------------------------------------
.. automodule:: telethon.errors.rpcbaseerrors
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,27 +0,0 @@
telethon\.extensions package
============================
telethon\.extensions\.binaryreader module
-----------------------------------------
.. automodule:: telethon.extensions.binaryreader
:members:
:undoc-members:
:show-inheritance:
telethon\.extensions\.markdown module
-------------------------------------
.. automodule:: telethon.extensions.markdown
:members:
:undoc-members:
:show-inheritance:
telethon\.extensions\.html module
---------------------------------
.. automodule:: telethon.extensions.html
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,35 +0,0 @@
telethon\.network package
=========================
telethon\.network\.connection module
------------------------------------
.. automodule:: telethon.network.connection
:members:
:undoc-members:
:show-inheritance:
telethon\.network\.mtprotoplainsender module
------------------------------------------------
.. automodule:: telethon.network.mtprotoplainsender
:members:
:undoc-members:
:show-inheritance:
telethon\.network\.mtprotosender module
-----------------------------------------
.. automodule:: telethon.network.mtprotosender
:members:
:undoc-members:
:show-inheritance:
telethon\.network\.authenticator module
---------------------------------------
.. automodule:: telethon.network.authenticator
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,90 +0,0 @@
.. _telethon-package:
telethon package
================
telethon\.client module
-----------------------
.. toctree::
telethon.client
.. automodule:: telethon.client
:members:
:undoc-members:
:show-inheritance:
telethon\.utils module
----------------------
.. automodule:: telethon.utils
:members:
:undoc-members:
:show-inheritance:
telethon\.helpers module
------------------------
.. automodule:: telethon.helpers
:members:
:undoc-members:
:show-inheritance:
telethon\.events package
------------------------
.. toctree::
telethon.events
telethon\.sessions module
-------------------------
.. automodule:: telethon.sessions
:members:
:undoc-members:
:show-inheritance:
telethon\.errors package
------------------------
.. toctree::
telethon.errors
telethon\.extensions package
----------------------------
.. toctree::
telethon.extensions
telethon\.network package
-------------------------
.. toctree::
telethon.network
telethon\.tl package
--------------------
.. toctree::
telethon.tl
Module contents
---------------
.. automodule:: telethon
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,16 +0,0 @@
telethon\.tl\.custom package
============================
.. toctree::
telethon.tl.custom
telethon\.tl\.tlobject module
-----------------------------
.. automodule:: telethon.tl.tlobject
:members:
:undoc-members:
:show-inheritance:

View File

@ -120,7 +120,7 @@ class AccountMethods(UserMethods):
files: bool = None,
max_file_size: bool = None) -> 'TelegramClient':
"""
Returns a :ref:`TelegramClient` which calls methods behind a takeout session.
Returns a :ref:`telethon-client` which calls methods behind a takeout session.
It does so by creating a proxy object over the current client through
which making requests will use :tl:`InvokeWithTakeoutRequest` to wrap
@ -190,6 +190,20 @@ class AccountMethods(UserMethods):
max_file_size (`int`):
The maximum file size, in bytes, that you plan
to download for each message with media.
Example:
.. code-block:: python
from telethon import errors
try:
with client.takeout() as takeout:
for message in takeout.iter_messages(chat, wait_time=0):
... # Do something with the message
except errors.TakeoutInitDelayError as e:
print('Must wait', e.seconds, 'before takeout')
"""
request_kwargs = dict(
contacts=contacts,

View File

@ -40,13 +40,6 @@ class AuthMethods(MessageParseMethods, UserMethods):
will be banned otherwise.** See https://telegram.org/tos
and https://core.telegram.org/api/terms.
Example usage:
>>> client = ...
>>> client.start(phone)
Please enter the code you received: 12345
Please enter your password: *******
(You are now logged in)
If the event loop is already running, this method returns a
coroutine that you should await on your own code; otherwise
the loop is ran until said coroutine completes.
@ -91,6 +84,24 @@ class AuthMethods(MessageParseMethods, UserMethods):
Returns:
This `TelegramClient`, so initialization
can be chained with ``.start()``.
Example:
.. code-block:: python
client = TelegramClient('anon', api_id, api_hash)
# Starting as a bot account
client.start(bot_token=bot_token)
# Starting as an user account
client.start(phone)
# Please enter the code you received: 12345
# Please enter your password: *******
# (You are now logged in)
# Starting using a context manager (this calls start()):
with client:
pass
"""
if code_callback is None:
def code_callback():
@ -452,6 +463,13 @@ class AuthMethods(MessageParseMethods, UserMethods):
Returns:
``True`` if the operation was successful.
Example:
.. code-block:: python
# Note: you will need to login again!
client.log_out()
"""
try:
await self(functions.auth.LogOutRequest())

View File

@ -39,6 +39,16 @@ class BotMethods(UserMethods):
Returns:
A list of `custom.InlineResult
<telethon.tl.custom.inlineresult.InlineResult>`.
Example:
.. code-block:: python
# Make an inline query to @like
results = client.inline_query('like', 'Do you like Telethon?')
# Send the first result to some chat
message = results[0].click('TelethonOffTopic')
"""
bot = await self.get_input_entity(bot)
result = await self(functions.messages.GetInlineBotResultsRequest(

View File

@ -328,6 +328,23 @@ class ChatMethods(UserMethods):
with an additional ``.participant`` attribute which is the
matched :tl:`ChannelParticipant` type for channels/megagroups
or :tl:`ChatParticipants` for normal chats.
Example:
.. code-block:: python
# Show all user IDs in a chat
for user in client.iter_participants(chat):
print(user.id)
# Search by name
for user in client.iter_participants(chat, search='name'):
print(user.username)
# Filter by admins
from telethon.tl.types import ChannelParticipantsAdmins
for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
print(user.first_name)
"""
return _ParticipantsIter(
self,
@ -343,7 +360,7 @@ class ChatMethods(UserMethods):
*args,
**kwargs) -> 'hints.TotalList':
"""
Same as `iter_participants`, but returns a
Same as `iter_participants()`, but returns a
`TotalList <telethon.helpers.TotalList>` instead.
"""
return await self.iter_participants(*args, **kwargs).collect()
@ -457,6 +474,20 @@ class ChatMethods(UserMethods):
Yields:
Instances of `telethon.tl.custom.adminlogevent.AdminLogEvent`.
Example:
.. code-block:: python
for event in client.iter_admin_log(channel):
if event.changed_title:
print('The title changed from', event.old, 'to', event.new)
# Get a list of deleted message events which said "heck"
events = client.get_admin_log(channel, search='heck', delete=True)
# Print the old message before it was deleted
print(events[0].old)
"""
return _AdminLogIter(
self,
@ -487,7 +518,7 @@ class ChatMethods(UserMethods):
*args,
**kwargs) -> 'hints.TotalList':
"""
Same as `iter_admin_log`, but returns a ``list`` instead.
Same as `iter_admin_log()`, but returns a ``list`` instead.
"""
return await self.iter_admin_log(*args, **kwargs).collect()

View File

@ -138,6 +138,21 @@ class DialogMethods(UserMethods):
Yields:
Instances of `telethon.tl.custom.dialog.Dialog`.
Example:
.. code-block:: python
# Get all open conversation, print the title of the first
dialogs = client.get_dialogs()
first = dialogs[0]
print(first.title)
# Use the dialog somewhere else
client.send_message(first, 'hi')
# Get drafts
drafts = client.get_drafts()
"""
return _DialogsIter(
self,
@ -150,7 +165,7 @@ class DialogMethods(UserMethods):
async def get_dialogs(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
"""
Same as `iter_dialogs`, but returns a
Same as `iter_dialogs()`, but returns a
`TotalList <telethon.helpers.TotalList>` instead.
"""
return await self.iter_dialogs(*args, **kwargs).collect()
@ -169,7 +184,7 @@ class DialogMethods(UserMethods):
async def get_drafts(self: 'TelegramClient') -> 'hints.TotalList':
"""
Same as :meth:`iter_drafts`, but returns a list instead.
Same as `iter_drafts()`, but returns a list instead.
"""
return await self.iter_drafts().collect()
@ -257,6 +272,35 @@ class DialogMethods(UserMethods):
Returns:
A `Conversation <telethon.tl.custom.conversation.Conversation>`.
Example:
.. code-block:: python
# <you> denotes outgoing messages you sent
# <usr> denotes incoming response messages
with bot.conversation(chat) as conv:
# <you> Hi!
conv.send_message('Hi!')
# <usr> Hello!
hello = conv.get_response()
# <you> Please tell me your name
conv.send_message('Please tell me your name')
# <usr> ?
name = conv.get_response().raw_text
while not any(x.isalpha() for x in name):
# <you> Your name didn't have any letters! Try again
conv.send_message("Your name didn't have any letters! Try again")
# <usr> Lonami
name = conv.get_response().raw_text
# <you> Thanks Lonami!
conv.send_message('Thanks {}!'.format(name))
"""
return custom.Conversation(
self,

View File

@ -56,6 +56,13 @@ class DownloadMethods(UserMethods):
Returns:
``None`` if no photo was provided, or if it was Empty. On success
the file path is returned since it may differ from the one given.
Example:
.. code-block:: python
path = client.download_profile_photo('me')
print(path)
"""
# hex(crc32(x.encode('ascii'))) for x in
# ('User', 'Chat', 'UserFull', 'ChatFull')
@ -173,6 +180,17 @@ class DownloadMethods(UserMethods):
Returns:
``None`` if no media was provided, or if it was Empty. On success
the file path is returned since it may differ from the one given.
Example:
.. code-block:: python
path = client.download_media(message)
client.download_media(message, filename)
# or
path = message.download_media()
message.download_media(filename)
"""
# TODO This won't work for messageService
if isinstance(message, types.Message):

View File

@ -413,6 +413,31 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Telegram's flood wait limit for :tl:`GetHistoryRequest` seems to
be around 30 seconds per 10 requests, therefore a sleep of 1
second is the default for this limit (or above).
Example:
.. code-block:: python
# From most-recent to oldest
for message in client.iter_messages(chat):
print(message.id, message.text)
# From oldest to most-recent
for message in client.iter_messages(chat, reverse=True):
print(message.id, message.text)
# Filter by sender
for message in client.iter_messages(chat, from_user='me'):
print(message.text)
# Server-side search with fuzzy text
for message in client.iter_messages(chat, search='hello'):
print(message.id)
# Filter by message type:
from telethon.tl.types import InputMessagesFilterPhotos
for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
print(message.photo)
"""
if ids is not None:
@ -436,7 +461,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
async def get_messages(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
"""
Same as `iter_messages`, but returns a
Same as `iter_messages()`, but returns a
`TotalList <telethon.helpers.TotalList>` instead.
If the `limit` is not set, it will be 1 by default unless both
@ -450,6 +475,21 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
If `ids` is present in the *named* arguments and is not a list,
a single `Message <telethon.tl.custom.message.Message>` will be
returned for convenience instead of a list.
Example:
.. code-block:: python
# Get 0 photos and print the total to show how many photos there are
from telethon.tl.types import InputMessagesFilterPhotos
photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
print(photos.total)
# Get all the photos
photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
# Get messages by ID:
message_1337 = client.get_messages(chats, ids=1337)
"""
if len(args) == 1 and 'limit' not in kwargs:
if 'min_id' in kwargs and 'max_id' in kwargs:
@ -501,6 +541,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
the bot.
Args:
entity (`entity`):
To who will it be sent.
@ -556,7 +597,65 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
notify them. Set it to ``True`` to alter this behaviour.
Returns:
The sent `custom.Message <telethon.tl.custom.message.Message>`.
Example:
.. code-block:: python
client.send_message('lonami', 'Thanks for the Telethon library!')
# Replies and responses
message = client.send_message('me', 'Trying out **markdown**')
message.reply('Trying replies')
message.respond('Trying responses')
# Default to another parse mode
client.parse_mode = 'html'
client.send_message('me', 'Some <b>bold</b> and <i>italic</i> text')
client.send_message('me', 'An <a href="https://example.com">URL</a>')
client.send_message('me', '<code>code</code> and <pre>pre\nblocks</pre>')
client.send_message('me', '<a href="tg://user?id=me">Mentions</a>')
# Explicit parse mode
# No parse mode by default
client.parse_mode = None
# ...but here I want markdown
client.send_message('me', 'Hello, **world**!', parse_mode='md')
# ...and here I need HTML
client.send_message('me', 'Hello, <i>world</i>!', parse_mode='html')
# If you logged in as a bot account, you can send buttons
from telethon import events, Button
@client.on(events.CallbackQuery)
async def callback(event):
await event.edit('Thank you for clicking {}!'.format(event.data))
# Single inline button
client.send_message(chat, 'A single button, with "clk1" as data',
buttons=Button.inline('Click me', b'clk1'))
# Matrix of inline buttons
client.send_message(chat, 'Pick one from this grid', buttons=[
[Button.inline('Left'), Button.inline('Right')],
[Button.url('Check this site!', 'https://lonamiwebs.github.io')]
])
# Reply keyboard
client.send_message(chat, 'Welcome', buttons=[
Button.text('Thanks!', resize=True, single_use=True),
Button.request_phone('Send phone'),
Button.request_location('Send location')
])
# Forcing replies or clearing buttons.
client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
"""
if file is not None:
return await self.send_file(
@ -685,6 +784,25 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Note that if all messages are invalid (i.e. deleted) the call
will fail with ``MessageIdInvalidError``. If only some are
invalid, the list will have ``None`` instead of those messages.
Example:
.. code-block:: python
# a single one
client.forward_messages(chat, message)
# or
client.forward_messages(chat, message_id, from_chat)
# or
message.forward_to(chat)
# multiple
client.forward_messages(chat, messages)
# or
client.forward_messages(chat, message_ids, from_chat)
# Forwarding as a copy
client.send_message(chat, message)
"""
single = not utils.is_list_like(messages)
if single:
@ -829,6 +947,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
The edited `telethon.tl.custom.message.Message`, unless
`entity` was a :tl:`InputBotInlineMessageID` in which
case this method returns a boolean.
Example:
.. code-block:: python
client.edit_message(message, 'New text')
# or
message.edit('New text')
# or
client.edit_message(chat, message_id, 'New text')
"""
if isinstance(entity, types.InputBotInlineMessageID):
text = message
@ -900,6 +1028,14 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Returns:
A list of :tl:`AffectedMessages`, each item being the result
for the delete calls of the messages in chunks of 100 each.
Example:
.. code-block:: python
client.delete_messages(chat, messages)
# or
message.delete()
"""
if not utils.is_list_like(message_ids):
message_ids = (message_ids,)
@ -955,6 +1091,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
If no message is provided, this will be the only action
taken.
Example:
.. code-block:: python
client.send_read_acknowledge(last_message)
# or
client.send_read_acknowledge(last_message_id)
# or
client.send_read_acknowledge(messages)
"""
if max_id is None:
if not message:

View File

@ -396,6 +396,13 @@ class TelegramBaseClient(abc.ABC):
If the event loop is already running, this method returns a
coroutine that you should await on your own code; otherwise
the loop is ran until said coroutine completes.
Example:
.. code-block:: python
# You don't need to use this if you used "with client"
client.disconnect()
"""
if self._loop.is_running():
return self._disconnect_coro()

View File

@ -117,7 +117,7 @@ class UpdateMethods(UserMethods):
callback: callable,
event: EventBuilder = None) -> int:
"""
Inverse operation of `add_event_handler`.
Inverse operation of `add_event_handler()`.
If no event is given, all events for this callback are removed.
Returns how many callbacks were removed.

View File

@ -232,6 +232,32 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
Returns:
The `telethon.tl.custom.message.Message` (or messages) containing
the sent file, or messages if a list of them was passed.
Example:
.. code-block:: python
# Normal files like photos
client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
# or
client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
# Voice notes or round videos
client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
client.send_file(chat, '/my/videos/video.mp4', video_note=True)
# Custom thumbnails
client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
# Only documents
client.send_file(chat, '/my/photos/photo.png', force_document=True)
# Albums
client.send_file(chat, [
'/my/photos/holiday1.jpg',
'/my/photos/holiday2.jpg',
'/my/drawings/portrait.png'
])
"""
# i.e. ``None`` was used
if not file:
@ -427,6 +453,23 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
:tl:`InputFileBig` if the file size is larger than 10MB,
`telethon.tl.custom.inputsizedfile.InputSizedFile`
(subclass of :tl:`InputFile`) otherwise.
Example:
.. code-block:: python
# Photos as photo and document
file = client.upload_file('photo.jpg')
client.send_file(chat, file) # sends as photo
client.send_file(chat, file, force_document=True) # sends as document
file.name = 'not a photo.jpg'
client.send_file(chat, file, force_document=True) # document, new name
# As song or as voice note
file = client.upload_file('song.ogg')
client.send_file(chat, file) # sends as song
client.send_file(chat, file, voice_note=True) # sends as voice note
"""
if isinstance(file, (types.InputFile, types.InputFileBig)):
return file # Already uploaded

View File

@ -191,6 +191,27 @@ class UserMethods(TelegramBaseClient):
Returns:
:tl:`User`, :tl:`Chat` or :tl:`Channel` corresponding to the
input entity. A list will be returned if more than one was given.
Example:
.. code-block:: python
from telethon import utils
me = client.get_entity('me')
print(utils.get_display_name(me))
chat = client.get_input_entity('username')
for message in client.iter_messages(chat):
...
# Note that you could have used the username directly, but it's
# good to use get_input_entity if you will reuse it a lot.
for message in client.iter_messages('username'):
...
# Note that for this to work the phone number must be in your contacts
some_id = client.get_peer_id('+34123456789')
"""
single = not utils.is_list_like(entity)
if single:

View File

@ -42,7 +42,7 @@ class StopPropagation(Exception):
def register(event=None):
"""
Decorator method to *register* event handlers. This is the client-less
`add_event_handler
`add_event_handler()
<telethon.client.updates.UpdateMethods.add_event_handler>` variant.
Note that this method only registers callbacks as handlers,

View File

@ -178,6 +178,20 @@ class InlineQuery(EventBuilder):
switch_pm_param (`str`, optional):
Optional parameter to start the bot with if
`switch_pm` was used.
Example:
.. code-block:: python
@bot.on(events.InlineQuery)
async def handler(event):
builder = event.builder
rev_text = event.text[::-1]
await event.answer([
builder.article('Reverse text', text=rev_text),
builder.photo('/path/to/photo.jpg')
])
"""
if self._answered:
return

View File

@ -95,7 +95,7 @@ class MessageRead(EventBuilder):
async def get_messages(self):
"""
Returns the list of `telethon.tl.custom.message.Message`
Returns the list of `Message <telethon.tl.custom.message.Message>`
**which contents'** were read.
Use :meth:`is_read` if you need to check whether a message

View File

@ -190,23 +190,23 @@ class UserUpdate(EventBuilder):
@property
def user(self):
"""Alias for `sender`."""
"""Alias for `sender <telethon.tl.custom.sendergetter.SenderGetter.sender>`."""
return self.sender
async def get_user(self):
"""Alias for `get_sender`."""
"""Alias for `get_sender <telethon.tl.custom.sendergetter.SenderGetter.get_sender>`."""
return await self.get_sender()
@property
def input_user(self):
"""Alias for `input_sender`."""
"""Alias for `input_sender <telethon.tl.custom.sendergetter.SenderGetter.input_sender>`."""
return self.input_sender
async def get_input_user(self):
"""Alias for `get_input_sender`."""
"""Alias for `get_input_sender <telethon.tl.custom.sendergetter.SenderGetter.get_input_sender>`."""
return await self.get_input_sender()
@property
def user_id(self):
"""Alias for `sender_id`."""
"""Alias for `sender_id <telethon.tl.custom.sendergetter.SenderGetter.sender_id>`."""
return self.sender_id

View File

@ -33,11 +33,11 @@ class InlineBuilder:
May be ``True`` to indicate that the game will be sent.
buttons (`list`, `custom.Button <telethon.tl.custom.button.Button>`, :tl:`KeyboardButton`, optional):
Same as ``buttons`` for `client.send_message
Same as ``buttons`` for `client.send_message()
<telethon.client.messages.MessageMethods.send_message>`.
parse_mode (`str`, optional):
Same as ``parse_mode`` for `client.send_message
Same as ``parse_mode`` for `client.send_message()
<telethon.client.messageparse.MessageParseMethods.parse_mode>`.
id (`str`, optional):
@ -119,7 +119,7 @@ class InlineBuilder:
Args:
file (`obj`, optional):
Same as ``file`` for `client.send_file
Same as ``file`` for `client.send_file()
<telethon.client.uploads.UploadMethods.send_file>`.
"""
try:
@ -173,7 +173,7 @@ class InlineBuilder:
Args:
file (`obj`):
Same as ``file`` for `client.send_file
Same as ``file`` for `client.send_file()
<telethon.client.uploads.UploadMethods.send_file>`.
title (`str`, optional):

View File

@ -784,6 +784,22 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
behave as if it clicked a button with said data. Note
that if the message does not have this data, it will
``raise DataInvalidError``.
Example:
.. code-block:: python
# Click the first button
message.click(0)
# Click some row/column
message.click(row, column)
# Click by text
message.click(text='👍')
# Click by data
message.click(data=b'payload')
"""
if not self._client:
return

View File

@ -937,11 +937,12 @@ def _encode_telegram_base64(string):
def resolve_bot_file_id(file_id):
"""
Given a Bot API-style `file_id`, returns the media it represents.
If the `file_id` is not valid, ``None`` is returned instead.
Given a Bot API-style `file_id <telethon.tl.custom.file.File.id>`,
returns the media it represents. If the `file_id <telethon.tl.custom.file.File.id>`
is not valid, ``None`` is returned instead.
Note that the `file_id` does not have information such as image
dimensions or file size, so these will be zero if present.
Note that the `file_id <telethon.tl.custom.file.File.id>` does not have information
such as image dimensions or file size, so these will be zero if present.
For thumbnails, the photo ID and hash will always be zero.
"""