Showing preview only (1,889K chars total). Download the full file or copy to clipboard to get everything.
Repository: LonamiWebs/Telethon
Branch: v1
Commit: dab6bc4d4fc0
Files: 224
Total size: 1.8 MB
Directory structure:
gitextract_c7m6jtsy/
├── .coveragerc
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ ├── config.yml
│ │ ├── documentation-issue.yml
│ │ └── feature-request.yml
│ ├── pull_request_template.md
│ └── workflows.disabled/
│ └── python.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── LICENSE
├── README.rst
├── dev-requirements.txt
├── optional-requirements.txt
├── pyproject.toml
├── readthedocs/
│ ├── Makefile
│ ├── basic/
│ │ ├── installation.rst
│ │ ├── next-steps.rst
│ │ ├── quick-start.rst
│ │ ├── signing-in.rst
│ │ └── updates.rst
│ ├── concepts/
│ │ ├── asyncio.rst
│ │ ├── botapi-vs-mtproto.rst
│ │ ├── chats-vs-channels.rst
│ │ ├── entities.rst
│ │ ├── errors.rst
│ │ ├── full-api.rst
│ │ ├── sessions.rst
│ │ ├── strings.rst
│ │ └── updates.rst
│ ├── conf.py
│ ├── custom_roles.py
│ ├── developing/
│ │ ├── coding-style.rst
│ │ ├── philosophy.rst
│ │ ├── project-structure.rst
│ │ ├── telegram-api-in-other-languages.rst
│ │ ├── test-servers.rst
│ │ ├── testing.rst
│ │ ├── tips-for-porting-the-project.rst
│ │ └── understanding-the-type-language.rst
│ ├── examples/
│ │ ├── chats-and-channels.rst
│ │ ├── users.rst
│ │ ├── word-of-warning.rst
│ │ └── working-with-messages.rst
│ ├── index.rst
│ ├── make.bat
│ ├── misc/
│ │ ├── changelog.rst
│ │ └── compatibility-and-convenience.rst
│ ├── modules/
│ │ ├── client.rst
│ │ ├── custom.rst
│ │ ├── errors.rst
│ │ ├── events.rst
│ │ ├── helpers.rst
│ │ ├── network.rst
│ │ ├── sessions.rst
│ │ └── utils.rst
│ ├── quick-references/
│ │ ├── client-reference.rst
│ │ ├── events-reference.rst
│ │ ├── faq.rst
│ │ └── objects-reference.rst
│ └── requirements.txt
├── requirements.txt
├── setup.py
├── telethon/
│ ├── __init__.py
│ ├── _updates/
│ │ ├── __init__.py
│ │ ├── entitycache.py
│ │ ├── messagebox.py
│ │ └── session.py
│ ├── client/
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── auth.py
│ │ ├── bots.py
│ │ ├── buttons.py
│ │ ├── chats.py
│ │ ├── dialogs.py
│ │ ├── downloads.py
│ │ ├── messageparse.py
│ │ ├── messages.py
│ │ ├── telegrambaseclient.py
│ │ ├── telegramclient.py
│ │ ├── updates.py
│ │ ├── uploads.py
│ │ └── users.py
│ ├── crypto/
│ │ ├── __init__.py
│ │ ├── aes.py
│ │ ├── aesctr.py
│ │ ├── authkey.py
│ │ ├── cdndecrypter.py
│ │ ├── factorization.py
│ │ ├── libssl.py
│ │ └── rsa.py
│ ├── custom.py
│ ├── errors/
│ │ ├── __init__.py
│ │ ├── common.py
│ │ └── rpcbaseerrors.py
│ ├── events/
│ │ ├── __init__.py
│ │ ├── album.py
│ │ ├── callbackquery.py
│ │ ├── chataction.py
│ │ ├── common.py
│ │ ├── inlinequery.py
│ │ ├── messagedeleted.py
│ │ ├── messageedited.py
│ │ ├── messageread.py
│ │ ├── newmessage.py
│ │ ├── raw.py
│ │ └── userupdate.py
│ ├── extensions/
│ │ ├── __init__.py
│ │ ├── binaryreader.py
│ │ ├── html.py
│ │ ├── markdown.py
│ │ └── messagepacker.py
│ ├── functions.py
│ ├── helpers.py
│ ├── hints.py
│ ├── network/
│ │ ├── __init__.py
│ │ ├── authenticator.py
│ │ ├── connection/
│ │ │ ├── __init__.py
│ │ │ ├── connection.py
│ │ │ ├── http.py
│ │ │ ├── tcpabridged.py
│ │ │ ├── tcpfull.py
│ │ │ ├── tcpintermediate.py
│ │ │ ├── tcpmtproxy.py
│ │ │ └── tcpobfuscated.py
│ │ ├── mtprotoplainsender.py
│ │ ├── mtprotosender.py
│ │ ├── mtprotostate.py
│ │ └── requeststate.py
│ ├── password.py
│ ├── requestiter.py
│ ├── sessions/
│ │ ├── __init__.py
│ │ ├── abstract.py
│ │ ├── memory.py
│ │ ├── sqlite.py
│ │ └── string.py
│ ├── sync.py
│ ├── tl/
│ │ ├── __init__.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── gzippacked.py
│ │ │ ├── messagecontainer.py
│ │ │ ├── rpcresult.py
│ │ │ └── tlmessage.py
│ │ ├── custom/
│ │ │ ├── __init__.py
│ │ │ ├── adminlogevent.py
│ │ │ ├── button.py
│ │ │ ├── chatgetter.py
│ │ │ ├── conversation.py
│ │ │ ├── dialog.py
│ │ │ ├── draft.py
│ │ │ ├── file.py
│ │ │ ├── forward.py
│ │ │ ├── inlinebuilder.py
│ │ │ ├── inlineresult.py
│ │ │ ├── inlineresults.py
│ │ │ ├── inputsizedfile.py
│ │ │ ├── message.py
│ │ │ ├── messagebutton.py
│ │ │ ├── participantpermissions.py
│ │ │ ├── qrlogin.py
│ │ │ └── sendergetter.py
│ │ ├── patched/
│ │ │ └── __init__.py
│ │ └── tlobject.py
│ ├── types.py
│ ├── utils.py
│ └── version.py
├── telethon_examples/
│ ├── LICENSE
│ ├── README.md
│ ├── assistant.py
│ ├── gui.py
│ ├── interactive_telegram_client.py
│ ├── payment.py
│ ├── print_messages.py
│ ├── print_updates.py
│ ├── quart_login.py
│ └── replier.py
├── telethon_generator/
│ ├── __init__.py
│ ├── data/
│ │ ├── api.tl
│ │ ├── errors.csv
│ │ ├── friendly.csv
│ │ ├── html/
│ │ │ ├── 404.html
│ │ │ ├── core.html
│ │ │ ├── css/
│ │ │ │ ├── docs.dark.css
│ │ │ │ ├── docs.h4x0r.css
│ │ │ │ └── docs.light.css
│ │ │ └── js/
│ │ │ └── search.js
│ │ ├── methods.csv
│ │ └── mtproto.tl
│ ├── docswriter.py
│ ├── generators/
│ │ ├── __init__.py
│ │ ├── docs.py
│ │ ├── errors.py
│ │ └── tlobject.py
│ ├── parsers/
│ │ ├── __init__.py
│ │ ├── errors.py
│ │ ├── methods.py
│ │ └── tlobject/
│ │ ├── __init__.py
│ │ ├── parser.py
│ │ ├── tlarg.py
│ │ └── tlobject.py
│ ├── sourcebuilder.py
│ ├── syncerrors.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ ├── readthedocs/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ └── quick_references/
│ │ ├── __init__.py
│ │ └── test_client_reference.py
│ └── telethon/
│ ├── __init__.py
│ ├── client/
│ │ ├── __init__.py
│ │ └── test_messages.py
│ ├── crypto/
│ │ ├── __init__.py
│ │ └── test_rsa.py
│ ├── events/
│ │ ├── __init__.py
│ │ └── test_chataction.py
│ ├── extensions/
│ │ ├── __init__.py
│ │ ├── test_html.py
│ │ └── test_markdown.py
│ ├── test_helpers.py
│ ├── test_pickle.py
│ ├── test_utils.py
│ └── tl/
│ ├── __init__.py
│ └── test_serialization.py
└── update-docs.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveragerc
================================================
[run]
branch = true
parallel = true
source =
telethon
[report]
precision = 2
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: Bug Report
description: Create a report about a bug inside the library.
body:
- type: textarea
id: reproducing-example
attributes:
label: Code that causes the issue
description: Provide a code example that reproduces the problem. Try to keep it short without other dependencies.
placeholder: |
```python
from telethon.sync import TelegramClient
...
```
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: Explain what you should expect to happen. Include reproduction steps.
placeholder: |
"I was doing... I was expecting the following to happen..."
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual behavior
description: Explain what actually happens.
placeholder: |
"This happened instead..."
validations:
required: true
- type: textarea
id: traceback
attributes:
label: Traceback
description: |
The traceback, if the problem is a crash.
placeholder: |
```
Traceback (most recent call last):
File "code.py", line 1, in <code>
```
- type: input
id: telethon-version
attributes:
label: Telethon version
description: The output of `python -c "import telethon; print(telethon.__version__)"`.
placeholder: "1.x"
validations:
required: true
- type: input
id: python-version
attributes:
label: Python version
description: The output of `python --version`.
placeholder: "3.x"
validations:
required: true
- type: input
id: os
attributes:
label: Operating system (including distribution name and version)
placeholder: Windows 11, macOS 13.4, Ubuntu 23.04...
validations:
required: true
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments. Is it a server? Network condition?
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: The error is in the library's code, and not in my own.
required: true
- label: I have searched for this issue before posting it and there isn't an open duplicate.
required: true
- label: I ran `pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip` and triggered the bug in the latest version.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Ask questions in StackOverflow
url: https://stackoverflow.com/questions/ask?tags=telethon
about: Questions are not bugs. Please ask them in StackOverflow instead. Questions in the bug tracker will be closed
- name: Find about updates and our Telegram groups
url: https://t.me/s/TelethonUpdates
about: Be notified of updates, chat with other people about the library or ask questions in these groups
================================================
FILE: .github/ISSUE_TEMPLATE/documentation-issue.yml
================================================
name: Documentation Issue
description: Report a problem with the documentation.
labels: [documentation]
body:
- type: textarea
id: description
attributes:
label: Description
description: Describe the problem in detail.
placeholder: This part is unclear...
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: This is a documentation problem, not a question or a bug report.
required: true
- label: I have searched for this issue before posting it and there isn't a duplicate.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: Feature Request
description: Suggest ideas, changes or other enhancements for the library.
labels: [enhancement]
body:
- type: textarea
id: feature-description
attributes:
label: Describe your suggested feature
description: Please describe your idea. Would you like another friendly method? Renaming them to something more appropriate? Changing the way something works?
placeholder: "It should work like this..."
validations:
required: true
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: I have searched for this issue before posting it and there isn't a duplicate.
required: true
================================================
FILE: .github/pull_request_template.md
================================================
<!--
Thanks for the PR! Please keep in mind that v1 is *feature frozen*.
New features very likely won't be merged, although fixes can be sent.
All new development should happen in v2. Thanks!
-->
================================================
FILE: .github/workflows.disabled/python.yml
================================================
name: Python Library
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.5", "3.6", "3.7", "3.8"]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Set up env
run: |
python -m pip install --upgrade pip
pip install tox
- name: Lint with flake8
run: |
tox -e flake
- name: Test with pytest
run: |
# use "py", which is the default python version
tox -e py
================================================
FILE: .gitignore
================================================
# Generated code
/telethon/tl/functions/
/telethon/tl/types/
/telethon/tl/alltlobjects.py
/telethon/errors/rpcerrorlist.py
# User session
*.session
/usermedia/
# Builds and testing
__pycache__/
/dist/
/build/
/*.egg-info/
/readthedocs/_build/
/.tox/
# API reference docs
/docs/
# File used to manually test new changes, contains sensitive data
/example.py
================================================
FILE: .pre-commit-config.yaml
================================================
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: 7539d8bd1a00a3c1bfd34cdb606d3a6372e83469
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-yaml
- id: double-quote-string-fixer
- id: end-of-file-fixer
- id: name-tests-test
- id: trailing-whitespace
- repo: git://github.com/pre-commit/mirrors-yapf
sha: v0.11.1
hooks:
- id: yapf
- repo: git://github.com/FalconSocial/pre-commit-python-sorter
sha: 1.0.4
hooks:
- id: python-import-sorter
args:
- --silent-overwrite
================================================
FILE: .readthedocs.yaml
================================================
# https://docs.readthedocs.io/en/stable/config-file/v2.html
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
sphinx:
configuration: readthedocs/conf.py
formats:
- pdf
- epub
python:
install:
- requirements: readthedocs/requirements.txt
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2016-Present LonamiWebs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.rst
================================================
Moved to https://codeberg.org/Lonami/Telethon. The GitHub repository may be deleted in the future.
----
Telethon
========
.. epigraph::
⭐️ Thanks **everyone** who has starred the project, it means a lot!
|logo| **Telethon** is an asyncio_ **Python 3**
MTProto_ library to interact with Telegram_'s API
as a user or through a bot account (bot API alternative).
.. important::
If you have code using Telethon before its 1.0 version, you must
read `Compatibility and Convenience`_ to learn how to migrate.
As with any third-party library for Telegram, be careful not to
break `Telegram's ToS`_ or `Telegram can ban the account`_.
What is this?
-------------
Telegram is a popular messaging application. This library is meant
to make it easy for you to write Python programs that can interact
with Telegram. Think of it as a wrapper that has already done the
heavy job for you, so you can focus on developing an application.
Installing
----------
.. code-block:: sh
pip3 install telethon
Creating a client
-----------------
.. code-block:: python
from telethon import TelegramClient, events, 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)
client.start()
Doing stuff
-----------
.. code-block:: python
print(client.get_me().stringify())
client.send_message('username', 'Hello! Talking to you from Telethon')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.download_profile_photo('me')
messages = client.get_messages('username')
messages[0].download_media()
@client.on(events.NewMessage(pattern='(?i)hi|hello'))
async def handler(event):
await event.respond('Hey!')
Next steps
----------
Do you like how Telethon looks? Check out `Read The Docs`_ for a more
in-depth explanation, with examples, troubleshooting issues, and more
useful information.
.. _asyncio: https://docs.python.org/3/library/asyncio.html
.. _MTProto: https://core.telegram.org/mtproto
.. _Telegram: https://telegram.org
.. _Compatibility and Convenience: https://docs.telethon.dev/en/stable/misc/compatibility-and-convenience.html
.. _Telegram's ToS: https://core.telegram.org/api/terms
.. _Telegram can ban the account: https://docs.telethon.dev/en/stable/quick-references/faq.html#my-account-was-deleted-limited-when-using-the-library
.. _Read The Docs: https://docs.telethon.dev
.. |logo| image:: logo.svg
:width: 24pt
:height: 24pt
================================================
FILE: dev-requirements.txt
================================================
pytest
pytest-cov
pytest-asyncio
================================================
FILE: optional-requirements.txt
================================================
cryptg
python-socks[asyncio]
hachoir
pillow
isal
================================================
FILE: pyproject.toml
================================================
# https://snarky.ca/what-the-heck-is-pyproject-toml/
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
# Need to use legacy format for the time being
# https://tox.readthedocs.io/en/3.20.0/example/basic.html#pyproject-toml-tox-legacy-ini
[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py35,py36,py37,py38
# run with tox -e py
[testenv]
deps =
-rrequirements.txt
-roptional-requirements.txt
-rdev-requirements.txt
commands =
# NOTE: you can run any command line tool here - not just tests
pytest {posargs}
# run with tox -e flake
[testenv:flake]
deps =
-rrequirements.txt
-roptional-requirements.txt
-rdev-requirements.txt
flake8
commands =
# stop the build if there are Python syntax errors or undefined names
flake8 telethon/ telethon_generator/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 telethon/ telethon_generator/ tests/ --count --exit-zero --exclude telethon/tl/,telethon/errors/rpcerrorlist.py --max-complexity=10 --max-line-length=127 --statistics
"""
================================================
FILE: readthedocs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = Telethon
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
================================================
FILE: readthedocs/basic/installation.rst
================================================
.. _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, `upgrade pip`__ and run:
.. code-block:: sh
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade telethon
…to install or upgrade the library to the latest version.
.. __: https://pythonspeed.com/articles/upgrade-pip/
Installing Development Versions
===============================
If you want the *latest* unreleased changes,
you can run the following command instead:
.. code-block:: sh
python3 -m pip install --upgrade https://github.com/LonamiWebs/Telethon/archive/v1.zip
.. 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.
.. note::
Some of the modules may require additional dependencies before being
installed through ``pip``. If you have an ``apt``-based system, consider
installing the most commonly missing dependencies (with the right ``pip``):
.. code-block:: sh
apt update
apt install clang lib{jpeg-turbo,webp}-dev python{,-dev} zlib-dev
pip install -U --user setuptools
pip install -U --user telethon cryptg pillow
Thanks to `@bb010g`_ for writing down this nice list.
.. _cryptg: https://github.com/cher-nov/cryptg
.. _pyaes: https://github.com/ricmoo/pyaes
.. _pillow: https://python-pillow.org
.. _aiohttp: https://docs.aiohttp.org
.. _hachoir: https://hachoir.readthedocs.io
.. _@bb010g: https://static.bb010g.com
================================================
FILE: readthedocs/basic/next-steps.rst
================================================
==========
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.
A note on developing applications
=================================
If you're using the library to make an actual application (and not just
automate things), you should make sure to `comply with the ToS`__:
[…] when logging in as an existing user, apps are supposed to call
[:tl:`GetTermsOfServiceUpdate`] to check for any updates to the Terms of
Service; this call should be repeated after ``expires`` seconds have
elapsed. If an update to the Terms Of Service is available, clients are
supposed to show a consent popup; if accepted, clients should call
[:tl:`AcceptTermsOfService`], providing the ``termsOfService id`` JSON
object; in case of denial, clients are to delete the account using
[:tl:`DeleteAccount`], providing Decline ToS update as deletion reason.
.. __: https://core.telegram.org/api/config#terms-of-service
However, if you use the library to automate or enhance your Telegram
experience, it's very likely that you are using other applications doing this
check for you (so you wouldn't run the risk of violating the ToS).
The library itself will not automatically perform this check or accept the ToS
because it should require user action (the only exception is during sign-up).
================================================
FILE: readthedocs/basic/quick-start.rst
================================================
===========
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 import TelegramClient
# Remember to use your own values from my.telegram.org!
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('anon', api_id, api_hash)
async def main():
# Getting information about yourself
me = await client.get_me()
# "me" is a 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:
async for dialog in client.iter_dialogs():
print(dialog.name, 'has ID', dialog.id)
# You can send messages to yourself...
await client.send_message('me', 'Hello, myself!')
# ...to some chat ID
await client.send_message(-100123456, 'Hello, group!')
# ...to your contacts
await client.send_message('+34600123123', 'Hello, friend!')
# ...or even to any username
await client.send_message('username', 'Testing Telethon!')
# You can, of course, use markdown in your messages:
message = await client.send_message(
'me',
'This message has **bold**, `code`, __italics__ and '
'a [nice website](https://example.com)!',
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
await message.reply('Cool!')
# Or send files, songs, documents, albums...
await client.send_file('me', '/home/me/Pictures/holidays.jpg')
# You can print the message history of any chat:
async 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 = await message.download_media()
print('File saved to', path) # printed after download is done
with client:
client.loop.run_until_complete(main())
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.
.. important::
Note that Telethon is an asynchronous library, and as such, you should
get used to it and learn a bit of basic `asyncio`. This will help a lot.
As a quick start, this means you generally want to write all your code
inside some ``async def`` like so:
.. code-block:: python
client = ...
async def do_something(me):
...
async def main():
# Most of your code should go here.
# You can of course make and use your own async def (do_something).
# They only need to be async if they need to await things.
me = await client.get_me()
await do_something(me)
with client:
client.loop.run_until_complete(main())
After you understand this, you may use the ``telethon.sync`` hack if you
want do so (see :ref:`compatibility-and-convenience`), but note you may
run into other issues (iPython, Anaconda, etc. have some issues with it).
================================================
FILE: readthedocs/basic/signing-in.rst
================================================
.. _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 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.loop.run_until_complete(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.
.. note::
Since Telethon is an asynchronous library, you need to ``await``
coroutine functions to have them run (or otherwise, run the loop
until they are complete). In this tiny example, we don't bother
making an ``async def main()``.
See :ref:`mastering-asyncio` to find out more.
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 an 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 python-socks[asyncio]`__
and then pass a proxy argument to the client:
.. code-block:: python
TelegramClient('anon', api_id, api_hash, proxy=...)
The ``proxy=`` argument should be a dict with the following properties:
.. code-block:: python
proxy = {
'proxy_type': 'socks5', # (mandatory) protocol to use (see above)
'addr': '1.1.1.1', # (mandatory) proxy IP address
'port': 5555, # (mandatory) proxy port number
'username': 'foo', # (optional) username if the proxy requires auth
'password': 'bar', # (optional) password if the proxy requires auth
'rdns': True # (optional) whether to use remote or local resolve, default remote
}
A warning will be emitted if the proxy is specified but ``python-socks`` is not installed.
.. __: https://github.com/romis2012/python-socks#installation
Using MTProto Proxies
=====================
MTProto Proxies are Telegram's alternative to normal proxies,
and work a bit differently. The following protocols are available:
* ``ConnectionTcpMTProxyAbridged``
* ``ConnectionTcpMTProxyIntermediate``
* ``ConnectionTcpMTProxyRandomizedIntermediate`` (preferred)
For now, you need to manually specify these special connection modes
if you want to use a MTProto Proxy. Your code would look like this:
.. code-block:: python
from telethon import TelegramClient, connection
# we need to change the connection ^^^^^^^^^^
client = TelegramClient(
'anon',
api_id,
api_hash,
# Use one of the available connection modes.
# Normally, this one works with most proxies.
connection=connection.ConnectionTcpMTProxyRandomizedIntermediate,
# Then, pass the proxy details as a tuple:
# (host name, port, proxy secret)
#
# If the proxy has no secret, the secret must be:
# '00000000000000000000000000000000'
proxy=('mtproxy.example.com', 2002, 'secret')
)
In future updates, we may make it easier to use MTProto Proxies
(such as avoiding the need to manually pass ``connection=``).
In short, the same code above but without comments to make it clearer:
.. code-block:: python
from telethon import TelegramClient, connection
client = TelegramClient(
'anon', api_id, api_hash,
connection=connection.ConnectionTcpMTProxyRandomizedIntermediate,
proxy=('mtproxy.example.com', 2002, 'secret')
)
================================================
FILE: readthedocs/basic/updates.rst
================================================
=======
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) %(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:: python
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.
================================================
FILE: readthedocs/concepts/asyncio.rst
================================================
.. _mastering-asyncio:
=================
Mastering asyncio
=================
.. contents::
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
code. Before (Python 3.4) we didn't have ``async`` or ``await``, but now we do.
`asyncio` stands for *Asynchronous Input Output*. This is a very powerful
concept to use whenever you work IO. Interacting with the web or external
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
thanks to `asyncio`, your code won't block while a response arrives.
The alternative would be to spawn a thread for each update so that
other code can run while the response arrives. That is *a lot* more
expensive.
The code will also run faster, because instead of switching back and
forth between the OS and your script, your script can handle it all.
Avoiding switching saves quite a bit of time, in Python or any other
language that supports asynchronous IO. It will also be cheaper,
because tasks are smaller than threads, which are smaller than processes.
What are asyncio basics?
========================
The code samples below assume that you have Python 3.7 or greater installed.
.. code-block:: python
# First we need the asyncio library
import asyncio
# We also need something to run
async def main():
for char in 'Hello, world!\n':
print(char, end='', flush=True)
await asyncio.sleep(0.2)
# Then, we can create a new asyncio loop and use it to run our coroutine.
# The creation and tear-down of the loop is hidden away from us.
asyncio.run(main())
What does telethon.sync do?
===========================
The moment you import any of these:
.. code-block:: python
from telethon import sync, ...
# or
from telethon.sync import ...
# or
import telethon.sync
The ``sync`` module rewrites most ``async def``
methods in Telethon to something similar to this:
.. code-block:: python
def new_method():
result = original_method()
if loop.is_running():
# the loop is already running, return the await-able to the user
return result
else:
# the loop is not running yet, so we can run it for the user
return loop.run_until_complete(result)
That means you can do this:
.. code-block:: python
print(client.get_me().username)
Instead of this:
.. code-block:: python
me = client.loop.run_until_complete(client.get_me())
print(me.username)
# or, using asyncio's default loop (it's the same)
import asyncio
loop = asyncio.get_running_loop() # == client.loop
me = loop.run_until_complete(client.get_me())
print(me.username)
As you can see, it's a lot of boilerplate and noise having to type
``run_until_complete`` all the time, so you can let the magic module
to rewrite it for you. But notice the comment above: it won't run
the loop if it's already running, because it can't. That means this:
.. code-block:: python
async def main():
# 3. the loop is running here
print(
client.get_me() # 4. this will return a coroutine!
.username # 5. this fails, coroutines don't have usernames
)
loop.run_until_complete( # 2. run the loop and the ``main()`` coroutine
main() # 1. calling ``async def`` "returns" a coroutine
)
Will fail. So if you're inside an ``async def``, then the loop is
running, and if the loop is running, you must ``await`` things yourself:
.. code-block:: python
async def main():
print((await client.get_me()).username)
loop.run_until_complete(main())
What are async, await and coroutines?
=====================================
The ``async`` keyword lets you define asynchronous functions,
also known as coroutines, and also iterate over asynchronous
loops or use ``async with``:
.. code-block:: python
import asyncio
async def main():
# ^ this declares the main() coroutine function
async with client:
# ^ this is an asynchronous with block
async for message in client.iter_messages(chat):
# ^ this is a for loop over an asynchronous generator
print(message.sender.username)
asyncio.run(main())
# ^ this will create a new asyncio loop behind the scenes and tear it down
# once the function returns. It will run the loop untiil main finishes.
# You should only use this function if there is no other loop running.
The ``await`` keyword blocks the *current* task, and the loop can run
other tasks. Tasks can be thought of as "threads", since many can run
concurrently:
.. code-block:: python
import asyncio
async def hello(delay):
await asyncio.sleep(delay) # await tells the loop this task is "busy"
print('hello') # eventually the loop resumes the code here
async def world(delay):
# the loop decides this method should run first
await asyncio.sleep(delay) # await tells the loop this task is "busy"
print('world') # eventually the loop finishes all tasks
async def main():
asyncio.create_task(world(2)) # create the world task, passing 2 as delay
asyncio.create_task(hello(delay=1)) # another task, but with delay 1
await asyncio.sleep(3) # wait for three seconds before exiting
try:
# create a new temporary asyncio loop and use it to run main
asyncio.run(main())
except KeyboardInterrupt:
pass
The same example, but without the comment noise:
.. code-block:: python
import asyncio
async def hello(delay):
await asyncio.sleep(delay)
print('hello')
async def world(delay):
await asyncio.sleep(delay)
print('world')
async def main():
asyncio.create_task(world(2))
asyncio.create_task(hello(delay=1))
await asyncio.sleep(3)
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
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. The
easiest and cleanest option is to use `asyncio.run` to create and manage
the new event loop for you:
.. code-block:: python
import asyncio
import threading
async def actual_work():
client = TelegramClient(..., loop=loop)
... # can use `await` here
def go():
asyncio.run(actual_work())
threading.Thread(target=go).start()
Generally, **you don't need threads** unless you know what you're doing.
Just create another task, as shown above. If you're using the Telethon
with a library that uses threads, you must be careful to use `threading.Lock`
whenever you use the client, or enable the compatible mode. For that, see
:ref:`compatibility-and-convenience`.
You may have seen this error:
.. code-block:: text
RuntimeError: There is no current event loop in thread 'Thread-1'.
It just means you didn't create a loop for that thread. Please refer to
the ``asyncio`` documentation to correctly learn how to set the event loop
for non-main threads.
client.run_until_disconnected() blocks!
=======================================
All of what `client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` does is
run the `asyncio`'s event loop until the client is disconnected. That means
*the loop is running*. And if the loop is running, it will run all the tasks
in it. So if you want to run *other* code, create tasks for it:
.. code-block:: python
from datetime import datetime
async def clock():
while True:
print('The time:', datetime.now())
await asyncio.sleep(1)
loop.create_task(clock())
...
client.run_until_disconnected()
This creates a task for a clock that prints the time every second.
You don't need to use `client.run_until_disconnected()
<telethon.client.updates.UpdateMethods.run_until_disconnected>` either!
You just need to make the loop is running, somehow. `loop.run_forever()
<asyncio.loop.run_forever()>` and `loop.run_until_complete()
<asyncio.loop.run_until_complete>` can also be used to run
the loop, and Telethon will be happy with any approach.
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
with Telethon.
* `aiohttp <https://github.com/aio-libs/aiohttp>`_ is like the infamous
`requests <https://github.com/requests/requests/>`_ but asynchronous.
* `quart <https://gitlab.com/pgjones/quart>`_ is an asynchronous alternative
to `Flask <http://flask.pocoo.org/>`_.
* `aiocron <https://github.com/gawel/aiocron>`_ lets you schedule things
to run things at a desired time, or run some tasks hourly, daily, etc.
And of course, `asyncio <https://docs.python.org/3/library/asyncio.html>`_
itself! It has a lot of methods that let you do nice things. For example,
you can run requests in parallel:
.. code-block:: python
async def main():
last, sent, download_path = await asyncio.gather(
client.get_messages('telegram', 10),
client.send_message('me', 'Using asyncio!'),
client.download_profile_photo('telegram')
)
loop.run_until_complete(main())
This code will get the 10 last messages from `@telegram
<https://t.me/telegram>`_, send one to the chat with yourself, and also
download the profile photo of the channel. `asyncio` will run all these
three tasks at the same time. You can run all the tasks you want this way.
A different way would be:
.. code-block:: python
loop.create_task(client.get_messages('telegram', 10))
loop.create_task(client.send_message('me', 'Using asyncio!'))
loop.create_task(client.download_profile_photo('telegram'))
They will run in the background as long as the loop is running too.
You can also `start an asyncio server
<https://docs.python.org/3/library/asyncio-stream.html#asyncio.start_server>`_
in the main script, and from another script, `connect to it
<https://docs.python.org/3/library/asyncio-stream.html#asyncio.open_connection>`_
to achieve `Inter-Process Communication
<https://en.wikipedia.org/wiki/Inter-process_communication>`_.
You can get as creative as you want. You can program anything you want.
When you use a library, you're not limited to use only its methods. You can
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
handlers and start the client without worrying about loops at all.
Using the client in a ``with`` block, `start
<telethon.client.auth.AuthMethods.start>`, `run_until_disconnected
<telethon.client.updates.UpdateMethods.run_until_disconnected>`, and
`disconnect <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`
all support this.
Where can I read more?
======================
`Check out my blog post
<https://lonami.dev/blog/asyncio/>`_ about `asyncio`, which
has some more examples and pictures to help you understand what happens
when the loop runs.
================================================
FILE: readthedocs/concepts/botapi-vs-mtproto.rst
================================================
.. _botapi:
=======================
HTTP Bot API vs MTProto
=======================
Telethon is more than just another viable alternative when developing bots
for Telegram. If you haven't decided which wrapper library for bots to use
yet, using Telethon from the beginning may save you some headaches later.
.. contents::
What is Bot API?
================
The `Telegram Bot API`_, also known as HTTP Bot API and from now on referred
to as simply "Bot API" is Telegram's official way for developers to control
their own Telegram bots. Quoting their main page:
The Bot API is an HTTP-based interface created for developers keen on
building bots for Telegram.
To learn how to create and set up a bot, please consult our
`Introduction to Bots`_ and `Bot FAQ`_.
Bot API is simply an HTTP endpoint which translates your requests to it into
MTProto calls through tdlib_, their bot backend.
Configuration of your bot, such as its available commands and auto-completion,
is configured through `@BotFather <https://t.me/BotFather>`_.
What is MTProto?
================
MTProto_ is Telegram's own protocol to communicate with their API when you
connect to their servers.
Telethon is an alternative MTProto-based backend written entirely in Python
and much easier to setup and use.
Both official applications and third-party clients (like your own
applications) logged in as either user or bots **can use MTProto** to
communicate directly with Telegram's API (which is not the HTTP bot API).
When we talk about MTProto, we often mean "MTProto-based clients".
Advantages of MTProto over Bot API
==================================
MTProto clients (like Telethon) connect directly to Telegram's servers,
which means there is no HTTP connection, no "polling" or "web hooks". This
means **less overhead**, since the protocol used between you and the server
is much more compact than HTTP requests with responses in wasteful JSON.
Since there is a direct connection to Telegram's servers, even if their
Bot API endpoint is down, you can still have connection to Telegram directly.
Using a MTProto client, you are also not limited to the public API that
they expose, and instead, **you have full control** of what your bot can do.
Telethon offers you all the power with often **much easier usage** than any
of the available Python Bot API wrappers.
If your application ever needs user features because bots cannot do certain
things, you will be able to easily login as a user and even keep your bot
without having to learn a new library.
If less overhead and full control didn't convince you to use Telethon yet,
check out the wiki page `MTProto vs HTTP Bot API`_ with a more exhaustive
and up-to-date list of differences.
Migrating from Bot API to Telethon
==================================
It doesn't matter if you wrote your bot with requests_ and you were
making API requests manually, or if you used a wrapper library like
python-telegram-bot_ or pyTelegramBotAPI_. It's never too late to
migrate to Telethon!
If you were using an asynchronous library like aiohttp_ or a wrapper like
aiogram_ or dumbot_, it will be even easier, because Telethon is also an
asynchronous library.
Next, we will see some examples from the most popular libraries.
Migrating from python-telegram-bot
----------------------------------
Let's take their `echobot.py`_ example and shorten it a bit:
.. code-block:: python
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
def start(update, context):
"""Send a message when the command /start is issued."""
update.message.reply_text('Hi!')
def echo(update, context):
"""Echo the user message."""
update.message.reply_text(update.message.text)
def main():
"""Start the bot."""
updater = Updater("TOKEN")
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", start))
dp.add_handler(MessageHandler(Filters.text & ~Filters.command, echo))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
After using Telethon:
.. code-block:: python
from telethon import TelegramClient, events
bot = TelegramClient('bot', 11111, 'a1b2c3d4').start(bot_token='TOKEN')
@bot.on(events.NewMessage(pattern='/start'))
async def start(event):
"""Send a message when the command /start is issued."""
await event.respond('Hi!')
raise events.StopPropagation
@bot.on(events.NewMessage)
async def echo(event):
"""Echo the user message."""
await event.respond(event.text)
def main():
"""Start the bot."""
bot.run_until_disconnected()
if __name__ == '__main__':
main()
Key differences:
* The recommended way to do it imports fewer things.
* All handlers trigger by default, so we need ``events.StopPropagation``.
* Adding handlers, responding and running is a lot less verbose.
* Telethon needs ``async def`` and ``await``.
* The ``bot`` isn't hidden away by ``Updater`` or ``Dispatcher``.
Migrating from pyTelegramBotAPI
-------------------------------
Let's show another echobot from their README:
.. code-block:: python
import telebot
bot = telebot.TeleBot("TOKEN")
@bot.message_handler(commands=['start'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
@bot.message_handler(func=lambda m: True)
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
Now we rewrite it to use Telethon:
.. code-block:: python
from telethon import TelegramClient, events
bot = TelegramClient('bot', 11111, 'a1b2c3d4').start(bot_token='TOKEN')
@bot.on(events.NewMessage(pattern='/start'))
async def send_welcome(event):
await event.reply('Howdy, how are you doing?')
@bot.on(events.NewMessage)
async def echo_all(event):
await event.reply(event.text)
bot.run_until_disconnected()
Key differences:
* Instead of doing ``bot.reply_to(message)``, we can do ``event.reply``.
Note that the ``event`` behaves just like their ``message``.
* Telethon also supports ``func=lambda m: True``, but it's not necessary.
Migrating from aiogram
----------------------
From their GitHub:
.. code-block:: python
from aiogram import Bot, Dispatcher, executor, types
API_TOKEN = 'BOT TOKEN HERE'
# Initialize bot and dispatcher
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
"""
This handler will be called when client send `/start` command.
"""
await message.reply("Hi!\nI'm EchoBot!\nPowered by aiogram.")
@dp.message_handler(regexp='(^cat[s]?$|puss)')
async def cats(message: types.Message):
with open('data/cats.jpg', 'rb') as photo:
await bot.send_photo(message.chat.id, photo, caption='Cats is here 😺',
reply_to_message_id=message.message_id)
@dp.message_handler()
async def echo(message: types.Message):
await bot.send_message(message.chat.id, message.text)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
After rewrite:
.. code-block:: python
from telethon import TelegramClient, events
# Initialize bot and... just the bot!
bot = TelegramClient('bot', 11111, 'a1b2c3d4').start(bot_token='TOKEN')
@bot.on(events.NewMessage(pattern='/start'))
async def send_welcome(event):
await event.reply('Howdy, how are you doing?')
@bot.on(events.NewMessage(pattern='(^cat[s]?$|puss)'))
async def cats(event):
await event.reply('Cats is here 😺', file='data/cats.jpg')
@bot.on(events.NewMessage)
async def echo_all(event):
await event.reply(event.text)
if __name__ == '__main__':
bot.run_until_disconnected()
Key differences:
* Telethon offers convenience methods to avoid retyping
``bot.send_photo(message.chat.id, ...)`` all the time,
and instead let you type ``event.reply``.
* Sending files is **a lot** easier. The methods for sending
photos, documents, audios, etc. are all the same!
Migrating from dumbot
---------------------
Showcasing their subclassing example:
.. code-block:: python
from dumbot import Bot
class Subbot(Bot):
async def init(self):
self.me = await self.getMe()
async def on_update(self, update):
await self.sendMessage(
chat_id=update.message.chat.id,
text='i am {}'.format(self.me.username)
)
Subbot(token).run()
After rewriting:
.. code-block:: python
from telethon import TelegramClient, events
class Subbot(TelegramClient):
def __init__(self, *a, **kw):
super().__init__(*a, **kw)
self.add_event_handler(self.on_update, events.NewMessage)
async def connect():
await super().connect()
self.me = await self.get_me()
async def on_update(event):
await event.reply('i am {}'.format(self.me.username))
bot = Subbot('bot', 11111, 'a1b2c3d4').start(bot_token='TOKEN')
bot.run_until_disconnected()
Key differences:
* Telethon method names are ``snake_case``.
* dumbot does not offer friendly methods like ``update.reply``.
* Telethon does not have an implicit ``on_update`` handler, so
we need to manually register one.
.. _Telegram Bot API: https://core.telegram.org/bots/api
.. _Introduction to Bots: https://core.telegram.org/bots
.. _Bot FAQ: https://core.telegram.org/bots/faq
.. _tdlib: https://core.telegram.org/tdlib
.. _MTProto: https://core.telegram.org/mtproto
.. _MTProto vs HTTP Bot API: https://github.com/LonamiWebs/Telethon/wiki/MTProto-vs-HTTP-Bot-API
.. _requests: https://pypi.org/project/requests/
.. _python-telegram-bot: https://python-telegram-bot.readthedocs.io
.. _pyTelegramBotAPI: https://github.com/eternnoir/pyTelegramBotAPI
.. _aiohttp: https://docs.aiohttp.org/en/stable
.. _aiogram: https://aiogram.readthedocs.io
.. _dumbot: https://github.com/Lonami/dumbot
.. _echobot.py: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/echobot.py
================================================
FILE: readthedocs/concepts/chats-vs-channels.rst
================================================
.. _chats-channels:
=================
Chats vs Channels
=================
Telegram's raw API can get very confusing sometimes, in particular when it
comes to talking about "chats", "channels", "groups", "megagroups", and all
those concepts.
This section will try to explain what each of these concepts are.
Chats
=====
A ``Chat`` can be used to talk about either the common "subclass" that both
chats and channels share, or the concrete :tl:`Chat` type.
Technically, both :tl:`Chat` and :tl:`Channel` are a form of the `Chat type`_.
**Most of the time**, the term :tl:`Chat` is used to talk about *small group
chats*. When you create a group through an official application, this is the
type that you get. Official applications refer to these as "Group".
Both the bot API and Telethon will add a minus sign (negate) the real chat ID
so that you can tell at a glance, with just a number, the entity type.
For example, if you create a chat with :tl:`CreateChatRequest`, the real chat
ID might be something like `123`. If you try printing it from a
`message.chat_id` you will see `-123`. This ID helps Telethon know you're
talking about a :tl:`Chat`.
Channels
========
Official applications create a *broadcast* channel when you create a new
channel (used to broadcast messages, only administrators can post messages).
Official applications implicitly *migrate* an *existing* :tl:`Chat` to a
*megagroup* :tl:`Channel` when you perform certain actions (exceed user limit,
add a public username, set certain permissions, etc.).
A ``Channel`` can be created directly with :tl:`CreateChannelRequest`, as
either a ``megagroup`` or ``broadcast``.
Official applications use the term "channel" **only** for broadcast channels.
The API refers to the different types of :tl:`Channel` with certain attributes:
* A **broadcast channel** is a :tl:`Channel` with the ``channel.broadcast``
attribute set to `True`.
* A **megagroup channel** is a :tl:`Channel` with the ``channel.megagroup``
attribute set to `True`. Official applications refer to this as "supergroup".
* A **gigagroup channel** is a :tl:`Channel` with the ``channel.gigagroup``
attribute set to `True`. Official applications refer to this as "broadcast
groups", and is used when a megagroup becomes very large and administrators
want to transform it into something where only they can post messages.
Both the bot API and Telethon will "concatenate" ``-100`` to the real chat ID
so that you can tell at a glance, with just a number, the entity type.
For example, if you create a new broadcast channel, the real channel ID might
be something like `456`. If you try printing it from a `message.chat_id` you
will see `-1000000000456`. This ID helps Telethon know you're talking about a
:tl:`Channel`.
Converting IDs
==============
You can convert between the "marked" identifiers (prefixed with a minus sign)
and the real ones with ``utils.resolve_id``. It will return a tuple with the
real ID, and the peer type (the class):
.. code-block:: python
from telethon import utils
real_id, peer_type = utils.resolve_id(-1000000000456)
print(real_id) # 456
print(peer_type) # <class 'telethon.tl.types.PeerChannel'>
peer = peer_type(real_id)
print(peer) # PeerChannel(channel_id=456)
The reverse operation can be done with ``utils.get_peer_id``:
.. code-block:: python
print(utils.get_peer_id(types.PeerChannel(456))) # -1000000000456
Note that this function can also work with other types, like :tl:`Chat` or
:tl:`Channel` instances.
If you need to convert other types like usernames which might need to perform
API calls to find out the identifier, you can use ``client.get_peer_id``:
.. code-block:: python
print(await client.get_peer_id('me')) # your id
If there is no "mark" (no minus sign), Telethon will assume your identifier
refers to a :tl:`User`. If this is **not** the case, you can manually fix it:
.. code-block:: python
from telethon import types
await client.send_message(types.PeerChannel(456), 'hello')
# ^^^^^^^^^^^^^^^^^ explicit peer type
A note on raw API
=================
Certain methods only work on a :tl:`Chat`, and some others only work on a
:tl:`Channel` (and these may only work in broadcast, or megagroup). Your code
likely knows what it's working with, so it shouldn't be too much of an issue.
If you need to find the :tl:`Channel` from a :tl:`Chat` that migrated to it,
access the `migrated_to` property:
.. code-block:: python
# chat is a Chat
channel = await client.get_entity(chat.migrated_to)
# channel is now a Channel
Channels do not have a "migrated_from", but a :tl:`ChannelFull` does. You can
use :tl:`GetFullChannelRequest` to obtain this:
.. code-block:: python
from telethon import functions
full = await client(functions.channels.GetFullChannelRequest(your_channel))
full_channel = full.full_chat
# full_channel is a ChannelFull
print(full_channel.migrated_from_chat_id)
This way, you can also access the linked discussion megagroup of a broadcast channel:
.. code-block:: python
print(full_channel.linked_chat_id) # prints ID of linked discussion group or None
You do not need to use ``client.get_entity`` to access the
``migrated_from_chat_id`` :tl:`Chat` or the ``linked_chat_id`` :tl:`Channel`.
They are in the ``full.chats`` attribute:
.. code-block:: python
if full_channel.migrated_from_chat_id:
migrated_from_chat = next(c for c in full.chats if c.id == full_channel.migrated_from_chat_id)
print(migrated_from_chat.title)
if full_channel.linked_chat_id:
linked_group = next(c for c in full.chats if c.id == full_channel.linked_chat_id)
print(linked_group.username)
.. _Chat type: https://tl.telethon.dev/types/chat.html
================================================
FILE: readthedocs/concepts/entities.rst
================================================
.. _entities:
========
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
in response to certain methods, such as :tl:`GetUsersRequest`.
.. note::
When something "entity-like" is required, it means that you need to
provide something that can be turned into an entity. These things include,
but are not limited to, usernames, exact titles, IDs, :tl:`Peer` objects,
or even entire :tl:`User`, :tl:`Chat` and :tl:`Channel` objects and even
phone numbers **from people you have in your contact list**.
To "encounter" an ID, you would have to "find it" like you would in the
normal app. If the peer is in your dialogs, you would need to
`client.get_dialogs() <telethon.client.dialogs.DialogMethods.get_dialogs>`.
If the peer is someone in a group, you would similarly
`client.get_participants(group) <telethon.client.chats.ChatMethods.get_participants>`.
Once you have encountered an ID, the library will (by default) have saved
their ``access_hash`` for you, which is needed to invoke most methods.
This is why sometimes you might encounter this error when working with
the library. You should ``except ValueError`` and run code that you know
should work to find the entity.
.. 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
you're able to just do this:
.. code-block:: python
# (These examples assume you are inside an "async def")
#
# 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 fills the entity cache.
dialogs = await client.get_dialogs()
# All of these work and do the same.
username = await client.get_entity('username')
username = await client.get_entity('t.me/username')
username = await client.get_entity('https://telegram.dog/username')
# Other kind of entities.
channel = await client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
contact = await client.get_entity('+34xxxxxxxxx')
friend = await client.get_entity(friend_id)
# Getting entities through their ID (User, Chat or Channel)
entity = await client.get_entity(some_id)
# You can be more explicit about the type for said ID by wrapping
# it inside a Peer instance. This is recommended but not necessary.
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
my_user = await client.get_entity(PeerUser(some_id))
my_chat = await client.get_entity(PeerChat(some_id))
my_channel = await client.get_entity(PeerChannel(some_id))
.. note::
You **don't** need to get the entity before using it! Just let the
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:`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('username', 'hi!')
<telethon.client.messages.MessageMethods.send_message>`
become possible.
Every entity the library encounters (in any response to any call) will by
default be cached in the ``.session`` file (an SQLite database), to avoid
performing unnecessary API calls. If the entity cannot be found, additonal
calls like :tl:`ResolveUsernameRequest` or :tl:`GetContactsRequest` may be
made to obtain the required information.
Entities vs. Input Entities
===========================
.. note::
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.
:tl:`InputPeerUser`, :tl:`InputChat`, etc.) only contains the minimum
information that's required from Telegram to be able to identify
who you're referring to: a :tl:`Peer`'s **ID** and **hash**. They
are named like this because they are input parameters in the requests.
Entities' ID are the same for all user and bot accounts, however, the access
hash is **different for each account**, so trying to reuse the access hash
from one account in another will **not** work.
Sometimes, Telegram only needs to indicate the type of the entity along
with their ID. For this purpose, :tl:`Peer` versions of the entities also
exist, which just have the ID. You cannot get the hash out of them since
you should not be needing it. The library probably has cached it before.
Peers are enough to identify an entity, but they are not enough to make
a request with them. You need to know their hash before you can
"use them", and to know the hash you need to "encounter" them, let it
be in your dialogs, participants, message forwards, etc.
.. note::
You *can* use peers with the library. Behind the scenes, they are
replaced with the input variant. Peers "aren't enough" on their own
but the library will do some more work to use the right type.
As we just mentioned, API calls don't need to know the whole information
about the entities, only their ID and hash. For this reason, another method,
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
is available. This will always use the cache while possible, making zero API
calls most of the time. When a request is made, if you provided the full
entity, e.g. an :tl:`User`, the library will convert it to the required
:tl:`InputPeer` automatically for you.
**You should always favour**
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
**over**
`client.get_entity() <telethon.client.users.UserMethods.get_entity>`
for this reason! Calling the latter will always make an API call to get
the most recent information about said entity, but invoking requests don't
need this information, just the :tl:`InputPeer`. Only use
`client.get_entity() <telethon.client.users.UserMethods.get_entity>`
if you need to get actual information, like the username, name, title, etc.
of the entity.
To further simplify the workflow, since the version ``0.16.2`` of the
library, the raw requests you make to the API are also able to call
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
wherever needed, so you can even do things like:
.. code-block:: python
await client(SendMessageRequest('username', 'hello'))
The library will call the ``.resolve()`` method of the request, which will
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
=============
In addition to :tl:`PeerUser`, :tl:`InputPeerUser`, :tl:`User` (and its
variants for chats and channels), there is also the concept of :tl:`UserFull`.
This full variant has additional information such as whether the user is
blocked, its notification settings, the bio or about of the user, etc.
There is also :tl:`messages.ChatFull` which is the equivalent of full entities
for chats and channels, with also the about section of the channel. Note that
the ``users`` field only contains bots for the channel (so that clients can
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
await message.get_chat()
# ...etc
`SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
.. code-block:: python
message.user_id
await message.get_input_sender()
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
# (These examples assume you are inside an "async def")
async with client:
# Does it have a username? Use it!
entity = await client.get_entity(username)
# Do you have a conversation open with them? Get dialogs.
await client.get_dialogs()
# Are they participant of some group? Get them.
await client.get_participants('username')
# Is the entity the original sender of a forwarded message? Get it.
await client.get_messages('username', 100)
# NOW you can use the ID, anywhere!
await client.send_message(123456, 'Hi!')
entity = await client.get_entity(123456)
print(entity)
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.
================================================
FILE: readthedocs/concepts/errors.rst
================================================
.. _rpc-errors:
==========
RPC Errors
==========
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).
You should import the errors from ``telethon.errors`` like so:
.. code-block:: python
from telethon import errors
try:
async with client.takeout() as takeout:
...
except errors.TakeoutInitDelayError as e:
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ here we except TAKEOUT_INIT_DELAY
print('Must wait', e.seconds, 'before takeout')
There isn't any official list of all possible RPC errors, so the
`list of known errors`_ is provided on a best-effort basis. When new methods
are available, the list may be lacking since we simply don't know what errors
can raise from them.
Once we do find out about a new error and what causes it, the list is
updated, so if you see an error without a specific class, do report it
(and what method caused it)!.
This list is used to generate documentation for the `raw API page`_.
For example, if we want to know what errors can occur from
`messages.sendMessage`_ we can simply navigate to its raw API page
and find it has 24 known RPC errors at the time of writing.
Base Errors
===========
All the "base" errors are listed in :ref:`telethon-errors`.
Any other more specific error will be a subclass of these.
If the library isn't aware of a specific error just yet, it will instead
raise one of these superclasses. This means you may find stuff like this:
.. code-block:: text
telethon.errors.rpcbaseerrors.BadRequestError: RPCError 400: MESSAGE_POLL_CLOSED (caused by SendVoteRequest)
If you do, make sure to open an issue or send a pull request to update the
`list of known errors`_.
Common Errors
=============
These are some of the errors you may normally need to deal with:
- ``FloodWaitError`` (420), the same request was repeated many times.
Must wait ``.seconds`` (you can access this attribute). For example:
.. code-block:: python
...
from telethon import errors
try:
messages = await client.get_messages(chat)
print(messages[0].text)
except errors.FloodWaitError as e:
print('Have to sleep', e.seconds, 'seconds')
time.sleep(e.seconds)
- ``SessionPasswordNeededError``, if you have setup two-steps
verification on Telegram and are trying to sign in.
- ``FilePartMissingError``, if you have tried to upload an empty file.
- ``ChatAdminRequiredError``, you don't have permissions to perform
said operation on a chat or channel. Try avoiding filters, i.e. when
searching messages.
The generic classes for different error codes are:
- ``InvalidDCError`` (303), the request must be repeated on another DC.
- ``BadRequestError`` (400), the request contained errors.
- ``UnauthorizedError`` (401), the user is not authorized yet.
- ``ForbiddenError`` (403), privacy violation error.
- ``NotFoundError`` (404), make sure you're invoking ``Request``\ 's!
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))``).
Attributes
==========
Some of the errors carry additional data in them. When they look like
``EMAIL_UNCONFIRMED_X``, the ``_X`` value will be accessible from the
error instance. The current list of errors that do this is the following:
- ``EmailUnconfirmedError`` has ``.code_length``.
- ``FileMigrateError`` has ``.new_dc``.
- ``FilePartMissingError`` has ``.which``.
- ``FloodTestPhoneWaitError`` has ``.seconds``.
- ``FloodWaitError`` has ``.seconds``.
- ``InterdcCallErrorError`` has ``.dc``.
- ``InterdcCallRichErrorError`` has ``.dc``.
- ``NetworkMigrateError`` has ``.new_dc``.
- ``PhoneMigrateError`` has ``.new_dc``.
- ``SlowModeWaitError`` has ``.seconds``.
- ``TakeoutInitDelayError`` has ``.seconds``.
- ``UserMigrateError`` has ``.new_dc``.
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.
.. _list of known errors: https://github.com/LonamiWebs/Telethon/blob/v1/telethon_generator/data/errors.csv
.. _raw API page: https://tl.telethon.dev/
.. _messages.sendMessage: https://tl.telethon.dev/methods/messages/send_message.html
================================================
FILE: readthedocs/concepts/full-api.rst
================================================
.. _full-api:
============
The Full API
============
.. important::
While you have access to this, you should always use the friendly
methods listed on :ref:`client-ref` unless you have a better reason
not to, like a method not existing or you wanting more control.
.. contents::
Introduction
============
The :ref:`telethon-client` doesn't offer a method for every single request
the Telegram API supports. However, it's very simple to *call* or *invoke*
any request defined in Telegram's API.
This section will teach you how to use what Telethon calls the `TL reference`_.
The linked page contains a list and a way to search through *all* types
generated from the definition of Telegram's API (in ``.tl`` file format,
hence the name). These types include requests and constructors.
.. note::
The reason to keep both https://tl.telethon.dev and this
documentation alive is that the former allows instant search results
as you type, and a "Copy import" button. If you like namespaces, you
can also do ``from telethon.tl import types, functions``. Both work.
Telegram makes these ``.tl`` files public, which other implementations, such
as Telethon, can also use to generate code. These files are versioned under
what's called "layers". ``.tl`` files consist of thousands of definitions,
and newer layers often add, change, or remove them. Each definition refers
to either a Remote Procedure Call (RPC) function, or a type (which the
`TL reference`_ calls "constructors", as they construct particular type
instances).
As such, the `TL reference`_ is a good place to go to learn about all possible
requests, types, and what they look like. If you're curious about what's been
changed between layers, you can refer to the `TL diff`_ site.
Navigating the TL reference
===========================
Functions
---------
"Functions" is the term used for the Remote Procedure Calls (RPC) that can be
sent to Telegram to ask it to perform something (e.g. "send message"). These
requests have an associated return type. These can be invoked ("called"):
.. code-block:: python
client = TelegramClient(...)
function_instance = SomeRequest(...)
# Invoke the request
returned_type = await client(function_instance)
Whenever you find the type for a function in the `TL reference`_, the page
will contain the following information:
* What type of account can use the method. This information is regenerated
from time to time (by attempting to invoke the function under both account
types and finding out where it fails). Some requests can only be used by
bot accounts, others by user accounts, and others by both.
* The TL definition. This helps you get a feel for the what the function
looks like. This is not Python code. It just contains the definition in
a concise manner.
* "Copy import" button. Does what it says: it will copy the necessary Python
code to import the function to your system's clipboard for easy access.
* Returns. The returned type. When you invoke the function, this is what the
result will be. It also includes which of the constructors can be returned
inline, to save you a click.
* Parameters. The parameters accepted by the function, including their type,
whether they expect a list, and whether they're optional.
* Known RPC errors. A best-effort list of known errors the request may cause.
This list is not complete and may be out of date, but should provide an
overview of what could go wrong.
* Example. Autogenerated example, showcasing how you may want to call it.
Bear in mind that this is *autogenerated*. It may be spitting out non-sense.
The goal of this example is not to show you everything you can do with the
request, only to give you a feel for what it looks like to use it.
It is very important to click through the links and navigate to get the full
picture. A specific page will show you what the specific function returns and
needs as input parameters. But it may reference other types, so you need to
navigate to those to learn what those contain or need.
Types
-----
"Types" as understood by TL are not actually generated in Telethon.
They would be the "abstract base class" of the constructors, but since Python
is duck-typed, there is hardly any need to generate mostly unnecessary code.
The page for a type contains:
* Constructors. Every type will have one or more constructors. These
constructors *are* generated and can be immported and used.
* Requests returning this type. A helpful way to find out "what requests can
return this?". This is how you may learn what request you need to use to
obtain a particular instance of a type.
* Requests accepting this type as input. A helpful way to find out "what
requests can use this type as one of their input parameters?". This is how
you may learn where a type is used.
* Other types containing this type. A helpful way to find out "where else
does this type appear?". This is how you can walk back through nested
objects.
Constructors
------------
Constructors are used to create instances of a particular type, and are also
returned when invoking requests. You will have to create instances yourself
when invoking requests that need a particular type as input.
The page for a constructor contains:
* Belongs to. The parent type. This is a link back to the types page for the
specific constructor. It also contains the sibling constructors inline, to
save you a click.
* Members. Both the input parameters *and* fields the constructor contains.
Using the TL reference
======================
After you've found a request you want to send, a good start would be to simply
copy and paste the autogenerated example into your script. Then you can simply
tweak it to your needs.
If you want to do it from scratch, first, make sure to import the request into
your code (either using the "Copy import" button near the top, or by manually
spelling out the package under ``telethon.tl.functions.*``).
Then, start reading the parameters one by one. If the parameter cannot be
omitted, you **will** need to specify it, so make sure to spell it out as
an input parameter when constructing the request instance. Let's look at
`PingRequest`_ for example. First, we copy the import:
.. code-block:: python
from telethon.tl.functions import PingRequest
Then, we look at the parameters:
ping_id - long
A single parameter, and it's a long (a integer number with a large range of
values). It doesn't say it can be omitted, so we must provide it, like so:
.. code-block:: python
PingRequest(
ping_id=48641868471
)
(In this case, the ping ID is a random number. You often have to guess what
the parameter needs just by looking at the name.)
Now that we have our request, we can invoke it:
.. code-block:: python
response = await client(PingRequest(
ping_id=48641868471
))
To find out what ``response`` looks like, we can do as the autogenerated
example suggests and "stringify" the result as a pretty-printed string:
.. code-block:: python
print(result.stringify())
This will print out the following:
.. code-block:: python
Pong(
msg_id=781875678118,
ping_id=48641868471
)
Which is a very easy way to get a feel for a response. You should nearly
always print the stringified result, at least once, when trying out requests,
to get a feel for what the response may look like.
But of course, you don't need to do that. Without writing any code, you could
have navigated through the "Returns" link to learn ``PingRequest`` returns a
``Pong``, which only has one constructor, and the constructor has two members,
``msg_id`` and ``ping_id``.
If you wanted to create your own ``Pong``, you would use both members as input
parameters:
.. code-block:: python
my_pong = Pong(
msg_id=781875678118,
ping_id=48641868471
)
(Yes, constructing object instances can use the same code that ``.stringify``
would return!)
And if you wanted to access the ``msg_id`` member, you would simply access it
like any other attribute access in Python:
.. code-block:: python
print(response.msg_id)
Example walkthrough
===================
Say `client.send_message()
<telethon.client.messages.MessageMethods.send_message>` didn't exist,
we could `use the search`_ to look for "message". There we would find
:tl:`SendMessageRequest`, which we can work with.
Every request is a Python class, and has the parameters needed for you
to invoke it. You can also call ``help(request)`` for information on
what input parameters it takes. Remember to "Copy import to the
clipboard", or your script won't be aware of this class! Now we have:
.. code-block:: python
from telethon.tl.functions.messages import SendMessageRequest
If you're going to use a lot of these, you may do:
.. code-block:: python
from telethon.tl import types, functions
# We now have access to 'functions.messages.SendMessageRequest'
We see that this request must take at least two parameters, a ``peer``
of type :tl:`InputPeer`, and a ``message`` which is just a Python
`str`\ ing.
How can we retrieve this :tl:`InputPeer`? We have two options. We manually
construct one, for instance:
.. code-block:: python
from telethon.tl.types import InputPeerUser
peer = InputPeerUser(user_id, user_hash)
Or we call `client.get_input_entity()
<telethon.client.users.UserMethods.get_input_entity>`:
.. code-block:: python
import telethon
async def main():
peer = await client.get_input_entity('someone')
client.loop.run_until_complete(main())
.. note::
Remember that ``await`` must occur inside an ``async def``.
Every full API example assumes you already know and do this.
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>`
is more straightforward (and often immediate, if you've seen the user before,
know their ID, etc.). If you also **need** to have information about the whole
user, use `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
instead:
.. code-block:: python
entity = await client.get_entity('someone')
In the later case, when you use the entity, the library will cast it to
its "input" version for you. If you already have the complete user and
want to cache its input version so the library doesn't have to do this
every time its used, simply call `telethon.utils.get_input_peer`:
.. code-block:: python
from telethon import utils
peer = utils.get_input_peer(entity)
.. note::
Since ``v0.16.2`` this is further simplified. The ``Request`` itself
will call `client.get_input_entity
<telethon.client.users.UserMethods.get_input_entity>` for you when
required, but it's good to remember what's happening.
After this small parenthesis about `client.get_entity
<telethon.client.users.UserMethods.get_entity>` versus
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`,
we have everything we need. To invoke our
request we do:
.. code-block:: python
result = await client(SendMessageRequest(peer, 'Hello there!'))
Message sent! Of course, this is only an example. There are over 250
methods available as of layer 80, and you can use every single of them
as you wish. Remember to use the right types! To sum up:
.. code-block:: python
result = await client(SendMessageRequest(
await client.get_input_entity('username'), 'Hello there!'
))
This can further be simplified to:
.. code-block:: python
result = await client(SendMessageRequest('username', 'Hello there!'))
# Or even
result = await client(SendMessageRequest(PeerChannel(id), 'Hello there!'))
.. note::
Note that some requests have a "hash" parameter. This is **not**
your ``api_hash``! It likely isn't your self-user ``.access_hash`` either.
It's a special hash used by Telegram to only send a difference of new data
that you don't already have with that request, so you can leave it to 0,
and it should work (which means no hash is known yet).
For those requests having a "limit" parameter, you can often set it to
zero to signify "return default amount". This won't work for all of them
though, for instance, in "messages.search" it will actually return 0 items.
Requests in Parallel
====================
The library will automatically merge outgoing requests into a single
*container*. Telegram's API supports sending multiple requests in a
single container, which is faster because it has less overhead and
the server can run them without waiting for others. You can also
force using a container manually:
.. code-block:: python
async def main():
# Letting the library do it behind the scenes
await asyncio.wait([
client.send_message('me', 'Hello'),
client.send_message('me', ','),
client.send_message('me', 'World'),
client.send_message('me', '.')
])
# Manually invoking many requests at once
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ', '),
SendMessageRequest('me', 'World'),
SendMessageRequest('me', '.')
])
Note that you cannot guarantee the order in which they are run.
Try running the above code more than one time. You will see the
order in which the messages arrive is different.
If you use the raw API (the first option), you can use ``ordered``
to tell the server that it should run the requests sequentially.
This will still be faster than going one by one, since the server
knows all requests directly:
.. code-block:: python
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ', '),
SendMessageRequest('me', 'World'),
SendMessageRequest('me', '.')
], ordered=True)
If any of the requests fails with a Telegram error (not connection
errors or any other unexpected events), the library will raise
`telethon.errors.common.MultiError`. You can ``except`` this
and still access the successful results:
.. code-block:: python
from telethon.errors import MultiError
try:
await client([
SendMessageRequest('me', 'Hello'),
SendMessageRequest('me', ''),
SendMessageRequest('me', 'World')
], ordered=True)
except MultiError as e:
# The first and third requests worked.
first = e.results[0]
third = e.results[2]
# The second request failed.
second = e.exceptions[1]
.. _TL reference: https://tl.telethon.dev
.. _TL diff: https://diff.telethon.dev
.. _PingRequest: https://tl.telethon.dev/methods/ping.html
.. _use the search: https://tl.telethon.dev/?q=message&redirect=no
================================================
FILE: readthedocs/concepts/sessions.rst
================================================
.. _sessions:
==============
Session Files
==============
.. contents::
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
the ``session``, and defaults to be the session name (or full path). That is,
if you create a ``TelegramClient('anon')`` instance and connect, an
``anon.session`` file will be created in the working directory.
Note that if you pass a string it will be a file in the current working
directory, although you can also pass absolute paths.
The session file contains enough information for you to login without
re-sending the code, so if you have to enter the code more than once,
maybe you're changing the working directory, renaming or removing the
file, or using random names.
These database files using ``sqlite3`` contain the required information to
talk to the Telegram servers, such as to which IP the client should connect,
port, authorization key so that messages can be encrypted, and so on.
These files will by default also save all the input entities that you've seen,
so that you can get information about a user or channel by just their ID.
Telegram will **not** send their ``access_hash`` required to retrieve more
information about them, if it thinks you have already seem them. For this
reason, the library needs to store this information offline.
The library will by default too save all the entities (chats and channels
with their name and username, and users with the phone too) in the session
file, so that you can quickly access them by username or phone number.
If you're not going to work with updates, or don't need to cache the
``access_hash`` associated with the entities' ID, you can disable this
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.
While it's often not the case, it's possible that SQLite is slow enough to
be noticeable, in which case you can also use a different storage. Note that
this is rare and most people won't have this issue, but it's worth a mention.
To use a custom session storage, simply pass the custom session instance to
:ref:`TelegramClient <telethon-client>` instead of
the session name.
Telethon contains three implementations of the abstract ``Session`` class:
.. 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 <string.StringSession>` is done as follows:
.. code-block:: python
from telethon.sync import TelegramClient
from telethon.sessions import StringSession
with TelegramClient(StringSession(string), api_id, api_hash) as client:
... # use the client
# Save the string session as a string; you should decide how
# you want to save this information (over a socket, remote
# database, print it and then paste the string in the code,
# etc.); the advantage is that you don't need to save it
# on the current disk as a separate file, and can be reused
# anywhere else once you log in.
string = client.session.save()
# Note that it's also possible to save any other session type
# as a string by using ``StringSession.save(session_instance)``:
client = TelegramClient('sqlite-session', api_id, api_hash)
string = StringSession.save(client.session)
There are other community-maintained implementations available:
* `SQLAlchemy <https://github.com/tulir/telethon-session-sqlalchemy>`_:
stores all sessions in a single database via SQLAlchemy.
* `Redis <https://github.com/ezdev128/telethon-session-redis>`_:
stores all sessions in a single Redis data store.
* `MongoDB <https://github.com/watzon/telethon-session-mongo>`_:
stores the current session in a MongoDB database.
Creating your Own Storage
=========================
The easiest way to create your own storage implementation is to use
`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 <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:
.. code-block:: python
from telethon.sync import TelegramClient
from telethon.sessions import StringSession
with TelegramClient(StringSession(), api_id, api_hash) as client:
print(client.session.save())
Think of this as a way to export your authorization key (what's needed
to login into your account). This will print a string in the standard
output (likely your terminal).
.. warning::
**Keep this string safe!** Anyone with this string can use it
to login into your account and do anything they want to.
This is similar to leaking your ``*.session`` files online,
but it is easier to leak a string than it is to leak a file.
Once you have the string (which is a bit long), load it into your script
somehow. You can use a normal text file and ``open(...).read()`` it or
you can save it in a variable directly:
.. code-block:: python
string = '1aaNk8EX-YRfwoRsebUkugFvht6DUPi_Q25UOCzOAqzc...'
with TelegramClient(StringSession(string), api_id, api_hash) as client:
client.loop.run_until_complete(client.send_message('me', 'Hi'))
These strings are really convenient for using in places like Heroku since
their ephemeral filesystem will delete external files once your application
is over.
================================================
FILE: readthedocs/concepts/strings.rst
================================================
======================
String-based Debugging
======================
Debugging is *really* important. Telegram's API is really big and there
are 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
entity = await client.get_entity('username')
print(entity)
That will show a huge **string** similar to the following:
.. code-block:: python
Channel(id=1066197625, title='Telegram Usernames', photo=ChatPhotoEmpty(), date=datetime.datetime(2016, 12, 16, 15, 15, 43, tzinfo=datetime.timezone.utc), version=0, creator=False, left=True, broadcast=True, verified=True, megagroup=False, restricted=False, signatures=False, min=False, scam=False, has_link=False, has_geo=False, slowmode_enabled=False, access_hash=-6309373984955162244, username='username', restriction_reason=[], admin_rights=None, banned_rights=None, default_banned_rights=None, participants_count=None)
That's a lot of text. But as you can see, all the properties are there.
So if you want the title you **don't use regex** or anything like
splitting ``str(entity)`` to get what you want. You just access the
attribute you need:
.. code-block:: python
title = entity.title
Can we get better than the shown string, though? Yes!
.. code-block:: python
print(entity.stringify())
Will show a much better representation:
.. code-block:: python
Channel(
id=1066197625,
title='Telegram Usernames',
photo=ChatPhotoEmpty(
),
date=datetime.datetime(2016, 12, 16, 15, 15, 43, tzinfo=datetime.timezone.utc),
version=0,
creator=False,
left=True,
broadcast=True,
verified=True,
megagroup=False,
restricted=False,
signatures=False,
min=False,
scam=False,
has_link=False,
has_geo=False,
slowmode_enabled=False,
access_hash=-6309373984955162244,
username='username',
restriction_reason=[
],
admin_rights=None,
banned_rights=None,
default_banned_rights=None,
participants_count=None
)
Now it's easy to see how we could get, for example,
the ``year`` value. It's inside ``date``:
.. code-block:: python
channel_year = entity.date.year
You don't need to print everything to see what all the possible values
can be. You can just search in http://tl.telethon.dev/.
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(entity.photo, types.ChatPhotoEmpty):
print('Channel has no photo')
================================================
FILE: readthedocs/concepts/updates.rst
================================================
================
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
asyncio.run(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`` for 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:
...
================================================
FILE: readthedocs/conf.py
================================================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Telethon documentation build configuration file, created by
# sphinx-quickstart on Fri Nov 17 15:36:11 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import re
import os
import sys
sys.path.insert(0, os.path.abspath(os.curdir))
sys.path.insert(0, os.path.abspath(os.pardir))
root = os.path.abspath(os.path.join(__file__, os.path.pardir, os.path.pardir))
tl_ref_url = 'https://tl.telethon.dev'
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.intersphinx',
'custom_roles'
]
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None)
}
# Change the default role so we can avoid prefixing everything with :obj:
default_role = "py:obj"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Telethon'
copyright = '2017 - 2019, Lonami'
author = 'Lonami'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
with open(os.path.join(root, 'telethon', 'version.py'), 'r') as f:
version = re.search(r"^__version__\s+=\s+'(.*)'$",
f.read(), flags=re.MULTILINE).group(1)
# The full version, including alpha/beta/rc tags.
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'friendly'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
def skip(app, what, name, obj, would_skip, options):
if name.endswith('__'):
# We want to show special methods names, except some which add clutter
return name in {
'__init__',
'__abstractmethods__',
'__module__',
'__doc__',
'__dict__'
}
return would_skip
def setup(app):
app.connect("autodoc-skip-member", skip)
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
'collapse_navigation': True,
'display_version': True,
'navigation_depth': 3,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'globaltoc.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'Telethondoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Telethon.tex', 'Telethon Documentation',
author, 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'telethon', 'Telethon Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Telethon', 'Telethon Documentation',
author, 'Telethon', 'One line description of project.',
'Miscellaneous'),
]
================================================
FILE: readthedocs/custom_roles.py
================================================
from docutils import nodes, utils
from docutils.parsers.rst.roles import set_classes
def make_link_node(rawtext, app, name, options):
"""
Create a link to the TL reference.
:param rawtext: Text being replaced with link node.
:param app: Sphinx application context
:param name: Name of the object to link to
:param options: Options dictionary passed to role func.
"""
try:
base = app.config.tl_ref_url
if not base:
raise AttributeError
except AttributeError as e:
raise ValueError('tl_ref_url config value is not set') from e
if base[-1] != '/':
base += '/'
set_classes(options)
node = nodes.reference(rawtext, utils.unescape(name),
refuri='{}?q={}'.format(base, name),
**options)
return node
# noinspection PyUnusedLocal
def tl_role(name, rawtext, text, lineno, inliner, options=None, content=None):
"""
Link to the TL reference.
Returns 2 part tuple containing list of nodes to insert into the
document and a list of system messages. Both are allowed to be empty.
:param name: The role name used in the document.
:param rawtext: The entire markup snippet, with role.
:param text: The text marked with the role.
:param lineno: The line number where rawtext appears in the input.
:param inliner: The inliner instance that called us.
:param options: Directive options for customization.
:param content: The directive content for customization.
"""
if options is None:
options = {}
# TODO Report error on type not found?
# Usage:
# msg = inliner.reporter.error(..., line=lineno)
# return [inliner.problematic(rawtext, rawtext, msg)], [msg]
app = inliner.document.settings.env.app
node = make_link_node(rawtext, app, text, options)
return [node], []
def setup(app):
"""
Install the plugin.
:param app: Sphinx application context.
"""
app.add_role('tl', tl_role)
app.add_config_value('tl_ref_url', None, 'env')
return
================================================
FILE: readthedocs/developing/coding-style.rst
================================================
============
Coding Style
============
Basically, make it **readable**, while keeping the style similar to the
code of whatever file you're working on.
Also note that not everyone has 4K screens for their primary monitors,
so please try to stick to the 80-columns limit. This makes it easy to
``git diff`` changes from a terminal before committing changes. If the
line has to be long, please don't exceed 120 characters.
For the commit messages, please make them *explanatory*. Not only
they're helpful to troubleshoot when certain issues could have been
introduced, but they're also used to construct the change log once a new
version is ready.
If you don't know enough Python, I strongly recommend reading `Dive Into
Python 3 <http://www.diveintopython3.net/>`__, available online for
free. For instance, remember to do ``if x is None`` or
``if x is not None`` instead ``if x == None``!
================================================
FILE: readthedocs/developing/philosophy.rst
================================================
==========
Philosophy
==========
The intention of the library is to have an existing MTProto library
existing with hardly any dependencies (indeed, wherever Python is
available, you can run this library).
Being written in Python means that performance will be nowhere close to
other implementations written in, for instance, Java, C++, Rust, or
pretty much any other compiled language. However, the library turns out
to actually be pretty decent for common operations such as sending
messages, receiving updates, or other scripting. Uploading files may be
notably slower, but if you would like to contribute, pull requests are
appreciated!
If ``libssl`` is available on your system, the library will make use of
it to speed up some critical parts such as encrypting and decrypting the
messages. Files will notably be sent and downloaded faster.
The main focus is to keep everything clean and simple, for everyone to
understand how working with MTProto and Telegram works. Don't be afraid
to read the source, the code won't bite you! It may prove useful when
using the library on your own use cases.
================================================
FILE: readthedocs/developing/project-structure.rst
================================================
=================
Project Structure
=================
Main interface
==============
The library itself is under the ``telethon/`` directory. The
``__init__.py`` file there exposes the main ``TelegramClient``, a class
that servers as a nice interface with the most commonly used methods on
Telegram such as sending messages, retrieving the message history,
handling updates, etc.
The ``TelegramClient`` inherits from several mixing ``Method`` classes,
since there are so many methods that having them in a single file would
make maintenance painful (it was three thousand lines before this separation
happened!). It's a "god object", but there is only a way to interact with
Telegram really.
The ``TelegramBaseClient`` is an ABC which will support all of these mixins
so they can work together nicely. It doesn't even know how to invoke things
because they need to be resolved with user information first (to work with
input entities comfortably).
The client makes use of the ``network/mtprotosender.py``. The
``MTProtoSender`` is responsible for connecting, reconnecting,
packing, unpacking, sending and receiving items from the network.
Basically, the low-level communication with Telegram, and handling
MTProto-related functions and types such as ``BadSalt``.
The sender makes use of a ``Connection`` class which knows the format in
which outgoing messages should be sent (how to encode their length and
their body, if they're further encrypted).
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
a specific format (such as ``.tl`` for objects and ``.json`` for errors)
and spit out the generated classes which represent, as Python classes,
the request and types defined in the ``.tl`` file. It also constructs
an index so that they can be imported easily.
Custom documentation can also be generated to easily navigate through
the vast amount of items offered by the API.
If you clone the repository, you will have to run ``python setup.py gen``
in order to generate the code. Installing the library runs the generator
too, but the mentioned command will just generate code.
================================================
FILE: readthedocs/developing/telegram-api-in-other-languages.rst
================================================
===============================
Telegram API in Other Languages
===============================
Telethon was made for **Python**, and it has inspired other libraries such as
`gramjs <https://github.com/gram-js/gramjs>`__ (JavaScript) and `grammers
<https://github.com/Lonami/grammers>`__ (Rust). But there is a lot more beyond
those, made independently by different developers.
If you're looking for something like Telethon but in a different programming
language, head over to `Telegram API in Other Languages in the official wiki
<https://github.com/LonamiWebs/Telethon/wiki/Telegram-API-in-Other-Languages>`__
for a (mostly) up-to-date list.
================================================
FILE: readthedocs/developing/test-servers.rst
================================================
============
Test Servers
============
To run Telethon on a test server, use the following code:
.. code-block:: python
client = TelegramClient(None, api_id, api_hash)
client.session.set_dc(dc_id, '149.154.167.40', 80)
You can check your ``'test ip'`` on https://my.telegram.org.
You should set `None` session so to ensure you're generating a new
authorization key for it (it would fail if you used a session where you
had previously connected to another data center).
Note that port 443 might not work, so you can try with 80 instead.
Once you're connected, you'll likely be asked to either sign in or sign up.
Remember `anyone can access the phone you
choose <https://core.telegram.org/api/datacenter#testing-redirects>`__,
so don't store sensitive data here.
Valid phone numbers are ``99966XYYYY``, where ``X`` is the ``dc_id`` and
``YYYY`` is any number you want, for example, ``1234`` in ``dc_id = 2`` would
be ``9996621234``. The code sent by Telegram will be ``dc_id`` repeated five
times, in this case, ``22222`` so we can hardcode that:
.. code-block:: python
client = TelegramClient(None, api_id, api_hash)
client.session.set_dc(2, '149.154.167.40', 80)
client.start(
phone='9996621234', code_callback=lambda: '22222'
)
Note that Telegram has changed the length of login codes multiple times in the
past, so if ``dc_id`` repeated five times does not work, try repeating it six
times.
================================================
FILE: readthedocs/developing/testing.rst
================================================
=====
Tests
=====
Telethon uses `Pytest <https://pytest.org/>`__, for testing, `Tox
<https://tox.readthedocs.io/en/latest/>`__ for environment setup, and
`pytest-asyncio <https://pypi.org/project/pytest-asyncio/>`__ and `pytest-cov
<https://pytest-cov.readthedocs.io/en/latest/>`__ for asyncio and
`coverage <https://coverage.readthedocs.io/>`__ integration.
While reading the full documentation for these is probably a good idea, there
is a lot to read, so a brief summary of these tools is provided below for
convienience.
Brief Introduction to Pytest
============================
`Pytest <https://pytest.org/>`__ is a tool for discovering and running python
tests, as well as allowing modular reuse of test setup code using fixtures.
Most Pytest tests will look something like this::
from module import my_thing, my_other_thing
def test_my_thing(fixture):
assert my_thing(fixture) == 42
@pytest.mark.asyncio
async def test_my_thing(event_loop):
assert await my_other_thing(loop=event_loop) == 42
Note here:
1. The test imports one specific function. The role of unit tests is to test
that the implementation of some unit, like a function or class, works.
It's role is not so much to test that components interact well with each
other. I/O, such as connecting to remote servers, should be avoided. This
helps with quickly identifying the source of an error, finding silent
breakage, and makes it easier to cover all possible code paths.
System or integration tests can also be useful, but are currently out of
scope of Telethon's automated testing.
2. A function ``test_my_thing`` is declared. Pytest searches for files
starting with ``test_``, classes starting with ``Test`` and executes any
functions or methods starting with ``test_`` it finds.
3. The function is declared with a parameter ``fixture``. Fixtures are used to
request things required to run the test, such as temporary directories,
free TCP ports, Connections, etc. Fixtures are declared by simply adding
the fixture name as parameter. A full list of available fixtures can be
found with the ``pytest --fixtures`` command.
4. The test uses a simple ``assert`` to test some condition is valid. Pytest
uses some magic to ensure that the errors from this are readable and easy
to debug.
5. The ``pytest.mark.asyncio`` fixture is provided by ``pytest-asyncio``. It
starts a loop and executes a test function as coroutine. This should be
used for testing asyncio code. It also declares the ``event_loop``
fixture, which will request an ``asyncio`` event loop.
Brief Introduction to Tox
=========================
`Tox <https://tox.readthedocs.io/en/latest/>`__ is a tool for automated setup
of virtual environments for testing. While the tests can be run directly by
just running ``pytest``, this only tests one specific python version in your
existing environment, which will not catch e.g. undeclared dependencies, or
version incompatabilities.
Tox environments are declared in the ``tox.ini`` file. The default
environments, declared at the top, can be simply run with ``tox``. The option
``tox -e py36,flake`` can be used to request specific environments to be run.
Brief Introduction to Pytest-cov
================================
Coverage is a useful metric for testing. It measures the lines of code and
branches that are exercised by the tests. The higher the coverage, the more
likely it is that any coding errors will be caught by the tests.
A brief coverage report can be generated with the ``--cov`` option to ``tox``,
which will be passed on to ``pytest``. Additionally, the very useful HTML
report can be generated with ``--cov --cov-report=html``, which contains a
browsable copy of the source code, annotated with coverage information for each
line.
================================================
FILE: readthedocs/developing/tips-for-porting-the-project.rst
================================================
============================
Tips for Porting the Project
============================
If you're going to use the code on this repository to guide you, please
be kind and don't forget to mention it helped you!
You should start by reading the source code on the `first
release <https://github.com/LonamiWebs/Telethon/releases/tag/v0.1>`__ of
the project, and start creating a ``MTProtoSender``. Once this is made,
you should write by hand the code to authenticate on the Telegram's
server, which are some steps required to get the key required to talk to
them. Save it somewhere! Then, simply mimic, or reinvent other parts of
the code, and it will be ready to go within a few days.
Good luck!
================================================
FILE: readthedocs/developing/understanding-the-type-language.rst
================================================
===============================
Understanding the Type Language
===============================
`Telegram's Type Language <https://core.telegram.org/mtproto/TL>`__
(also known as TL, found on ``.tl`` files) is a concise way to define
what other programming languages commonly call classes or structs.
Every definition is written as follows for a Telegram object is defined
as follows:
``name#id argument_name:argument_type = CommonType``
This means that in a single line you know what the ``TLObject`` name is.
You know it's unique ID, and you know what arguments it has. It really
isn't that hard to write a generator for generating code to any
platform!
The generated code should also be able to *encode* the ``TLObject`` (let
this be a request or a type) into bytes, so they can be sent over the
network. This isn't a big deal either, because you know how the
``TLObject``\ 's are made, and how the types should be serialized.
You can either write your own code generator, or use the one this
library provides, but please be kind and keep some special mention to
this project for helping you out.
This is only a introduction. The ``TL`` language is not *that* easy. But
it's not that hard either. You're free to sniff the
``telethon_generator/`` files and learn how to parse other more complex
lines, such as ``flags`` (to indicate things that may or may not be
written at all) and ``vector``\ 's.
================================================
FILE: readthedocs/examples/chats-and-channels.rst
================================================
===============================
Working with Chats and Channels
===============================
.. note::
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
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:
.. code-block:: python
from telethon.tl.functions.channels import JoinChannelRequest
await client(JoinChannelRequest(channel))
# In the same way, you can also leave such channel
from telethon.tl.functions.channels import LeaveChannelRequest
await client(LeaveChannelRequest(input_channel))
For more on channels, check the `channels namespace`__.
__ https://tl.telethon.dev/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
enough information to join! The part after the
``https://t.me/joinchat/``, this is, ``AAAAAFFszQPyPEZ7wgxLtd`` on this
example, is the ``hash`` of the chat or channel. Now you can use
:tl:`ImportChatInviteRequest` as follows:
.. code-block:: python
from telethon.tl.functions.messages import ImportChatInviteRequest
updates = await client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
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
use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
.. code-block:: python
# For normal chats
from telethon.tl.functions.messages import AddChatUserRequest
# Note that ``user_to_add`` is NOT the name of the parameter.
# It's the user you want to add (``user_id=user_to_add``).
await client(AddChatUserRequest(
chat_id,
user_to_add,
fwd_limit=10 # Allow the user to see the 10 last messages
))
# For channels (which includes megagroups)
from telethon.tl.functions.channels import InviteToChannelRequest
await client(InviteToChannelRequest(
channel,
[users_to_add]
))
Note that this method will only really work for friends or bot accounts.
Trying to mass-add users with this approach will not work, and can put both
your account and group to risk, possibly being flagged as spam and limited.
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
the hash of said channel or group.
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
use :tl:`GetMessagesViewsRequest`, setting ``increment=True``:
.. code-block:: python
# Obtain `channel' through dialogs or through client.get_entity() or anyhow.
# Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list.
await client(GetMessagesViewsRequest(
peer=channel,
id=msg_ids,
increment=True
))
Note that you can only do this **once or twice a day** per account,
running this in a loop will obviously not increase the views forever
unless you wait a day between each iteration. If you run it any sooner
than that, the views simply won't be increased.
__ https://github.com/LonamiWebs/Telethon/issues/233
__ https://github.com/LonamiWebs/Telethon/issues/305
__ https://github.com/LonamiWebs/Telethon/issues/409
__ https://github.com/LonamiWebs/Telethon/issues/447
================================================
FILE: readthedocs/examples/users.rst
================================================
=====
Users
=====
.. note::
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`:
.. code-block:: python
from telethon.tl.functions.users import GetFullUserRequest
full = await client(GetFullUserRequest(user))
# or even
full = await client(GetFullUserRequest('username'))
bio = full.full_user.about
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`:
.. code-block:: python
from telethon.tl.functions.account import UpdateProfileRequest
await client(UpdateProfileRequest(
about='This is a test from Telethon'
))
Updating your username
======================
You need to use :tl:`account.UpdateUsername`:
.. code-block:: python
from telethon.tl.functions.account import UpdateUsernameRequest
await client(UpdateUsernameRequest('new_username'))
Updating your profile photo
===========================
The easiest way is to upload a new file and use that as the profile photo
through :tl:`UploadProfilePhoto`:
.. code-block:: python
from telethon.tl.functions.photos import UploadProfilePhotoRequest
await client(UploadProfilePhotoRequest(
await client.upload_file('/path/to/some/file')
))
================================================
FILE: readthedocs/examples/word-of-warning.rst
================================================
=================
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 the
`wiki page of projects using Telethon <https://github.com/LonamiWebs/Telethon/wiki/Projects-using-Telethon>`__.
================================================
FILE: readthedocs/examples/working-with-messages.rst
================================================
=====================
Working with messages
=====================
.. note::
These examples assume you have read :ref:`full-api`.
This section has been `moved to the wiki`_, where it can be easily edited as new
features arrive and the API changes. Please refer to the linked page to learn how
to send spoilers, custom emoji, stickers, react to messages, and more things.
.. _moved to the wiki: https://github.com/LonamiWebs/Telethon/wiki/Sending-more-than-just-messages
================================================
FILE: readthedocs/index.rst
================================================
========================
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()
* 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`.
* Coming from Bot API or want to create new bots? See :ref:`botapi`.
* Need the full API reference? https://tl.telethon.dev/.
What is this?
-------------
Telegram is a popular messaging application. This library is meant
to make it easy for you to write Python programs that can interact
with Telegram. Think of it as a wrapper that has already done the
heavy job for you, so you can focus on developing an application.
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::
:hidden:
:caption: First Steps
basic/installation
basic/signing-in
basic/quick-start
basic/updates
basic/next-steps
.. toctree::
:hidden:
:caption: Quick References
quick-references/faq
quick-references/client-reference
quick-references/events-reference
quick-references/objects-reference
.. toctree::
:hidden:
:caption: Concepts
concepts/strings
concepts/entities
concepts/chats-vs-channels
concepts/updates
concepts/sessions
concepts/full-api
concepts/errors
concepts/botapi-vs-mtproto
concepts/asyncio
.. toctree::
:hidden:
:caption: Full API Examples
examples/word-of-warning
examples/chats-and-channels
examples/users
examples/working-with-messages
.. toctree::
:hidden:
:caption: Developing
developing/philosophy.rst
developing/test-servers.rst
developing/project-structure.rst
developing/coding-style.rst
developing/testing.rst
developing/understanding-the-type-language.rst
developing/tips-for-porting-the-project.rst
developing/telegram-api-in-other-languages.rst
.. toctree::
:hidden:
:caption: Miscellaneous
misc/changelog
misc/compatibility-and-convenience
.. toctree::
:hidden:
:caption: Telethon Modules
modules/client
modules/events
modules/custom
modules/utils
modules/errors
modules/sessions
modules/network
modules/helpers
================================================
FILE: readthedocs/make.bat
================================================
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=Telethon
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
================================================
FILE: readthedocs/misc/changelog.rst
================================================
.. _changelog:
===========================
Changelog (Version History)
===========================
This page lists all the available versions of the library,
in chronological order. You should read this when upgrading
the library to know where your code can break, and where
it can take advantage of new goodies!
.. contents:: List of All Versions
New layer (v1.42)
=================
+------------------------+
| Scheme layer used: 216 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=214&to=216>`__.
Bug fixes
~~~~~~~~~
* Fixed support for Python 3.14.
* Removed potential misuse when downloading files using inferred path.
New layer (v1.41)
=================
+------------------------+
| Scheme layer used: 214 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=201&to=214>`__.
Additions
~~~~~~~~~
* ``send_as`` and ``effect`` added to ``send_file``.
* ``mime_type`` added to ``send_file``.
* ``tg-emoji`` now works with HTML parse mode.
* Clicking a button now lets you choose whether to open the browser.
* Persistent and placeholder buttons.
* More separate RPC error classes.
Enhancements
~~~~~~~~~~~~
* Update entities should now be cached to session more reliably.
* ``utils.get_display_name`` now handles more types.
* Improved some type hints.
* Reply properties for stories now behave as expected.
* ``isal`` can now be used as an optional dependency for faster compression.
* Potential slight speed improvements to deserialization.
Bug fixes
~~~~~~~~~
* Library was not saving update sequence from certain updates.
* Input peer cache should no longer overwrite valid data with min peers.
* Spoiler for input photos and documents was not being respected.
New layer (v1.40)
=================
+------------------------+
| Scheme layer used: 201 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=199&to=201>`__.
Additions
~~~~~~~~~
* ``send_as`` and ``effect`` added to ``send_message`` and related methods.
* :tl:`MessageMediaGeoLive` is now recognized for auto-input conversion.
Enhancements
~~~~~~~~~~~~
* Improved wording when using a likely unintended session file.
* Improved behaviour for matching Markdown links.
* A truly clean update-state is now fetched upon login. This was most notably important for bots.
* Time offset is now updated more reliably after connecting. This should fix legitimate "message too old/new" issues.
Bug fixes
~~~~~~~~~
* :tl:`ChannelParticipantLeft` is now skipped in ``iter_participants``.
* ``spoiler`` flag was lost on :tl:`MessageMediaPhoto` auto-input conversion.
* :tl:`KeyboardButtonCopy` is now recognized as an inline button.
* Downloading web-documents should now work again. Note that this still fetches the file from the original server.
New layer (v1.39)
=================
+------------------------+
| Scheme layer used: 199 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=193&to=199>`__.
Additions
~~~~~~~~~
* ``drop_media_captions`` added to ``forward_messages``, and documented together with ``drop_author``.
* :tl:`InputMediaDocumentExternal` is now recognized when sending albums.
Enhancements
~~~~~~~~~~~~
* ``receive_updates=False`` now covers more cases, however, Telegram is still free to ignore it.
* Better type-hints in several methods.
* Markdown parsing of inline links should cover more cases.
* ``range`` is now considered "list-like" and can be used on e.g. ``ids`` parameters.
Bug fixes
~~~~~~~~~
* Session is now saved after setting the DC.
* Fixed rare crash in entity cache handling when iterating through dialogs.
* Fixed IOError that could occur during automatic resizing of some photos.
New layer (v1.38)
=================
+------------------------+
| Scheme layer used: 193 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=188&to=193>`__.
Bug fixes
~~~~~~~~~
* Formatting entities misbehaved with albums.
* Sending a Message object with a file did not use the new file.
New layer (v1.37)
=================
+------------------------+
| Scheme layer used: 188 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=181&to=188>`__.
Additions
~~~~~~~~~
* Support for CDN downloads should be back. Telethon still prefers no CDN by default.
Enhancements
~~~~~~~~~~~~
* ``FloodWaitPremium`` should now be handled like any other floodwaits.
Bug fixes
~~~~~~~~~
* Fixed edge-case when using ``get_messages(..., reverse=True)``.
* ``ConnectionError`` when using proxies should be raised properly.
New layer (v1.36)
=================
+------------------------+
| Scheme layer used: 181 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=178&to=181>`__.
Bug fixes
~~~~~~~~~
* Certain updates, such as :tl:`UpdateBotStopped`, should now be processed reliably.
New layer (v1.35)
=================
+------------------------+
| Scheme layer used: 178 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=173&to=178>`__.
Additions
~~~~~~~~~
* ``drop_author`` parameter now exposed in ``forward_messages``.
Enhancements
~~~~~~~~~~~~
* "Custom secret support" should work with ``TcpMTProxy``.
* Some type hints should now be more accurate.
Bug fixes
~~~~~~~~~
* Session path couldn't be a ``pathlib.Path`` or ``None``.
* Python versions older than 3.9 should now be supported again.
* Readthedocs should hopefully build the v1 documentation again.
New layer (v1.34)
=================
+------------------------+
| Scheme layer used: 173 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=167&to=173>`__.
Additions
~~~~~~~~~
* ``reply_to_chat`` and ``reply_to_sender`` are now in ``Message``.
This is useful when you lack access to the chat, but Telegram still included some basic information.
Bug fixes
~~~~~~~~~
* ``parse_mode`` with a custom instance containing both ``parse`` and ``unparse`` should now work.
* Parsing and unparsing message entities should now behave better in certain corner-cases.
New layer (v1.33)
=================
+------------------------+
| Scheme layer used: 167 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=166&to=167>`__.
Enhancements
~~~~~~~~~~~~
* ``webbrowser`` is now imported conditionally, to support niche environments.
* Library should now retry on the suddenly-common ``TimedOutError``.
Bug fixes
~~~~~~~~~
* Sending photos which were automatically resized should work again (included in the v1.32 series).
New layer (v1.32)
=================
+------------------------+
| Scheme layer used: 166 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=165&to=166>`__.
This enables you to use custom languages in preformatted blocks using HTML:
.. code-block:: html
<pre>
<code class='language-python'>from telethon import TelegramClient</code>
</pre>
Note that Telethon v1's markdown is a custom format and won't support language tags.
If you want to set a custom language, you have to use HTML or a custom formatter.
Dropped imghdr support (v1.31)
==============================
+------------------------+
| Scheme layer used: 165 |
+------------------------+
This release contains a breaking change in preparation for Python 3.12.
If you were sending photos from in-memory ``bytes`` or ``BytesIO`` containing images,
you should now use ``BytesIO`` and set the ``.name`` property to a dummy name.
This will allow Telethon to detect the correct extension (and file type).
.. code-block:: python
# before
image_data = b'...'
client.send_file(chat, image_data)
# after
from io import BytesIO
image_data = BytesIO(b'...')
image_data.name = 'a.jpg' # any name, only the extension matters
client.send_file(chat, image_data)
Bug fixes
~~~~~~~~~
* Code generation wasn't working under PyPy.
* Obtaining markdown or HTML from message text could produce unexpected results sometimes.
* Other fixes for bugs from the previous version, which were already fixed in patch versions.
Breaking Changes
~~~~~~~~~~~~~~~~
* ``imghdr`` is deprecated in newer Python versions, so Telethon no longer uses it.
This means there might be some cases where Telethon fails to infer the file extension for buffers containing images.
If you were relying on this, add ``.name = 'a.jpg'`` (or other extension) to the ``BytesIO`` buffers you upload.
Layer bump and small changes (v1.30)
====================================
+------------------------+
| Scheme layer used: 162 |
+------------------------+
Some of the bug fixes were already present in patch versions of ``v1.29``, but
the new layer necessitated a minor bump.
Enhancements
~~~~~~~~~~~~
* Removed client-side checks for editing messages.
This only affects ``Message.edit``, as ``client.edit_message`` already had
no checks.
* Library should not understand more server-side errors during update handling
which should reduce crashes.
* Client-side image compression should behave better now.
Bug fixes
~~~~~~~~~
* Some updates such as ``UpdateChatParticipant`` were being missed due to the
order in which Telegram sent them. The library now more carefully checks for
the sequence and pts contained in them to avoid dropping them.
* Fixed ``is_inline`` check for :tl:`KeyboardButtonWebView`.
* Fixed some issues getting entity from cache by ID.
* ``reply_to`` should now work when sending albums.
More bug fixing (v1.29)
=======================
+------------------------+
| Scheme layer used: 160 |
+------------------------+
This layer introduces the necessary raw API methods to work with stories.
The library is aiming to be "feature-frozen" for as long as v1 is active,
so friendly client methods are not implemented, but example code to use
stories can be found in the GitHub wiki of the project.
Enhancements
~~~~~~~~~~~~
* Removed client-side checks for methods dealing with chat permissions.
In particular, this means you can now ban channels.
* Improved some error messages and added new classes for more RPC errors.
* The client-side check for valid usernames has been loosened, so that
very short premium usernames are no longer considered invalid.
Bug fixes
~~~~~~~~~
* Attempting to download a thumbnail from documnets without one would fail,
rather than do nothing (since nothing can be downloaded if there is no thumb).
* More errors are caught in the update handling loop.
* HTML ``.text`` should now "unparse" any message contents correctly.
* Fixed some problems related to logging.
* ``comment_to`` should now work as expected with albums.
* ``asyncio.CancelledError`` should now correctly propagate from the update loop.
* Removed some absolute imports in favour of relative imports.
* ``UserUpdate.last_seen`` should now behave correctly.
* Fixed a rare ``ValueError`` during ``connect`` if the session cache was bad.
New Layer and housekeeping (v1.28)
==================================
+------------------------+
| Scheme layer used: 155 |
+------------------------+
Plenty of stale issues closed, as well as improvements for some others.
Additions
~~~~~~~~~
* New ``entity_cache_limit`` parameter in the ``TelegramClient`` constructor.
This should help a bit in keeping memory usage in check.
Enhancements
~~~~~~~~~~~~
* ``progress_callback`` is now called when dealing with albums. See the
documentation on `client.send_file() <telethon.client.uploads.UploadMethods.send_file>`
for details.
* Update state and entities are now periodically saved, so that the information
isn't lost in the case of crash or unexpected script terminations. You should
still be calling ``disconnect`` or using the context-manager, though.
* The client should no longer unnecessarily call ``get_me`` every time it's started.
Bug fixes
~~~~~~~~~
* Messages obtained via raw API could not be used in ``forward_messages``.
* ``force_sms`` and ``sign_up`` have been deprecated. See `issue 4050`_ for details.
It is no longer possible for third-party applications, such as those made with
Telethon, to use those features.
* ``events.ChatAction`` should now work in more cases in groups with hidden members.
* Errors that occur at the connection level should now be properly propagated, so that
you can actually have a chance to handle them.
* Update handling should be more resilient.
* ``PhoneCodeExpiredError`` will correctly clear the stored hash if it occurs in ``sign_in``.
* In patch ``v1.28.2``, :tl:`InputBotInlineMessageID64` can now be used
to edit inline messages.
.. _issue 4050: https://github.com/LonamiWebs/Telethon/issues/4050
New Layer and some Bug fixes (v1.27)
====================================
+------------------------+
| Scheme layer used: 152 |
+------------------------+
Bug fixes
~~~~~~~~~
* When the account is logged-out, the library should now correctly propagate
an error through ``run_until_disconnected`` to let you handle it.
* The library no longer uses ``asyncio.get_event_loop()`` in newer Python
versions, which should get rid of some deprecation warnings.
* It could happen that bots would receive messages sent by themselves,
very often right after they deleted a message. This should happen far
less often now (but might still happen with unlucky timings).
* Maximum photo size for automatic image resizing is now larger.
* The initial request is now correctly wrapped in ``invokeWithoutUpdates``
when updates are disabled after constructing the client instance.
* Using a ``pathlib.Path`` to download contacts and web documents should
now work correctly.
New Layer and some Bug fixes (v1.26)
====================================
+------------------------+
| Scheme layer used: 149 |
+------------------------+
This new layer includes things such as emoji status, more admin log events,
forum topics and message reactions, among other things. You can access these
using raw API. It also contains a few bug fixes.
These were fixed in the v1.25 series:
* ``client.edit_admin`` did not work on small group chats.
* ``client.get_messages`` could stop early in some channels.
* ``client.download_profile_photo`` now should work even if ``User.min``.
* ``client.disconnect`` should no longer hang when being called from within
an event handlers.
* ``client.get_dialogs`` now initializes the update state for channels.
* The message sender should not need to be fetched in more cases.
* Lowered the severity of some log messages to be less spammy.
These are new to v1.26.0:
* Layer update.
* New documented RPC errors.
* Sometimes the first message update to a channel could be missed if said
message was read immediately.
* ``client.get_dialogs`` would fail when the total count evenly divided
the chunk size of 100.
* ``client.get_messages`` could get stuck during a global search.
* Potentially fixed some issues when sending certain videos.
* Update handling should be more resilient.
* The client should handle having its auth key destroyed more gracefully.
* Fixed some issues when logging certain messages.
Bug fixes (v1.25.1)
===================
This version should fix some of the problems that came with the revamped
update handling.
* Some inline URLs were not parsing correctly with markdown.
* ``events.Raw`` was handling :tl:`UpdateShort` which it shouldn't do.
* ``events.Album`` should now work again.
* ``CancelledError`` was being incorrectly logged as a fatal error.
* Some fixes to update handling primarly aimed for bot accounts.
* Update handling now can deal with more errors without crashing.
* Unhandled errors from update handling will now be propagated through
``client.run_until_disconnected``.
* Invite links with ``+`` are now recognized.
* Added new known RPC errors.
* ``telethon.types`` could not be used as a module.
* 0-length message entities are now stripped to avoid errors.
* ``client.send_message`` was not returning a message with ``reply_to``
in some cases.
* ``aggressive`` in ``client.iter_participants`` now does nothing (it did
not really work anymore anyway, and this should prevent other errors).
* ``client.iter_participants`` was failing in some groups.
* Text with HTML URLs could sometimes fail to parse.
* Added a hard timeout during disconnect in order to prevent the program
from freezing.
Please be sure to report issues with update handling if you still encounter
some errors!
Update handling overhaul (v1.25)
================================
+------------------------+
| Scheme layer used: 144 |
+------------------------+
I had plans to release v2 way earlier, but my motivation drained off, so that
didn't happen. The reason for another v1 release is that there was a clear
need to fix some things regarding update handling (which were present in v2).
I did not want to make this release. But with the release date for v2 still
being unclear, I find it necessary to release another v1 version. I apologize
for the delay (I should've done this a lot sooner but didn't because in my
head I would've pushed through and finished v2, but I underestimated how much
work that was and I probably experienced burn-out).
I still don't intend to make new additions to the v1 series (beyond updating
the Telegram layer being used). I still have plans to finish v2 some day.
But in the meantime, new features, such as reactions, will have to be used
through raw API.
This update also backports the update overhaul from v2. If you experience
issues with updates, please report them on the GitHub page for the project.
However, this new update handling should be more reliable, and ``catch_up``
should actually work properly.
Breaking Changes
~~~~~~~~~~~~~~~~
* In order for ``catch_up`` to work (new flag in the ``TelegramClient``
constructor), sessions need to impleemnt the new ``get_update_states``.
Third-party session storages won't have this implemented by the time
this version released, so ``catch_up`` may not work with those.
Rushed release to fix login (v1.24)
===================================
+------------------------+
| Scheme layer used: 133 |
+------------------------+
This is a rushed release. It contains a layer recent enough to not fail with
``UPDATE_APP_TO_LOGIN``, but still not the latest, to avoid breaking more
than necessary.
Breaking Changes
~~~~~~~~~~~~~~~~
* The biggest change is user identifiers (and chat identifiers, and others)
**now use up to 64 bits**, rather than 32. If you were storing them in some
storage with fixed size, you may need to update (such as database tables
storing only integers).
There have been other changes which I currently don't have the time to document.
You can refer to the following link to see them early:
https://github.com/LonamiWebs/Telethon/compare/v1.23.0...v1.24.0
New schema and bug fixes (v1.23)
================================
+------------------------+
| Scheme layer used: 130 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=129&to=130>`__.
Enhancements
~~~~~~~~~~~~
* `client.pin_message() <telethon.client.messages.MessageMethods.pin_message>`
can now pin on a single side in PMs.
* Iterating participants should now be less expensive floodwait-wise.
Bug fixes
~~~~~~~~~
* The QR login URL was being encoded incorrectly.
* ``force_document`` was being ignored in inline queries for document.
* ``manage_call`` permission was accidentally set to ``True`` by default.
New schema and bug fixes (v1.22)
================================
+------------------------+
| Scheme layer used: 129 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=125&to=129>`__.
Enhancements
~~~~~~~~~~~~
* You can now specify a message in `client.get_stats()
<telethon.client.chats.ChatMethods.get_stats>`.
* Metadata extraction from audio files with ``hachoir`` now recognises "artist".
* Get default chat permissions by not supplying a user to `client.get_permissions()
<telethon.client.chats.ChatMethods.get_permissions>`.
* You may now use ``thumb`` when editing messages.
Bug fixes
~~~~~~~~~
* Fixes regarding bot markup in messages.
* Gracefully handle :tl:`ChannelForbidden` in ``get_sender``.
And from v1.21.1:
* ``file.width`` and ``.height`` was not working correctly in photos.
* Raw API was mis-interpreting ``False`` values on boolean flag parameters.
New schema and QoL improvements (v1.21)
=======================================
+------------------------+
| Scheme layer used: 125 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=124&to=125>`__.
Not many changes in this release, mostly the layer change. Lately quite a few
people have been reporting `TypeNotFoundError`, which occurs when the server
**sends types that it shouldn't**. This can happen when Telegram decides to
add a new, incomplete layer, and then they change the layer without bumping
the layer number (so some constructor IDs no longer match and the error
occurs). This layer change
`should fix it <https://github.com/LonamiWebs/Telethon/issues/1724>`__.
Additions
~~~~~~~~~
* `Message.click() <telethon.tl.custom.message.Message.click>` now supports
a ``password`` parameter, needed when doing things like changing the owner
of a bot via `@BotFather <https://t.me/BotFather>`__.
Enhancements
~~~~~~~~~~~~
* ``tgcrypto`` will now be used for encryption when installed.
Bug fixes
~~~~~~~~~
* `Message.edit <telethon.tl.custom.message.Message.edit>` wasn't working in
your own chat on events other than ``NewMessage``.
* `client.delete_dialog() <telethon.client.dialogs.DialogMethods.delete_dialog>`
was not working on chats.
* ``events.UserUpdate`` should now handle channels' typing status.
* :tl:`InputNotifyPeer` auto-cast should now work on other ``TLObject``.
* For some objects, ``False`` was not correctly serialized.
New schema and QoL improvements (v1.20)
=======================================
+------------------------+
| Scheme layer used: 124 |
+------------------------+
`View new and changed raw API methods <https://diff.telethon.dev/?from=122&to=124>`__.
A bit late to the party, but Telethon now offers a convenient way to comment
on channel posts. It works very similar to ``reply_to``:
.. code-block:: python
client.send_message(channel, 'Great update!', comment_to=1134)
This code will leave a comment to the channel post with ID ``1134`` in
``channel``.
In addition, the library now logs warning or error messages to ``stderr`` by
default! You no longer should be left wondering "why isn't my event handler
working" if you forgot to configure logging. It took so long for this change
to arrive because nobody noticed that Telethon was using a
``logging.NullHandler`` when it really shouldn't have.
If you want the old behaviour of no messages being logged, you can configure
`logging` to ``CRITICAL`` severity:
.. code-block:: python
import logging
logging.basicConfig(level=logging.CRITICAL)
This is not considered a breaking change because ``stderr`` should only be
used for logging purposes, not to emit information others may consume (use
``stdout`` for that).
Additions
~~~~~~~~~
* New ``comment_to`` parameter in `client.send_message()
<telethon.client.messages.MessageMethods.send_message>`, and
`client.send_file() <telethon.client.uploads.UploadMethods.send_file>`
to comment on channel posts.
Enhancements
~~~~~~~~~~~~
* ``utils.resolve_invite_link`` handles the newer link format.
* Downloading files now retries once on `TimeoutError`, which has been
happening recently. It is not guaranteed to work, but it should help.
* Sending albums of photo URLs is now supported.
* EXIF metadata is respected when automatically resizing photos, so the
orientation information should no longer be lost.
* Downloading a thumbnail by index should now use the correct size ordering.
Bug fixes
~~~~~~~~~
* Fixed a `KeyError` on certain cases with ``Conversation``.
* Thumbnails should properly render on more clients. Installing ``hachoir``
may help.
* Message search was broken when using a certain combination of parameters.
* ``utils.resolve_id`` was misbehaving with some identifiers.
* Fix ``TypeNotFoundError`` was not being propagated, causing deadlocks.
* Invoking multiple requests at once with ``ordered=True`` was deadlocking.
New raw API call methods (v1.19)
================================
+------------------------+
| Scheme layer used: 122 |
+------------------------+
Telegram has had group calls for some weeks now. This new version contains the
raw API methods needed to initiate and manage these group calls, however, the
library will likely **not offer ways to stream audio directly**.
Telethon's focus is being an asyncio-based, pure-Python implementation to
interact with Telegram's API. Streaming audio is beyond the current scope of
the project and would be a big undertaking.
However, that doesn't mean calls are not possible with Telethon. If you want
to help design a Python library to perform audio calls, which can then be used
with Telethon (so you can use Telethon + that new library to perform calls
with Telethon), please refer to `@pytgcallschat <https://t.me/pytgcallschat/>`__
and join the relevant chat to discuss and help with the implementation!
The above message was also `posted in the official Telegram group
<https://t.me/TelethonChat/284717>`__, if you wish to discuss it further.
With that out of the way, let's list the additions and bug fixes in this
release:
Additions
~~~~~~~~~
* New ``has_left`` property for user permissions on `client.get_permissions()
<telethon.client.chats.ChatMethods.get_permissions>`.
Enhancements
~~~~~~~~~~~~
* Updated documentation and list of known RPC errors.
* The library now treats a lack of ping responses as a network error.
* `client.kick_participant() <telethon.client.chats.ChatMethods.kick_participant>`
now returns the service message about the user being kicked, so you can
delete it.
Bug fixes
~~~~~~~~~
* When editing inline messages, the text parameter is preferred if provided.
* Additional senders are unconditionally disconnected when disconnecting the
main client, which should reduce the amount of asyncio warnings.
* Automatic reconnection with no retries was failing.
* :tl:`PhotoPathSize` is now ignored when determining a download size, since
this "size" is not a JPEG thumbnail unlike the rest.
* `events.ChatAction <telethon.events.chataction.ChatAction>` should misbehave
less.
New layer and QoL improvements (v1.18)
======================================
+------------------------+
| Scheme layer used: 120 |
+------------------------+
Mostly fixes, and added some new things that can be done in this new layer.
For proxy users, a pull request was merged that will use the ``python-socks``
library when available for proxy support. This library natively supports
`asyncio`, so it should work better than the old ``pysocks``. ``pysocks`` will
still be used if the new library is not available, and both will be handled
transparently by Telethon so you don't need to worry about it.
Additions
~~~~~~~~~
* New `client.set_proxy()
<telethon.client.telegrambaseclient.TelegramBaseClient.set_proxy>` method
which lets you change the proxy without recreating the client. You will need
to reconnect for it to take effect, but you won't need to recreate the
client. This is also an external contribution.
* New method to unpin messages `client.unpin_message()
<telethon.client.messages.MessageMethods.unpin_message>`.
Enhancements
~~~~~~~~~~~~
* Empty peers are excluded from the list of dialogs.
* If the ``python-socks`` library is installed (new optional requirement), it
will be used instead of ``pysocks`` for proxy support. This should fix some
issues with proxy timeouts, because the new library natively supports
`asyncio`.
* `client.send_file() <telethon.client.uploads.UploadMethods.send_file>` will
now group any media type, instead of sending non-image documents separatedly.
This lets you create music albums, for example.
* You can now search messages with a ``from_user`` that's not a user. This is
a Telegram feature, we know the name isn't great, but backwards-compatibility
has to be kept.
Bug fixes
~~~~~~~~~
* Fixes related to conversation timeouts.
* Large dates (over year 2038) now wrap around a 32-bit integer, which is the
only way we can represent them to Telegram. Even if "wrong", it makes things
not crash, and it's the best we can do with 32-bit dates.
* The library was accidentally using a deprecated argument in one of its
friendly methods, producing a warning.
* Improvements to the way marked IDs are parsed.
* ``SlowModeWaitError`` floods are no longer cached.
* Getting the buttons for a message could fail sometimes.
* Getting the display name for "forbidden" chats now works.
* Better handling of errors in some internal methods.
Channel comments and Anonymous Admins (v1.17)
=============================================
+------------------------+
| Scheme layer used: 119 |
+------------------------+
New minor version, new layer change! This time is a good one to remind every
consumer of Python libraries that **you should always specify fixed versions
of your dependencies**! If you're using a ``requirements.txt`` file and you
want to stick with the old version (or any version) for the time being, you
can `use the following syntax <https://pip.pypa.io/en/stable/user_guide/>`__:
.. code-block:: text
telethon~=1.16.0
This will install any version compatible with the written version (so, any in
the ``1.16`` series). Patch releases will never break your code (and if they
do, it's a bug). You can also use that syntax in ``pip install``. Your code
can't know what new versions will look like, so saying it will work with all
versions is a lie and will cause issues.
The reason to bring this up is that Telegram has changed things again, and
with the introduction of anonymous administrators and channel comments, the
sender of a message may not be a :tl:`User`! To accomodate for this, the field
is now a :tl:`Peer` and not `int`. As a reminder, it's always a good idea to
use Telethon's friendly methods and custom properties, which have a higher
stability guarantee than accessing raw API fields.
Even if you don't update, your code will still need to account for the fact
that the sender of a message might be one of the accounts Telegram introduced
to preserve backwards compatibility, because this is a server-side change, so
it's better to update and not lag behind. As it's mostly just a single person
driving the project on their free time, bug-fixes are not backported.
This version also updates the format of SQLite sessions (the default), so
after upgrading and using an old session, the session will be updated, which
means trying to use it back in older versions of the library won't work.
For backwards-compatibility sake, the library has introduced the properties
`Message.reply_to_msg_id <telethon.tl.custom.message.Message.reply_to_msg_id>`
and `Message.to_id <telethon.tl.custom.message.Message.to_id>` that behave
like they did before (Telegram has renamed and changed how these fields work).
Breaking Changes
~~~~~~~~~~~~~~~~
* ``Message.from_id`` is now a :tl:`Peer`, not `int`! If you want the marked
sender ID (much like old behaviour), replace all uses of ``.from_id`` with
``.sender_id``. This will mostly work, but of course in old and new versions
you have to account for the fact that this sender may no longer be a user.
* You can no longer assign to `Message.reply_to_msg_id
<telethon.tl.custom.message.Message.reply_to_msg_id>` and `Message.to_id
<telethon.tl.custom.message.Message.to_id>` because these are now properties
that offer a "view" to the real value from a different field.
* Answering inline queries with a ``photo`` or ``document`` will now send the
photo or document used in the resulting message by default. Not sending the
media was technically a bug, but some people may be relying on this old
behaviour. You can use the old behaviour with ``include_media=False``.
Additions
~~~~~~~~~
* New ``raise_last_call_error`` parameter in the client constructor to raise
the same error produced by the last failing call, rather than a generic
`ValueError`.
* New ``formatting_entities`` parameter in `client.send_message()
<telethon.client.messages.MessageMethods.send_message>`, and
`client.send_file() <telethon.client.uploads.UploadMethods.send_file>`
to bypass the parse mode and manually specify the formatting entities.
* New `client.get_permissions() <telethon.client.chats.ChatMethods.get_permissions>`
method to query a participant's permissions in a group or channel. This
request is slightly expensive in small group chats because it has to fetch
the entire chat to check just a user, so use of a cache is advised.
* `Message.click() <telethon.tl.custom.message.Message.click>` now works on
normal polls!
* New ``local_addr`` parameter in the client constructor to use a specific
local network address when connecting to Telegram.
* `client.inline_query() <telethon.client.bots.BotMethods.inline_query>` now
lets you specify the chat where the query is being made from, which some
bots need to provide certain functionality.
* You can now get comments in a channel post with the ``reply_to`` parameter in
`client.iter_messages() <telethon.client.messages.MessageMethods.iter_messages>`.
Comments are messages that "reply to" a specific channel message, hence the
name (which is consistent with how Telegram's API calls it).
Enhancements
~~~~~~~~~~~~
* Updated documentation and list of known errors.
* If ``hachoir`` is available, the file metadata can now be extracted from
streams and in-memory bytes.
* The default parameters used to initialize a connection now match the format
of those used by Telegram Desktop.
* Specifying 0 retries will no longer cause the library to attempt to reconnect.
* The library should now be able to reliably download very large files.
* Global search should work more reliably now.
* Old usernames are evicted from cache, so getting entities by cached username
should now be more reliable.
* Slightly less noisy logs.
* Stability regarding transport-level errors (transport flood, authorization
key not found) should be improved. In particular, you should no longer be
getting unnecessarily logged out.
* Reconnection should no longer occur if the client gets logged out (for
example, another client revokes the session).
Bug fixes
~~~~~~~~~
* In some cases, there were issues when using `events.Album
<telethon.events.album.Album>` together with `events.Raw
<telethon.events.raw.Raw>`.
* For some channels, one of their channel photos would not show up in
`client.iter_profile_photos() <telethon.client.chats.ChatMethods.iter_profile_photos>`.
* In some cases, a request that failed to be sent would be forgotten, causing
the original caller to be "locked" forever for a response that would never
arrive. Failing requests should now consistently be automatically re-sent.
* The library should more reliably handle certain updates with "empty" data.
* Sending documents in inline queries should now work fine.
* Manually using `client.sign_up <telethon.client.auth.AuthMethods.sign_up>`
should now work correctly, instead of claiming "code invalid".
Special mention to some of the other changes in the 1.16.x series:
* The ``thumb`` for ``download_media`` now supports both `str` and :tl:`VideoSize`.
* Thumbnails are sorted, so ``-1`` is always the largest.
Bug Fixes (v1.16.1)
===================
The last release added support to ``force_file`` on any media, including
things that were not possible before like ``.webp`` files. However, the
``force_document`` toggle commonly used for photos was applied "twice"
(one told the library to send it as a document, and then to send that
document as file), which prevented Telegram for analyzing the images. Long
story short, sending files to the stickers bot stopped working, but that's
been fixed now, and sending photos as documents include the size attribute
again as long as Telegram adds it.
Enhancements
~~~~~~~~~~~~
* When trying to `client.start() <telethon.client.auth.AuthMethods.start>` to
another account if you were previously logged in, the library will now warn
you because this is probably not intended. To avoid the warning, make sure
you're logging in to the right account or logout from the other first.
* Sending a copy of messages with polls will now work when possible.
* The library now automatically retries on inter-dc call errors (which occur
when Telegram has internal issues).
Bug Fixes
~~~~~~~~~
* The aforementioned issue with ``force_document``.
* Square brackets removed from IPv6 addresses. This may fix IPv6 support.
Channel Statistics (v1.16)
==========================
+------------------------+
| Scheme layer used: 116 |
+------------------------+
The newest Telegram update has a new method to also retrieve megagroup
statistics, which can now be used with `client.get_stats()
<telethon.client.chats.ChatMethods.get_stats>`. This way you'll be able
to access the raw data about your channel or megagroup statistics.
The maximum file size limit has also been increased to 2GB on the server,
so you can send even larger files.
Breaking Changes
~~~~~~~~~~~~~~~~
* Besides the obvious layer change, the ``loop`` argument **is now ignored**.
It has been deprecated since Python 3.8 and will be removed in Python 3.10,
and also caused some annoying warning messages when using certain parts of
the library. If you were (incorrectly) relying on using a different loop
from the one that was set, things may break.
Enhancements
~~~~~~~~~~~~
* `client.upload_file() <telethon.client.uploads.UploadMethods.upload_file>`
now works better when streaming files (anything that has a ``.read()``),
instead of reading it all into memory when possible.
QR login (v1.15)
================
*Published at 2020/07/04*
+------------------------+
| Scheme layer used: 114 |
+------------------------+
The library now has a friendly method to perform QR-login, as detailed in
https://core.telegram.org/api/qr-login. It won't generate QR images, but it
provides a way for you to easily do so with any other library of your choice.
Additions
~~~~~~~~~
* New `client.qr_login() <telethon.client.auth.AuthMethods.qr_login>`.
* `message.click <telethon.tl.custom.message.Message.click>` now lets you
click on buttons requesting phone or location.
Enhancements
~~~~~~~~~~~~
* Updated documentation and list of known errors.
* `events.Album <telethon.events.album.Album>` should now handle albums from
different data centers more gracefully.
* `client.download_file()
<telethon.client.downloads.DownloadMethods.download_file>` now supports
`pathlib.Path` as the destination.
Bug fixes
~~~~~~~~~
* No longer crash on updates received prior to logging in.
* Server-side changes caused clicking on inline buttons to trigger a different
error, which is now handled correctly.
Minor quality of life improvements (v1.14)
==========================================
*Published at 2020/05/26*
+------------------------+
| Scheme layer used: 113 |
+------------------------+
Some nice things that were missing, along with the usual bug-fixes.
Additions
~~~~~~~~~
* New `Message.dice <telethon.tl.custom.message.Message.dice>` property.
* The ``func=`` parameter of events can now be an ``async`` function.
Bug fixes
~~~~~~~~~
* Fixed `client.action() <telethon.client.chats.ChatMethods.action>`
having an alias wrong.
* Fixed incorrect formatting of some errors.
* Probably more reliable detection of pin events in small groups.
* Fixed send methods on `client.conversation()
<telethon.client.dialogs.DialogMethods.conversation>` were not honoring
cancellation.
* Flood waits of zero seconds are handled better.
* Getting the pinned message in a chat was failing.
* Fixed the return value when forwarding messages if some were missing
and also the return value of albums.
Enhancements
~~~~~~~~~~~~
* ``.tgs`` files are now recognised as animated stickers.
* The service message produced by `Message.pin()
<telethon.tl.custom.message.Message.pin>` is now returned.
* Sending a file with `client.send_file()
<telethon.client.uploads.UploadMethods.send_file>` now works fine when
you pass an existing dice media (e.g. sending a message copy).
* `client.edit_permissions() <telethon.client.chats.ChatMethods.edit_permissions>`
now has the ``embed_links`` parameter which was missing.
Bug Fixes (v1.13)
=================
*Published at 2020/04/25*
+------------------------+
| Scheme layer used: 112 |
+------------------------+
Bug fixes and layer bump.
Bug fixes
~~~~~~~~~
* Passing ``None`` as the entity to `client.delete_messages()
<telethon.client.messages.MessageMethods.delete_messages>` would fail.
* When downloading a thumbnail, the name inferred was wrong.
Bug Fixes (v1.12)
=================
*Published at 2020/04/20*
+------------------------+
| Scheme layer used: 111 |
+------------------------+
Once again nothing major, but a few bug fixes and primarily the new layer
deserves a new minor release.
Bug fixes
~~~~~~~~~
These were already included in the ``v1.11.3`` patch:
* ``libssl`` check was failing on macOS.
* Getting input users would sometimes fail on `events.ChatAction
<telethon.events.chataction.ChatAction>`.
These bug fixes are available in this release and beyond:
* Avoid another occurrence of `MemoryError`.
* Sending large files in albums would fail because it tried to cache them.
* The ``thumb`` was being ignored when sending files from :tl:`InputFile`.
* Fixed editing inline messages from callback queries in some cases.
* Proxy connection is now blocking which should help avoid some errors.
Bug Fixes (v1.11)
=================
*Published at 2020/02/20*
+------------------------+
| Scheme layer used: 110 |
+------------------------+
It has been a while since the last release, and a few bug fixes have been
made since then. This release includes them and updates the scheme layer.
Note that most of the bug-fixes are available in the ``v1.10.10`` patch.
Bug fixes
~~~~~~~~~
* Fix ``MemoryError`` when casting certain media.
* Fix `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
on small group chats.
* `client.delete_dialog() <telethon.client.dialogs.DialogMethods.delete_dialog>`
now handles deactivated chats more gracefully.
* Sending a message with ``file=`` would ignore some of the parameters.
* Errors are now un-pickle-able once again.
* Fixed some issues regarding markdown and HTML (un)parsing.
The following are also present in ``v1.10.10``:
* Fixed some issues with `events.Album <telethon.events.album.Album>`.
* Fixed some issues with `client.kick_participant()
<telethon.client.chats.ChatMethods.kick_participant>` and
`client.edit_admin() <telethon.client.chats.ChatMethods.edit_admin>`.
* Fixed sending albums and more within `client.conversation()
<telethon.client.dialogs.DialogMethods.conversation>`.
* Fixed some import issues.
* And a lot more minor stuff.
Enhancements
~~~~~~~~~~~~
* Videos can now be included when sending albums.
* Getting updates after reconnect should be more reliable.
* Updated documentation and added more examples.
* More security checks during the generation of the authorization key.
The following are also present in ``v1.10.10``:
* URLs like ``t.me/@username`` are now valid.
* Auto-sleep now works for slow-mode too.
* Improved some error messages.
* Some internal improvements and updating.
* `client.pin_message() <telethon.client.messages.MessageMethods.pin_message>`
now also works with message objects.
* Asynchronous file descriptors are now allowed during download and upload.
Scheduled Messages (v1.10)
==========================
*Published at 2019/09/08*
+------------------------+
| Scheme layer used: 105 |
+------------------------+
You can now schedule messages to be sent (or edited, or forwarded…) at a later
time, which can also work as reminders for yourself when used in your own chat!
.. code-block:: python
from datetime import timedelta
# Remind yourself to walk the dog in 10 minutes (after you play with Telethon's update)
await client.send_message('me', 'Walk the dog',
schedule=timedelta(minutes=10))
# Remind your friend tomorrow to update Telethon
await client.send_message(friend, 'Update Telethon!',
schedule=timedelta(days=1))
Additions
~~~~~~~~~
* New `Button.auth <telethon.tl.custom.button.Button.auth>` friendly button
you can use to ask users to login to your bot.
* Telethon's repository now contains ``*.nix`` expressions that you can use.
* New `client.kick_participant() <telethon.client.chats.ChatMethods.kick_participant>`
method to truly kick (not ban) participants.
* New ``schedule`` parameter in `client.send_message()
<telethon.client.messages.MessageMethods.send_message>`, `client.edit_message()
<telethon.client.messages.MessageMethods.edit_message>`, `client.forward_messages()
<telethon.client.messages.MessageMethods.forward_messages>` and `client.send_file()
<telethon.client.uploads.UploadMethods.send_file>`.
Bug fixes
~~~~~~~~~
* Fix calling ``flush`` on file objects which lack this attribute.
* Fix `CallbackQuery <telethon.events.callbackquery.CallbackQuery>` pattern.
* Fix `client.action() <telethon.client.chats.ChatMethods.action>` not returning
itself when used in a context manager (so the ``as`` would be `None`).
* Fix sending :tl:`InputKeyboardButtonUrlAuth` as inline buttons.
* Fix `client.edit_permissions() <telethon.client.chats.ChatMethods.edit_permissions>`
defaults.
* Fix `Forward <telethon.tl.custom.forward.Forward>` had its ``client`` as `None`.
* Fix (de)serialization of negative timestamps (caused by the information in some
sites with instant view, where the date could be very old).
* Fix HTML un-parsing.
* Fix ``to/from_id`` in private messages when using multiple clients.
* Stop disconnecting from `None` (incorrect logging).
* Fix double-read on double-connect.
* Fix `client.get_messages() <telethon.client.messages.MessageMethods.get_messages>`
when being passed more than 100 IDs.
* Fix `Message.document <telethon.tl.custom.message.Message.document>`
for documents coming from web-pages.
Enhancements
~~~~~~~~~~~~
* Some documentation improvements, including the TL reference.
* Documentation now avoids ``telethon.sync``, which should hopefully be less confusing.
* Better error messages for flood wait.
* You can now `client.get_drafts() <telethon.client.dialogs.DialogMethods.get_drafts>`
for a single entity (which means you can now get a single draft from a single chat).
* New-style file IDs now work with Telethon.
* The ``progress_callback`` for `client.upload_file()
<telethon.client.uploads.UploadMethods.upload_file>` can now be an ``async def``.
Animated Stickers (v1.9)
========================
*Published at 2019/07/06*
+------------------------+
| Scheme layer used: 103 |
+------------------------+
With the layer 103, Telethon is now able to send and receive animated
stickers! These use the ``'application/x-tgsticker'`` mime-type and for
now, you can access its raw data, which is a gzipped JSON.
Additions
~~~~~~~~~
* New `events.Album <telethon.events.album.Album>` to easily receive entire albums!
* New `client.edit_admin() <telethon.client.chats.ChatMethods.edit_admin>`
and `client.edit_permissions() <telethon.client.chats.ChatMethods.edit_permissions>`
methods to more easily manage your groups.
* New ``pattern=`` in `CallbackQuery
<telethon.events.callbackquery.CallbackQuery>`.
* New `conversation.cancel_all()
<telethon.tl.custom.conversation.Conversation.cancel>` method,
to cancel all currently-active conversations in a particular chat.
* New `telethon.utils.encode_waveform` and `telethon.utils.decode_waveform`
methods as implemented by Telegram Desktop, which lets you customize how
voice notes will render.
* New ``ignore_pinned`` parameter in `client.iter_dialogs()
<telethon.client.dialogs.DialogMethods.iter_dialogs>`.
* New `Message.mark_read() <telethon.tl.custom.message.Message.mark_read>`
method.
* You can now use strike-through in markdown with ``~~text~~``, and the
corresponding HTML tags for strike-through, quotes and underlined text.
* You can now nest entities, as in ``**__text__**``.
Bug fixes
~~~~~~~~~
* Fixed downloading contacts.
* Fixed `client.iter_dialogs()
<telethon.client.dialogs.DialogMethods.iter_dialogs>` missing some under
certain circumstances.
* Fixed incredibly slow imports under some systems due to expensive path
resolution when searching for ``libssl``.
* Fixed captions when sending albums.
* Fixed invalid states in `Conversation
<telethon.tl.custom.conversation.Conversation>`.
* Fixes to some methods in utils regarding extensions.
* Fixed memory cycle in `Forward <telethon.tl.custom.forward.Forward>`
which let you do things like the following:
.. code-block:: python
original_fwd = message.forward.original_fwd.original_fwd.original_fwd.original_fwd.original_fwd.original_fwd
Hopefully you didn't rely on that in your code.
* Fixed `File.ext <telethon.tl.custom.file.File.ext>` not working on
unknown mime-types, despite the file name having the extension.
* Fixed ``ids=..., reverse=True`` in `client.iter_messages()
<telethon.client.messages.MessageMethods.iter_messages>`.
* Fixed `Draft <telethon.tl.custom.draft.Draft>` not being aware
of the entity.
* Added missing re-exports in ``telethon.sync``.
Enhancements
~~~~~~~~~~~~
* Improved `conversation.cancel()
<telethon.tl.custom.conversation.Conversation.cancel>`
behaviour. Now you can use it from anywhere.
* The ``progress_callback`` in `client.download_media()
<telethon.client.downloads.DownloadMethods.download_media>`
now lets you use ``async def``.
* Improved documentation and the online
method reference at https://tl.telethon.dev.
Documentation Overhaul (v1.8)
=============================
*Published at 2019/05/30*
+------------------------+
| Scheme layer used: 100 |
+------------------------+
The documentation has been completely reworked from the ground up,
with awesome new quick references such as :ref:`client-ref` to help
you quickly find what you need!
Raw methods also warn you when a friendly variant is available, so
that you don't accidentally make your life harder than it has to be.
In addition, all methods in the client now are fully annotated with type
hints! More work needs to be done, but this should already help a lot when
using Telethon from any IDEs.
You may have noticed that the patch versions between ``v1.7.2`` to ``v1.7.7``
have not been documented. This is because patch versions should only contain
bug fixes, no new features or breaking changes. This hasn't been the case in
the past, but from now on, the library will try to adhere more strictly to
the `Semantic Versioning <https://semver.org>`_ principles.
If you ever want to look at those bug fixes, please use the appropriated
``git`` command, such as ``git shortlog v1.7.1...v1.7.4``, but in general,
they probably just fixed your issue.
With that out of the way, let's look at the full change set:
Breaking Changes
~~~~~~~~~~~~~~~~
* The layer changed, so take note if you use the raw API, as it's usual.
* The way photos are downloaded changed during the layer update of the
previous version, and fixing that bug as a breaking change in itself.
`client.download_media() <telethon.client.downloads.DownloadMethods.download_media>`
now offers a different way to deal with thumbnails.
Additions
~~~~~~~~~
* New `Message.file <telethon.tl.cus
gitextract_c7m6jtsy/ ├── .coveragerc ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.yml │ │ ├── config.yml │ │ ├── documentation-issue.yml │ │ └── feature-request.yml │ ├── pull_request_template.md │ └── workflows.disabled/ │ └── python.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── LICENSE ├── README.rst ├── dev-requirements.txt ├── optional-requirements.txt ├── pyproject.toml ├── readthedocs/ │ ├── Makefile │ ├── basic/ │ │ ├── installation.rst │ │ ├── next-steps.rst │ │ ├── quick-start.rst │ │ ├── signing-in.rst │ │ └── updates.rst │ ├── concepts/ │ │ ├── asyncio.rst │ │ ├── botapi-vs-mtproto.rst │ │ ├── chats-vs-channels.rst │ │ ├── entities.rst │ │ ├── errors.rst │ │ ├── full-api.rst │ │ ├── sessions.rst │ │ ├── strings.rst │ │ └── updates.rst │ ├── conf.py │ ├── custom_roles.py │ ├── developing/ │ │ ├── coding-style.rst │ │ ├── philosophy.rst │ │ ├── project-structure.rst │ │ ├── telegram-api-in-other-languages.rst │ │ ├── test-servers.rst │ │ ├── testing.rst │ │ ├── tips-for-porting-the-project.rst │ │ └── understanding-the-type-language.rst │ ├── examples/ │ │ ├── chats-and-channels.rst │ │ ├── users.rst │ │ ├── word-of-warning.rst │ │ └── working-with-messages.rst │ ├── index.rst │ ├── make.bat │ ├── misc/ │ │ ├── changelog.rst │ │ └── compatibility-and-convenience.rst │ ├── modules/ │ │ ├── client.rst │ │ ├── custom.rst │ │ ├── errors.rst │ │ ├── events.rst │ │ ├── helpers.rst │ │ ├── network.rst │ │ ├── sessions.rst │ │ └── utils.rst │ ├── quick-references/ │ │ ├── client-reference.rst │ │ ├── events-reference.rst │ │ ├── faq.rst │ │ └── objects-reference.rst │ └── requirements.txt ├── requirements.txt ├── setup.py ├── telethon/ │ ├── __init__.py │ ├── _updates/ │ │ ├── __init__.py │ │ ├── entitycache.py │ │ ├── messagebox.py │ │ └── session.py │ ├── client/ │ │ ├── __init__.py │ │ ├── account.py │ │ ├── auth.py │ │ ├── bots.py │ │ ├── buttons.py │ │ ├── chats.py │ │ ├── dialogs.py │ │ ├── downloads.py │ │ ├── messageparse.py │ │ ├── messages.py │ │ ├── telegrambaseclient.py │ │ ├── telegramclient.py │ │ ├── updates.py │ │ ├── uploads.py │ │ └── users.py │ ├── crypto/ │ │ ├── __init__.py │ │ ├── aes.py │ │ ├── aesctr.py │ │ ├── authkey.py │ │ ├── cdndecrypter.py │ │ ├── factorization.py │ │ ├── libssl.py │ │ └── rsa.py │ ├── custom.py │ ├── errors/ │ │ ├── __init__.py │ │ ├── common.py │ │ └── rpcbaseerrors.py │ ├── events/ │ │ ├── __init__.py │ │ ├── album.py │ │ ├── callbackquery.py │ │ ├── chataction.py │ │ ├── common.py │ │ ├── inlinequery.py │ │ ├── messagedeleted.py │ │ ├── messageedited.py │ │ ├── messageread.py │ │ ├── newmessage.py │ │ ├── raw.py │ │ └── userupdate.py │ ├── extensions/ │ │ ├── __init__.py │ │ ├── binaryreader.py │ │ ├── html.py │ │ ├── markdown.py │ │ └── messagepacker.py │ ├── functions.py │ ├── helpers.py │ ├── hints.py │ ├── network/ │ │ ├── __init__.py │ │ ├── authenticator.py │ │ ├── connection/ │ │ │ ├── __init__.py │ │ │ ├── connection.py │ │ │ ├── http.py │ │ │ ├── tcpabridged.py │ │ │ ├── tcpfull.py │ │ │ ├── tcpintermediate.py │ │ │ ├── tcpmtproxy.py │ │ │ └── tcpobfuscated.py │ │ ├── mtprotoplainsender.py │ │ ├── mtprotosender.py │ │ ├── mtprotostate.py │ │ └── requeststate.py │ ├── password.py │ ├── requestiter.py │ ├── sessions/ │ │ ├── __init__.py │ │ ├── abstract.py │ │ ├── memory.py │ │ ├── sqlite.py │ │ └── string.py │ ├── sync.py │ ├── tl/ │ │ ├── __init__.py │ │ ├── core/ │ │ │ ├── __init__.py │ │ │ ├── gzippacked.py │ │ │ ├── messagecontainer.py │ │ │ ├── rpcresult.py │ │ │ └── tlmessage.py │ │ ├── custom/ │ │ │ ├── __init__.py │ │ │ ├── adminlogevent.py │ │ │ ├── button.py │ │ │ ├── chatgetter.py │ │ │ ├── conversation.py │ │ │ ├── dialog.py │ │ │ ├── draft.py │ │ │ ├── file.py │ │ │ ├── forward.py │ │ │ ├── inlinebuilder.py │ │ │ ├── inlineresult.py │ │ │ ├── inlineresults.py │ │ │ ├── inputsizedfile.py │ │ │ ├── message.py │ │ │ ├── messagebutton.py │ │ │ ├── participantpermissions.py │ │ │ ├── qrlogin.py │ │ │ └── sendergetter.py │ │ ├── patched/ │ │ │ └── __init__.py │ │ └── tlobject.py │ ├── types.py │ ├── utils.py │ └── version.py ├── telethon_examples/ │ ├── LICENSE │ ├── README.md │ ├── assistant.py │ ├── gui.py │ ├── interactive_telegram_client.py │ ├── payment.py │ ├── print_messages.py │ ├── print_updates.py │ ├── quart_login.py │ └── replier.py ├── telethon_generator/ │ ├── __init__.py │ ├── data/ │ │ ├── api.tl │ │ ├── errors.csv │ │ ├── friendly.csv │ │ ├── html/ │ │ │ ├── 404.html │ │ │ ├── core.html │ │ │ ├── css/ │ │ │ │ ├── docs.dark.css │ │ │ │ ├── docs.h4x0r.css │ │ │ │ └── docs.light.css │ │ │ └── js/ │ │ │ └── search.js │ │ ├── methods.csv │ │ └── mtproto.tl │ ├── docswriter.py │ ├── generators/ │ │ ├── __init__.py │ │ ├── docs.py │ │ ├── errors.py │ │ └── tlobject.py │ ├── parsers/ │ │ ├── __init__.py │ │ ├── errors.py │ │ ├── methods.py │ │ └── tlobject/ │ │ ├── __init__.py │ │ ├── parser.py │ │ ├── tlarg.py │ │ └── tlobject.py │ ├── sourcebuilder.py │ ├── syncerrors.py │ └── utils.py ├── tests/ │ ├── __init__.py │ ├── readthedocs/ │ │ ├── __init__.py │ │ ├── conftest.py │ │ └── quick_references/ │ │ ├── __init__.py │ │ └── test_client_reference.py │ └── telethon/ │ ├── __init__.py │ ├── client/ │ │ ├── __init__.py │ │ └── test_messages.py │ ├── crypto/ │ │ ├── __init__.py │ │ └── test_rsa.py │ ├── events/ │ │ ├── __init__.py │ │ └── test_chataction.py │ ├── extensions/ │ │ ├── __init__.py │ │ ├── test_html.py │ │ └── test_markdown.py │ ├── test_helpers.py │ ├── test_pickle.py │ ├── test_utils.py │ └── tl/ │ ├── __init__.py │ └── test_serialization.py └── update-docs.sh
SYMBOL INDEX (1346 symbols across 122 files)
FILE: readthedocs/conf.py
function skip (line 102) | def skip(app, what, name, obj, would_skip, options):
function setup (line 116) | def setup(app):
FILE: readthedocs/custom_roles.py
function make_link_node (line 5) | def make_link_node(rawtext, app, name, options):
function tl_role (line 32) | def tl_role(name, rawtext, text, lineno, inliner, options=None, content=...
function setup (line 59) | def setup(app):
FILE: setup.py
class TempWorkDir (line 28) | class TempWorkDir:
method __init__ (line 32) | def __init__(self, new=None):
method __enter__ (line 36) | def __enter__(self):
method __exit__ (line 43) | def __exit__(self, *args):
function generate (line 68) | def generate(which, action='gen'):
function main (line 156) | def main(argv):
FILE: telethon/_updates/entitycache.py
class EntityCache (line 7) | class EntityCache:
method __init__ (line 8) | def __init__(
method set_self_user (line 18) | def set_self_user(self, id, bot, hash):
method get (line 24) | def get(self, id):
method extend (line 31) | def extend(self, users, chats):
method put (line 52) | def put(self, entity):
method retain (line 55) | def retain(self, filter):
method __len__ (line 58) | def __len__(self):
FILE: telethon/_updates/messagebox.py
class Sentinel (line 49) | class Sentinel:
method __init__ (line 52) | def __init__(self, tag=None):
method __repr__ (line 55) | def __repr__(self):
function next_updates_deadline (line 71) | def next_updates_deadline():
function epoch (line 74) | def epoch():
class GapError (line 77) | class GapError(ValueError):
method __repr__ (line 78) | def __repr__(self):
class PrematureEndReason (line 82) | class PrematureEndReason(Enum):
class PtsInfo (line 88) | class PtsInfo:
method __init__ (line 91) | def __init__(
method from_update (line 102) | def from_update(cls, update):
method __repr__ (line 118) | def __repr__(self):
class State (line 123) | class State:
method __init__ (line 126) | def __init__(
method __repr__ (line 136) | def __repr__(self):
class PossibleGap (line 148) | class PossibleGap:
method __init__ (line 151) | def __init__(
method __repr__ (line 160) | def __repr__(self):
class MessageBox (line 167) | class MessageBox:
method __init__ (line 170) | def __init__(
method _trace (line 206) | def _trace(self, msg, *args, **kwargs):
method load (line 217) | def load(self, session_state, channel_states):
method session_state (line 237) | def session_state(self):
method is_empty (line 250) | def is_empty(self) -> bool:
method check_deadlines (line 256) | def check_deadlines(self):
method reset_deadlines (line 297) | def reset_deadlines(self, entries, deadline):
method reset_channel_deadline (line 315) | def reset_channel_deadline(self, channel_id, timeout):
method set_state (line 322) | def set_state(self, state, reset=True):
method try_set_channel_state (line 351) | def try_set_channel_state(self, id, pts):
method try_begin_get_diff (line 362) | def try_begin_get_diff(self, entry, reason):
method end_get_diff (line 380) | def end_get_diff(self, entry):
method process_updates (line 405) | def process_updates(
method apply_pts_info (line 514) | def apply_pts_info(
method get_difference (line 608) | def get_difference(self):
method apply_difference (line 627) | def apply_difference(
method apply_difference_type (line 671) | def apply_difference_type(
method end_difference (line 702) | def end_difference(self):
method get_channel_difference (line 723) | def get_channel_difference(
method apply_channel_difference (line 757) | def apply_channel_difference(
method end_channel_difference (line 808) | def end_channel_difference(self, request, reason: PrematureEndReason, ...
FILE: telethon/_updates/session.py
class SessionState (line 6) | class SessionState:
method __init__ (line 24) | def __init__(
method __repr__ (line 44) | def __repr__(self):
class ChannelState (line 48) | class ChannelState:
method __init__ (line 57) | def __init__(
method __repr__ (line 65) | def __repr__(self):
class EntityType (line 69) | class EntityType(IntEnum):
method canonical (line 87) | def canonical(self):
class Entity (line 104) | class Entity:
method __init__ (line 118) | def __init__(
method is_user (line 129) | def is_user(self):
method is_group (line 136) | def is_group(self):
method is_broadcast (line 145) | def is_broadcast(self):
method from_str (line 154) | def from_str(cls, string: str):
method from_bytes (line 169) | def from_bytes(cls, blob):
method __str__ (line 180) | def __str__(self):
method __bytes__ (line 183) | def __bytes__(self):
method _as_input_peer (line 186) | def _as_input_peer(self):
method __repr__ (line 194) | def __repr__(self):
FILE: telethon/client/account.py
class _TakeoutClient (line 15) | class _TakeoutClient:
method __init__ (line 21) | def __init__(self, finalize, client, request):
method success (line 31) | def success(self):
method success (line 35) | def success(self, value):
method __aenter__ (line 38) | async def __aenter__(self):
method __aexit__ (line 48) | async def __aexit__(self, exc_type, exc_value, traceback):
method __call__ (line 62) | async def __call__(self, request, ordered=False):
method __getattribute__ (line 80) | def __getattribute__(self, name):
method __getattr__ (line 93) | def __getattr__(self, name):
method __setattr__ (line 103) | def __setattr__(self, name, value):
class AccountMethods (line 110) | class AccountMethods:
method takeout (line 111) | def takeout(
method end_takeout (line 222) | async def end_takeout(self: 'TelegramClient', success: bool) -> bool:
FILE: telethon/client/auth.py
class AuthMethods (line 16) | class AuthMethods:
method start (line 20) | def start(
method _start (line 131) | async def _start(
method _parse_phone_and_hash (line 254) | def _parse_phone_and_hash(self, phone, phone_hash):
method sign_in (line 270) | async def sign_in(
method sign_up (line 371) | async def sign_up(
method _on_login (line 385) | async def _on_login(self, user):
method send_code_request (line 409) | async def send_code_request(
method qr_login (line 491) | async def qr_login(self: 'TelegramClient', ignored_ids: typing.List[in...
method log_out (line 531) | async def log_out(self: 'TelegramClient') -> bool:
method edit_2fa (line 559) | async def edit_2fa(
method __aenter__ (line 668) | async def __aenter__(self):
method __aexit__ (line 671) | async def __aexit__(self, *args):
FILE: telethon/client/bots.py
class BotMethods (line 10) | class BotMethods:
method inline_query (line 11) | async def inline_query(
FILE: telethon/client/buttons.py
class ButtonMethods (line 7) | class ButtonMethods:
method build_reply_markup (line 9) | def build_reply_markup(
FILE: telethon/client/chats.py
class _ChatAction (line 19) | class _ChatAction:
method __init__ (line 45) | def __init__(self, client, chat, action, *, delay, auto_cancel):
method __aenter__ (line 55) | async def __aenter__(self):
method __aexit__ (line 68) | async def __aexit__(self, *args):
method _update (line 82) | async def _update(self):
method progress (line 94) | def progress(self, current, total):
class _ParticipantsIter (line 99) | class _ParticipantsIter(RequestIter):
method _init (line 100) | async def _init(self, entity, filter, search):
method _load_next_chunk (line 184) | async def _load_next_chunk(self):
class _AdminLogIter (line 241) | class _AdminLogIter(RequestIter):
method _init (line 242) | async def _init(
method _load_next_chunk (line 275) | async def _load_next_chunk(self):
class _ProfilePhotoIter (line 302) | class _ProfilePhotoIter(RequestIter):
method _init (line 303) | async def _init(
method _load_next_chunk (line 341) | async def _load_next_chunk(self):
class ChatMethods (line 395) | class ChatMethods:
method iter_participants (line 399) | def iter_participants(
method get_participants (line 470) | async def get_participants(
method iter_admin_log (line 493) | def iter_admin_log(
method get_admin_log (line 641) | async def get_admin_log(
method iter_profile_photos (line 661) | def iter_profile_photos(
method get_profile_photos (line 707) | async def get_profile_photos(
method action (line 728) | def action(
method edit_admin (line 825) | async def edit_admin(
method edit_permissions (line 974) | async def edit_permissions(
method kick_participant (line 1124) | async def kick_participant(
method get_permissions (line 1190) | async def get_permissions(
method get_stats (line 1258) | async def get_stats(
FILE: telethon/client/dialogs.py
function _dialog_message_key (line 16) | def _dialog_message_key(peer, message_id):
class _DialogsIter (line 27) | class _DialogsIter(RequestIter):
method _init (line 28) | async def _init(
method _load_next_chunk (line 51) | async def _load_next_chunk(self):
class _DraftsIter (line 116) | class _DraftsIter(RequestIter):
method _init (line 117) | async def _init(self, entities, **kwargs):
method _load_next_chunk (line 139) | async def _load_next_chunk(self):
class DialogMethods (line 143) | class DialogMethods:
method iter_dialogs (line 147) | def iter_dialogs(
method get_dialogs (line 236) | async def get_dialogs(self: 'TelegramClient', *args, **kwargs) -> 'hin...
method iter_drafts (line 264) | def iter_drafts(
method get_drafts (line 298) | async def get_drafts(
method edit_folder (line 322) | async def edit_folder(
method delete_dialog (line 405) | async def delete_dialog(
method conversation (line 476) | def conversation(
FILE: telethon/client/downloads.py
class _CdnRedirect (line 31) | class _CdnRedirect(Exception):
method __init__ (line 32) | def __init__(self, cdn_redirect=None):
class _DirectDownloadIter (line 36) | class _DirectDownloadIter(RequestIter):
method _init (line 37) | async def _init(
method _load_next_chunk (line 78) | async def _load_next_chunk(self):
method _request (line 87) | async def _request(self):
method close (line 141) | async def close(self):
method __aenter__ (line 153) | async def __aenter__(self):
method __aexit__ (line 156) | async def __aexit__(self, *args):
class _GenericDownloadIter (line 163) | class _GenericDownloadIter(_DirectDownloadIter):
method _load_next_chunk (line 164) | async def _load_next_chunk(self):
class DownloadMethods (line 214) | class DownloadMethods:
method download_profile_photo (line 218) | async def download_profile_photo(
method download_media (line 332) | async def download_media(
method download_file (line 453) | async def download_file(
method _download_file (line 527) | async def _download_file(
method iter_download (line 603) | def iter_download(
method _iter_download (line 709) | def _iter_download(
method _get_thumb (line 780) | def _get_thumb(thumbs, thumb):
method _download_cached_photo_size (line 823) | def _download_cached_photo_size(self: 'TelegramClient', size, file):
method _download_photo (line 845) | async def _download_photo(self: 'TelegramClient', photo, file, date, t...
method _get_kind_and_names (line 885) | def _get_kind_and_names(attributes):
method _download_document (line 908) | async def _download_document(
method _download_contact (line 948) | def _download_contact(cls, mm_contact, file):
method _download_web_document (line 987) | async def _download_web_document(cls, web, file, progress_callback):
method _get_proper_filename (line 1027) | def _get_proper_filename(file, kind, extension,
FILE: telethon/client/messageparse.py
class MessageParseMethods (line 12) | class MessageParseMethods:
method parse_mode (line 17) | def parse_mode(self: 'TelegramClient'):
method parse_mode (line 53) | def parse_mode(self: 'TelegramClient', mode: str):
method _replace_with_mention (line 60) | async def _replace_with_mention(self: 'TelegramClient', entities, i, u...
method _parse_message_text (line 74) | async def _parse_message_text(self: 'TelegramClient', message, parse_m...
method _get_response_message (line 113) | def _get_response_message(self: 'TelegramClient', request, result, inp...
FILE: telethon/client/messages.py
class _MessagesIter (line 16) | class _MessagesIter(RequestIter):
method _init (line 20) | async def _init(
method _load_next_chunk (line 178) | async def _load_next_chunk(self):
method _message_in_range (line 241) | def _message_in_range(self, message):
method _update_offset (line 257) | def _update_offset(self, last_message, response):
class _IDsIter (line 285) | class _IDsIter(RequestIter):
method _init (line 286) | async def _init(self, entity, ids):
method _load_next_chunk (line 297) | async def _load_next_chunk(self):
class MessageMethods (line 341) | class MessageMethods:
method iter_messages (line 347) | def iter_messages(
method get_messages (line 557) | async def get_messages(
method _get_comment_data (line 614) | async def _get_comment_data(
method send_message (line 627) | async def send_message(
method forward_messages (line 946) | async def forward_messages(
method edit_message (line 1085) | async def edit_message(
method delete_messages (line 1263) | async def delete_messages(
method send_read_acknowledge (line 1340) | async def send_read_acknowledge(
method pin_message (line 1427) | async def pin_message(
method unpin_message (line 1468) | async def unpin_message(
method _pin (line 1498) | async def _pin(self, entity, message, *, unpin, notify=False, pm_onesi...
FILE: telethon/client/telegrambaseclient.py
class _ExportState (line 43) | class _ExportState:
method __init__ (line 44) | def __init__(self):
method add_borrow (line 51) | def add_borrow(self):
method add_return (line 55) | def add_return(self):
method should_disconnect (line 61) | def should_disconnect(self):
method need_connect (line 66) | def need_connect(self):
method mark_disconnected (line 69) | def mark_disconnected(self):
class TelegramBaseClient (line 75) | class TelegramBaseClient(abc.ABC):
method __init__ (line 244) | def __init__(
method loop (line 454) | def loop(self: 'TelegramClient') -> asyncio.AbstractEventLoop:
method disconnected (line 473) | def disconnected(self: 'TelegramClient') -> asyncio.Future:
method flood_sleep_threshold (line 489) | def flood_sleep_threshold(self):
method flood_sleep_threshold (line 493) | def flood_sleep_threshold(self, value):
method connect (line 501) | async def connect(self: 'TelegramClient') -> None:
method is_connected (line 622) | def is_connected(self: 'TelegramClient') -> bool:
method disconnect (line 637) | def disconnect(self: 'TelegramClient'):
method set_proxy (line 674) | def set_proxy(self: 'TelegramClient', proxy: typing.Union[tuple, dict]):
method _save_states_and_entities (line 703) | async def _save_states_and_entities(self: 'TelegramClient'):
method _disconnect_coro (line 725) | async def _disconnect_coro(self: 'TelegramClient'):
method _disconnect (line 759) | async def _disconnect(self: 'TelegramClient'):
method _switch_dc (line 771) | async def _switch_dc(self: 'TelegramClient', new_dc):
method _auth_key_callback (line 787) | async def _auth_key_callback(self: 'TelegramClient', auth_key):
method _get_dc (line 799) | async def _get_dc(self: 'TelegramClient', dc_id, cdn=False):
method _create_exported_sender (line 830) | async def _create_exported_sender(self: 'TelegramClient', dc_id):
method _borrow_exported_sender (line 858) | async def _borrow_exported_sender(self: 'TelegramClient', dc_id):
method _return_exported_sender (line 890) | async def _return_exported_sender(self: 'TelegramClient', sender):
method _clean_exported_senders (line 900) | async def _clean_exported_senders(self: 'TelegramClient'):
method _get_cdn_client (line 914) | async def _get_cdn_client(self: 'TelegramClient', cdn_redirect):
method __call__ (line 947) | def __call__(self: 'TelegramClient', request, ordered=False):
method _update_loop (line 973) | def _update_loop(self: 'TelegramClient'):
method _handle_auto_reconnect (line 977) | async def _handle_auto_reconnect(self: 'TelegramClient'):
FILE: telethon/client/telegramclient.py
class TelegramClient (line 8) | class TelegramClient(
FILE: telethon/client/updates.py
class OperationalError (line 20) | class OperationalError(Exception):
class UpdateMethods (line 37) | class UpdateMethods:
method _run_until_disconnected (line 41) | async def _run_until_disconnected(self: 'TelegramClient'):
method set_receive_updates (line 54) | async def set_receive_updates(self: 'TelegramClient', receive_updates):
method run_until_disconnected (line 65) | def run_until_disconnected(self: 'TelegramClient'):
method on (line 112) | def on(self: 'TelegramClient', event: EventBuilder):
method add_event_handler (line 139) | def add_event_handler(
method remove_event_handler (line 188) | def remove_event_handler(
method list_event_handlers (line 227) | def list_event_handlers(self: 'TelegramClient')\
method catch_up (line 248) | async def catch_up(self: 'TelegramClient'):
method _update_loop (line 267) | async def _update_loop(self: 'TelegramClient'):
method _preprocess_updates (line 507) | async def _preprocess_updates(self, updates, users, chats):
method _keepalive_loop (line 516) | async def _keepalive_loop(self: 'TelegramClient'):
method _dispatch_update (line 556) | async def _dispatch_update(self: 'TelegramClient', update):
method _dispatch_event (line 623) | async def _dispatch_event(self: 'TelegramClient', event):
method _handle_auto_reconnect (line 664) | async def _handle_auto_reconnect(self: 'TelegramClient'):
class EventBuilderDict (line 710) | class EventBuilderDict:
method __init__ (line 714) | def __init__(self, client: 'TelegramClient', update, others):
method __getitem__ (line 719) | def __getitem__(self, builder):
FILE: telethon/client/uploads.py
class _CacheType (line 25) | class _CacheType:
method __init__ (line 27) | def __init__(self, cls):
method __call__ (line 30) | def __call__(self, *args, **kwargs):
method __eq__ (line 33) | def __eq__(self, other):
function _resize_photo_if_needed (line 37) | def _resize_photo_if_needed(
class UploadMethods (line 109) | class UploadMethods:
method send_file (line 113) | async def send_file(
method _send_album (line 486) | async def _send_album(self: 'TelegramClient', entity, files, caption='',
method upload_file (line 577) | async def upload_file(
method _file_to_media (line 765) | async def _file_to_media(
FILE: telethon/client/users.py
function _fmt_flood (line 18) | def _fmt_flood(delay, request, *, early=False, td=datetime.timedelta):
class UserMethods (line 28) | class UserMethods:
method __call__ (line 29) | async def __call__(self: 'TelegramClient', request, ordered=False, flo...
method _call (line 32) | async def _call(self: 'TelegramClient', sender, request, ordered=False...
method get_me (line 144) | async def get_me(self: 'TelegramClient', input_peer: bool = False) \
method _self_id (line 181) | def _self_id(self: 'TelegramClient') -> typing.Optional[int]:
method is_bot (line 190) | async def is_bot(self: 'TelegramClient') -> bool:
method is_user_authorized (line 207) | async def is_user_authorized(self: 'TelegramClient') -> bool:
method get_entity (line 229) | async def get_entity(
method get_input_entity (line 354) | async def get_input_entity(
method _get_peer (line 482) | async def _get_peer(self: 'TelegramClient', peer: 'hints.EntityLike'):
method get_peer_id (line 486) | async def get_peer_id(
method _get_entity_from_string (line 523) | async def _get_entity_from_string(self: 'TelegramClient', string):
method _get_input_dialog (line 587) | async def _get_input_dialog(self: 'TelegramClient', dialog):
method _get_input_notify (line 604) | async def _get_input_notify(self: 'TelegramClient', notify):
FILE: telethon/crypto/aes.py
class AES (line 29) | class AES:
method decrypt_ige (line 35) | def decrypt_ige(cipher_text, key, iv):
method encrypt_ige (line 72) | def encrypt_ige(plain_text, key, iv):
FILE: telethon/crypto/aesctr.py
class AESModeCTR (line 7) | class AESModeCTR:
method __init__ (line 11) | def __init__(self, key, iv):
method encrypt (line 26) | def encrypt(self, data):
method decrypt (line 35) | def decrypt(self, data):
FILE: telethon/crypto/authkey.py
class AuthKey (line 10) | class AuthKey:
method __init__ (line 15) | def __init__(self, data):
method key (line 24) | def key(self):
method key (line 28) | def key(self, value):
method calc_new_nonce_hash (line 45) | def calc_new_nonce_hash(self, new_nonce, number):
method __bool__ (line 59) | def __bool__(self):
method __eq__ (line 62) | def __eq__(self, other):
FILE: telethon/crypto/cdndecrypter.py
class CdnDecrypter (line 12) | class CdnDecrypter:
method __init__ (line 18) | def __init__(self, cdn_client, file_token, cdn_aes, cdn_file_hashes):
method prepare_decrypter (line 33) | async def prepare_decrypter(client, cdn_client, cdn_redirect):
method get_file (line 76) | def get_file(self):
method check (line 96) | def check(data, cdn_hash):
FILE: telethon/crypto/factorization.py
class Factorization (line 7) | class Factorization:
method factorize (line 12) | def factorize(cls, pq):
method gcd (line 56) | def gcd(a, b):
FILE: telethon/crypto/libssl.py
function _find_ssl_lib (line 18) | def _find_ssl_lib():
class AES_KEY (line 91) | class AES_KEY(ctypes.Structure):
function decrypt_ige (line 98) | def decrypt_ige(cipher_text, key, iv):
function encrypt_ige (line 120) | def encrypt_ige(plain_text, key, iv):
FILE: telethon/crypto/rsa.py
function get_byte_array (line 21) | def get_byte_array(integer):
function _compute_fingerprint (line 37) | def _compute_fingerprint(key):
function add_key (line 50) | def add_key(pub, *, old):
function encrypt (line 57) | def encrypt(fingerprint, data, *, use_old=False):
FILE: telethon/errors/__init__.py
function rpc_message_to_error (line 18) | def rpc_message_to_error(rpc_error, request):
FILE: telethon/errors/common.py
class ReadCancelledError (line 8) | class ReadCancelledError(Exception):
method __init__ (line 10) | def __init__(self):
class TypeNotFoundError (line 14) | class TypeNotFoundError(Exception):
method __init__ (line 19) | def __init__(self, invalid_constructor_id, remaining):
class InvalidChecksumError (line 30) | class InvalidChecksumError(Exception):
method __init__ (line 35) | def __init__(self, checksum, valid_checksum):
class InvalidBufferError (line 45) | class InvalidBufferError(BufferError):
method __init__ (line 50) | def __init__(self, payload):
class AuthKeyNotFound (line 62) | class AuthKeyNotFound(Exception):
method __init__ (line 74) | def __init__(self):
class SecurityError (line 78) | class SecurityError(Exception):
method __init__ (line 82) | def __init__(self, *args):
class CdnFileTamperedError (line 88) | class CdnFileTamperedError(SecurityError):
method __init__ (line 93) | def __init__(self):
class AlreadyInConversationError (line 99) | class AlreadyInConversationError(Exception):
method __init__ (line 103) | def __init__(self):
class BadMessageError (line 110) | class BadMessageError(Exception):
method __init__ (line 149) | def __init__(self, request, code):
class MultiError (line 157) | class MultiError(Exception):
method __new__ (line 160) | def __new__(cls, exceptions, result, requests):
FILE: telethon/errors/rpcbaseerrors.py
class RPCError (line 13) | class RPCError(Exception):
method __init__ (line 18) | def __init__(self, request, message, code=None):
method _fmt_request (line 27) | def _fmt_request(request):
method __reduce__ (line 38) | def __reduce__(self):
class InvalidDCError (line 42) | class InvalidDCError(RPCError):
class BadRequestError (line 50) | class BadRequestError(RPCError):
class UnauthorizedError (line 60) | class UnauthorizedError(RPCError):
class ForbiddenError (line 69) | class ForbiddenError(RPCError):
class NotFoundError (line 78) | class NotFoundError(RPCError):
class AuthKeyError (line 86) | class AuthKeyError(RPCError):
class FloodError (line 95) | class FloodError(RPCError):
class ServerError (line 106) | class ServerError(RPCError):
class TimedOutError (line 116) | class TimedOutError(RPCError):
FILE: telethon/events/__init__.py
class StopPropagation (line 16) | class StopPropagation(Exception):
function register (line 43) | def register(event=None):
function unregister (line 87) | def unregister(callback, event=None):
function is_handler (line 120) | def is_handler(callback):
function list (line 128) | def list(callback):
function _get_handlers (line 136) | def _get_handlers(callback):
FILE: telethon/events/album.py
class AlbumHack (line 22) | class AlbumHack:
method __init__ (line 35) | def __init__(self, client, event):
method extend (line 44) | def extend(self, messages):
method deliver_event (line 50) | async def deliver_event(self):
class Album (line 68) | class Album(EventBuilder):
method __init__ (line 94) | def __init__(
method build (line 99) | def build(cls, update, others=None, self_id=None):
method filter (line 140) | def filter(self, event):
class Event (line 145) | class Event(EventCommon, SenderGetter):
method __init__ (line 153) | def __init__(self, messages):
method _set_client (line 160) | def _set_client(self, client):
method grouped_id (line 177) | def grouped_id(self):
method text (line 184) | def text(self):
method raw_text (line 192) | def raw_text(self):
method is_reply (line 200) | def is_reply(self):
method forward (line 212) | def forward(self):
method get_reply_message (line 224) | async def get_reply_message(self):
method respond (line 233) | async def respond(self, *args, **kwargs):
method reply (line 241) | async def reply(self, *args, **kwargs):
method forward_to (line 249) | async def forward_to(self, *args, **kwargs):
method edit (line 260) | async def edit(self, *args, **kwargs):
method delete (line 288) | async def delete(self, *args, **kwargs):
method mark_read (line 302) | async def mark_read(self):
method pin (line 313) | async def pin(self, *, notify=False):
method __len__ (line 321) | def __len__(self):
method __iter__ (line 329) | def __iter__(self):
method __getitem__ (line 337) | def __getitem__(self, n):
FILE: telethon/events/callbackquery.py
class CallbackQuery (line 11) | class CallbackQuery(EventBuilder):
method __init__ (line 58) | def __init__(
method build (line 90) | def build(cls, update, others=None, self_id=None):
method filter (line 100) | def filter(self, event):
class Event (line 126) | class Event(EventCommon, SenderGetter):
method __init__ (line 142) | def __init__(self, query, peer, msg_id):
method _set_client (line 151) | def _set_client(self, client):
method id (line 157) | def id(self):
method message_id (line 165) | def message_id(self):
method data (line 172) | def data(self):
method chat_instance (line 179) | def chat_instance(self):
method get_message (line 186) | async def get_message(self):
method _refetch_sender (line 202) | async def _refetch_sender(self):
method answer (line 219) | async def answer(
method via_inline (line 256) | def via_inline(self):
method respond (line 270) | async def respond(self, *args, **kwargs):
method reply (line 284) | async def reply(self, *args, **kwargs):
method edit (line 299) | async def edit(self, *args, **kwargs):
method delete (line 326) | async def delete(self, *args, **kwargs):
FILE: telethon/events/chataction.py
class ChatAction (line 7) | class ChatAction(EventBuilder):
method build (line 35) | def build(cls, update, others=None, self_id=None):
class Event (line 122) | class Event(EventCommon):
method __init__ (line 164) | def __init__(self, where, new_photo=None,
method _set_client (line 219) | def _set_client(self, client):
method respond (line 224) | async def respond(self, *args, **kwargs):
method reply (line 233) | async def reply(self, *args, **kwargs):
method delete (line 248) | async def delete(self, *args, **kwargs):
method get_pinned_message (line 266) | async def get_pinned_message(self):
method get_pinned_messages (line 277) | async def get_pinned_messages(self):
method added_by (line 293) | def added_by(self):
method get_added_by (line 304) | async def get_added_by(self):
method kicked_by (line 314) | def kicked_by(self):
method get_kicked_by (line 325) | async def get_kicked_by(self):
method user (line 335) | def user(self):
method get_user (line 345) | async def get_user(self):
method input_user (line 353) | def input_user(self):
method get_input_user (line 360) | async def get_input_user(self):
method user_id (line 368) | def user_id(self):
method users (line 376) | def users(self):
method get_users (line 395) | async def get_users(self):
method input_users (line 412) | def input_users(self):
method get_input_users (line 436) | async def get_input_users(self):
method user_ids (line 453) | def user_ids(self):
FILE: telethon/events/common.py
function _into_id_set (line 10) | async def _into_id_set(client, chats):
class EventBuilder (line 41) | class EventBuilder(abc.ABC):
method __init__ (line 68) | def __init__(self, chats=None, *, blacklist_chats=False, func=None):
method build (line 77) | def build(cls, update, others=None, self_id=None):
method resolve (line 89) | async def resolve(self, client):
method _resolve (line 102) | async def _resolve(self, client):
method filter (line 105) | def filter(self, event):
class EventCommon (line 130) | class EventCommon(ChatGetter, abc.ABC):
method __init__ (line 143) | def __init__(self, chat_peer=None, msg_id=None, broadcast=None):
method _set_client (line 150) | def _set_client(self, client):
method client (line 162) | def client(self):
method __str__ (line 168) | def __str__(self):
method stringify (line 171) | def stringify(self):
method to_dict (line 174) | def to_dict(self):
function name_inner_event (line 180) | def name_inner_event(cls):
FILE: telethon/events/inlinequery.py
class InlineQuery (line 13) | class InlineQuery(EventBuilder):
method __init__ (line 50) | def __init__(
method build (line 64) | def build(cls, update, others=None, self_id=None):
method filter (line 68) | def filter(self, event):
class Event (line 77) | class Event(EventCommon, SenderGetter):
method __init__ (line 92) | def __init__(self, query):
method _set_client (line 99) | def _set_client(self, client):
method id (line 105) | def id(self):
method text (line 112) | def text(self):
method offset (line 119) | def offset(self):
method geo (line 127) | def geo(self):
method builder (line 136) | def builder(self):
method answer (line 143) | async def answer(
method _as_future (line 241) | def _as_future(obj):
FILE: telethon/events/messagedeleted.py
class MessageDeleted (line 6) | class MessageDeleted(EventBuilder):
method build (line 39) | def build(cls, update, others=None, self_id=None):
class Event (line 51) | class Event(EventCommon):
method __init__ (line 52) | def __init__(self, deleted_ids, peer):
FILE: telethon/events/messageedited.py
class MessageEdited (line 7) | class MessageEdited(NewMessage):
method build (line 46) | def build(cls, update, others=None, self_id=None):
class Event (line 51) | class Event(NewMessage.Event):
FILE: telethon/events/messageread.py
class MessageRead (line 7) | class MessageRead(EventBuilder):
method __init__ (line 32) | def __init__(
method build (line 38) | def build(cls, update, others=None, self_id=None):
method filter (line 57) | def filter(self, event):
class Event (line 63) | class Event(EventCommon):
method __init__ (line 80) | def __init__(self, peer=None, max_id=None, out=False, contents=False,
method inbox (line 90) | def inbox(self):
method message_ids (line 97) | def message_ids(self):
method get_messages (line 106) | async def get_messages(self):
method is_read (line 124) | def is_read(self, message):
method __contains__ (line 138) | def __contains__(self, message):
FILE: telethon/events/newmessage.py
class NewMessage (line 9) | class NewMessage(EventBuilder):
method __init__ (line 59) | def __init__(self, chats=None, *, blacklist_chats=False, func=None,
method _resolve (line 92) | async def _resolve(self, client):
method build (line 97) | def build(cls, update, others=None, self_id=None):
method filter (line 142) | def filter(self, event):
class Event (line 166) | class Event(EventCommon):
method __init__ (line 199) | def __init__(self, message):
method _set_client (line 207) | def _set_client(self, client):
method __getattr__ (line 213) | def __getattr__(self, item):
method __setattr__ (line 219) | def __setattr__(self, name, value):
FILE: telethon/events/raw.py
class Raw (line 5) | class Raw(EventBuilder):
method __init__ (line 26) | def __init__(self, types=None, *, func=None):
method resolve (line 41) | async def resolve(self, client):
method build (line 45) | def build(cls, update, others=None, self_id=None):
method filter (line 48) | def filter(self, event):
FILE: telethon/events/userupdate.py
function _requires_action (line 19) | def _requires_action(function):
function _requires_status (line 27) | def _requires_status(function):
class UserUpdate (line 36) | class UserUpdate(EventBuilder):
method build (line 52) | def build(cls, update, others=None, self_id=None):
class Event (line 68) | class Event(EventCommon, SenderGetter):
method __init__ (line 88) | def __init__(self, peer, *, status=None, chat_peer=None, typing=None):
method _set_client (line 95) | def _set_client(self, client):
method user (line 101) | def user(self):
method get_user (line 105) | async def get_user(self):
method input_user (line 110) | def input_user(self):
method get_input_user (line 114) | async def get_input_user(self):
method user_id (line 119) | def user_id(self):
method typing (line 125) | def typing(self):
method uploading (line 133) | def uploading(self):
method recording (line 149) | def recording(self):
method playing (line 161) | def playing(self):
method cancel (line 169) | def cancel(self):
method geo (line 177) | def geo(self):
method audio (line 185) | def audio(self):
method round (line 196) | def round(self):
method video (line 207) | def video(self):
method contact (line 218) | def contact(self):
method document (line 226) | def document(self):
method sticker (line 234) | def sticker(self):
method photo (line 242) | def photo(self):
method last_seen (line 250) | def last_seen(self):
method until (line 259) | def until(self):
method _last_seen_delta (line 266) | def _last_seen_delta(self):
method online (line 282) | def online(self):
method recently (line 290) | def recently(self):
method within_weeks (line 298) | def within_weeks(self):
method within_months (line 306) | def within_months(self):
FILE: telethon/extensions/binaryreader.py
class BinaryReader (line 16) | class BinaryReader:
method __init__ (line 21) | def __init__(self, data):
method read_byte (line 30) | def read_byte(self):
method read_int (line 36) | def read_int(self, signed=True):
method read_long (line 43) | def read_long(self, signed=True):
method read_float (line 50) | def read_float(self):
method read_double (line 56) | def read_double(self):
method read_large_int (line 62) | def read_large_int(self, bits, signed=True):
method read (line 67) | def read(self, length=-1):
method get_bytes (line 84) | def get_bytes(self):
method tgread_bytes (line 92) | def tgread_bytes(self):
method tgread_string (line 113) | def tgread_string(self):
method tgread_bool (line 117) | def tgread_bool(self):
method tgread_date (line 127) | def tgread_date(self):
method tgread_object (line 134) | def tgread_object(self):
method tgread_vector (line 160) | def tgread_vector(self):
method close (line 170) | def close(self):
method tell_position (line 176) | def tell_position(self):
method set_position (line 180) | def set_position(self, position):
method seek (line 184) | def seek(self, offset):
method __enter__ (line 195) | def __enter__(self):
method __exit__ (line 198) | def __exit__(self, exc_type, exc_val, exc_tb):
FILE: telethon/extensions/html.py
class HTMLToTelegramParser (line 20) | class HTMLToTelegramParser(HTMLParser):
method __init__ (line 21) | def __init__(self):
method handle_starttag (line 29) | def handle_starttag(self, tag, attrs):
method handle_data (line 97) | def handle_data(self, text):
method handle_endtag (line 109) | def handle_endtag(self, tag):
function parse (line 120) | def parse(html: str) -> Tuple[str, List[TypeMessageEntity]]:
function unparse (line 161) | def unparse(text: str, entities: Iterable[TypeMessageEntity]) -> str:
FILE: telethon/extensions/markdown.py
function parse (line 29) | def parse(message, delimiters=None, url_re=None):
function unparse (line 137) | def unparse(text, entities, delimiters=None, url_fmt=None):
FILE: telethon/extensions/messagepacker.py
class MessagePacker (line 11) | class MessagePacker:
method __init__ (line 25) | def __init__(self, state, loggers):
method append (line 31) | def append(self, state):
method extend (line 35) | def extend(self, states):
method get (line 39) | async def get(self):
FILE: telethon/helpers.py
class _EntityType (line 15) | class _EntityType(enum.Enum):
function generate_random_long (line 27) | def generate_random_long(signed=True):
function ensure_parent_dir_exists (line 32) | def ensure_parent_dir_exists(file_path):
function add_surrogate (line 39) | def add_surrogate(text):
function del_surrogate (line 48) | def del_surrogate(text):
function within_surrogate (line 52) | def within_surrogate(text, index, *, length=None):
function strip_text (line 66) | def strip_text(text, entities):
function retry_range (line 140) | def retry_range(retries, force_retry=True):
function _maybe_await (line 159) | async def _maybe_await(value):
function _cancel (line 166) | async def _cancel(log, **tasks):
function _sync_enter (line 203) | def _sync_enter(self):
function _sync_exit (line 222) | def _sync_exit(self, *args):
function _entity_type (line 231) | def _entity_type(entity):
function generate_key_data_from_nonce (line 271) | def generate_key_data_from_nonce(server_nonce, new_nonce):
class TotalList (line 289) | class TotalList(list):
method __init__ (line 312) | def __init__(self, *args, **kwargs):
method __str__ (line 316) | def __str__(self):
method __repr__ (line 320) | def __repr__(self):
class _FileStream (line 325) | class _FileStream(io.IOBase):
method __init__ (line 335) | def __init__(self, file, *, file_size=None):
method __aenter__ (line 345) | async def __aenter__(self):
method __aexit__ (line 389) | async def __aexit__(self, exc_type, exc_val, exc_tb):
method file_size (line 394) | def file_size(self):
method name (line 398) | def name(self):
method read (line 402) | def read(self, *args, **kwargs): return self._stream.read(*args, **kwa...
method readinto (line 403) | def readinto(self, *args, **kwargs): return self._stream.readinto(*arg...
method write (line 404) | def write(self, *args, **kwargs): return self._stream.write(*args, **k...
method fileno (line 405) | def fileno(self, *args, **kwargs): return self._stream.fileno(*args, *...
method flush (line 406) | def flush(self, *args, **kwargs): return self._stream.flush(*args, **k...
method isatty (line 407) | def isatty(self, *args, **kwargs): return self._stream.isatty(*args, *...
method readable (line 408) | def readable(self, *args, **kwargs): return self._stream.readable(*arg...
method readline (line 409) | def readline(self, *args, **kwargs): return self._stream.readline(*arg...
method readlines (line 410) | def readlines(self, *args, **kwargs): return self._stream.readlines(*a...
method seek (line 411) | def seek(self, *args, **kwargs): return self._stream.seek(*args, **kwa...
method seekable (line 412) | def seekable(self, *args, **kwargs): return self._stream.seekable(*arg...
method tell (line 413) | def tell(self, *args, **kwargs): return self._stream.tell(*args, **kwa...
method truncate (line 414) | def truncate(self, *args, **kwargs): return self._stream.truncate(*arg...
method writable (line 415) | def writable(self, *args, **kwargs): return self._stream.writable(*arg...
method writelines (line 416) | def writelines(self, *args, **kwargs): return self._stream.writelines(...
method close (line 422) | def close(self, *args, **kwargs):
function get_running_loop (line 427) | def get_running_loop():
FILE: telethon/network/authenticator.py
function do_authentication (line 22) | async def do_authentication(sender):
function get_int (line 203) | def get_int(byte_array, signed=True):
FILE: telethon/network/connection/connection.py
class Connection (line 20) | class Connection(abc.ABC):
method __init__ (line 36) | def __init__(self, ip, port, dc_id, *, loggers, proxy=None, local_addr...
method _wrap_socket_ssl (line 54) | def _wrap_socket_ssl(sock):
method _parse_proxy (line 68) | def _parse_proxy(proxy_type, addr, port, rdns=True, username=None, pas...
method _proxy_connect (line 106) | async def _proxy_connect(self, timeout=None, local_addr=None):
method _connect (line 207) | async def _connect(self, timeout=None, ssl=None):
method connect (line 246) | async def connect(self, timeout=None, ssl=None):
method disconnect (line 257) | async def disconnect(self):
method send (line 290) | def send(self, data):
method recv (line 301) | async def recv(self):
method _send_loop (line 316) | async def _send_loop(self):
method _recv_loop (line 334) | async def _recv_loop(self):
method _init_conn (line 364) | def _init_conn(self):
method _send (line 376) | def _send(self, data):
method _recv (line 379) | async def _recv(self):
method __str__ (line 382) | def __str__(self):
class ObfuscatedConnection (line 389) | class ObfuscatedConnection(Connection):
method _init_conn (line 398) | def _init_conn(self):
method _send (line 402) | def _send(self, data):
method _recv (line 405) | async def _recv(self):
class PacketCodec (line 409) | class PacketCodec(abc.ABC):
method __init__ (line 421) | def __init__(self, connection):
method encode_packet (line 428) | def encode_packet(self, data):
method read_packet (line 435) | async def read_packet(self, reader):
FILE: telethon/network/connection/http.py
class HttpPacketCodec (line 9) | class HttpPacketCodec(PacketCodec):
method encode_packet (line 13) | def encode_packet(self, data):
method read_packet (line 23) | async def read_packet(self, reader):
class ConnectionHttp (line 35) | class ConnectionHttp(Connection):
method connect (line 38) | async def connect(self, timeout=None, ssl=None):
FILE: telethon/network/connection/tcpabridged.py
class AbridgedPacketCodec (line 6) | class AbridgedPacketCodec(PacketCodec):
method encode_packet (line 10) | def encode_packet(self, data):
method read_packet (line 18) | async def read_packet(self, reader):
class ConnectionTcpAbridged (line 27) | class ConnectionTcpAbridged(Connection):
FILE: telethon/network/connection/tcpfull.py
class FullPacketCodec (line 9) | class FullPacketCodec(PacketCodec):
method __init__ (line 12) | def __init__(self, connection):
method encode_packet (line 16) | def encode_packet(self, data):
method read_packet (line 25) | async def read_packet(self, reader):
class ConnectionTcpFull (line 54) | class ConnectionTcpFull(Connection):
FILE: telethon/network/connection/tcpintermediate.py
class IntermediatePacketCodec (line 8) | class IntermediatePacketCodec(PacketCodec):
method encode_packet (line 12) | def encode_packet(self, data):
method read_packet (line 15) | async def read_packet(self, reader):
class RandomizedIntermediatePacketCodec (line 20) | class RandomizedIntermediatePacketCodec(IntermediatePacketCodec):
method encode_packet (line 28) | def encode_packet(self, data):
method read_packet (line 33) | async def read_packet(self, reader):
class ConnectionTcpIntermediate (line 41) | class ConnectionTcpIntermediate(Connection):
FILE: telethon/network/connection/tcpmtproxy.py
class MTProxyIO (line 16) | class MTProxyIO:
method __init__ (line 23) | def __init__(self, connection):
method init_header (line 33) | def init_header(secret, dc_id, packet_codec):
method readexactly (line 76) | async def readexactly(self, n):
method write (line 79) | def write(self, data):
class TcpMTProxy (line 83) | class TcpMTProxy(ObfuscatedConnection):
method __init__ (line 99) | def __init__(self, ip, port, dc_id, *, loggers, proxy=None, local_addr...
method _connect (line 106) | async def _connect(self, timeout=None, ssl=None):
method address_info (line 129) | def address_info(proxy_info):
method normalize_secret (line 135) | def normalize_secret(secret):
class ConnectionTcpMTProxyAbridged (line 147) | class ConnectionTcpMTProxyAbridged(TcpMTProxy):
class ConnectionTcpMTProxyIntermediate (line 154) | class ConnectionTcpMTProxyIntermediate(TcpMTProxy):
class ConnectionTcpMTProxyRandomizedIntermediate (line 161) | class ConnectionTcpMTProxyRandomizedIntermediate(TcpMTProxy):
FILE: telethon/network/connection/tcpobfuscated.py
class ObfuscatedIO (line 9) | class ObfuscatedIO:
method __init__ (line 12) | def __init__(self, connection):
method init_header (line 21) | def init_header(packet_codec):
method readexactly (line 47) | async def readexactly(self, n):
method write (line 50) | def write(self, data):
class ConnectionTcpObfuscated (line 54) | class ConnectionTcpObfuscated(ObfuscatedConnection):
FILE: telethon/network/mtprotoplainsender.py
class MTProtoPlainSender (line 12) | class MTProtoPlainSender:
method __init__ (line 17) | def __init__(self, connection, *, loggers):
method send (line 26) | async def send(self, request):
FILE: telethon/network/mtprotosender.py
class MTProtoSender (line 33) | class MTProtoSender:
method __init__ (line 48) | def __init__(self, auth_key, *, loggers,
method connect (line 123) | async def connect(self, connection):
method is_connected (line 137) | def is_connected(self):
method _transport_connected (line 140) | def _transport_connected(self):
method disconnect (line 147) | async def disconnect(self):
method send (line 154) | def send(self, request, ordered=False):
method disconnected (line 209) | def disconnected(self):
method _disconnected (line 220) | def _disconnected(self):
method _connect (line 228) | async def _connect(self):
method _try_connect (line 287) | async def _try_connect(self, attempt):
method _try_gen_auth_key (line 299) | async def _try_gen_auth_key(self, attempt):
method _disconnect (line 320) | async def _disconnect(self, error=None):
method _reconnect (line 354) | async def _reconnect(self, last_error):
method _start_reconnect (line 423) | def _start_reconnect(self, error):
method _keepalive_ping (line 438) | def _keepalive_ping(self, rnd_id):
method _send_loop (line 452) | async def _send_loop(self):
method _recv_loop (line 503) | async def _recv_loop(self):
method _process_message (line 568) | async def _process_message(self, message):
method _pop_states (line 579) | def _pop_states(self, msg_id):
method _handle_rpc_result (line 603) | async def _handle_rpc_result(self, message):
method _handle_container (line 657) | async def _handle_container(self, message):
method _handle_gzip_packed (line 667) | async def _handle_gzip_packed(self, message):
method _handle_update (line 678) | async def _handle_update(self, message):
method _store_own_updates (line 692) | def _store_own_updates(self, obj, *, _update_ids=frozenset((
method _handle_pong (line 731) | async def _handle_pong(self, message):
method _handle_bad_server_salt (line 747) | async def _handle_bad_server_salt(self, message):
method _handle_bad_notification (line 763) | async def _handle_bad_notification(self, message):
method _handle_detailed_info (line 799) | async def _handle_detailed_info(self, message):
method _handle_new_detailed_info (line 811) | async def _handle_new_detailed_info(self, message):
method _handle_new_session_created (line 823) | async def _handle_new_session_created(self, message):
method _handle_ack (line 834) | async def _handle_ack(self, message):
method _handle_future_salts (line 858) | async def _handle_future_salts(self, message):
method _handle_state_forgotten (line 873) | async def _handle_state_forgotten(self, message):
method _handle_msg_all (line 882) | async def _handle_msg_all(self, message):
method _handle_destroy_session (line 887) | async def _handle_destroy_session(self, message):
method _handle_destroy_auth_key (line 903) | async def _handle_destroy_auth_key(self, message):
FILE: telethon/network/mtprotostate.py
class _OpaqueRequest (line 27) | class _OpaqueRequest(TLRequest):
method __init__ (line 31) | def __init__(self, data: bytes):
method _bytes (line 34) | def _bytes(self):
class MTProtoState (line 39) | class MTProtoState:
method __init__ (line 62) | def __init__(self, auth_key, loggers):
method reset (line 74) | def reset(self):
method update_message_id (line 86) | def update_message_id(self, message):
method _calc_key (line 94) | def _calc_key(auth_key, msg_key, client):
method write_data_as_message (line 109) | def write_data_as_message(self, buffer, data, content_related,
method encrypt_message_data (line 130) | def encrypt_message_data(self, data):
method decrypt_message_data (line 151) | def decrypt_message_data(self, body):
method _count_ignored (line 232) | def _count_ignored(self):
method _get_new_msg_id (line 239) | def _get_new_msg_id(self):
method update_time_offset (line 254) | def update_time_offset(self, correct_msg_id):
method _get_seq_no (line 275) | def _get_seq_no(self, content_related):
FILE: telethon/network/requeststate.py
class RequestState (line 4) | class RequestState:
method __init__ (line 13) | def __init__(self, request, after=None):
FILE: telethon/password.py
function check_prime_and_good_check (line 8) | def check_prime_and_good_check(prime: int, g: int):
function check_prime_and_good (line 45) | def check_prime_and_good(prime_bytes: bytes, g: int):
function is_good_large (line 71) | def is_good_large(number: int, p: int) -> bool:
function num_bytes_for_hash (line 78) | def num_bytes_for_hash(number: bytes) -> bytes:
function big_num_for_hash (line 82) | def big_num_for_hash(g: int) -> bytes:
function sha256 (line 86) | def sha256(*p: bytes) -> bytes:
function is_good_mod_exp_first (line 93) | def is_good_mod_exp_first(modexp, prime) -> bool:
function xor (line 105) | def xor(a: bytes, b: bytes) -> bytes:
function pbkdf2sha512 (line 109) | def pbkdf2sha512(password: bytes, salt: bytes, iterations: int):
function compute_hash (line 113) | def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512...
function compute_digest (line 121) | def compute_digest(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA5...
function compute_check (line 136) | def compute_check(request: types.account.Password, password: str):
FILE: telethon/requestiter.py
class RequestIter (line 8) | class RequestIter(abc.ABC):
method __init__ (line 29) | def __init__(self, client, limit, *, reverse=False, wait_time=None, **...
method _init (line 41) | async def _init(self, **kwargs):
method __anext__ (line 55) | async def __anext__(self):
method __next__ (line 85) | def __next__(self):
method __aiter__ (line 91) | def __aiter__(self):
method __iter__ (line 98) | def __iter__(self):
method collect (line 107) | async def collect(self):
method _load_next_chunk (line 120) | async def _load_next_chunk(self):
method __reversed__ (line 132) | def __reversed__(self):
FILE: telethon/sessions/abstract.py
class Session (line 4) | class Session(ABC):
method __init__ (line 5) | def __init__(self):
method clone (line 8) | def clone(self, to_instance=None):
method set_dc (line 15) | def set_dc(self, dc_id, server_address, port):
method dc_id (line 25) | def dc_id(self):
method server_address (line 33) | def server_address(self):
method port (line 41) | def port(self):
method auth_key (line 49) | def auth_key(self):
method auth_key (line 58) | def auth_key(self, value):
method takeout_id (line 66) | def takeout_id(self):
method takeout_id (line 75) | def takeout_id(self, value):
method get_update_state (line 82) | def get_update_state(self, entity_id):
method set_update_state (line 92) | def set_update_state(self, entity_id, state):
method get_update_states (line 101) | def get_update_states(self):
method close (line 106) | def close(self):
method save (line 113) | def save(self):
method delete (line 121) | def delete(self):
method list_sessions (line 129) | def list_sessions(cls):
method process_entities (line 136) | def process_entities(self, tlo):
method get_input_entity (line 144) | def get_input_entity(self, key):
method cache_file (line 154) | def cache_file(self, md5_digest, file_size, instance):
method get_file (line 165) | def get_file(self, md5_digest, file_size, cls):
FILE: telethon/sessions/memory.py
class _SentFileType (line 13) | class _SentFileType(Enum):
method from_type (line 18) | def from_type(cls):
class MemorySession (line 27) | class MemorySession(Session):
method __init__ (line 28) | def __init__(self):
method set_dc (line 42) | def set_dc(self, dc_id, server_address, port):
method dc_id (line 48) | def dc_id(self):
method server_address (line 52) | def server_address(self):
method port (line 56) | def port(self):
method auth_key (line 60) | def auth_key(self):
method tmp_auth_key (line 64) | def tmp_auth_key(self):
method auth_key (line 68) | def auth_key(self, value):
method tmp_auth_key (line 72) | def tmp_auth_key(self, value):
method takeout_id (line 76) | def takeout_id(self):
method takeout_id (line 80) | def takeout_id(self, value):
method get_update_state (line 83) | def get_update_state(self, entity_id):
method set_update_state (line 86) | def set_update_state(self, entity_id, state):
method get_update_states (line 89) | def get_update_states(self):
method close (line 92) | def close(self):
method save (line 95) | def save(self):
method delete (line 98) | def delete(self):
method _entity_values_to_row (line 102) | def _entity_values_to_row(id, hash, username, phone, name):
method _entity_to_row (line 108) | def _entity_to_row(self, e):
method _entities_to_rows (line 137) | def _entities_to_rows(self, tlo):
method process_entities (line 159) | def process_entities(self, tlo):
method get_entity_rows_by_phone (line 162) | def get_entity_rows_by_phone(self, phone):
method get_entity_rows_by_username (line 169) | def get_entity_rows_by_username(self, username):
method get_entity_rows_by_name (line 176) | def get_entity_rows_by_name(self, name):
method get_entity_rows_by_id (line 183) | def get_entity_rows_by_id(self, id, exact=True):
method get_input_entity (line 199) | def get_input_entity(self, key):
method cache_file (line 248) | def cache_file(self, md5_digest, file_size, instance):
method get_file (line 255) | def get_file(self, md5_digest, file_size, cls):
FILE: telethon/sessions/sqlite.py
class SQLiteSession (line 24) | class SQLiteSession(MemorySession):
method __init__ (line 33) | def __init__(self, session_id=None, store_tmp_auth_key_on_disk:bool=Fa...
method clone (line 117) | def clone(self, to_instance=None):
method _upgrade_database (line 122) | def _upgrade_database(self, old):
method _create_table (line 166) | def _create_table(c, *definitions):
method set_dc (line 172) | def set_dc(self, dc_id, server_address, port):
method auth_key (line 189) | def auth_key(self, value):
method tmp_auth_key (line 194) | def tmp_auth_key(self, value):
method takeout_id (line 199) | def takeout_id(self, value):
method _update_session_table (line 203) | def _update_session_table(self):
method get_update_state (line 221) | def get_update_state(self, entity_id):
method set_update_state (line 230) | def set_update_state(self, entity_id, state):
method get_update_states (line 235) | def get_update_states(self):
method save (line 249) | def save(self):
method _cursor (line 256) | def _cursor(self):
method _execute (line 263) | def _execute(self, stmt, *values):
method close (line 274) | def close(self):
method delete (line 282) | def delete(self):
method list_sessions (line 293) | def list_sessions(cls):
method process_entities (line 302) | def process_entities(self, tlo):
method get_entity_rows_by_phone (line 323) | def get_entity_rows_by_phone(self, phone):
method get_entity_rows_by_username (line 327) | def get_entity_rows_by_username(self, username):
method get_entity_rows_by_name (line 348) | def get_entity_rows_by_name(self, name):
method get_entity_rows_by_id (line 352) | def get_entity_rows_by_id(self, id, exact=True):
method get_file (line 366) | def get_file(self, md5_digest, file_size, cls):
method cache_file (line 376) | def cache_file(self, md5_digest, file_size, instance):
FILE: telethon/sessions/string.py
class StringSession (line 14) | class StringSession(MemorySession):
method __init__ (line 29) | def __init__(self, string: str = None):
method encode (line 45) | def encode(x: bytes) -> str:
method decode (line 49) | def decode(x: str) -> bytes:
method save (line 52) | def save(self: Session):
FILE: telethon/sync.py
function _syncify_wrap (line 29) | def _syncify_wrap(t, method_name):
function syncify (line 46) | def syncify(*types):
FILE: telethon/tl/core/gzippacked.py
class GzipPacked (line 10) | class GzipPacked(TLObject):
method __init__ (line 13) | def __init__(self, data):
method gzip_if_smaller (line 17) | def gzip_if_smaller(content_related, data):
method __bytes__ (line 30) | def __bytes__(self):
method read (line 35) | def read(reader):
method from_reader (line 41) | def from_reader(cls, reader):
method to_dict (line 44) | def to_dict(self):
FILE: telethon/tl/core/messagecontainer.py
class MessageContainer (line 5) | class MessageContainer(TLObject):
method __init__ (line 23) | def __init__(self, messages):
method to_dict (line 26) | def to_dict(self):
method from_reader (line 36) | def from_reader(cls, reader):
FILE: telethon/tl/core/rpcresult.py
class RpcResult (line 6) | class RpcResult(TLObject):
method __init__ (line 9) | def __init__(self, req_msg_id, body, error):
method from_reader (line 15) | def from_reader(cls, reader):
method to_dict (line 29) | def to_dict(self):
FILE: telethon/tl/core/tlmessage.py
class TLMessage (line 4) | class TLMessage(TLObject):
method __init__ (line 23) | def __init__(self, msg_id, seq_no, obj):
method to_dict (line 28) | def to_dict(self):
FILE: telethon/tl/custom/adminlogevent.py
class AdminLogEvent (line 5) | class AdminLogEvent:
method __init__ (line 26) | def __init__(self, original, entities):
method id (line 33) | def id(self):
method date (line 40) | def date(self):
method user_id (line 47) | def user_id(self):
method action (line 54) | def action(self):
method old (line 61) | def old(self):
method new (line 107) | def new(self):
method changed_about (line 156) | def changed_about(self):
method changed_title (line 166) | def changed_title(self):
method changed_username (line 176) | def changed_username(self):
method changed_photo (line 186) | def changed_photo(self):
method changed_sticker_set (line 196) | def changed_sticker_set(self):
method changed_message (line 206) | def changed_message(self):
method deleted_message (line 217) | def deleted_message(self):
method changed_admin (line 228) | def changed_admin(self):
method changed_restrictions (line 241) | def changed_restrictions(self):
method changed_invites (line 253) | def changed_invites(self):
method changed_location (line 263) | def changed_location(self):
method joined (line 273) | def joined(self):
method joined_invite (line 282) | def joined_invite(self):
method left (line 294) | def left(self):
method changed_hide_history (line 302) | def changed_hide_history(self):
method changed_signatures (line 313) | def changed_signatures(self):
method changed_pin (line 324) | def changed_pin(self):
method changed_default_banned_rights (line 335) | def changed_default_banned_rights(self):
method stopped_poll (line 346) | def stopped_poll(self):
method started_group_call (line 357) | def started_group_call(self):
method discarded_group_call (line 367) | def discarded_group_call(self):
method user_muted (line 377) | def user_muted(self):
method user_unmutted (line 387) | def user_unmutted(self):
method changed_call_settings (line 397) | def changed_call_settings(self):
method changed_history_ttl (line 407) | def changed_history_ttl(self):
method deleted_exported_invite (line 420) | def deleted_exported_invite(self):
method edited_exported_invite (line 430) | def edited_exported_invite(self):
method revoked_exported_invite (line 441) | def revoked_exported_invite(self):
method joined_by_invite (line 451) | def joined_by_invite(self):
method changed_user_volume (line 462) | def changed_user_volume(self):
method __str__ (line 471) | def __str__(self):
method stringify (line 474) | def stringify(self):
FILE: telethon/tl/custom/button.py
class Button (line 5) | class Button:
method __init__ (line 40) | def __init__(self, button, *, resize, single_use, selective,
method _is_inline (line 50) | def _is_inline(button):
method inline (line 66) | def inline(text, data=None):
method switch_inline (line 94) | def switch_inline(text, query='', same_peer=False):
method url (line 112) | def url(text, url=None):
method auth (line 128) | def auth(text, url=None, *, bot=None, write_access=False, fwd_text=None):
method text (line 174) | def text(cls, text, *, resize=None, single_use=None, selective=None,
method request_location (line 222) | def request_location(cls, text, *, resize=None, single_use=None, selec...
method request_phone (line 244) | def request_phone(cls, text, *, resize=None, single_use=None,
method request_poll (line 266) | def request_poll(cls, text, *, force_quiz=False, resize=None, single_u...
method clear (line 295) | def clear(selective=None):
method force_reply (line 306) | def force_reply(single_use=None, selective=None, placeholder=None):
method buy (line 320) | def buy(text):
method game (line 335) | def game(text):
FILE: telethon/tl/custom/chatgetter.py
class ChatGetter (line 7) | class ChatGetter(abc.ABC):
method __init__ (line 13) | def __init__(self, chat_peer=None, *, input_chat=None, chat=None, broa...
method chat (line 21) | def chat(self):
method get_chat (line 35) | async def get_chat(self):
method input_chat (line 56) | def input_chat(self):
method get_input_chat (line 76) | async def get_input_chat(self):
method chat_id (line 96) | def chat_id(self):
method is_private (line 111) | def is_private(self):
method is_group (line 121) | def is_group(self):
method is_channel (line 141) | def is_channel(self):
method _refetch_chat (line 147) | async def _refetch_chat(self):
FILE: telethon/tl/custom/conversation.py
function _checks_cancelled (line 16) | def _checks_cancelled(f):
class Conversation (line 26) | class Conversation(ChatGetter):
method __init__ (line 41) | def __init__(self, client, input_chat,
method send_message (line 82) | async def send_message(self, *args, **kwargs):
method send_file (line 98) | async def send_file(self, *args, **kwargs):
method mark_read (line 114) | def mark_read(self, message=None):
method get_response (line 133) | def get_response(self, message=None, *, timeout=None):
method get_reply (line 162) | def get_reply(self, message=None, *, timeout=None):
method _get_message (line 171) | def _get_message(
method get_edit (line 232) | def get_edit(self, message=None, *, timeout=None):
method wait_read (line 261) | def wait_read(self, message=None, *, timeout=None):
method wait_event (line 280) | async def wait_event(self, event, *, timeout=None):
method _check_custom (line 346) | async def _check_custom(self, built):
method _on_new_message (line 360) | def _on_new_message(self, response):
method _on_edit (line 387) | def _on_edit(self, message):
method _on_read (line 413) | def _on_read(self, event):
method _get_message_id (line 424) | def _get_message_id(self, message):
method _get_result (line 433) | def _get_result(self, future, start_time, timeout, pending, target_id):
method _cancel_all (line 451) | def _cancel_all(self, exception=None):
method __aenter__ (line 468) | async def __aenter__(self):
method cancel (line 499) | def cancel(self):
method cancel_all (line 508) | async def cancel_all(self):
method __aexit__ (line 519) | async def __aexit__(self, exc_type, exc_val, exc_tb):
FILE: telethon/tl/custom/dialog.py
class Dialog (line 6) | class Dialog:
method __init__ (line 72) | def __init__(self, client, dialog, entities, message):
method send_message (line 99) | async def send_message(self, *args, **kwargs):
method delete (line 107) | async def delete(self, revoke=False):
method archive (line 120) | async def archive(self, folder=1):
method to_dict (line 147) | def to_dict(self):
method __str__ (line 157) | def __str__(self):
method stringify (line 160) | def stringify(self):
FILE: telethon/tl/custom/draft.py
class Draft (line 11) | class Draft:
method __init__ (line 27) | def __init__(self, client, entity, draft):
method entity (line 43) | def entity(self):
method input_entity (line 50) | def input_entity(self):
method get_entity (line 63) | async def get_entity(self):
method get_input_entity (line 76) | async def get_input_entity(self):
method text (line 85) | def text(self):
method raw_text (line 93) | def raw_text(self):
method is_empty (line 101) | def is_empty(self):
method set_message (line 107) | async def set_message(
method send (line 155) | async def send(self, clear=True, parse_mode=()):
method delete (line 166) | async def delete(self):
method to_dict (line 172) | def to_dict(self):
method __str__ (line 187) | def __str__(self):
method stringify (line 190) | def stringify(self):
FILE: telethon/tl/custom/file.py
class File (line 8) | class File:
method __init__ (line 18) | def __init__(self, media):
method id (line 22) | def id(self):
method name (line 42) | def name(self):
method ext (line 49) | def ext(self):
method mime_type (line 63) | def mime_type(self):
method width (line 73) | def width(self):
method height (line 84) | def height(self):
method duration (line 95) | def duration(self):
method title (line 103) | def title(self):
method performer (line 110) | def performer(self):
method emoji (line 117) | def emoji(self):
method sticker_set (line 124) | def sticker_set(self):
method size (line 131) | def size(self):
method _from_attr (line 142) | def _from_attr(self, cls, field):
FILE: telethon/tl/custom/forward.py
class Forward (line 7) | class Forward(ChatGetter, SenderGetter):
method __init__ (line 26) | def __init__(self, client, original, entities):
FILE: telethon/tl/custom/inlinebuilder.py
class InlineBuilder (line 21) | class InlineBuilder:
method __init__ (line 70) | def __init__(self, client):
method article (line 74) | async def article(
method photo (line 151) | async def photo(
method document (line 227) | async def document(
method game (line 352) | async def game(
method _message (line 380) | async def _message(
FILE: telethon/tl/custom/inlineresult.py
class InlineResult (line 5) | class InlineResult:
method __init__ (line 32) | def __init__(self, client, original, query_id=None, *, entity=None):
method type (line 39) | def type(self):
method message (line 52) | def message(self):
method title (line 60) | def title(self):
method description (line 67) | def description(self):
method url (line 74) | def url(self):
method photo (line 84) | def photo(self):
method document (line 95) | def document(self):
method click (line 105) | async def click(self, entity=None, reply_to=None, comment_to=None,
method download_media (line 166) | async def download_media(self, *args, **kwargs):
FILE: telethon/tl/custom/inlineresults.py
class InlineResults (line 6) | class InlineResults(list):
method __init__ (line 47) | def __init__(self, client, original, *, entity=None):
method results_valid (line 60) | def results_valid(self):
method _to_str (line 67) | def _to_str(self, item_function):
method __str__ (line 79) | def __str__(self):
method __repr__ (line 82) | def __repr__(self):
FILE: telethon/tl/custom/inputsizedfile.py
class InputSizedFile (line 4) | class InputSizedFile(InputFile):
method __init__ (line 6) | def __init__(self, id_, parts, name, md5, size):
FILE: telethon/tl/custom/message.py
class Message (line 14) | class Message(ChatGetter, SenderGetter, TLObject):
method __init__ (line 175) | def __init__(
method _finish_init (line 312) | def _finish_init(self, client, entities, input_chat):
method client (line 378) | def client(self):
method text (line 389) | def text(self):
method text (line 404) | def text(self, value):
method raw_text (line 412) | def raw_text(self):
method raw_text (line 423) | def raw_text(self, value):
method is_reply (line 429) | def is_reply(self):
method forward (line 441) | def forward(self):
method reply_to_chat (line 449) | def reply_to_chat(self):
method reply_to_sender (line 457) | def reply_to_sender(self):
method buttons (line 465) | def buttons(self):
method get_buttons (line 485) | async def get_buttons(self):
method button_count (line 504) | def button_count(self):
method file (line 519) | def file(self):
method photo (line 538) | def photo(self):
method document (line 557) | def document(self):
method web_preview (line 570) | def web_preview(self):
method audio (line 579) | def audio(self):
method voice (line 587) | def voice(self):
method video (line 595) | def video(self):
method video_note (line 602) | def video_note(self):
method gif (line 610) | def gif(self):
method sticker (line 621) | def sticker(self):
method contact (line 628) | def contact(self):
method game (line 636) | def game(self):
method geo (line 644) | def geo(self):
method invoice (line 654) | def invoice(self):
method poll (line 662) | def poll(self):
method venue (line 670) | def venue(self):
method dice (line 678) | def dice(self):
method action_entities (line 686) | def action_entities(self):
method via_bot (line 702) | def via_bot(self):
method via_input_bot (line 712) | def via_input_bot(self):
method reply_to_msg_id (line 719) | def reply_to_msg_id(self):
method to_id (line 731) | def to_id(self):
method get_entities_text (line 747) | def get_entities_text(self, cls=None):
method get_reply_message (line 787) | async def get_reply_message(self):
method respond (line 815) | async def respond(self, *args, **kwargs):
method reply (line 825) | async def reply(self, *args, **kwargs):
method forward_to (line 836) | async def forward_to(self, *args, **kwargs):
method edit (line 851) | async def edit(self, *args, **kwargs):
method delete (line 897) | async def delete(self, *args, **kwargs):
method download_media (line 915) | async def download_media(self, *args, **kwargs):
method click (line 926) | async def click(self, i=None, j=None,
method mark_read (line 1123) | async def mark_read(self):
method pin (line 1134) | async def pin(self, *, notify=False, pm_oneside=False):
method unpin (line 1147) | async def unpin(self):
method _reload_message (line 1161) | async def _reload_message(self):
method _refetch_sender (line 1186) | async def _refetch_sender(self):
method _set_buttons (line 1189) | def _set_buttons(self, chat, bot):
method _needed_markup_bot (line 1201) | def _needed_markup_bot(self):
method _document_by_attribute (line 1229) | def _document_by_attribute(self, kind, condition=None):
FILE: telethon/tl/custom/messagebutton.py
class MessageButton (line 12) | class MessageButton:
method __init__ (line 30) | def __init__(self, client, original, chat, bot, msg_id):
method client (line 38) | def client(self):
method text (line 46) | def text(self):
method data (line 51) | def data(self):
method inline_query (line 57) | def inline_query(self):
method url (line 63) | def url(self):
method click (line 68) | async def click(self, share_phone=None, share_geo=None, *, password=No...
FILE: telethon/tl/custom/participantpermissions.py
function _admin_prop (line 4) | def _admin_prop(field_name, doc):
class ParticipantPermissions (line 21) | class ParticipantPermissions:
method __init__ (line 38) | def __init__(self, participant, chat: bool):
method is_admin (line 43) | def is_admin(self):
method is_creator (line 54) | def is_creator(self):
method has_default_permissions (line 64) | def has_default_permissions(self):
method is_banned (line 76) | def is_banned(self):
method has_left (line 83) | def has_left(self):
method add_admins (line 90) | def add_admins(self):
FILE: telethon/tl/custom/qrlogin.py
class QRLogin (line 9) | class QRLogin:
method __init__ (line 16) | def __init__(self, client, ignored_ids):
method recreate (line 22) | async def recreate(self):
method token (line 30) | def token(self) -> bytes:
method url (line 41) | def url(self) -> str:
method expires (line 60) | def expires(self) -> datetime.datetime:
method wait (line 68) | async def wait(self, timeout: float = None):
FILE: telethon/tl/custom/sendergetter.py
class SenderGetter (line 6) | class SenderGetter(abc.ABC):
method __init__ (line 12) | def __init__(self, sender_id=None, *, sender=None, input_sender=None):
method sender (line 19) | def sender(self):
method get_sender (line 33) | async def get_sender(self):
method input_sender (line 62) | def input_sender(self):
method get_input_sender (line 80) | async def get_input_sender(self):
method sender_id (line 90) | def sender_id(self):
method _refetch_sender (line 99) | async def _refetch_sender(self):
FILE: telethon/tl/patched/__init__.py
class MessageEmpty (line 4) | class MessageEmpty(_Message, types.MessageEmpty):
class MessageService (line 10) | class MessageService(_Message, types.MessageService):
class Message (line 16) | class Message(_Message, types.Message):
FILE: telethon/tl/tlobject.py
function _datetime_to_timestamp (line 12) | def _datetime_to_timestamp(dt):
function _json_default (line 25) | def _json_default(value):
class TLObject (line 34) | class TLObject:
method pretty_format (line 39) | def pretty_format(obj, indent=None):
method serialize_bytes (line 106) | def serialize_bytes(data):
method serialize_datetime (line 141) | def serialize_datetime(dt):
method __eq__ (line 160) | def __eq__(self, o):
method __ne__ (line 163) | def __ne__(self, o):
method __str__ (line 166) | def __str__(self):
method stringify (line 169) | def stringify(self):
method to_dict (line 172) | def to_dict(self):
method to_json (line 175) | def to_json(self, fp=None, default=_json_default, **kwargs):
method __bytes__ (line 192) | def __bytes__(self):
method _bytes (line 205) | def _bytes(self):
method from_reader (line 209) | def from_reader(cls, reader):
class TLRequest (line 213) | class TLRequest(TLObject):
method read_result (line 218) | def read_result(reader):
method resolve (line 221) | async def resolve(self, client, utils):
FILE: telethon/utils.py
function chunks (line 73) | def chunks(iterable, size=100):
function get_display_name (line 84) | def get_display_name(entity):
function get_extension (line 106) | def get_extension(media):
function _raise_cast_fail (line 132) | def _raise_cast_fail(entity, target):
function get_input_peer (line 137) | def get_input_peer(entity, allow_self=True, check_hash=True):
function get_input_channel (line 233) | def get_input_channel(entity):
function get_input_user (line 261) | def get_input_user(entity):
function get_input_dialog (line 301) | def get_input_dialog(dialog):
function get_input_document (line 319) | def get_input_document(document):
function get_input_photo (line 344) | def get_input_photo(photo):
function get_input_chat_photo (line 382) | def get_input_chat_photo(photo):
function get_input_geo (line 401) | def get_input_geo(geo):
function get_input_media (line 424) | def get_input_media(
function get_input_message (line 560) | def get_input_message(message):
function get_input_group_call (line 575) | def get_input_group_call(call):
function _get_entity_pair (line 586) | def _get_entity_pair(entity_id, entities, cache,
function get_message_id (line 607) | def get_message_id(message):
function _get_metadata (line 628) | def _get_metadata(file):
function get_attributes (line 679) | def get_attributes(file, *, attributes=None, mime_type=None,
function sanitize_parse_mode (line 766) | def sanitize_parse_mode(mode):
function get_input_location (line 799) | def get_input_location(location):
function _get_file_info (line 810) | def _get_file_info(location):
function _get_extension (line 843) | def _get_extension(file):
function is_image (line 860) | def is_image(file):
function is_gif (line 871) | def is_gif(file):
function is_audio (line 878) | def is_audio(file):
function is_video (line 892) | def is_video(file):
function is_list_like (line 906) | def is_list_like(obj):
function parse_phone (line 917) | def parse_phone(phone):
function parse_username (line 927) | def parse_username(username):
function get_inner_text (line 952) | def get_inner_text(text, entities):
function get_peer (line 971) | def get_peer(peer):
function get_peer_id (line 1005) | def get_peer_id(peer, add_mark=True):
function resolve_id (line 1053) | def resolve_id(marked_id):
function _rle_decode (line 1066) | def _rle_decode(data):
function _rle_encode (line 1086) | def _rle_encode(string):
function _decode_telegram_base64 (line 1103) | def _decode_telegram_base64(string):
function _encode_telegram_base64 (line 1119) | def _encode_telegram_base64(string):
function resolve_bot_file_id (line 1129) | def resolve_bot_file_id(file_id):
function pack_bot_file_id (line 1236) | def pack_bot_file_id(file):
function resolve_invite_link (line 1284) | def resolve_invite_link(link):
function resolve_inline_message_id (line 1321) | def resolve_inline_message_id(inline_msg_id):
function get_appropriated_part_size (line 1342) | def get_appropriated_part_size(file_size):
function encode_waveform (line 1354) | def encode_waveform(waveform):
function decode_waveform (line 1395) | def decode_waveform(waveform):
function split_text (line 1420) | def split_text(text, entities, *, limit=4096, max_entities=100, split_at...
class AsyncClassWrapper (line 1515) | class AsyncClassWrapper:
method __init__ (line 1516) | def __init__(self, wrapped):
method __getattr__ (line 1519) | def __getattr__(self, item):
function stripped_photo_to_jpg (line 1531) | def stripped_photo_to_jpg(stripped):
function _photo_size_byte_count (line 1548) | def _photo_size_byte_count(size):
function maybe_async (line 1566) | async def maybe_async(coro):
FILE: telethon_examples/assistant.py
function get_env (line 39) | def get_env(name, message, cast=str):
function main (line 57) | async def main():
FILE: telethon_examples/gui.py
function get_env (line 24) | def get_env(name, message, cast=str):
function sanitize_str (line 42) | def sanitize_str(string):
function callback (line 47) | def callback(func):
function allow_copy (line 61) | def allow_copy(widget):
class App (line 69) | class App(tkinter.Tk):
method __init__ (line 81) | def __init__(self, client, *args, **kwargs):
method post_init (line 137) | async def post_init(self):
method on_message (line 150) | async def on_message(self, event):
method sign_in (line 182) | async def sign_in(self, event=None):
method set_signed_in (line 211) | def set_signed_in(self, me):
method send_message (line 227) | async def send_message(self, event=None):
method check_chat (line 309) | async def check_chat(self, event=None):
function main (line 344) | async def main(interval=0.05):
FILE: telethon_examples/interactive_telegram_client.py
function sprint (line 13) | def sprint(string, *args, **kwargs):
function print_title (line 23) | def print_title(title):
function bytes_to_string (line 31) | def bytes_to_string(byte_count):
function async_input (line 43) | async def async_input(prompt):
function get_env (line 53) | def get_env(name, message, cast=str):
class InteractiveTelegramClient (line 66) | class InteractiveTelegramClient(TelegramClient):
method __init__ (line 75) | def __init__(self, session_user_id, api_id, api_hash,
method init (line 109) | async def init(self):
method run (line 145) | async def run(self):
method send_photo (line 305) | async def send_photo(self, path, entity):
method send_document (line 313) | async def send_document(self, path, entity):
method download_media_by_id (line 322) | async def download_media_by_id(self, media_id):
method download_progress_callback (line 343) | def download_progress_callback(downloaded_bytes, total_bytes):
method upload_progress_callback (line 349) | def upload_progress_callback(uploaded_bytes, total_bytes):
method print_progress (line 355) | def print_progress(progress_type, downloaded_bytes, total_bytes):
method message_handler (line 361) | async def message_handler(self, event):
function main (line 393) | async def main():
FILE: telethon_examples/payment.py
function get_env (line 24) | def get_env(name, message, cast=str):
function payment_pre_checkout_handler (line 47) | async def payment_pre_checkout_handler(event: types.UpdateBotPrecheckout...
function payment_received_handler (line 81) | async def payment_received_handler(event):
function generate_invoice (line 93) | def generate_invoice(price_label: str, price_amount: int, currency: str,...
function start_handler (line 135) | async def start_handler(event: events.NewMessage.Event):
function start_handler (line 140) | async def start_handler(event: events.NewMessage.Event):
function start_handler (line 151) | async def start_handler(event: events.NewMessage.Event):
function start_handler (line 162) | async def start_handler(event: events.NewMessage.Event):
function main (line 172) | async def main():
FILE: telethon_examples/print_messages.py
function get_env (line 10) | def get_env(name, message, cast=str):
function handler (line 36) | async def handler(event):
FILE: telethon_examples/print_updates.py
function get_env (line 14) | def get_env(name, message, cast=str):
function handler (line 34) | async def handler(update):
FILE: telethon_examples/quart_login.py
function get_env (line 10) | def get_env(name, message):
function format_message (line 64) | async def format_message(message):
function startup (line 83) | async def startup():
function cleanup (line 91) | async def cleanup():
function root (line 96) | async def root():
FILE: telethon_examples/replier.py
function get_env (line 22) | def get_env(name, message, cast=str):
function can_react (line 34) | def can_react(chat_id):
function handler (line 53) | async def handler(event):
FILE: telethon_generator/data/html/js/search.js
function find (line 87) | function find(haystack, needle) {
function getSearchArray (line 127) | function getSearchArray(original, originalu, query) {
function buildList (line 144) | function buildList(countSpan, resultList, foundElements) {
function updateSearch (line 159) | function updateSearch(event) {
function getQuery (line 213) | function getQuery(name) {
FILE: telethon_generator/docswriter.py
class DocsWriter (line 5) | class DocsWriter:
method __init__ (line 9) | def __init__(self, filename, type_to_path):
method _rel (line 32) | def _rel(self, path):
method write_head (line 41) | def write_head(self, title, css_path, default_css):
method set_menu_separator (line 69) | def set_menu_separator(self, img):
method add_menu (line 79) | def add_menu(self, name, link=None):
method end_menu (line 100) | def end_menu(self):
method write_title (line 106) | def write_title(self, title, level=1, id=None):
method write_code (line 117) | def write_code(self, tlobject):
method begin_table (line 198) | def begin_table(self, column_count):
method add_row (line 205) | def add_row(self, text, link=None, bold=False, align=None):
method end_table (line 237) | def end_table(self):
method write_text (line 244) | def write_text(self, text):
method write_copy_button (line 248) | def write_copy_button(self, text, text_to_copy):
method add_script (line 255) | def add_script(self, src='', path=None):
method end_body (line 262) | def end_body(self):
method write (line 280) | def write(self, s, *args, **kwargs):
method __enter__ (line 288) | def __enter__(self):
method __exit__ (line 294) | def __exit__(self, exc_type, exc_val, exc_tb):
FILE: telethon_generator/generators/docs.py
function _get_file_name (line 20) | def _get_file_name(tlobject):
function get_import_code (line 29) | def get_import_code(tlobject):
function _get_path_for (line 37) | def _get_path_for(tlobject):
function _get_path_for_type (line 46) | def _get_path_for_type(type_):
function _find_title (line 57) | def _find_title(html_file):
function _build_menu (line 69) | def _build_menu(docs):
function _generate_index (line 90) | def _generate_index(folder, paths,
function _get_description (line 160) | def _get_description(arg):
function _copy_replace (line 201) | def _copy_replace(src, dst, replacements):
function _write_html_pages (line 211) | def _write_html_pages(tlobjects, methods, layer, input_res):
function _copy_resources (line 608) | def _copy_resources(res_dir):
function _create_structure (line 617) | def _create_structure(tlobjects):
function generate_docs (line 646) | def generate_docs(tlobjects, methods_info, layer, input_res):
FILE: telethon_generator/generators/errors.py
function generate_errors (line 1) | def generate_errors(errors, f):
FILE: telethon_generator/generators/tlobject.py
function _write_modules (line 54) | def _write_modules(
function _write_source_code (line 162) | def _write_source_code(tlobject, kind, builder, type_constructors):
function _write_class_init (line 179) | def _write_class_init(tlobject, kind, type_constructors, builder):
function _write_resolve (line 254) | def _write_resolve(tlobject, builder):
function _write_to_dict (line 287) | def _write_to_dict(tlobject, builder):
function _write_to_bytes (line 323) | def _write_to_bytes(tlobject, builder):
function _write_from_reader (line 361) | def _write_from_reader(tlobject, builder):
function _write_read_result (line 371) | def _write_read_result(tlobject, builder):
function _write_arg_to_bytes (line 399) | def _write_arg_to_bytes(builder, arg, tlobject, name=None):
function _write_arg_read_code (line 531) | def _write_arg_read_code(builder, arg, tlobject, name):
function _write_all_tlobjects (line 654) | def _write_all_tlobjects(tlobjects, layer, builder):
function generate_tlobjects (line 684) | def generate_tlobjects(tlobjects, layer, import_depth, output_dir):
function clean_tlobjects (line 709) | def clean_tlobjects(output_dir):
FILE: telethon_generator/parsers/errors.py
function _get_class_name (line 20) | def _get_class_name(error_code):
class Error (line 41) | class Error:
method __init__ (line 42) | def __init__(self, codes, name, description):
function parse_errors (line 64) | def parse_errors(csv_file):
FILE: telethon_generator/parsers/methods.py
class Usability (line 6) | class Usability(enum.Enum):
method key (line 13) | def key(self):
class MethodInfo (line 22) | class MethodInfo:
method __init__ (line 23) | def __init__(self, name, usability, errors, friendly):
function parse_methods (line 39) | def parse_methods(csv_file, friendly_csv_file, errors_dict):
FILE: telethon_generator/parsers/tlobject/parser.py
function _from_line (line 38) | def _from_line(line, is_function, method_info, layer):
function parse_tl (line 82) | def parse_tl(file_path, layer, methods=None, ignored_ids=CORE_TYPES):
function find_layer (line 141) | def find_layer(file_path):
FILE: telethon_generator/parsers/tlobject/tlarg.py
function _fmt_strings (line 4) | def _fmt_strings(*dicts):
class TLArg (line 91) | class TLArg:
method __init__ (line 92) | def __init__(self, name, arg_type, generic_definition):
method type_hint (line 169) | def type_hint(self):
method real_type (line 192) | def real_type(self):
method __str__ (line 212) | def __str__(self):
method __repr__ (line 219) | def __repr__(self):
method orig_name (line 222) | def orig_name(self):
method to_dict (line 225) | def to_dict(self):
method as_example (line 231) | def as_example(self, f, indent=0):
method omit_example (line 254) | def omit_example(self):
FILE: telethon_generator/parsers/tlobject/tlobject.py
class TLObject (line 15) | class TLObject:
method __init__ (line 16) | def __init__(self, fullname, object_id, args, result,
method innermost_result (line 62) | def innermost_result(self):
method sorted_args (line 69) | def sorted_args(self):
method __repr__ (line 77) | def __repr__(self, ignore_id=False):
method infer_id (line 90) | def infer_id(self):
method to_dict (line 106) | def to_dict(self):
method is_good_example (line 118) | def is_good_example(self):
method as_example (line 121) | def as_example(self, f, indent=0):
FILE: telethon_generator/sourcebuilder.py
class SourceBuilder (line 1) | class SourceBuilder:
method __init__ (line 4) | def __init__(self, out_stream, indent_size=4):
method indent (line 13) | def indent(self):
method write (line 19) | def write(self, string, *args, **kwargs):
method writeln (line 34) | def writeln(self, string='', *args, **kwargs):
method end_block (line 48) | def end_block(self):
method __str__ (line 57) | def __str__(self):
method __enter__ (line 61) | def __enter__(self):
method __exit__ (line 64) | def __exit__(self, exc_type, exc_val, exc_tb):
FILE: telethon_generator/syncerrors.py
function main (line 18) | def main():
FILE: telethon_generator/utils.py
function snake_to_camel_case (line 4) | def snake_to_camel_case(name, suffix=None):
FILE: tests/readthedocs/conftest.py
function docs_dir (line 7) | def docs_dir():
FILE: tests/readthedocs/quick_references/test_client_reference.py
function test_all_methods_present (line 6) | def test_all_methods_present(docs_dir):
FILE: tests/telethon/client/test_messages.py
function test_send_message_with_file_forwards_args (line 13) | async def test_send_message_with_file_forwards_args():
class TestMessageMethods (line 47) | class TestMessageMethods:
method test_send_msg_and_file (line 53) | async def test_send_msg_and_file(self, formatting_entities):
FILE: tests/telethon/crypto/test_rsa.py
function server_key_fp (line 10) | def server_key_fp():
function test_encryption_inv_key (line 21) | def test_encryption_inv_key():
function test_encryption_old_key (line 26) | def test_encryption_old_key(server_key_fp):
function test_encryption_allowed_old_key (line 31) | def test_encryption_allowed_old_key(server_key_fp):
function test_encryption_current_key (line 38) | def test_encryption_current_key(server_key_fp):
FILE: tests/telethon/events/test_chataction.py
function get_client (line 6) | def get_client():
function get_user_456 (line 10) | def get_user_456():
function test_get_input_users_no_action_message_no_entities (line 19) | async def test_get_input_users_no_action_message_no_entities():
function test_get_input_users_no_action_message (line 31) | async def test_get_input_users_no_action_message():
function test_get_users_no_action_message_no_entities (line 45) | async def test_get_users_no_action_message_no_entities():
function test_get_users_no_action_message (line 57) | async def test_get_users_no_action_message():
FILE: tests/telethon/extensions/test_html.py
function test_entity_edges (line 8) | def test_entity_edges():
function test_malformed_entities (line 18) | def test_malformed_entities():
function test_trailing_malformed_entities (line 29) | def test_trailing_malformed_entities():
function test_entities_together (line 41) | def test_entities_together():
function test_nested_entities (line 56) | def test_nested_entities():
function test_offset_at_emoji (line 72) | def test_offset_at_emoji():
FILE: tests/telethon/extensions/test_markdown.py
function test_entity_edges (line 8) | def test_entity_edges():
function test_malformed_entities (line 18) | def test_malformed_entities():
function test_trailing_malformed_entities (line 29) | def test_trailing_malformed_entities():
function test_entities_together (line 41) | def test_entities_together():
function test_nested_entities (line 56) | def test_nested_entities():
function test_offset_at_emoji (line 71) | def test_offset_at_emoji():
FILE: tests/telethon/test_helpers.py
function test_strip_text (line 15) | def test_strip_text():
class TestSyncifyAsyncContext (line 41) | class TestSyncifyAsyncContext:
class NoopContextManager (line 42) | class NoopContextManager:
method __init__ (line 43) | def __init__(self, loop=None):
method __aenter__ (line 47) | async def __aenter__(self):
method __aexit__ (line 51) | async def __aexit__(self, exc_type, *args):
method test_sync_acontext (line 58) | def test_sync_acontext(self):
method test_async_acontext (line 68) | async def test_async_acontext(self):
function test_generate_key_data_from_nonce (line 78) | def test_generate_key_data_from_nonce():
FILE: tests/telethon/test_pickle.py
function _assert_equality (line 6) | def _assert_equality(error, unpickled_error):
function test_base_rpcerror_pickle (line 13) | def test_base_rpcerror_pickle():
function test_rpcerror_pickle (line 19) | def test_rpcerror_pickle():
function test_fancy_rpcerror_pickle (line 25) | def test_fancy_rpcerror_pickle():
function test_fancy_rpcerror_capture_pickle (line 31) | def test_fancy_rpcerror_capture_pickle():
FILE: tests/telethon/test_utils.py
function test_game_input_media_memory_error (line 12) | def test_game_input_media_memory_error():
function test_private_get_extension (line 26) | def test_private_get_extension():
function test_rle_encode_trailing_zeros (line 57) | def test_rle_encode_trailing_zeros():
FILE: tests/telethon/tl/test_serialization.py
function test_nested_invalid_serialization (line 6) | def test_nested_invalid_serialization():
Condensed preview — 224 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,918K chars).
[
{
"path": ".coveragerc",
"chars": 82,
"preview": "[run]\nbranch = true\nparallel = true\nsource =\n telethon\n\n[report]\nprecision = 2\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 2710,
"preview": "name: Bug Report\ndescription: Create a report about a bug inside the library.\nbody:\n\n - type: textarea\n id: reproduc"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 470,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Ask questions in StackOverflow\n url: https://stackoverflow.com/q"
},
{
"path": ".github/ISSUE_TEMPLATE/documentation-issue.yml",
"chars": 711,
"preview": "name: Documentation Issue\ndescription: Report a problem with the documentation.\nlabels: [documentation]\nbody:\n\n - type:"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yml",
"chars": 805,
"preview": "name: Feature Request\ndescription: Suggest ideas, changes or other enhancements for the library.\nlabels: [enhancement]\nb"
},
{
"path": ".github/pull_request_template.md",
"chars": 196,
"preview": "<!--\nThanks for the PR! Please keep in mind that v1 is *feature frozen*.\nNew features very likely won't be merged, altho"
},
{
"path": ".github/workflows.disabled/python.yml",
"chars": 654,
"preview": "name: Python Library\n\non: [push, pull_request]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n strategy:\n matrix:\n "
},
{
"path": ".gitignore",
"chars": 360,
"preview": "# Generated code\n/telethon/tl/functions/\n/telethon/tl/types/\n/telethon/tl/alltlobjects.py\n/telethon/errors/rpcerrorlist."
},
{
"path": ".pre-commit-config.yaml",
"chars": 658,
"preview": "- repo: git://github.com/pre-commit/pre-commit-hooks\n sha: 7539d8bd1a00a3c1bfd34cdb606d3a6372e83469\n hooks:\n "
},
{
"path": ".readthedocs.yaml",
"chars": 268,
"preview": "# https://docs.readthedocs.io/en/stable/config-file/v2.html\nversion: 2\n\nbuild:\n os: ubuntu-22.04\n tools:\n python: \""
},
{
"path": "LICENSE",
"chars": 1075,
"preview": "MIT License\n\nCopyright (c) 2016-Present LonamiWebs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "README.rst",
"chars": 2661,
"preview": "Moved to https://codeberg.org/Lonami/Telethon. The GitHub repository may be deleted in the future.\n\n----\n\nTelethon\n====="
},
{
"path": "dev-requirements.txt",
"chars": 33,
"preview": "pytest\npytest-cov\npytest-asyncio\n"
},
{
"path": "optional-requirements.txt",
"chars": 49,
"preview": "cryptg\npython-socks[asyncio]\nhachoir\npillow\nisal\n"
},
{
"path": "pyproject.toml",
"chars": 1166,
"preview": "# https://snarky.ca/what-the-heck-is-pyproject-toml/\n[build-system]\nrequires = [\"setuptools\", \"wheel\"]\nbuild-backend = \""
},
{
"path": "readthedocs/Makefile",
"chars": 605,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "readthedocs/basic/installation.rst",
"chars": 3143,
"preview": ".. _installation:\n\n============\nInstallation\n============\n\nTelethon is a Python library, which means you need to downloa"
},
{
"path": "readthedocs/basic/next-steps.rst",
"chars": 2124,
"preview": "==========\nNext Steps\n==========\n\nThese basic first steps should have gotten you started with the library.\n\nBy now, you "
},
{
"path": "readthedocs/basic/quick-start.rst",
"chars": 4040,
"preview": "===========\nQuick-Start\n===========\n\nLet's see a longer example to learn some of the methods that the library\nhas to off"
},
{
"path": "readthedocs/basic/signing-in.rst",
"chars": 6149,
"preview": ".. _signing-in:\n\n==========\nSigning In\n==========\n\nBefore working with Telegram's API, you need to get your own API ID a"
},
{
"path": "readthedocs/basic/updates.rst",
"chars": 4767,
"preview": "=======\nUpdates\n=======\n\nUpdates are an important topic in a messaging platform like Telegram.\nAfter all, you want to be"
},
{
"path": "readthedocs/concepts/asyncio.rst",
"chars": 11742,
"preview": ".. _mastering-asyncio:\n\n=================\nMastering asyncio\n=================\n\n.. contents::\n\n\nWhat's asyncio?\n========="
},
{
"path": "readthedocs/concepts/botapi-vs-mtproto.rst",
"chars": 10327,
"preview": ".. _botapi:\n\n=======================\nHTTP Bot API vs MTProto\n=======================\n\n\nTelethon is more than just anothe"
},
{
"path": "readthedocs/concepts/chats-vs-channels.rst",
"chars": 5835,
"preview": ".. _chats-channels:\n\n=================\nChats vs Channels\n=================\n\nTelegram's raw API can get very confusing so"
},
{
"path": "readthedocs/concepts/entities.rst",
"chars": 12348,
"preview": ".. _entities:\n\n========\nEntities\n========\n\nThe library widely uses the concept of \"entities\". An entity will refer\nto an"
},
{
"path": "readthedocs/concepts/errors.rst",
"chars": 5325,
"preview": ".. _rpc-errors:\n\n==========\nRPC Errors\n==========\n\nRPC stands for Remote Procedure Call, and when the library raises\na `"
},
{
"path": "readthedocs/concepts/full-api.rst",
"chars": 14935,
"preview": ".. _full-api:\n\n============\nThe Full API\n============\n\n.. important::\n\n While you have access to this, you should alw"
},
{
"path": "readthedocs/concepts/sessions.rst",
"chars": 6549,
"preview": ".. _sessions:\n\n==============\nSession Files\n==============\n\n.. contents::\n\nThey are an important part for the library to"
},
{
"path": "readthedocs/concepts/strings.rst",
"chars": 2779,
"preview": "======================\nString-based Debugging\n======================\n\nDebugging is *really* important. Telegram's API is"
},
{
"path": "readthedocs/concepts/updates.rst",
"chars": 7423,
"preview": "================\nUpdates in Depth\n================\n\nProperties vs. Methods\n======================\n\nThe event shown above"
},
{
"path": "readthedocs/conf.py",
"chars": 6243,
"preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# Telethon documentation build configuration file, created by\n# sphinx-"
},
{
"path": "readthedocs/custom_roles.py",
"chars": 2096,
"preview": "from docutils import nodes, utils\nfrom docutils.parsers.rst.roles import set_classes\n\n\ndef make_link_node(rawtext, app, "
},
{
"path": "readthedocs/developing/coding-style.rst",
"chars": 894,
"preview": "============\nCoding Style\n============\n\n\nBasically, make it **readable**, while keeping the style similar to the\ncode of"
},
{
"path": "readthedocs/developing/philosophy.rst",
"chars": 1104,
"preview": "==========\nPhilosophy\n==========\n\n\nThe intention of the library is to have an existing MTProto library\nexisting with har"
},
{
"path": "readthedocs/developing/project-structure.rst",
"chars": 2218,
"preview": "=================\nProject Structure\n=================\n\n\nMain interface\n==============\n\nThe library itself is under the `"
},
{
"path": "readthedocs/developing/telegram-api-in-other-languages.rst",
"chars": 647,
"preview": "===============================\nTelegram API in Other Languages\n===============================\n\nTelethon was made for *"
},
{
"path": "readthedocs/developing/test-servers.rst",
"chars": 1438,
"preview": "============\nTest Servers\n============\n\n\nTo run Telethon on a test server, use the following code:\n\n.. code-block:: pyth"
},
{
"path": "readthedocs/developing/testing.rst",
"chars": 3861,
"preview": "=====\nTests\n=====\n\nTelethon uses `Pytest <https://pytest.org/>`__, for testing, `Tox\n<https://tox.readthedocs.io/en/late"
},
{
"path": "readthedocs/developing/tips-for-porting-the-project.rst",
"chars": 697,
"preview": "============================\nTips for Porting the Project\n============================\n\n\nIf you're going to use the code"
},
{
"path": "readthedocs/developing/understanding-the-type-language.rst",
"chars": 1413,
"preview": "===============================\nUnderstanding the Type Language\n===============================\n\n\n`Telegram's Type Langu"
},
{
"path": "readthedocs/examples/chats-and-channels.rst",
"chars": 4034,
"preview": "===============================\nWorking with Chats and Channels\n===============================\n\n\n.. note::\n\n These e"
},
{
"path": "readthedocs/examples/users.rst",
"chars": 1587,
"preview": "=====\nUsers\n=====\n\n\n.. note::\n\n These examples assume you have read :ref:`full-api`.\n\n.. contents::\n\n\nRetrieving full"
},
{
"path": "readthedocs/examples/word-of-warning.rst",
"chars": 762,
"preview": "=================\nA Word of Warning\n=================\n\nFull API is **not** how you are intended to use the library. You "
},
{
"path": "readthedocs/examples/working-with-messages.rst",
"chars": 477,
"preview": "=====================\nWorking with messages\n=====================\n\n.. note::\n\n These examples assume you have read :r"
},
{
"path": "readthedocs/index.rst",
"chars": 2938,
"preview": "========================\nTelethon's Documentation\n========================\n\n.. code-block:: python\n\n from telethon.syn"
},
{
"path": "readthedocs/make.bat",
"chars": 776,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-bu"
},
{
"path": "readthedocs/misc/changelog.rst",
"chars": 170914,
"preview": ".. _changelog:\n\n\n===========================\nChangelog (Version History)\n===========================\n\n\nThis page lists a"
},
{
"path": "readthedocs/misc/compatibility-and-convenience.rst",
"chars": 6228,
"preview": ".. _compatibility-and-convenience:\n\n=============================\nCompatibility and Convenience\n========================"
},
{
"path": "readthedocs/modules/client.rst",
"chars": 2328,
"preview": ".. _telethon-client:\n\n==============\nTelegramClient\n==============\n\n.. currentmodule:: telethon.client\n\nThe `TelegramCli"
},
{
"path": "readthedocs/modules/custom.rst",
"chars": 2632,
"preview": "==============\nCustom package\n==============\n\nThe `telethon.tl.custom` package contains custom classes that the library\n"
},
{
"path": "readthedocs/modules/errors.rst",
"chars": 463,
"preview": ".. _telethon-errors:\n\n==========\nAPI Errors\n==========\n\nThese are the base errors that Telegram's API may raise.\n\nSee :r"
},
{
"path": "readthedocs/modules/events.rst",
"chars": 1430,
"preview": ".. _telethon-events:\n\n=============\nUpdate Events\n=============\n\n.. currentmodule:: telethon.events\n\nEvery event (builde"
},
{
"path": "readthedocs/modules/helpers.rst",
"chars": 115,
"preview": "=======\nHelpers\n=======\n\n.. automodule:: telethon.helpers\n :members:\n :undoc-members:\n :show-inheritance:\n"
},
{
"path": "readthedocs/modules/network.rst",
"chars": 757,
"preview": ".. _telethon-network:\n\n================\nConnection Modes\n================\n\nThe only part about network that you should w"
},
{
"path": "readthedocs/modules/sessions.rst",
"chars": 522,
"preview": ".. _telethon-sessions:\n\n========\nSessions\n========\n\nThese are the different built-in session storage that you may subcla"
},
{
"path": "readthedocs/modules/utils.rst",
"chars": 196,
"preview": ".. _telethon-utils:\n\n=========\nUtilities\n=========\n\nThese are the utilities that the library has to offer.\n\n.. automodul"
},
{
"path": "readthedocs/quick-references/client-reference.rst",
"chars": 3158,
"preview": ".. _client-ref:\n\n================\nClient Reference\n================\n\nThis page contains a summary of all the important m"
},
{
"path": "readthedocs/quick-references/events-reference.rst",
"chars": 5187,
"preview": "================\nEvents Reference\n================\n\nHere you will find a quick summary of all the methods\nand properties"
},
{
"path": "readthedocs/quick-references/faq.rst",
"chars": 16986,
"preview": ".. _faq:\n\n===\nFAQ\n===\n\nLet's start the quick references section with some useful tips to keep in\nmind, with the hope tha"
},
{
"path": "readthedocs/quick-references/objects-reference.rst",
"chars": 6896,
"preview": "=================\nObjects Reference\n=================\n\nThis is the quick reference for those objects returned by client "
},
{
"path": "readthedocs/requirements.txt",
"chars": 27,
"preview": "./\nsphinx-rtd-theme~=1.3.0\n"
},
{
"path": "requirements.txt",
"chars": 10,
"preview": "pyaes\nrsa\n"
},
{
"path": "setup.py",
"chars": 8904,
"preview": "#!/usr/bin/env python3\n\"\"\"A setuptools based setup module.\n\nSee:\nhttps://packaging.python.org/en/latest/distributing.htm"
},
{
"path": "telethon/__init__.py",
"chars": 407,
"preview": "from .client.telegramclient import TelegramClient\nfrom .network import connection\nfrom .tl.custom import Button\nfrom .tl"
},
{
"path": "telethon/_updates/__init__.py",
"chars": 170,
"preview": "from .entitycache import EntityCache\nfrom .messagebox import MessageBox, GapError, PrematureEndReason\nfrom .session impo"
},
{
"path": "telethon/_updates/entitycache.py",
"chars": 1738,
"preview": "from .session import EntityType, Entity\n\n\n_sentinel = object()\n\n\nclass EntityCache:\n def __init__(\n self,\n "
},
{
"path": "telethon/_updates/messagebox.py",
"chars": 34420,
"preview": "\"\"\"\nThis module deals with correct handling of updates, including gaps, and knowing when the code\nshould \"get difference"
},
{
"path": "telethon/_updates/session.py",
"chars": 6179,
"preview": "from typing import Optional, Tuple\nfrom enum import IntEnum\nfrom ..tl.types import InputPeerUser, InputPeerChat, InputPe"
},
{
"path": "telethon/client/__init__.py",
"chars": 1200,
"preview": "\"\"\"\nThis package defines clients as subclasses of others, and then a single\n`telethon.client.telegramclient.TelegramClie"
},
{
"path": "telethon/client/account.py",
"chars": 9572,
"preview": "import functools\nimport inspect\nimport typing\n\nfrom .users import _NOT_A_REQUEST\nfrom .. import helpers, utils\nfrom ..tl"
},
{
"path": "telethon/client/auth.py",
"chars": 25668,
"preview": "import getpass\nimport inspect\nimport os\nimport sys\nimport typing\nimport warnings\n\nfrom .. import utils, helpers, errors,"
},
{
"path": "telethon/client/bots.py",
"chars": 2453,
"preview": "import typing\n\nfrom .. import hints\nfrom ..tl import types, functions, custom\n\nif typing.TYPE_CHECKING:\n from .telegr"
},
{
"path": "telethon/client/buttons.py",
"chars": 3339,
"preview": "import typing\n\nfrom .. import utils, hints\nfrom ..tl import types, custom\n\n\nclass ButtonMethods:\n @staticmethod\n d"
},
{
"path": "telethon/client/chats.py",
"chars": 51481,
"preview": "import asyncio\nimport inspect\nimport itertools\nimport string\nimport typing\n\nfrom .. import helpers, utils, hints, errors"
},
{
"path": "telethon/client/dialogs.py",
"chars": 23008,
"preview": "import asyncio\nimport inspect\nimport itertools\nimport typing\n\nfrom .. import helpers, utils, hints, errors\nfrom ..reques"
},
{
"path": "telethon/client/downloads.py",
"chars": 42059,
"preview": "import datetime\nimport io\nimport os\nimport pathlib\nimport typing\nimport inspect\nimport asyncio\n\nfrom ..crypto import AES"
},
{
"path": "telethon/client/messageparse.py",
"chars": 9387,
"preview": "import itertools\nimport re\nimport typing\n\nfrom .. import helpers, utils\nfrom ..tl import types\n\nif typing.TYPE_CHECKING:"
},
{
"path": "telethon/client/messages.py",
"chars": 64970,
"preview": "import inspect\nimport itertools\nimport typing\nimport warnings\n\nfrom .. import helpers, utils, errors, hints\nfrom ..reque"
},
{
"path": "telethon/client/telegrambaseclient.py",
"chars": 40037,
"preview": "import abc\nimport inspect\nimport re\nimport asyncio\nimport collections\nimport logging\nimport platform\nimport time\nimport "
},
{
"path": "telethon/client/telegramclient.py",
"chars": 478,
"preview": "from . import (\n AccountMethods, AuthMethods, DownloadMethods, DialogMethods, ChatMethods,\n BotMethods, MessageMet"
},
{
"path": "telethon/client/updates.py",
"chars": 31996,
"preview": "import asyncio\nimport inspect\nimport itertools\nimport random\nimport sys\nimport time\nimport traceback\nimport typing\nimpor"
},
{
"path": "telethon/client/uploads.py",
"chars": 38530,
"preview": "import hashlib\nimport io\nimport itertools\nimport os\nimport pathlib\nimport re\nimport typing\nfrom io import BytesIO\n\nfrom "
},
{
"path": "telethon/client/users.py",
"chars": 25847,
"preview": "import asyncio\nimport datetime\nimport itertools\nimport time\nimport typing\n\nfrom .. import errors, helpers, utils, hints\n"
},
{
"path": "telethon/crypto/__init__.py",
"chars": 349,
"preview": "\"\"\"\nThis module contains several utilities regarding cryptographic purposes,\nsuch as the AES IGE mode used by Telegram, "
},
{
"path": "telethon/crypto/aes.py",
"chars": 3138,
"preview": "\"\"\"\nAES IGE implementation in Python.\n\nIf available, cryptg will be used instead, otherwise\nif available, libssl will be"
},
{
"path": "telethon/crypto/aesctr.py",
"chars": 1216,
"preview": "\"\"\"\nThis module holds the AESModeCTR wrapper class.\n\"\"\"\nimport pyaes\n\n\nclass AESModeCTR:\n \"\"\"Wrapper around pyaes.AES"
},
{
"path": "telethon/crypto/authkey.py",
"chars": 1887,
"preview": "\"\"\"\nThis module holds the AuthKey class.\n\"\"\"\nimport struct\nfrom hashlib import sha1\n\nfrom ..extensions import BinaryRead"
},
{
"path": "telethon/crypto/cdndecrypter.py",
"chars": 3844,
"preview": "\"\"\"\nThis module holds the CdnDecrypter utility class.\n\"\"\"\nfrom hashlib import sha256\n\nfrom ..tl.functions.upload import "
},
{
"path": "telethon/crypto/factorization.py",
"chars": 1633,
"preview": "\"\"\"\nThis module holds a fast Factorization class.\n\"\"\"\nfrom random import randint\n\n\nclass Factorization:\n \"\"\"\n Simp"
},
{
"path": "telethon/crypto/libssl.py",
"chars": 4528,
"preview": "\"\"\"\nHelper module around the system's libssl library if available for IGE mode.\n\"\"\"\nimport ctypes\nimport ctypes.util\nimp"
},
{
"path": "telethon/crypto/rsa.py",
"chars": 6525,
"preview": "\"\"\"\nThis module holds several utilities regarding RSA and server fingerprints.\n\"\"\"\nimport os\nimport struct\nfrom hashlib "
},
{
"path": "telethon/custom.py",
"chars": 25,
"preview": "from .tl.custom import *\n"
},
{
"path": "telethon/errors/__init__.py",
"chars": 1659,
"preview": "\"\"\"\nThis module holds all the base and automatically generated errors that the\nTelegram API has. See telethon_generator/"
},
{
"path": "telethon/errors/common.py",
"chars": 6485,
"preview": "\"\"\"Errors not related to the Telegram API itself\"\"\"\nimport struct\nimport textwrap\n\nfrom ..tl import TLRequest\n\n\nclass Re"
},
{
"path": "telethon/errors/rpcbaseerrors.py",
"chars": 3470,
"preview": "from ..tl import functions\n\n_NESTS_QUERY = (\n functions.InvokeAfterMsgRequest,\n functions.InvokeAfterMsgsRequest,\n"
},
{
"path": "telethon/events/__init__.py",
"chars": 4275,
"preview": "from .raw import Raw\nfrom .album import Album\nfrom .chataction import ChatAction\nfrom .messagedeleted import MessageDele"
},
{
"path": "telethon/events/album.py",
"chars": 12890,
"preview": "import asyncio\nimport time\nimport weakref\n\nfrom .common import EventBuilder, EventCommon, name_inner_event\nfrom .. impor"
},
{
"path": "telethon/events/callbackquery.py",
"chars": 13651,
"preview": "import re\nimport struct\n\nfrom .common import EventBuilder, EventCommon, name_inner_event\nfrom .. import utils\nfrom ..tl "
},
{
"path": "telethon/events/chataction.py",
"chars": 17966,
"preview": "from .common import EventBuilder, EventCommon, name_inner_event\nfrom .. import utils\nfrom ..tl import types\n\n\n@name_inne"
},
{
"path": "telethon/events/common.py",
"chars": 6315,
"preview": "import abc\nimport asyncio\nimport warnings\n\nfrom .. import utils\nfrom ..tl import TLObject, types\nfrom ..tl.custom.chatge"
},
{
"path": "telethon/events/inlinequery.py",
"chars": 8974,
"preview": "import inspect\nimport re\n\nimport asyncio\n\nfrom .common import EventBuilder, EventCommon, name_inner_event\nfrom .. import"
},
{
"path": "telethon/events/messagedeleted.py",
"chars": 2128,
"preview": "from .common import EventBuilder, EventCommon, name_inner_event\nfrom ..tl import types\n\n\n@name_inner_event\nclass Message"
},
{
"path": "telethon/events/messageedited.py",
"chars": 1886,
"preview": "from .common import name_inner_event\nfrom .newmessage import NewMessage\nfrom ..tl import types\n\n\n@name_inner_event\nclass"
},
{
"path": "telethon/events/messageread.py",
"chars": 5470,
"preview": "from .common import EventBuilder, EventCommon, name_inner_event\nfrom .. import utils\nfrom ..tl import types\n\n\n@name_inne"
},
{
"path": "telethon/events/newmessage.py",
"chars": 9161,
"preview": "import re\n\nfrom .common import EventBuilder, EventCommon, name_inner_event, _into_id_set\nfrom .. import utils\nfrom ..tl "
},
{
"path": "telethon/events/raw.py",
"chars": 1651,
"preview": "from .common import EventBuilder\nfrom .. import utils\n\n\nclass Raw(EventBuilder):\n \"\"\"\n Raw events are not actual e"
},
{
"path": "telethon/events/userupdate.py",
"chars": 10620,
"preview": "import datetime\nimport functools\n\nfrom .common import EventBuilder, EventCommon, name_inner_event\nfrom .. import utils\nf"
},
{
"path": "telethon/extensions/__init__.py",
"chars": 280,
"preview": "\"\"\"\nSeveral extensions Python is missing, such as a proper class to handle a TCP\ncommunication with support for cancelli"
},
{
"path": "telethon/extensions/binaryreader.py",
"chars": 6270,
"preview": "\"\"\"\nThis module contains the BinaryReader utility class.\n\"\"\"\nimport struct\nimport time\nfrom datetime import datetime, ti"
},
{
"path": "telethon/extensions/html.py",
"chars": 7120,
"preview": "\"\"\"\nSimple HTML -> Telegram entity parser.\n\"\"\"\nfrom collections import deque\nfrom html import escape\nfrom html.parser im"
},
{
"path": "telethon/extensions/markdown.py",
"chars": 6910,
"preview": "\"\"\"\nSimple markdown parser which does not support nesting. Intended primarily\nfor use within the library, which attempts"
},
{
"path": "telethon/extensions/messagepacker.py",
"chars": 4075,
"preview": "import asyncio\nimport collections\nimport io\nimport struct\n\nfrom ..tl import TLRequest\nfrom ..tl.core.messagecontainer im"
},
{
"path": "telethon/functions.py",
"chars": 28,
"preview": "from .tl.functions import *\n"
},
{
"path": "telethon/helpers.py",
"chars": 14651,
"preview": "\"\"\"Various helpers not related to the Telegram API itself\"\"\"\nimport asyncio\nimport io\nimport enum\nimport os\nimport struc"
},
{
"path": "telethon/hints.py",
"chars": 1688,
"preview": "import datetime\nimport typing\n\nfrom . import helpers\nfrom .tl import types, custom\n\nPhone = str\nUsername = str\nPeerID = "
},
{
"path": "telethon/network/__init__.py",
"chars": 585,
"preview": "\"\"\"\nThis module contains several classes regarding network, low level connection\nwith Telegram's servers and the protoco"
},
{
"path": "telethon/network/authenticator.py",
"chars": 7869,
"preview": "\"\"\"\nThis module contains several functions that authenticate the client machine\nwith Telegram's servers, effectively cre"
},
{
"path": "telethon/network/connection/__init__.py",
"chars": 423,
"preview": "from .connection import Connection\nfrom .tcpfull import ConnectionTcpFull\nfrom .tcpintermediate import ConnectionTcpInte"
},
{
"path": "telethon/network/connection/connection.py",
"chars": 16161,
"preview": "import abc\nimport asyncio\nimport socket\nimport sys\n\ntry:\n import ssl as ssl_mod\nexcept ImportError:\n ssl_mod = Non"
},
{
"path": "telethon/network/connection/http.py",
"chars": 1220,
"preview": "import asyncio\n\nfrom .connection import Connection, PacketCodec\n\n\nSSL_PORT = 443\n\n\nclass HttpPacketCodec(PacketCodec):\n "
},
{
"path": "telethon/network/connection/tcpabridged.py",
"chars": 961,
"preview": "import struct\n\nfrom .connection import Connection, PacketCodec\n\n\nclass AbridgedPacketCodec(PacketCodec):\n tag = b'\\xe"
},
{
"path": "telethon/network/connection/tcpfull.py",
"chars": 2152,
"preview": "import asyncio\nimport struct\nfrom zlib import crc32\n\nfrom .connection import Connection, PacketCodec\nfrom ...errors impo"
},
{
"path": "telethon/network/connection/tcpintermediate.py",
"chars": 1374,
"preview": "import struct\nimport random\nimport os\n\nfrom .connection import Connection, PacketCodec\n\n\nclass IntermediatePacketCodec(P"
},
{
"path": "telethon/network/connection/tcpmtproxy.py",
"chars": 5755,
"preview": "import asyncio\nimport hashlib\nimport base64\nimport os\n\nfrom .connection import ObfuscatedConnection\nfrom .tcpabridged im"
},
{
"path": "telethon/network/connection/tcpobfuscated.py",
"chars": 2003,
"preview": "import os\n\nfrom .tcpabridged import AbridgedPacketCodec\nfrom .connection import ObfuscatedConnection\n\nfrom ...crypto imp"
},
{
"path": "telethon/network/mtprotoplainsender.py",
"chars": 2019,
"preview": "\"\"\"\nThis module contains the class used to communicate with Telegram's servers\nin plain text, when no authorization key "
},
{
"path": "telethon/network/mtprotosender.py",
"chars": 38797,
"preview": "import asyncio\nimport collections\nimport struct\nimport datetime\nimport time\n\nfrom . import authenticator\nfrom ..extensio"
},
{
"path": "telethon/network/mtprotostate.py",
"chars": 11377,
"preview": "import os\nimport struct\nimport time\nfrom hashlib import sha256\nfrom collections import deque\n\nfrom ..crypto import AES\nf"
},
{
"path": "telethon/network/requeststate.py",
"chars": 644,
"preview": "import asyncio\n\n\nclass RequestState:\n \"\"\"\n This request state holds several information relevant to sent messages,"
},
{
"path": "telethon/password.py",
"chars": 7194,
"preview": "import hashlib\nimport os\n\nfrom .crypto import factorization\nfrom .tl import types\n\n\ndef check_prime_and_good_check(prime"
},
{
"path": "telethon/requestiter.py",
"chars": 4386,
"preview": "import abc\nimport asyncio\nimport time\n\nfrom . import helpers\n\n\nclass RequestIter(abc.ABC):\n \"\"\"\n Helper class to d"
},
{
"path": "telethon/sessions/__init__.py",
"chars": 132,
"preview": "from .abstract import Session\nfrom .memory import MemorySession\nfrom .sqlite import SQLiteSession\nfrom .string import St"
},
{
"path": "telethon/sessions/abstract.py",
"chars": 5091,
"preview": "from abc import ABC, abstractmethod\n\n\nclass Session(ABC):\n def __init__(self):\n pass\n\n def clone(self, to_i"
},
{
"path": "telethon/sessions/memory.py",
"chars": 8531,
"preview": "from enum import Enum\n\nfrom .abstract import Session\nfrom .. import utils\nfrom ..tl import TLObject\nfrom ..tl.types impo"
},
{
"path": "telethon/sessions/sqlite.py",
"chars": 13309,
"preview": "import datetime\nimport os\nimport time\n\nfrom ..tl import types\nfrom .memory import MemorySession, _SentFileType\nfrom .. i"
},
{
"path": "telethon/sessions/string.py",
"chars": 1990,
"preview": "import base64\nimport ipaddress\nimport struct\n\nfrom .abstract import Session\nfrom .memory import MemorySession\nfrom ..cry"
},
{
"path": "telethon/sync.py",
"chars": 2609,
"preview": "\"\"\"\nThis magical module will rewrite all public methods in the public interface\nof the library so they can run the loop "
},
{
"path": "telethon/tl/__init__.py",
"chars": 42,
"preview": "from .tlobject import TLObject, TLRequest\n"
},
{
"path": "telethon/tl/core/__init__.py",
"chars": 1104,
"preview": "\"\"\"\nThis module holds core \"special\" types, which are more convenient ways\nto do stuff in a `telethon.network.mtprotosen"
},
{
"path": "telethon/tl/core/gzippacked.py",
"chars": 1380,
"preview": "try:\n from isal import igzip as gzip\nexcept ImportError:\n import gzip\nimport struct\n\nfrom .. import TLObject\n\n\ncla"
},
{
"path": "telethon/tl/core/messagecontainer.py",
"chars": 1763,
"preview": "from .tlmessage import TLMessage\nfrom ..tlobject import TLObject\n\n\nclass MessageContainer(TLObject):\n CONSTRUCTOR_ID "
},
{
"path": "telethon/tl/core/rpcresult.py",
"chars": 1157,
"preview": "from .gzippacked import GzipPacked\nfrom .. import TLObject\nfrom ..types import RpcError\n\n\nclass RpcResult(TLObject):\n "
},
{
"path": "telethon/tl/core/tlmessage.py",
"chars": 1070,
"preview": "from .. import TLObject\n\n\nclass TLMessage(TLObject):\n \"\"\"\n https://core.telegram.org/mtproto/service_messages#simp"
},
{
"path": "telethon/tl/custom/__init__.py",
"chars": 510,
"preview": "from .adminlogevent import AdminLogEvent\nfrom .draft import Draft\nfrom .dialog import Dialog\nfrom .inputsizedfile import"
},
{
"path": "telethon/tl/custom/adminlogevent.py",
"chars": 16228,
"preview": "from ...tl import types\nfrom ...utils import get_input_peer\n\n\nclass AdminLogEvent:\n \"\"\"\n Represents a more friendl"
},
{
"path": "telethon/tl/custom/button.py",
"chars": 13473,
"preview": "from .. import types\nfrom ... import utils\n\n\nclass Button:\n \"\"\"\n .. note::\n\n This class is used to **define"
},
{
"path": "telethon/tl/custom/chatgetter.py",
"chars": 5276,
"preview": "import abc\n\nfrom ... import errors, utils\nfrom ...tl import types\n\n\nclass ChatGetter(abc.ABC):\n \"\"\"\n Helper base c"
},
{
"path": "telethon/tl/custom/conversation.py",
"chars": 19403,
"preview": "import asyncio\nimport functools\nimport inspect\nimport itertools\nimport time\n\nfrom .chatgetter import ChatGetter\nfrom ..."
},
{
"path": "telethon/tl/custom/dialog.py",
"chars": 5630,
"preview": "from . import Draft\nfrom .. import TLObject, types, functions\nfrom ... import utils\n\n\nclass Dialog:\n \"\"\"\n Custom c"
},
{
"path": "telethon/tl/custom/draft.py",
"chars": 5978,
"preview": "import datetime\n\nfrom .. import TLObject, types\nfrom ..functions.messages import SaveDraftRequest\nfrom ..types import Dr"
},
{
"path": "telethon/tl/custom/file.py",
"chars": 4229,
"preview": "import mimetypes\nimport os\n\nfrom ... import utils\nfrom ...tl import types\n\n\nclass File:\n \"\"\"\n Convenience class ov"
},
{
"path": "telethon/tl/custom/forward.py",
"chars": 2129,
"preview": "from .chatgetter import ChatGetter\nfrom .sendergetter import SenderGetter\nfrom ... import utils, helpers\nfrom ...tl impo"
},
{
"path": "telethon/tl/custom/inlinebuilder.py",
"chars": 16993,
"preview": "import hashlib\n\nfrom .. import functions, types\nfrom ... import utils\n\n_TYPE_TO_MIMES = {\n 'gif': ['image/gif'], # '"
},
{
"path": "telethon/tl/custom/inlineresult.py",
"chars": 6304,
"preview": "from .. import types, functions\nfrom ... import utils\n\n\nclass InlineResult:\n \"\"\"\n Custom class that encapsulates a"
},
{
"path": "telethon/tl/custom/inlineresults.py",
"chars": 2754,
"preview": "import time\n\nfrom .inlineresult import InlineResult\n\n\nclass InlineResults(list):\n \"\"\"\n Custom class that encapsula"
},
{
"path": "telethon/tl/custom/inputsizedfile.py",
"chars": 310,
"preview": "from ..types import InputFile\n\n\nclass InputSizedFile(InputFile):\n \"\"\"InputFile class with two extra parameters: md5 ("
},
{
"path": "telethon/tl/custom/message.py",
"chars": 47080,
"preview": "from typing import Optional, List, TYPE_CHECKING\nfrom datetime import datetime\nfrom .chatgetter import ChatGetter\nfrom ."
},
{
"path": "telethon/tl/custom/messagebutton.py",
"chars": 6275,
"preview": "from .. import types, functions\nfrom ... import password as pwd_mod\nfrom ...errors import BotResponseTimeoutError\ntry:\n "
},
{
"path": "telethon/tl/custom/participantpermissions.py",
"chars": 4131,
"preview": "from .. import types\n\n\ndef _admin_prop(field_name, doc):\n \"\"\"\n Helper method to build properties that return `True"
},
{
"path": "telethon/tl/custom/qrlogin.py",
"chars": 4205,
"preview": "import asyncio\nimport base64\nimport datetime\n\nfrom .. import types, functions\nfrom ... import events\n\n\nclass QRLogin:\n "
},
{
"path": "telethon/tl/custom/sendergetter.py",
"chars": 3854,
"preview": "import abc\n\nfrom ... import utils\n\n\nclass SenderGetter(abc.ABC):\n \"\"\"\n Helper base class that introduces the `send"
},
{
"path": "telethon/tl/patched/__init__.py",
"chars": 552,
"preview": "from .. import types, alltlobjects\nfrom ..custom.message import Message as _Message\n\nclass MessageEmpty(_Message, types."
},
{
"path": "telethon/tl/tlobject.py",
"chars": 7390,
"preview": "import base64\nimport json\nimport struct\nfrom datetime import datetime, date, timedelta, timezone\nimport time\n\n_EPOCH_NAI"
},
{
"path": "telethon/types.py",
"chars": 24,
"preview": "from .tl.types import *\n"
},
{
"path": "telethon/utils.py",
"chars": 55012,
"preview": "\"\"\"\nUtilities for working with the Telegram API itself (such as handy methods\nto convert between an entity like a User, "
},
{
"path": "telethon/version.py",
"chars": 96,
"preview": "# Versions should comply with PEP440.\n# This line is parsed in setup.py:\n__version__ = '1.42.0'\n"
},
{
"path": "telethon_examples/LICENSE",
"chars": 6555,
"preview": "CC0 1.0 Universal\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclus"
},
{
"path": "telethon_examples/README.md",
"chars": 7169,
"preview": "# Examples\n\nThis folder contains several single-file examples using [Telethon].\n\n## Requisites\n\nYou should have the `tel"
},
{
"path": "telethon_examples/assistant.py",
"chars": 1736,
"preview": "\"\"\"\nThis file is only the \"core\" of the bot. It is responsible for loading the\nplugins module and initializing it. You m"
},
{
"path": "telethon_examples/gui.py",
"chars": 13098,
"preview": "import asyncio\nimport collections\nimport functools\nimport inspect\nimport os\nimport re\nimport sys\nimport time\nimport tkin"
},
{
"path": "telethon_examples/interactive_telegram_client.py",
"chars": 16392,
"preview": "import asyncio\nimport os\nimport sys\nimport time\nfrom getpass import getpass\n\nfrom telethon import TelegramClient, events"
},
{
"path": "telethon_examples/payment.py",
"chars": 6399,
"preview": "from telethon import TelegramClient, events, types, functions\n\nimport asyncio\nimport logging\nimport tracemalloc\nimport o"
},
{
"path": "telethon_examples/print_messages.py",
"chars": 1513,
"preview": "#!/usr/bin/env python3\n# A simple script to print some messages.\nimport os\nimport sys\nimport time\n\nfrom telethon import "
},
{
"path": "telethon_examples/print_updates.py",
"chars": 1421,
"preview": "#!/usr/bin/env python3\n# A simple script to print all updates received.\n# Import modules to access environment, sleep, w"
},
{
"path": "telethon_examples/quart_login.py",
"chars": 4326,
"preview": "import base64\nimport os\n\nfrom quart import Quart, render_template_string, request\n\nfrom telethon import TelegramClient, "
},
{
"path": "telethon_examples/replier.py",
"chars": 3119,
"preview": "#!/usr/bin/env python3\n\"\"\"\nA example script to automatically send messages based on certain triggers.\n\nThis script assum"
},
{
"path": "telethon_generator/__init__.py",
"chars": 1,
"preview": "\n"
},
{
"path": "telethon_generator/data/api.tl",
"chars": 259814,
"preview": "boolFalse#bc799737 = Bool;\nboolTrue#997275b5 = Bool;\n\ntrue#3fedd339 = True;\n\nvector#1cb5c415 {t:Type} # [ t ] = Vector t"
},
{
"path": "telethon_generator/data/errors.csv",
"chars": 40226,
"preview": "name,codes,description\n2FA_CONFIRM_WAIT_X,420,The account is 2FA protected so it will be deleted in a week. Otherwise it"
},
{
"path": "telethon_generator/data/friendly.csv",
"chars": 1882,
"preview": "ns,friendly,raw\naccount.AccountMethods,takeout,invokeWithTakeout account.initTakeoutSession account.finishTakeoutSession"
},
{
"path": "telethon_generator/data/html/404.html",
"chars": 1107,
"preview": "<!DOCTYPE html>\n<html><head>\n <title>Oopsie! | Telethon</title>\n\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Con"
},
{
"path": "telethon_generator/data/html/core.html",
"chars": 7730,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <title>Teletho"
},
{
"path": "telethon_generator/data/html/css/docs.dark.css",
"chars": 2812,
"preview": "body {\n font-family: 'Nunito', sans-serif;\n color: #bbb;\n background-color:#000;\n font-size: 16px;\n}\n\na {\n "
},
{
"path": "telethon_generator/data/html/css/docs.h4x0r.css",
"chars": 4022,
"preview": "/* Begin of https://cdn.jsdelivr.net/npm/hack-font@3/build/web/hack.css\n *\n * Hack typeface https://github.com/source-f"
},
{
"path": "telethon_generator/data/html/css/docs.light.css",
"chars": 2777,
"preview": "body {\n font-family: 'Nunito', sans-serif;\n color: #333;\n background-color:#eee;\n font-size: 16px;\n}\n\na {\n "
},
{
"path": "telethon_generator/data/html/js/search.js",
"chars": 7487,
"preview": "root = document.getElementById(\"main_div\");\nroot.innerHTML = `\n<!-- You can append '?q=query' to the URL to default to a"
},
{
"path": "telethon_generator/data/methods.csv",
"chars": 24617,
"preview": "method,usability,errors\naccount.acceptAuthorization,user,\naccount.cancelPasswordEmail,user,\naccount.changePhone,user,PHO"
},
{
"path": "telethon_generator/data/mtproto.tl",
"chars": 5415,
"preview": "// Core types (no need to gen)\n\n//vector#1cb5c415 {t:Type} # [ t ] = Vector t;\n\n///////////////////////////////\n/// Auth"
},
{
"path": "telethon_generator/docswriter.py",
"chars": 9711,
"preview": "import os\nimport re\n\n\nclass DocsWriter:\n \"\"\"\n Utility class used to write the HTML files used on the documentation"
},
{
"path": "telethon_generator/generators/__init__.py",
"chars": 126,
"preview": "from .errors import generate_errors\nfrom .tlobject import generate_tlobjects, clean_tlobjects\nfrom .docs import generate"
},
{
"path": "telethon_generator/generators/docs.py",
"chars": 24850,
"preview": "#!/usr/bin/env python3\nimport functools\nimport os\nimport pathlib\nimport re\nimport shutil\nfrom collections import default"
},
{
"path": "telethon_generator/generators/errors.py",
"chars": 2295,
"preview": "def generate_errors(errors, f):\n # Exact/regex match to create {CODE: ErrorClassName}\n exact_match = []\n regex_"
},
{
"path": "telethon_generator/generators/tlobject.py",
"chars": 26719,
"preview": "import functools\nimport os\nimport re\nimport shutil\nimport struct\nfrom collections import defaultdict\nfrom zlib import cr"
},
{
"path": "telethon_generator/parsers/__init__.py",
"chars": 151,
"preview": "from .errors import Error, parse_errors\nfrom .methods import MethodInfo, Usability, parse_methods\nfrom .tlobject import "
},
{
"path": "telethon_generator/parsers/errors.py",
"chars": 2956,
"preview": "import csv\nimport re\n\nfrom ..utils import snake_to_camel_case\n\n# Core base classes depending on the integer error code\nK"
},
{
"path": "telethon_generator/parsers/methods.py",
"chars": 2100,
"preview": "import csv\nimport enum\nimport warnings\n\n\nclass Usability(enum.Enum):\n UNKNOWN = 0\n USER = 1\n BOT = 2\n BOTH ="
},
{
"path": "telethon_generator/parsers/tlobject/__init__.py",
"chars": 97,
"preview": "from .tlarg import TLArg\nfrom .tlobject import TLObject\nfrom .parser import parse_tl, find_layer\n"
},
{
"path": "telethon_generator/parsers/tlobject/parser.py",
"chars": 4613,
"preview": "import collections\nimport re\n\nfrom .tlarg import TLArg\nfrom .tlobject import TLObject\nfrom ..methods import Usability\n\n\n"
},
{
"path": "telethon_generator/parsers/tlobject/tlarg.py",
"chars": 8590,
"preview": "import re\n\n\ndef _fmt_strings(*dicts):\n for d in dicts:\n for k, v in d.items():\n if v in ('None', 'T"
},
{
"path": "telethon_generator/parsers/tlobject/tlobject.py",
"chars": 5210,
"preview": "import re\nimport struct\nimport zlib\n\nfrom ...utils import snake_to_camel_case\n\n# https://github.com/telegramdesktop/tdes"
}
]
// ... and 24 more files (download for full content)
About this extraction
This page contains the full source code of the LonamiWebs/Telethon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 224 files (1.8 MB), approximately 427.7k tokens, and a symbol index with 1346 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.