mirror of
https://github.com/TeamPGM/pyrogram.git
synced 2024-11-27 16:45:19 +00:00
Various improvements
This commit is contained in:
parent
80d0966691
commit
8c8288412f
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@ -1,2 +1,3 @@
|
||||
github: delivrance
|
||||
custom: https://docs.pyrogram.org/support
|
||||
liberapay: delivrance
|
||||
open_collective: pyrogram
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a bug report affecting the library or the documentation
|
||||
about: Create a bug report affecting the framework or the documentation
|
||||
---
|
||||
|
||||
<!-- WARNING: Ignoring or altering this template could lead to the issue being closed as invalid -->
|
||||
|
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -2,7 +2,7 @@ blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Ask Pyrogram related questions
|
||||
url: https://stackoverflow.com/questions/tagged/pyrogram
|
||||
about: This place is for issues about Pyrogram. If you'd like to ask a question, please do so at StackOverflow.
|
||||
- name: Join the Telegram community
|
||||
about: This place is only for reporting issues about Pyrogram. You can ask questions at StackOverflow.
|
||||
- name: Join the Telegram channel
|
||||
url: https://t.me/pyrogram
|
||||
about: Join the official channel to stay tuned for news and updates.
|
||||
about: Join the official channel and stay tuned for news, updates and announcements.
|
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -7,7 +7,7 @@ labels: "enhancement"
|
||||
<!-- WARNING: Ignoring or altering this template could lead to the issue being closed as invalid -->
|
||||
|
||||
## Checklist
|
||||
- [ ] I believe the idea is awesome and would benefit the library.
|
||||
- [ ] I believe the idea is awesome and would benefit the framework.
|
||||
- [ ] I have searched in the issue tracker for similar requests, including closed ones.
|
||||
|
||||
## Description
|
||||
|
60
README.md
60
README.md
@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/pyrogram/pyrogram">
|
||||
<img src="https://i.imgur.com/BOgY9ai.png" alt="Pyrogram">
|
||||
<img src="https://docs.pyrogram.org/_static/pyrogram.png" alt="Pyrogram" width="128">
|
||||
</a>
|
||||
<br>
|
||||
<b>Telegram MTProto API Framework for Python</b>
|
||||
@ -9,17 +9,19 @@
|
||||
Documentation
|
||||
</a>
|
||||
•
|
||||
<a href="https://github.com/pyrogram/pyrogram/releases">
|
||||
<a href="https://docs.pyrogram.org/releases">
|
||||
Releases
|
||||
</a>
|
||||
•
|
||||
<a href="https://t.me/Pyrogram">
|
||||
Community
|
||||
<a href="https://t.me/pyrogram">
|
||||
News
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Pyrogram
|
||||
|
||||
> Elegant, modern and asynchronous Telegram MTProto API framework in Python for users and bots
|
||||
|
||||
``` python
|
||||
from pyrogram import Client, filters
|
||||
|
||||
@ -28,34 +30,33 @@ app = Client("my_account")
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def hello(client, message):
|
||||
await message.reply_text(f"Hello {message.from_user.mention}")
|
||||
await message.reply("Hello from Pyrogram!")
|
||||
|
||||
|
||||
app.run()
|
||||
```
|
||||
|
||||
**Pyrogram** is a modern, elegant and easy-to-use [Telegram](https://telegram.org/) client library framework written
|
||||
from the ground up in Python and C. It enables you to easily create custom Telegram client applications for both user
|
||||
and bot identities (bot API alternative) via the [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi).
|
||||
**Pyrogram** is a modern, elegant and asynchronous [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi)
|
||||
framework. It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot
|
||||
identity (bot API alternative) using Python.
|
||||
|
||||
### Features
|
||||
### Support
|
||||
|
||||
- **Easy**: You can install Pyrogram with pip and start building your applications right away.
|
||||
- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way.
|
||||
- **Fast**: Crypto parts are boosted up by [TgCrypto](https://github.com/pyrogram/tgcrypto), a high-performance library
|
||||
written in pure C.
|
||||
- **Asynchronous**: Allows both synchronous and asynchronous models to fit all usage needs.
|
||||
- **Documented**: API methods, types and public interfaces are all [well documented](https://docs.pyrogram.org).
|
||||
If you'd like to support Pyrogram, you can consider:
|
||||
|
||||
- [Become a GitHub sponsor](https://github.com/sponsors/delivrance).
|
||||
- [Become a LiberaPay patron](https://liberapay.com/delivrance).
|
||||
- [Become an OpenCollective backer](https://opencollective.com/pyrogram>).
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Ready**: Install Pyrogram with pip and start building your applications right away.
|
||||
- **Easy**: Makes the Telegram API simple and intuitive, while still allowing advanced usages.
|
||||
- **Elegant**: Low-level details are abstracted and re-presented in a more convenient way.
|
||||
- **Fast**: Boosted up by [TgCrypto](https://github.com/pyrogram/tgcrypto), a high-performance crypto library written in pure C.
|
||||
- **Type-hinted**: Types and methods are all type-hinted, enabling excellent editor support.
|
||||
- **Updated**, to make use of the latest Telegram API version and features.
|
||||
- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed.
|
||||
- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code.
|
||||
- **Comprehensive**: Execute any advanced action an official client is able to do, and even more.
|
||||
|
||||
### Requirements
|
||||
|
||||
- Python 3.6 or higher.
|
||||
- A [Telegram API key](https://docs.pyrogram.org/intro/setup#api-keys).
|
||||
- **Async**: Fully asynchronous (also usable synchronously if wanted, for convenience).
|
||||
- **Powerful**: Full access to Telegram's API to execute any official client action and more.
|
||||
|
||||
### Installing
|
||||
|
||||
@ -65,11 +66,6 @@ pip3 install pyrogram
|
||||
|
||||
### Resources
|
||||
|
||||
- The docs contain lots of resources to help you get started with Pyrogram: https://docs.pyrogram.org.
|
||||
- Seeking extra help? Come join and ask our community: https://t.me/pyrogram.
|
||||
- For other kind of inquiries, you can send a [message](https://t.me/haskell) or an [e-mail](mailto:dan@pyrogram.org).
|
||||
|
||||
### Copyright & License
|
||||
|
||||
- Copyright (C) 2017-2021 Dan <<https://github.com/delivrance>>
|
||||
- Licensed under the terms of the [GNU Lesser General Public License v3 or later (LGPLv3+)](COPYING.lesser)
|
||||
- Check out the docs at https://docs.pyrogram.org to learn more about Pyrogram, get started right
|
||||
away and discover more in-depth material for building your client applications.
|
||||
- Join the official channel at https://t.me/pyrogram and stay tuned for news, updates and announcements.
|
||||
|
@ -158,6 +158,7 @@ def pyrogram_api():
|
||||
send_venue
|
||||
send_contact
|
||||
send_cached_media
|
||||
send_reaction
|
||||
edit_message_text
|
||||
edit_message_caption
|
||||
edit_message_media
|
||||
@ -180,7 +181,9 @@ def pyrogram_api():
|
||||
retract_vote
|
||||
send_dice
|
||||
search_messages
|
||||
search_messages_count
|
||||
search_global
|
||||
search_global_count
|
||||
download_media
|
||||
get_discussion_message
|
||||
""",
|
||||
@ -284,6 +287,7 @@ def pyrogram_api():
|
||||
send_game
|
||||
set_game_score
|
||||
get_game_high_scores
|
||||
set_bot_commands
|
||||
""",
|
||||
authorization="""
|
||||
Authorization
|
||||
@ -360,6 +364,7 @@ def pyrogram_api():
|
||||
ChatEvent
|
||||
ChatEventFilter
|
||||
ChatMemberUpdated
|
||||
ChatJoinRequest
|
||||
Dialog
|
||||
Restriction
|
||||
""",
|
||||
@ -384,6 +389,7 @@ def pyrogram_api():
|
||||
Poll
|
||||
PollOption
|
||||
Dice
|
||||
Reaction
|
||||
VoiceChatScheduled
|
||||
VoiceChatStarted
|
||||
VoiceChatEnded
|
||||
@ -420,6 +426,8 @@ def pyrogram_api():
|
||||
InlineQueryResultArticle
|
||||
InlineQueryResultPhoto
|
||||
InlineQueryResultAnimation
|
||||
InlineQueryResultAudio
|
||||
InlineQueryResultVideo
|
||||
ChosenInlineResult
|
||||
""",
|
||||
input_message_content="""
|
||||
|
7
compiler/docs/template/bound-methods.rst
vendored
7
compiler/docs/template/bound-methods.rst
vendored
@ -1,12 +1,11 @@
|
||||
Bound Methods
|
||||
=============
|
||||
|
||||
Some Pyrogram types define what are called bound methods. Bound methods are functions attached to a class which are
|
||||
accessed via an instance of that class. They make it even easier to call specific methods by automatically inferring
|
||||
Some Pyrogram types define what are called bound methods. Bound methods are functions attached to a type which are
|
||||
accessed via an instance of that type. They make it even easier to call specific methods by automatically inferring
|
||||
some of the required arguments.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 8
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
@ -15,7 +14,7 @@ some of the required arguments.
|
||||
|
||||
@app.on_message()
|
||||
def hello(client, message)
|
||||
message.reply_text("hi")
|
||||
message.reply("hi")
|
||||
|
||||
|
||||
app.run()
|
||||
|
7
compiler/docs/template/methods.rst
vendored
7
compiler/docs/template/methods.rst
vendored
@ -1,18 +1,17 @@
|
||||
Available Methods
|
||||
=================
|
||||
|
||||
This page is about Pyrogram methods. All the methods listed here are bound to a :class:`~pyrogram.Client` instance,
|
||||
except for :meth:`~pyrogram.idle()`, which is a special function that can be found in the main package directly.
|
||||
This page is about Pyrogram methods. All the methods listed here are bound to a :class:`~pyrogram.Client` instance.
|
||||
Some other utility functions can instead be found in the main package directly.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 6
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
app.send_message("haskell", "hi")
|
||||
app.send_message("me", "hi")
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
|
1
compiler/docs/template/types.rst
vendored
1
compiler/docs/template/types.rst
vendored
@ -6,7 +6,6 @@ Unless required as argument to a client method, most of the types don't need to
|
||||
are only returned by other methods. You also don't need to import them, unless you want to type-hint your variables.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 1
|
||||
|
||||
from pyrogram.types import User, Message, ...
|
||||
|
||||
|
@ -62,6 +62,7 @@ CHAT_NOT_MODIFIED The chat settings (title, permissions, photo, etc..) were not
|
||||
CHAT_RESTRICTED The chat is restricted and cannot be used
|
||||
CHAT_SEND_INLINE_FORBIDDEN You cannot use inline bots to send messages in this chat
|
||||
CHAT_TITLE_EMPTY The chat title is empty
|
||||
CHAT_TOO_BIG The chat is too big for this action
|
||||
CODE_EMPTY The provided code is empty
|
||||
CODE_HASH_INVALID The provided code hash invalid
|
||||
CODE_INVALID The provided code is invalid (i.e. from email)
|
||||
@ -347,4 +348,4 @@ WEBDOCUMENT_URL_EMPTY The web document URL is empty
|
||||
WEBDOCUMENT_URL_INVALID The web document URL is invalid
|
||||
WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL
|
||||
WEBPAGE_MEDIA_EMPTY The URL doesn't contain any valid media
|
||||
YOU_BLOCKED_USER You blocked this user
|
||||
YOU_BLOCKED_USER You blocked this user
|
|
@ -2,7 +2,7 @@ id message
|
||||
ACTIVE_USER_REQUIRED The method is only available to already activated users
|
||||
AUTH_KEY_INVALID The key is invalid
|
||||
AUTH_KEY_PERM_EMPTY The method is unavailable for temporary authorization key, not bound to permanent
|
||||
AUTH_KEY_UNREGISTERED The key is not registered in the system
|
||||
AUTH_KEY_UNREGISTERED The key is not registered in the system. Delete your session file and login again
|
||||
SESSION_EXPIRED The authorization has expired
|
||||
SESSION_PASSWORD_NEEDED The two-step verification is enabled and a password is required
|
||||
SESSION_REVOKED The authorization has been invalidated, because of the user terminating all sessions
|
||||
|
|
@ -1,8 +0,0 @@
|
||||
# Pyrogram Docs
|
||||
|
||||
- Install requirements.
|
||||
- Install `pandoc` and `latexmk`.
|
||||
- HTML: `make html`
|
||||
- PDF: `make latexpdf`
|
||||
|
||||
TODO: Explain better
|
@ -1,6 +1,6 @@
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
||||
sphinx_rtd_theme==1.0.0
|
||||
sphinx_copybutton
|
||||
pypandoc
|
||||
requests
|
||||
sphinx-autobuild
|
||||
sphinx-autobuild
|
||||
|
@ -1,7 +0,0 @@
|
||||
User-agent: *
|
||||
|
||||
Allow: /
|
||||
|
||||
Disallow: /old*
|
||||
|
||||
Sitemap: https://docs.pyrogram.org/sitemap.xml
|
@ -1,84 +0,0 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2021 Dan <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import pypandoc
|
||||
import requests
|
||||
|
||||
URL = "https://api.github.com/repos/pyrogram/pyrogram/releases"
|
||||
DEST = Path("../source/releases")
|
||||
INTRO = """
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
Release notes for Pyrogram releases will describe what's new in each version, and will also make you aware of any
|
||||
backwards-incompatible changes made in that version.
|
||||
|
||||
When upgrading to a new version of Pyrogram, you will need to check all the breaking changes in order to find
|
||||
incompatible code in your application, but also to take advantage of new features and improvements.
|
||||
|
||||
**Contents**
|
||||
|
||||
""".lstrip("\n")
|
||||
|
||||
shutil.rmtree(DEST, ignore_errors=True)
|
||||
DEST.mkdir(parents=True)
|
||||
|
||||
releases = requests.get(URL).json()
|
||||
|
||||
with open(DEST / "index.rst", "w") as index:
|
||||
index.write(INTRO)
|
||||
|
||||
tags = []
|
||||
|
||||
for release in releases:
|
||||
tag = release["tag_name"]
|
||||
title = release["name"]
|
||||
name = title.split(" - ")[1]
|
||||
|
||||
date = datetime.strptime(
|
||||
release["published_at"],
|
||||
"%Y-%m-%dT%H:%M:%SZ"
|
||||
).strftime("%b %d, %Y")
|
||||
|
||||
body = pypandoc.convert_text(
|
||||
release["body"].replace(r"\r\n", "\n"),
|
||||
"rst",
|
||||
format="markdown_github",
|
||||
extra_args=["--wrap=none"]
|
||||
)
|
||||
|
||||
tarball_url = release["tarball_url"]
|
||||
zipball_url = release["zipball_url"]
|
||||
|
||||
index.write("- :doc:`{} <{}>`\n".format(title, tag))
|
||||
tags.append(tag)
|
||||
|
||||
with open(DEST / "{}.rst".format(tag), "w") as page:
|
||||
page.write("Pyrogram " + tag + "\n" + "=" * (len(tag) + 9) + "\n\n")
|
||||
page.write("\t\tReleased on " + str(date) + "\n\n")
|
||||
page.write("- :download:`Source Code (zip) <{}>`\n".format(zipball_url))
|
||||
page.write("- :download:`Source Code (tar.gz) <{}>`\n\n".format(tarball_url))
|
||||
page.write(name + "\n" + "-" * len(name) + "\n\n")
|
||||
page.write(body + "\n\n")
|
||||
|
||||
index.write("\n.. toctree::\n :hidden:\n\n")
|
||||
index.write("\n".join(" {}".format(tag) for tag in tags))
|
@ -1,81 +0,0 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2021 Dan <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
canonical = "https://docs.pyrogram.org/"
|
||||
|
||||
dirs = {
|
||||
".": ("weekly", 1.0),
|
||||
"intro": ("weekly", 0.9),
|
||||
"start": ("weekly", 0.9),
|
||||
"api": ("weekly", 0.8),
|
||||
"topics": ("weekly", 0.8),
|
||||
"releases": ("weekly", 0.8),
|
||||
"telegram": ("weekly", 0.6)
|
||||
}
|
||||
|
||||
|
||||
def now():
|
||||
return datetime.datetime.today().strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
with open("sitemap.xml", "w") as f:
|
||||
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
|
||||
f.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n')
|
||||
|
||||
urls = []
|
||||
|
||||
|
||||
def search(path):
|
||||
try:
|
||||
for j in os.listdir(path):
|
||||
search(f"{path}/{j}")
|
||||
except NotADirectoryError:
|
||||
if not path.endswith(".rst"):
|
||||
return
|
||||
|
||||
path = path.split("/")[2:]
|
||||
|
||||
if path[0].endswith(".rst"):
|
||||
folder = "."
|
||||
else:
|
||||
folder = path[0]
|
||||
|
||||
path = f"{canonical}{'/'.join(path)}"[:-len(".rst")]
|
||||
|
||||
if path.endswith("index"):
|
||||
path = path[:-len("index")]
|
||||
|
||||
urls.append((path, now(), *dirs[folder]))
|
||||
|
||||
|
||||
search("../source")
|
||||
|
||||
urls.sort(key=lambda x: x[3], reverse=True)
|
||||
|
||||
for i in urls:
|
||||
f.write(f" <url>\n")
|
||||
f.write(f" <loc>{i[0]}</loc>\n")
|
||||
f.write(f" <lastmod>{i[1]}</lastmod>\n")
|
||||
f.write(f" <changefreq>{i[2]}</changefreq>\n")
|
||||
f.write(f" <priority>{i[3]}</priority>\n")
|
||||
f.write(f" </url>\n")
|
||||
|
||||
f.write("</urlset>")
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@ -8,7 +8,6 @@ found starting from this page.
|
||||
This page is about the Client class, which exposes high-level methods for an easy access to the API.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 1-3
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
|
@ -1,16 +1,12 @@
|
||||
Decorators
|
||||
==========
|
||||
|
||||
While still being methods bound to the :class:`~pyrogram.Client` class, decorators are of a special kind and thus
|
||||
deserve a dedicated page.
|
||||
|
||||
Decorators are able to register callback functions for handling updates in a much easier and cleaner way compared to
|
||||
:doc:`Handlers <handlers>`; they do so by instantiating the correct handler and calling
|
||||
:meth:`~pyrogram.Client.add_handler` automatically. All you need to do is adding the decorators on top of your
|
||||
functions.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 6
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
|
@ -5,7 +5,6 @@ Handlers are used to instruct Pyrogram about which kind of updates you'd like to
|
||||
For a much more convenient way of registering callback functions have a look at :doc:`Decorators <decorators>` instead.
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 2, 11
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.handlers import MessageHandler
|
||||
|
@ -29,35 +29,37 @@ from pygments.styles.friendly import FriendlyStyle
|
||||
FriendlyStyle.background_color = "#f3f2f1"
|
||||
|
||||
project = "Pyrogram"
|
||||
copyright = f"2017-{datetime.now().year}, Dan"
|
||||
copyright = f"2017-present, Dan"
|
||||
author = "Dan"
|
||||
|
||||
version = ".".join(__version__.split(".")[:-1])
|
||||
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.napoleon",
|
||||
"sphinx.ext.autosummary",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_tabs.tabs"
|
||||
"sphinx_copybutton"
|
||||
]
|
||||
|
||||
master_doc = "index"
|
||||
source_suffix = ".rst"
|
||||
autodoc_member_order = "bysource"
|
||||
|
||||
version = __version__
|
||||
release = version
|
||||
|
||||
templates_path = ["_templates"]
|
||||
templates_path = ["_resources/templates"]
|
||||
html_copy_source = False
|
||||
|
||||
napoleon_use_rtype = False
|
||||
napoleon_use_param = False
|
||||
|
||||
pygments_style = "friendly"
|
||||
|
||||
copybutton_prompt_text = "$ "
|
||||
|
||||
suppress_warnings = ["image.not_readable"]
|
||||
|
||||
html_title = "Pyrogram Documentation"
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_static_path = ["_static"]
|
||||
html_static_path = ["_resources/static"]
|
||||
html_show_sourcelink = True
|
||||
html_show_copyright = False
|
||||
html_theme_options = {
|
||||
@ -65,17 +67,15 @@ html_theme_options = {
|
||||
"collapse_navigation": True,
|
||||
"sticky_navigation": False,
|
||||
"logo_only": True,
|
||||
"display_version": True,
|
||||
"display_version": False,
|
||||
"style_external_links": True
|
||||
}
|
||||
|
||||
napoleon_use_param = False
|
||||
|
||||
html_logo = "_images/pyrogram.png"
|
||||
html_favicon = "_images/favicon.ico"
|
||||
html_logo = "_resources/static/img/pyrogram.png"
|
||||
html_favicon = "_resources/static/img/favicon.ico"
|
||||
|
||||
latex_engine = "xelatex"
|
||||
latex_logo = "_images/pyrogram.png"
|
||||
latex_logo = "_resources/static/img/pyrogram.png"
|
||||
|
||||
latex_elements = {
|
||||
"pointsize": "12pt",
|
||||
|
@ -1,407 +0,0 @@
|
||||
Pyrogram FAQ
|
||||
============
|
||||
|
||||
.. role:: strike
|
||||
:class: strike
|
||||
|
||||
This FAQ page provides answers to common questions about Pyrogram and, to some extent, Telegram in general.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you think something interesting could be added here, feel free to propose it by opening a `Feature Request`_.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
What is Pyrogram?
|
||||
-----------------
|
||||
|
||||
**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and
|
||||
C. It enables you to easily create custom applications for both user and bot identities (bot API alternative) via the
|
||||
:doc:`MTProto API <topics/mtproto-vs-botapi>` with the Python programming language.
|
||||
|
||||
.. _Telegram: https://telegram.org
|
||||
|
||||
Where does the name come from?
|
||||
------------------------------
|
||||
|
||||
The name "Pyrogram" is composed by **pyro**, which comes from the Greek word *πῦρ (pyr)*, meaning fire, and **gram**,
|
||||
from *Telegram*. The word *pyro* itself is built from *Python*, **py** for short, and the suffix **ro** to come up with
|
||||
the word *fire*, which also inspired the project logo.
|
||||
|
||||
How old is Pyrogram?
|
||||
--------------------
|
||||
|
||||
Pyrogram was first released on December 12, 2017. The actual work on the framework began roughly three months prior to the
|
||||
initial public release on `GitHub`_.
|
||||
|
||||
.. _GitHub: https://github.com/pyrogram/pyrogram
|
||||
|
||||
Why Pyrogram?
|
||||
-------------
|
||||
|
||||
- **Easy**: You can install Pyrogram with pip and start building your applications right away.
|
||||
- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way.
|
||||
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
||||
- **Asynchronous**: Allows both synchronous and asynchronous models to fit all usage needs.
|
||||
- **Documented**: API methods, types and public interfaces are all well documented.
|
||||
- **Type-hinted**: Types and methods are all type-hinted, enabling excellent editor support.
|
||||
- **Updated**, to make use of the latest Telegram API version and features.
|
||||
- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed.
|
||||
- **Pluggable**: The :doc:`Smart Plugin <topics/smart-plugins>` system allows to write components with minimal
|
||||
boilerplate code.
|
||||
- **Comprehensive**: Execute any :doc:`advanced action <topics/advanced-usage>` an official client is able to do, and
|
||||
even more.
|
||||
|
||||
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
|
||||
|
||||
Why is Pyrogram defined as both Client Library and Framework?
|
||||
-------------------------------------------------------------
|
||||
|
||||
Simply because it falls in both categories, depending on how you use it.
|
||||
|
||||
Pyrogram as a client library makes it easy and intuitive accessing the Telegram API by offering idiomatic Python code
|
||||
that is generated or hand-written. Low-level details and client-server communication protocols are handled under the
|
||||
hood. Pyrogram acts as a client library when *you call* its methods and use its types in a batch application that
|
||||
executes a set of instructions.
|
||||
|
||||
Pyrogram as a framework makes it easy to handle live events by allowing you to register event handlers that will be
|
||||
executed as soon as they arrive from the server side. Pyrogram acts as a framework when it's Pyrogram itself that
|
||||
*calls your code*, that is, your registered event handlers. Such applications are usually started and left online
|
||||
indefinitely, until you decide to stop them.
|
||||
|
||||
What can MTProto do more than the Bot API?
|
||||
------------------------------------------
|
||||
|
||||
For a detailed answer, please refer to the :doc:`MTProto vs. Bot API <topics/mtproto-vs-botapi>` page.
|
||||
|
||||
Why do I need an API key for bots?
|
||||
----------------------------------
|
||||
|
||||
Requests against the official bot API endpoint are made via JSON/HTTP, but are handled by an intermediate server
|
||||
application that implements the MTProto protocol -- just like Pyrogram -- and uses its own API key, which is always
|
||||
required, but hidden to the public.
|
||||
|
||||
.. figure:: https://i.imgur.com/WvwBoZo.png
|
||||
:align: center
|
||||
|
||||
Using MTProto is the only way to communicate with the actual Telegram servers, and the main API requires developers to
|
||||
identify applications by means of a unique key; the bot token identifies a bot as a user and replaces the user's phone
|
||||
number only.
|
||||
|
||||
Can I use Webhooks?
|
||||
-------------------
|
||||
|
||||
Lots of people ask this question because they are used to the bot API, but things are different in Pyrogram!
|
||||
|
||||
There is no webhook in Pyrogram, simply because there is no HTTP involved, by default. However, a similar technique is
|
||||
being used to make receiving updates efficient.
|
||||
|
||||
Pyrogram uses persistent connections via TCP sockets to interact with the server and instead of actively asking for
|
||||
updates every time (polling), Pyrogram will simply sit down and wait for the server to send updates by itself
|
||||
the very moment they are available (server push).
|
||||
|
||||
Can I use the same file_id across different accounts?
|
||||
-----------------------------------------------------
|
||||
|
||||
No, Telegram doesn't allow this.
|
||||
|
||||
File ids are personal and bound to a specific account; an attempt in using a foreign file id will result in errors such
|
||||
as ``[400 MEDIA_EMPTY]``.
|
||||
|
||||
The only exception are stickers' file ids; you can use them across different accounts without any problem, like this
|
||||
one: ``CAADBAADyg4AAvLQYAEYD4F7vcZ43AI``.
|
||||
|
||||
Can I use Bot API's file_id values in Pyrogram?
|
||||
-----------------------------------------------
|
||||
|
||||
Yes! All file ids you take or might have taken from the Bot API are 100% compatible and re-usable in Pyrogram.
|
||||
The opposite is also valid, you can take any file id generated by Pyrogram and re-use in the Bot API.
|
||||
|
||||
Can I use multiple clients at once on the same account?
|
||||
-------------------------------------------------------
|
||||
|
||||
Yes, you can. Both user and bot accounts are able to run multiple sessions in parallel (up to 10 per account). However,
|
||||
you must pay attention and not use the *same* exact session in more than one client at the same time. In other words:
|
||||
|
||||
- Avoid copying your session file: even if you rename the file, the copied sessions will still point to a specific one
|
||||
stored in the server.
|
||||
|
||||
- Make sure that only one instance of your script runs, using your session file.
|
||||
|
||||
If you -- even accidentally -- fail to do so, all the previous session copies will immediately stop receiving updates
|
||||
and eventually the server will start throwing the error ``[406 AUTH_KEY_DUPLICATED]``, inviting you to login again.
|
||||
|
||||
Why is that so? Because the server has recognized two identical sessions are running in two different locations, and
|
||||
concludes it could possibly be due to a cloned/stolen device. Having the session terminated in such occasions will
|
||||
protect the user's privacy.
|
||||
|
||||
So, the only correct way to run multiple clients on the same account is authorizing your account (either user or bot)
|
||||
from the beginning every time, and use one separate session for each parallel client you are going to use.
|
||||
|
||||
I started a client and nothing happens!
|
||||
---------------------------------------
|
||||
|
||||
If you are connecting from Russia, China or Iran :doc:`you need a proxy <topics/proxy>`, because Telegram could be
|
||||
partially or totally blocked in those countries. More information about this block can be found at
|
||||
`Wikipedia <https://en.wikipedia.org/wiki/Blocking_Telegram_in_Russia>`_.
|
||||
|
||||
Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on
|
||||
the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable network
|
||||
in a bunch of seconds:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
Another way to confirm you aren't able to connect to Telegram is by pinging the IP addresses below and see whether ping
|
||||
fails or not.
|
||||
|
||||
What are the IP addresses of Telegram Data Centers?
|
||||
---------------------------------------------------
|
||||
|
||||
The Telegram cloud is currently composed by a decentralized, multi-DC infrastructure (currently 5 DCs, each of which can
|
||||
work independently) spread in different locations worldwide. However, some of the less busy DCs have been lately
|
||||
dismissed and their IP addresses are now kept as aliases to the nearest one.
|
||||
|
||||
.. csv-table:: Production Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.53``, ``2001:b28:f23d:f001::a``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.51``, ``2001:67c:4e8:f002::a``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.100``, ``2001:b28:f23d:f003::a``
|
||||
DC4, "AMS, Amsterdam, NL", ``149.154.167.91``, ``2001:67c:4e8:f004::a``
|
||||
DC5, "SIN, Singapore, SG", ``91.108.56.130``, ``2001:b28:f23f:f005::a``
|
||||
|
||||
.. csv-table:: Test Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.10``, ``2001:b28:f23d:f001::e``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.40``, ``2001:67c:4e8:f002::e``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.117``, ``2001:b28:f23d:f003::e``
|
||||
|
||||
.. centered:: More info about the Test Environment can be found :doc:`here <topics/test-servers>`.
|
||||
|
||||
***** Alias DC
|
||||
|
||||
Thanks to `@FrayxRulez <https://t.me/tgbetachat/104921>`_ for telling about alias DCs.
|
||||
|
||||
I want to migrate my account from DCX to DCY.
|
||||
---------------------------------------------
|
||||
|
||||
This question is often asked by people who find their account(s) always being connected to DC1 - USA (for example), but
|
||||
are connecting from a place far away (e.g DC4 - Europe), thus resulting in slower interactions when using the API
|
||||
because of the great physical distance between the user and its associated DC.
|
||||
|
||||
When registering an account for the first time, is up to Telegram to decide which DC the new user is going to be created
|
||||
in, based on the phone number origin.
|
||||
|
||||
Even though Telegram `documentations <https://core.telegram.org/api/datacenter#user-migration>`_ state the server might
|
||||
decide to automatically migrate a user in case of prolonged usages from a distant, unusual location and albeit this
|
||||
mechanism is also `confirmed <https://twitter.com/telegram/status/427131446655197184>`_ to exist by Telegram itself,
|
||||
it's currently not possible to have your account migrated, in any way, simply because the feature was once planned but
|
||||
not yet implemented.
|
||||
|
||||
Thanks to `@gabriel <https://t.me/AnotherGroup/217699>`_ for confirming the feature was not implemented yet.
|
||||
|
||||
Why is my client reacting slowly in supergroups?
|
||||
------------------------------------------------
|
||||
|
||||
This issue affects only some supergroups or only some members within the same supergroup. Mostly, it affects supergroups
|
||||
whose creator's account (and thus the supergroup itself) lives inside a **different DC**, far away from yours, but could
|
||||
also depend on where a member is connecting from.
|
||||
|
||||
Because of how Telegram works internally, every single message you receive from and send to other members must pass
|
||||
through the creator's DC, and in the worst case where you, the creator and another member all belong to three different
|
||||
DCs, the other member messages have to go through from its DC to the creator's DC and finally to your DC. This process
|
||||
will inevitably take its time.
|
||||
|
||||
To confirm this theory and see it by yourself, you can test in a supergroup where you are sure all parties live
|
||||
inside the same DC. In this case the responses will be faster.
|
||||
|
||||
Another reason that makes responses come slowly is that messages are **dispatched by priority**. Depending on the kind
|
||||
of member, some users receive messages faster than others and for big and busy supergroups the delay might become
|
||||
noticeable, especially if you are among the lower end of the priority list:
|
||||
|
||||
1. Creator.
|
||||
2. Administrators.
|
||||
3. Bots.
|
||||
4. Mentioned users.
|
||||
5. Recent online users.
|
||||
6. Everyone else.
|
||||
|
||||
Thanks to `@Manuel15 <https://t.me/PyrogramChat/76990>`_ for the priority list.
|
||||
|
||||
I keep getting PEER_ID_INVALID error!
|
||||
-------------------------------------
|
||||
|
||||
The error in question is ``[400 PEER_ID_INVALID]``, and could mean several things:
|
||||
|
||||
- The chat id you tried to use is simply wrong, double check it.
|
||||
- The chat id refers to a group or channel you are not a member of.
|
||||
- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``.
|
||||
- The chat id refers to a user or chat your current session hasn't met yet.
|
||||
|
||||
About the last point: in order for you to meet a user and thus communicate with them, you should ask yourself how to
|
||||
contact people using official apps. The answer is the same for Pyrogram too and involves normal usages such as searching
|
||||
for usernames, meeting them in a common group, having their phone contacts saved, getting a message mentioning them
|
||||
(either a forward or a mention in the message text) or obtaining the dialogs list.
|
||||
|
||||
Code hangs when I stop, restart, add/remove_handler
|
||||
---------------------------------------------------
|
||||
|
||||
You tried to ``.stop()``, ``.restart()``, ``.add_handler()`` or ``.remove_handler()`` *inside* a running handler, but
|
||||
that can't be done because the way Pyrogram deals with handlers would make it hang.
|
||||
|
||||
When calling one of the methods above inside an event handler, Pyrogram needs to wait for all running handlers to finish
|
||||
in order to safely continue. In other words, since your handler is blocking the execution by waiting for the called
|
||||
method to finish and since Pyrogram needs to wait for your handler to finish, you are left with a deadlock.
|
||||
|
||||
The solution to this problem is to pass ``block=False`` to such methods so that they return immediately and the actual
|
||||
code called asynchronously.
|
||||
|
||||
UnicodeEncodeError: '<encoding>' codec can't encode …
|
||||
-----------------------------------------------------
|
||||
|
||||
Where ``<encoding>`` might be *ascii*, *cp932*, *charmap* or anything else other than **utf-8**. This error usually
|
||||
shows up when you try to print something and has very little to do with Pyrogram itself as it is strictly related to
|
||||
your own terminal. To fix it, either find a way to change the encoding settings of your terminal to UTF-8 or switch to a
|
||||
better terminal altogether.
|
||||
|
||||
Uploading with URLs gives error WEBPAGE_CURL_FAILED
|
||||
---------------------------------------------------
|
||||
|
||||
When uploading media files using an URL, the server automatically tries to download the media and uploads it to the
|
||||
Telegram cloud. This error usually happens in case the provided URL is not publicly accessible by Telegram itself or the
|
||||
media exceeds 20 MB in size. In such cases, your only option is to download the media yourself and upload from your
|
||||
local machine.
|
||||
|
||||
sqlite3.OperationalError: database is locked
|
||||
--------------------------------------------
|
||||
|
||||
This error occurs when more than one process is using the same session file, that is, when you run two or more clients
|
||||
at the same time using the same session name.
|
||||
|
||||
It could also occur when a background script is still running and you forgot about it. In this case, you either restart
|
||||
your system or find and kill the process that is locking the database. On Unix based systems, you can do the following:
|
||||
|
||||
#. ``cd`` into your session file directory.
|
||||
#. ``fuser my_account.session`` to find the process id.
|
||||
#. ``kill 1234`` to gracefully stop the process.
|
||||
#. If the last command doesn't help, use ``kill -9 1234`` instead.
|
||||
|
||||
If you want to run multiple clients on the same account, you must authorize your account (either user or bot)
|
||||
from the beginning every time, and use different session names for each parallel client you are going to use.
|
||||
|
||||
sqlite3.OperationalError: unable to open database file
|
||||
------------------------------------------------------
|
||||
|
||||
Stackoverflow to the rescue: https://stackoverflow.com/questions/4636970
|
||||
|
||||
sqlite3.InterfaceError: Error binding parameter 0
|
||||
-------------------------------------------------
|
||||
|
||||
This error occurs when you pass a chat id value of the wrong type when trying to call a method. Most likely, you
|
||||
accidentally passed the whole user or chat object instead of the id or username.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Wrong. You passed the whole Chat instance
|
||||
app.send_message(chat, "text")
|
||||
|
||||
# Correct
|
||||
app.send_message(chat.id, "text")
|
||||
|
||||
My verification code expires immediately!
|
||||
-----------------------------------------
|
||||
|
||||
That is because you likely shared it across any of your Telegram chats. Yes, that's right: the server keeps scanning the
|
||||
messages you send and if an active verification code is found it will immediately expire, automatically.
|
||||
|
||||
The reason behind this is to protect unaware users from giving their account access to any potential scammer, but if you
|
||||
legitimately want to share your account(s) verification codes, consider scrambling them, e.g. ``12345`` → ``1-2-3-4-5``.
|
||||
|
||||
How can avoid Flood Waits?
|
||||
--------------------------
|
||||
|
||||
Long story short: make less requests, and remember that the API is designed to be used by official apps, by real people;
|
||||
anything above normal usage could be limited.
|
||||
|
||||
This question is being asked quite a lot of times, but the bottom line is that nobody knows the exact limits and it's
|
||||
unlikely that such information will be ever disclosed, because otherwise people could easily circumvent them and defeat
|
||||
their whole purpose.
|
||||
|
||||
Do also note that Telegram wants to be a safe and reliable place and that limits exist to protect itself from abuses.
|
||||
Having said that, here's some insights about limits:
|
||||
|
||||
- They are tuned by Telegram based on real people usage and can change anytime.
|
||||
- Some limits are be applied to single sessions, some others apply to the whole account.
|
||||
- Limits vary based on methods and the arguments passed to methods. For example: log-ins are expensive and thus have
|
||||
stricter limits; replying to a user command could cause a flood wait in case the user starts flooding, but
|
||||
such limit will only be applied to that particular chat (i.e.: other users are not affected).
|
||||
- You can catch Flood Wait exceptions in your code and wait the required seconds before continuing, this way:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import time
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
try:
|
||||
... # Your code
|
||||
except FloodWait as e:
|
||||
time.sleep(e.x) # Wait "x" seconds before continuing
|
||||
|
||||
|
||||
More info about error handling can be found `here <start/errors>`_.
|
||||
|
||||
My account has been deactivated/limited!
|
||||
----------------------------------------
|
||||
|
||||
First of all, you should understand that Telegram wants to be a safe place for people to stay in, and to pursue this
|
||||
goal there are automatic protection systems running to prevent flood and spam, as well as a moderation team of humans
|
||||
who review reports.
|
||||
|
||||
.. centered:: Pyrogram is a tool at your commands; it only does what you tell it to do, the rest is up to you.
|
||||
|
||||
Having said that, here's a list of what Telegram definitely doesn't like:
|
||||
|
||||
- Flood, abusing the API.
|
||||
- Spam, sending unsolicited messages or adding people to unwanted groups and channels.
|
||||
- Virtual/VoIP and cheap real numbers, because they are relatively easy to get and likely used for spam/flood.
|
||||
|
||||
And thanks to `@koteeq <https://t.me/koteeq>`_, here's a good explanation of how, probably, the system works:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script
|
||||
async src="https://telegram.org/js/telegram-widget.js?5"
|
||||
data-telegram-post="PyrogramChat/69424"
|
||||
data-width="100%">
|
||||
</script>
|
||||
<br><br>
|
||||
|
||||
However, you might be right, and your account was deactivated/limited without any good reason. This could happen because
|
||||
of mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at
|
||||
recover@telegram.org, contact `@smstelegram`_ on Twitter or use `this form`_.
|
||||
|
||||
Are there any secret easter eggs?
|
||||
---------------------------------
|
||||
|
||||
Yes. If you found one, `let me know`_!
|
||||
|
||||
.. _let me know: https://t.me/pyrogram
|
||||
|
||||
.. _@smstelegram: https://twitter.com/smstelegram
|
||||
.. _this form: https://telegram.org/support
|
||||
|
||||
.. _Bug Report: https://github.com/pyrogram/pyrogram/issues/new?labels=bug&template=bug_report.md
|
||||
.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md
|
11
docs/source/faq/client-started-but-nothing-happens.rst
Normal file
11
docs/source/faq/client-started-but-nothing-happens.rst
Normal file
@ -0,0 +1,11 @@
|
||||
Client started, but nothing happens
|
||||
===================================
|
||||
|
||||
A possible cause might be network issues, either yours or Telegram's. To check this, add the following code at
|
||||
the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable
|
||||
network:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
@ -0,0 +1,12 @@
|
||||
Code hangs when calling stop, restart, add/remove_handler
|
||||
=========================================================
|
||||
|
||||
You tried to ``.stop()``, ``.restart()``, ``.add_handler()`` or ``.remove_handler()`` inside a running handler, but
|
||||
that can't be done because the way Pyrogram deals with handlers would make it hang.
|
||||
|
||||
When calling one of the methods above inside an event handler, Pyrogram needs to wait for all running handlers to finish
|
||||
in order to continue. Since your handler is blocking the execution by waiting for the called method to finish
|
||||
and since Pyrogram needs to wait for your handler to finish, you are left with a deadlock.
|
||||
|
||||
The solution to this problem is to pass ``block=False`` to such methods so that they return immediately and the actual
|
||||
code called asynchronously.
|
23
docs/source/faq/how-to-avoid-flood-waits.rst
Normal file
23
docs/source/faq/how-to-avoid-flood-waits.rst
Normal file
@ -0,0 +1,23 @@
|
||||
How to avoid Flood Waits?
|
||||
=========================
|
||||
|
||||
Slow things down and make less requests. Moreover, exact limits are unknown and can change anytime based on normal
|
||||
usages.
|
||||
|
||||
When a flood wait happens the server will tell you how much time to wait before continuing.
|
||||
The following shows how to catch the exception in your code and wait the required seconds.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import time
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
...
|
||||
try:
|
||||
... # Your code
|
||||
except FloodWait as e:
|
||||
await asyncio.sleep(e.x) # Wait "x" seconds before continuing
|
||||
...
|
||||
|
||||
|
||||
More info about error handling can be found :doc:`here <../start/errors>`.
|
9
docs/source/faq/how-to-use-webhooks.rst
Normal file
9
docs/source/faq/how-to-use-webhooks.rst
Normal file
@ -0,0 +1,9 @@
|
||||
How to use webhooks?
|
||||
====================
|
||||
|
||||
There is no webhook in Pyrogram, simply because there is no HTTP involved. However, a similar technique is
|
||||
being used to make receiving updates efficient.
|
||||
|
||||
Pyrogram uses persistent connections via TCP sockets to interact with the server and instead of actively asking for
|
||||
updates every time (polling), Pyrogram will sit down and wait for the server to send updates by itself the very moment
|
||||
they are available (server push).
|
47
docs/source/faq/index.rst
Normal file
47
docs/source/faq/index.rst
Normal file
@ -0,0 +1,47 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
This FAQ page provides answers to common questions about Pyrogram and, to some extent, Telegram in general.
|
||||
|
||||
**Contents**
|
||||
|
||||
- :doc:`why-is-the-api-key-needed-for-bots`
|
||||
- :doc:`how-to-use-webhooks`
|
||||
- :doc:`using-the-same-file-id-across-different-accounts`
|
||||
- :doc:`using-multiple-clients-at-once-on-the-same-account`
|
||||
- :doc:`client-started-but-nothing-happens`
|
||||
- :doc:`what-are-the-ip-addresses-of-telegram-data-centers`
|
||||
- :doc:`migrating-the-account-to-another-data-center`
|
||||
- :doc:`why-is-the-client-reacting-slowly-in-supergroups-channels`
|
||||
- :doc:`peer-id-invalid-error`
|
||||
- :doc:`code-hangs-when-calling-stop-restart-add-remove-handler`
|
||||
- :doc:`unicodeencodeerror-codec-cant-encode`
|
||||
- :doc:`uploading-with-urls-gives-error-webpage-curl-failed`
|
||||
- :doc:`why-is-the-event-handler-triggered-twice-or-more`
|
||||
- :doc:`sqlite3-operationalerror-database-is-locked`
|
||||
- :doc:`sqlite3-interfaceerror-error-binding-parameter`
|
||||
- :doc:`socket-send-raised-exception-oserror-timeouterror`
|
||||
- :doc:`how-to-avoid-flood-waits`
|
||||
- :doc:`the-account-has-been-limited-deactivated`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
why-is-the-api-key-needed-for-bots
|
||||
how-to-use-webhooks
|
||||
using-the-same-file-id-across-different-accounts
|
||||
using-multiple-clients-at-once-on-the-same-account
|
||||
client-started-but-nothing-happens
|
||||
what-are-the-ip-addresses-of-telegram-data-centers
|
||||
migrating-the-account-to-another-data-center
|
||||
why-is-the-client-reacting-slowly-in-supergroups-channels
|
||||
peer-id-invalid-error
|
||||
code-hangs-when-calling-stop-restart-add-remove-handler
|
||||
unicodeencodeerror-codec-cant-encode
|
||||
uploading-with-urls-gives-error-webpage-curl-failed
|
||||
why-is-the-event-handler-triggered-twice-or-more
|
||||
sqlite3-operationalerror-database-is-locked
|
||||
sqlite3-interfaceerror-error-binding-parameter
|
||||
socket-send-raised-exception-oserror-timeouterror
|
||||
how-to-avoid-flood-waits
|
||||
the-account-has-been-limited-deactivated
|
@ -0,0 +1,10 @@
|
||||
Migrating the account to another data center
|
||||
============================================
|
||||
|
||||
This question is asked by people who find their account always being connected to one DC (data center), but are
|
||||
connecting from a place far away, thus resulting in slower interactions when using the API because of the greater
|
||||
physical distance between the user and the associated DC.
|
||||
|
||||
When registering an account for the first time, is up to Telegram to decide which DC the new user is going to be
|
||||
created in. It's also up to the server to decide whether to automatically migrate a user in case of prolonged usages
|
||||
from a distant location.
|
14
docs/source/faq/peer-id-invalid-error.rst
Normal file
14
docs/source/faq/peer-id-invalid-error.rst
Normal file
@ -0,0 +1,14 @@
|
||||
PEER_ID_INVALID error
|
||||
=====================
|
||||
|
||||
This error could mean several things:
|
||||
|
||||
- The chat id you tried to use is simply wrong, check it again.
|
||||
- The chat id refers to a group or channel you are not a member of.
|
||||
- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``.
|
||||
- The chat id refers to a user or chat your current session hasn't met yet.
|
||||
|
||||
About the last point: in order for you to meet a user and thus communicate with them, you should ask yourself how to
|
||||
contact people using official apps. The answer is the same for Pyrogram too and involves normal usages such as searching
|
||||
for usernames, meeting them in a common group, having their phone contacts saved, getting a message mentioning them
|
||||
or obtaining the dialogs list.
|
@ -0,0 +1,10 @@
|
||||
socket.send() raised exception, OSError(), TimeoutError()
|
||||
=========================================================
|
||||
|
||||
If you get this error chances are you are blocking the event loop for too long.
|
||||
In general, it means you are executing thread-blocking code that prevents the event loop from
|
||||
running properly. For example:
|
||||
|
||||
- You are using ``time.sleep()`` instead of ``asyncio.sleep()``.
|
||||
- You are running processing loops that take too much time to complete.
|
||||
- You are reading/writing files to disk that take too much time to complete.
|
@ -0,0 +1,13 @@
|
||||
sqlite3.InterfaceError: Error binding parameter
|
||||
===============================================
|
||||
|
||||
This error occurs when you pass a chat id value of the wrong type when trying to call a method. Most likely, you
|
||||
accidentally passed the whole user or chat object instead of the id or username.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Wrong. You passed the whole Chat instance
|
||||
app.send_message(chat, "text")
|
||||
|
||||
# Correct
|
||||
app.send_message(chat.id, "text")
|
@ -0,0 +1,17 @@
|
||||
sqlite3.OperationalError: database is locked
|
||||
============================================
|
||||
|
||||
This error occurs when more than one process is using the same session file, that is, when you run two or more clients
|
||||
at the same time using the same session name or in case another program has accessed the file.
|
||||
|
||||
For example, it could occur when a background script is still running and you forgot about it. In this case, you either
|
||||
restart your system or find and kill the process that is locking the database. On Unix based systems, you can try the
|
||||
following:
|
||||
|
||||
#. ``cd`` into your session file directory.
|
||||
#. ``fuser my_account.session`` to find the process id.
|
||||
#. ``kill 1234`` to gracefully stop the process.
|
||||
#. If the last command doesn't help, use ``kill -9 1234`` instead.
|
||||
|
||||
If you want to run multiple clients on the same account, you must authorize your account (either user or bot)
|
||||
from the beginning every time, and use different session names for each parallel client you are going to use.
|
16
docs/source/faq/the-account-has-been-limited-deactivated.rst
Normal file
16
docs/source/faq/the-account-has-been-limited-deactivated.rst
Normal file
@ -0,0 +1,16 @@
|
||||
The account has been limited/deactivated
|
||||
========================================
|
||||
|
||||
Pyrogram is a framework that interfaces with Telegram; it is at your commands, meaning it only does what you tell it to
|
||||
do, the rest is up to you and Telegram (see `Telegram's ToS`_).
|
||||
|
||||
If you found your account being limited/deactivated, it could be due spam/flood/abuse of the API or the usage of certain
|
||||
virtual/VoIP numbers.
|
||||
|
||||
If you think your account was limited/deactivated by mistake, you can write to recover@telegram.org, contact
|
||||
`@SpamBot`_ or use `this form`_.
|
||||
|
||||
.. _@SpamBot: https://t.me/spambot
|
||||
.. _this form: https://telegram.org/support
|
||||
.. _Telegram's ToS: https://telegram.org/tos
|
||||
|
7
docs/source/faq/unicodeencodeerror-codec-cant-encode.rst
Normal file
7
docs/source/faq/unicodeencodeerror-codec-cant-encode.rst
Normal file
@ -0,0 +1,7 @@
|
||||
UnicodeEncodeError: '...' codec can't encode ...
|
||||
================================================
|
||||
|
||||
Where ``<encoding>`` might be *ascii*, *cp932*, *charmap* or anything else other than *utf-8*. This error usually
|
||||
shows up when you try to print something and has very little to do with Pyrogram itself as it is strictly related to
|
||||
your own terminal. To fix it, either find a way to change the encoding settings of your terminal to UTF-8 or switch to
|
||||
another terminal altogether.
|
@ -0,0 +1,7 @@
|
||||
Uploading with URLs gives error WEBPAGE_CURL_FAILED
|
||||
===================================================
|
||||
|
||||
When uploading media files using an URL, the server automatically tries to download the media and uploads it to the
|
||||
Telegram cloud. This error usually happens in case the provided URL is not publicly accessible by Telegram itself or the
|
||||
media file is too large. In such cases, your only option is to download the media yourself and upload it from your
|
||||
local machine.
|
@ -0,0 +1,7 @@
|
||||
Using multiple clients at once on the same account
|
||||
==================================================
|
||||
|
||||
Both user and bot accounts are able to run multiple sessions in parallel. However, you must not use the same session
|
||||
in more than one client at the same time. The correct way to run multiple clients on the same account is by authorizing
|
||||
your account (either user or bot) from the beginning each time, and use one separate session for each parallel client.
|
||||
|
@ -0,0 +1,6 @@
|
||||
Using the same file_id across different accounts
|
||||
================================================
|
||||
|
||||
Telegram file_id strings are bound to the account which generated them. An attempt in using a foreign file id will
|
||||
result in errors such as ``[400 MEDIA_EMPTY]``. The only exception are stickers' file ids; you can use them across
|
||||
different accounts without any problem.
|
@ -0,0 +1,30 @@
|
||||
What are the IP addresses of Telegram Data Centers?
|
||||
===================================================
|
||||
|
||||
Telegram is currently composed by a decentralized, multi-DC infrastructure (currently 5 DCs, each of which can
|
||||
work independently) spread across different locations worldwide. However, some of the less busy DCs have been lately
|
||||
dismissed and their IP addresses are now kept as aliases to the nearest one.
|
||||
|
||||
.. csv-table:: Production Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.53``, ``2001:b28:f23d:f001::a``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.51``, ``2001:67c:4e8:f002::a``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.100``, ``2001:b28:f23d:f003::a``
|
||||
DC4, "AMS, Amsterdam, NL", ``149.154.167.91``, ``2001:67c:4e8:f004::a``
|
||||
DC5, "SIN, Singapore, SG", ``91.108.56.130``, ``2001:b28:f23f:f005::a``
|
||||
|
||||
.. csv-table:: Test Environment
|
||||
:header: ID, Location, IPv4, IPv6
|
||||
:widths: auto
|
||||
:align: center
|
||||
|
||||
DC1, "MIA, Miami FL, USA", ``149.154.175.10``, ``2001:b28:f23d:f001::e``
|
||||
DC2, "AMS, Amsterdam, NL", ``149.154.167.40``, ``2001:67c:4e8:f002::e``
|
||||
DC3*, "MIA, Miami FL, USA", ``149.154.175.117``, ``2001:b28:f23d:f003::e``
|
||||
|
||||
.. centered:: More info about the Test Environment can be found :doc:`here <../topics/test-servers>`.
|
||||
|
||||
***** Alias DC
|
12
docs/source/faq/why-is-the-api-key-needed-for-bots.rst
Normal file
12
docs/source/faq/why-is-the-api-key-needed-for-bots.rst
Normal file
@ -0,0 +1,12 @@
|
||||
Why is the API key needed for bots?
|
||||
===================================
|
||||
|
||||
Requests against the official bot API endpoints are made via JSON/HTTP and are handled by an intermediate server
|
||||
application that implements the MTProto protocol and uses its own API key to communicate with the MTProto servers.
|
||||
|
||||
.. figure:: //_static/img/mtproto-vs-bot-api.png
|
||||
:align: center
|
||||
|
||||
Using MTProto is the only way to communicate with the actual Telegram servers, and the main API requires developers to
|
||||
identify applications by means of a unique key; the bot token identifies a bot as a user and replaces the user's phone
|
||||
number only.
|
@ -0,0 +1,18 @@
|
||||
Why is the client reacting slowly in supergroups/channels?
|
||||
==========================================================
|
||||
|
||||
Because of how Telegram works internally, every message you receive and send must pass through the creator's DC, and in
|
||||
the worst case where you, the creator and another member all belong to three different DCs, the other member messages
|
||||
have to go through from their DC to the creator's DC and finally to your DC. This is applied to each message and member
|
||||
of a supergroup/channel and the process will inevitably take its time.
|
||||
|
||||
Another reason that makes responses come slowly is that messages are dispatched by priority. Depending on the kind
|
||||
of member, some users receive messages faster than others and for big and busy supergroups the delay might become
|
||||
noticeable, especially if you are among the lower end of the priority list:
|
||||
|
||||
1. Creator.
|
||||
2. Administrators.
|
||||
3. Bots.
|
||||
4. Mentioned users.
|
||||
5. Recent online users.
|
||||
6. Everyone else.
|
@ -0,0 +1,28 @@
|
||||
Why is the event handler called twice or more?
|
||||
==============================================
|
||||
|
||||
The event handler is being called twice or more because one or more message edit events have arrived.
|
||||
By default, Pyrogram listens to both new and edit message events inside ``on_message`` handlers. To prevent edit events
|
||||
from calling the handler, use the "not edited" filter ``~filters.edited``.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
...
|
||||
|
||||
@app.on_message(... & ~filters.edited)
|
||||
async def handler(client, message):
|
||||
...
|
||||
|
||||
Or, avoid handling any edited message altogether this way:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
...
|
||||
|
||||
@app.on_message(filters.edited)
|
||||
async def edited(client, message):
|
||||
pass
|
||||
|
||||
... # other handlers
|
@ -1,86 +0,0 @@
|
||||
Pyrogram Glossary
|
||||
=================
|
||||
|
||||
This page contains a list of common words with brief explanations related to Pyrogram and, to some extent, Telegram in
|
||||
general. Some words may as well link to dedicated articles in case the topic is covered in a more detailed fashion.
|
||||
|
||||
.. tip::
|
||||
|
||||
If you think something interesting could be added here, feel free to propose it by opening a `Feature Request`_.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Terms
|
||||
-----
|
||||
|
||||
.. glossary::
|
||||
:sorted:
|
||||
|
||||
API
|
||||
Application Programming Interface: a set of methods, protocols and tools that make it easier to develop programs
|
||||
by providing useful building blocks to the developer.
|
||||
|
||||
API key
|
||||
A secret code used to authenticate and/or authorize a specific application to Telegram in order for it to
|
||||
control how the API is being used, for example, to prevent abuses of the API.
|
||||
:doc:`More on API keys <intro/setup>`.
|
||||
|
||||
DC
|
||||
Also known as *data center*, is a place where lots of computer systems are housed and used together in order to
|
||||
achieve high quality and availability for services.
|
||||
|
||||
RPC
|
||||
Acronym for Remote Procedure Call, that is, a function which gets executed at some remote place (i.e. Telegram
|
||||
server) and not in your local machine.
|
||||
|
||||
RPCError
|
||||
An error caused by an RPC which must be returned in place of the successful result in order to let the caller
|
||||
know something went wrong. :doc:`More on RPCError <start/errors>`.
|
||||
|
||||
MTProto
|
||||
The name of the custom-made, open and encrypted protocol by Telegram, implemented in Pyrogram.
|
||||
:doc:`More on MTProto <topics/mtproto-vs-botapi>`.
|
||||
|
||||
MTProto API
|
||||
The Telegram main API Pyrogram makes use of, which is able to connect both users and normal bots to Telegram
|
||||
using MTProto as application layer protocol and execute any method Telegram provides from its public TL-schema.
|
||||
:doc:`More on MTProto API <topics/mtproto-vs-botapi>`.
|
||||
|
||||
Bot API
|
||||
The Telegram Bot API that is able to only connect normal bots only to Telegram using HTTP as application layer
|
||||
protocol and allows to execute a sub-set of the main Telegram API.
|
||||
:doc:`More on Bot API <topics/mtproto-vs-botapi>`.
|
||||
|
||||
Pyrogrammer
|
||||
A developer that uses Pyrogram to build Telegram applications.
|
||||
|
||||
Userbot
|
||||
Also known as *user bot* or *ubot* for short, is a user logged in by third-party Telegram libraries --- such as
|
||||
Pyrogram --- to automate some behaviours, like sending messages or reacting to text commands or any other event.
|
||||
Not to be confused with *bot*, that is, a normal Telegram bot created by `@BotFather <https://t.me/botfather>`_.
|
||||
|
||||
Session
|
||||
Also known as *login session*, is a strictly personal piece of data created and held by both parties
|
||||
(client and server) which is used to grant permission into a single account without having to start a new
|
||||
authorization process from scratch.
|
||||
|
||||
Callback
|
||||
Also known as *callback function*, is a user-defined generic function that *can be* registered to and then
|
||||
called-back by the framework when specific events occurs.
|
||||
|
||||
Handler
|
||||
An object that wraps around a callback function that is *actually meant* to be registered into the framework,
|
||||
which will then be able to handle a specific kind of events, such as a new incoming message, for example.
|
||||
:doc:`More on Handlers <start/updates>`.
|
||||
|
||||
Decorator
|
||||
Also known as *function decorator*, in Python, is a callable object that is used to modify another function.
|
||||
Decorators in Pyrogram are used to automatically register callback functions for handling updates.
|
||||
:doc:`More on Decorators <start/updates>`.
|
||||
|
||||
.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md
|
@ -5,7 +5,8 @@ Welcome to Pyrogram
|
||||
|
||||
<div align="center">
|
||||
<a href="/">
|
||||
<div><img src="_static/pyrogram.png" alt="Pyrogram Logo" width="420"></div>
|
||||
<div class="pyrogram-logo-index"><img src="_static/pyrogram.png" alt="Pyrogram"></div>
|
||||
<div class="pyrogram-text pyrogram-text-index">Pyrogram</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -14,15 +15,15 @@ Welcome to Pyrogram
|
||||
|
||||
<br>
|
||||
<a href="https://github.com/pyrogram/pyrogram">
|
||||
Source Code
|
||||
Development
|
||||
</a>
|
||||
•
|
||||
<a href="https://github.com/pyrogram/pyrogram/releases">
|
||||
<a href="https://docs.pyrogram.org/releases">
|
||||
Releases
|
||||
</a>
|
||||
•
|
||||
<a href="https://t.me/Pyrogram">
|
||||
Community
|
||||
<a href="https://t.me/pyrogram">
|
||||
News
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -35,16 +36,34 @@ Welcome to Pyrogram
|
||||
|
||||
@app.on_message(filters.private)
|
||||
async def hello(client, message):
|
||||
await message.reply_text(f"Hello {message.from_user.mention}")
|
||||
await message.reply("Hello from Pyrogram!")
|
||||
|
||||
|
||||
app.run()
|
||||
|
||||
**Pyrogram** is a modern, elegant and easy-to-use Telegram_ framework written from the ground up in Python and C.
|
||||
It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the
|
||||
:doc:`MTProto API <topics/mtproto-vs-botapi>`.
|
||||
**Pyrogram** is a modern, elegant and asynchronous :doc:`MTProto API <topics/mtproto-vs-botapi>` framework.
|
||||
It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot identity
|
||||
(bot API alternative) using Python.
|
||||
|
||||
.. _Telegram: https://telegram.org
|
||||
Support
|
||||
-------
|
||||
|
||||
If you'd like to support Pyrogram, you can consider:
|
||||
|
||||
- `Become a GitHub sponsor <https://github.com/sponsors/delivrance>`_.
|
||||
- `Become a LiberaPay patron <https://liberapay.com/delivrance>`_.
|
||||
- `Become an OpenCollective backer <https://opencollective.com/pyrogram>`_.
|
||||
|
||||
Key Features
|
||||
------------
|
||||
|
||||
- **Ready**: Install Pyrogram with pip and start building your applications right away.
|
||||
- **Easy**: Makes the Telegram API simple and intuitive, while still allowing advanced usages.
|
||||
- **Elegant**: Low-level details are abstracted and re-presented in a more convenient way.
|
||||
- **Fast**: Boosted up by :doc:`TgCrypto <topics/tgcrypto>`, a high-performance crypto library written in pure C.
|
||||
- **Type-hinted**: Types and methods are all type-hinted, enabling excellent editor support.
|
||||
- **Async**: Fully asynchronous (also usable synchronously if wanted, for convenience).
|
||||
- **Powerful**: Full access to Telegram's API to execute any official client action and more.
|
||||
|
||||
How the Documentation is Organized
|
||||
----------------------------------
|
||||
@ -53,18 +72,11 @@ Contents are organized into sections composed of self-contained topics which can
|
||||
following them in order using the :guilabel:`Next` button at the end of each page. Here below you can, instead, find a
|
||||
list of the most relevant pages for a quick access.
|
||||
|
||||
.. admonition :: Cloud Credits
|
||||
:class: tip
|
||||
|
||||
If you need a cloud server to host your applications, we recommend using **Hetzner Cloud**. Sign up with
|
||||
`this link <https://hetzner.cloud/?ref=9CyT92gZEINU>`_ to get €20 in cloud credits and help support Pyrogram as
|
||||
well.
|
||||
|
||||
First Steps
|
||||
^^^^^^^^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 2
|
||||
:columns: 1
|
||||
|
||||
- :doc:`Quick Start <intro/quickstart>`: Overview to get you started quickly.
|
||||
- :doc:`Calling Methods <start/invoking>`: How to call Pyrogram's methods.
|
||||
@ -75,7 +87,7 @@ API Reference
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 2
|
||||
:columns: 1
|
||||
|
||||
- :doc:`Pyrogram Client <api/client>`: Reference details about the Client class.
|
||||
- :doc:`Available Methods <api/methods/index>`: List of available high-level methods.
|
||||
@ -86,16 +98,12 @@ Meta
|
||||
^^^^
|
||||
|
||||
.. hlist::
|
||||
:columns: 2
|
||||
:columns: 1
|
||||
|
||||
- :doc:`Pyrogram FAQ <faq>`: Answers to common Pyrogram questions.
|
||||
- :doc:`Pyrogram Glossary <glossary>`: List of words with brief explanations.
|
||||
- :doc:`Pyrogram FAQ <faq/index>`: Answers to common Pyrogram questions.
|
||||
- :doc:`Support Pyrogram <support>`: Ways to show your appreciation.
|
||||
- :doc:`About the License <license>`: Information about the Project license.
|
||||
- :doc:`Release Notes <releases/index>`: Release notes for Pyrogram releases.
|
||||
|
||||
Last updated on |today|
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:caption: Introduction
|
||||
@ -136,14 +144,13 @@ Last updated on |today|
|
||||
topics/more-on-updates
|
||||
topics/config-file
|
||||
topics/smart-plugins
|
||||
topics/session-settings
|
||||
topics/client-settings
|
||||
topics/tgcrypto
|
||||
topics/storage-engines
|
||||
topics/text-formatting
|
||||
topics/serializing
|
||||
topics/proxy
|
||||
topics/scheduling
|
||||
topics/bots-interaction
|
||||
topics/mtproto-vs-botapi
|
||||
topics/debugging
|
||||
topics/test-servers
|
||||
@ -154,10 +161,8 @@ Last updated on |today|
|
||||
:hidden:
|
||||
:caption: Meta
|
||||
|
||||
faq
|
||||
glossary
|
||||
faq/index
|
||||
support
|
||||
license
|
||||
releases/index
|
||||
|
||||
.. toctree::
|
||||
|
@ -1,16 +1,9 @@
|
||||
Install Guide
|
||||
=============
|
||||
|
||||
Being a modern Python library, **Pyrogram** requires Python 3.6+ to be installed in your system.
|
||||
Being a modern Python framework, Pyrogram requires an up to date version of Python to be installed in your system.
|
||||
We recommend using the latest versions of both Python 3 and pip.
|
||||
|
||||
- Get **Python 3** from https://www.python.org/downloads/ (or with your package manager).
|
||||
- Get **pip** by following the instructions at https://pip.pypa.io/en/latest/installing/.
|
||||
|
||||
.. important::
|
||||
|
||||
Pyrogram supports **Python 3** only, starting from version 3.6. **PyPy** is supported too.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
@ -36,12 +29,7 @@ Install Pyrogram
|
||||
Bleeding Edge
|
||||
-------------
|
||||
|
||||
Pyrogram is always evolving, although new releases on PyPI are published only when enough changes are added, but this
|
||||
doesn't mean you can't try new features right now!
|
||||
|
||||
In case you'd like to try out the latest Pyrogram features, the `GitHub repo`_ is always kept updated with new changes;
|
||||
you can install the development version straight from the ``master`` branch using this command (note "master.zip" in
|
||||
the link):
|
||||
You can install the development version from the git ``master`` branch using this command:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@ -57,6 +45,6 @@ If no error shows up you are good to go.
|
||||
|
||||
>>> import pyrogram
|
||||
>>> pyrogram.__version__
|
||||
'|version|'
|
||||
'x.y.z'
|
||||
|
||||
.. _`Github repo`: http://github.com/pyrogram/pyrogram
|
||||
|
@ -1,49 +1,54 @@
|
||||
Quick Start
|
||||
===========
|
||||
|
||||
The next few steps serve as a quick start for all new :term:`Pyrogrammers <Pyrogrammer>` that want to see Pyrogram in
|
||||
action as fast as possible. Let's go!
|
||||
The next few steps serve as a quick start to see Pyrogram in action as fast as possible.
|
||||
|
||||
Get Pyrogram Real Fast
|
||||
----------------------
|
||||
|
||||
.. admonition :: Cloud Credits
|
||||
:class: tip
|
||||
|
||||
If you need a cloud server to host your applications, try Hetzner Cloud. You can sign up with
|
||||
`this link <https://hetzner.cloud/?ref=9CyT92gZEINU>`_ to get €20 in cloud credits.
|
||||
|
||||
1. Install Pyrogram with ``pip3 install -U pyrogram``.
|
||||
|
||||
2. Get your own Telegram API key from https://my.telegram.org/apps.
|
||||
|
||||
3. Open your best text editor and paste the following:
|
||||
3. Open the text editor of your choice and paste the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from pyrogram import Client
|
||||
|
||||
api_id = 12345
|
||||
api_hash = "0123456789abcdef0123456789abcdef"
|
||||
|
||||
with Client("my_account", api_id, api_hash) as app:
|
||||
app.send_message("me", "Greetings from **Pyrogram**!")
|
||||
async def main():
|
||||
async with Client("my_account", api_id, api_hash) as app:
|
||||
await app.send_message("me", "Greetings from **Pyrogram**!")
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
4. Replace *api_id* and *api_hash* values with your own.
|
||||
|
||||
5. Save the file as ``pyro.py``.
|
||||
5. Save the file as ``hello.py``.
|
||||
|
||||
6. Run the script with ``python3 pyro.py``
|
||||
6. Run the script with ``python3 hello.py``
|
||||
|
||||
7. Follow the instructions on your terminal to login.
|
||||
|
||||
8. Watch Pyrogram send a message to yourself.
|
||||
|
||||
9. Join our `community`_.
|
||||
|
||||
10. Say, "hi!".
|
||||
|
||||
Enjoy the API
|
||||
-------------
|
||||
|
||||
That was just a quick overview that barely scratched the surface!
|
||||
In the next few pages of the introduction, we'll take a much more in-depth look of what we have just done above.
|
||||
That was just a quick overview. In the next few pages of the introduction, we'll take a much more in-depth look of what
|
||||
we have just done above.
|
||||
|
||||
Feeling eager to continue? You can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back later to
|
||||
learn some more details.
|
||||
If you are feeling eager to continue you can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back
|
||||
later to learn some more details.
|
||||
|
||||
.. _community: https://t.me/Pyrogram
|
||||
|
@ -2,7 +2,7 @@ Project Setup
|
||||
=============
|
||||
|
||||
We have just :doc:`installed Pyrogram <install>`. In this page we'll discuss what you need to do in order to set up a
|
||||
project with the library. Let's see how it's done.
|
||||
project with the framework.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -17,18 +17,13 @@ API Keys
|
||||
The very first step requires you to obtain a valid Telegram API key (API id/hash pair):
|
||||
|
||||
#. Visit https://my.telegram.org/apps and log in with your Telegram Account.
|
||||
#. Fill out the form to register a new Telegram application.
|
||||
#. Done! The API key consists of two parts: **api_id** and **api_hash**.
|
||||
|
||||
.. important::
|
||||
|
||||
The API key is personal and must be kept secret.
|
||||
#. Fill out the form with your details and register a new Telegram application.
|
||||
#. Done. The API key consists of two parts: **api_id** and **api_hash**. Keep it secret.
|
||||
|
||||
.. note::
|
||||
|
||||
The API key is unique for each user, but defines a token for a Telegram *application* you are going to build. This
|
||||
means that you are able to authorize multiple users (and bots too) to access the Telegram database through the
|
||||
MTProto API by a single API key.
|
||||
The API key defines a token for a Telegram *application* you are going to build.
|
||||
This means that you are able to authorize multiple users or bots with a single API key.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
@ -36,9 +31,9 @@ Configuration
|
||||
Having the API key from the previous step in handy, we can now begin to configure a Pyrogram project.
|
||||
There are two ways to do so, and you can choose what fits better for you:
|
||||
|
||||
- First option (recommended): create a new ``config.ini`` file next to your main script, copy-paste the following and
|
||||
replace the **api_id** and **api_hash** values with your own. This is the preferred method because allows you to
|
||||
keep your credentials out of your code without having to deal with how to load them:
|
||||
- First option: create a new ``config.ini`` file next to your main script, copy-paste the following and
|
||||
replace the *api_id* and *api_hash* values with your own. This method allows you to keep your credentials out of
|
||||
your code without having to deal with how to load them.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@ -47,8 +42,7 @@ There are two ways to do so, and you can choose what fits better for you:
|
||||
api_hash = 0123456789abcdef0123456789abcdef
|
||||
|
||||
- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* parameters of the
|
||||
Client class. This way you can have full control on how to store and load your credentials (e.g., you can load the
|
||||
credentials from the environment variables and directly pass the values into Pyrogram):
|
||||
Client class. This way you can have full control on how to store and load your credentials:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
About the License
|
||||
=================
|
||||
|
||||
.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png
|
||||
:align: left
|
||||
|
||||
Pyrogram is free software and is currently licensed under the terms of the
|
||||
`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it
|
||||
provided that modifications are described and licensed for free under LGPLv3+.
|
||||
|
||||
In other words: you can use and integrate Pyrogram into your code (either open source, under the same or a different
|
||||
license, or even proprietary) for any purpose whatsoever without being required to release the source code of your
|
||||
applications. Derivative works, including modifications to the library itself can only be redistributed under the same
|
||||
LGPLv3+ license.
|
||||
|
||||
.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser
|
@ -26,23 +26,20 @@ the :meth:`~pyrogram.Client.run` method:
|
||||
app = Client("my_account")
|
||||
app.run()
|
||||
|
||||
This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_) and the
|
||||
**phone code** you will receive in your devices that are already authorized or via SMS:
|
||||
This starts an interactive shell asking you to input your **phone number**, including your `Country Code`_ (the plus
|
||||
``+`` and minus ``-`` symbols can be omitted) and the **phone code** you will receive in your devices that are already
|
||||
authorized or via SMS:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Enter phone number: +39**********
|
||||
Is "+39**********" correct? (y/n): y
|
||||
Enter phone code: 32768
|
||||
Logged in successfully as Dan
|
||||
Enter phone number: +1-123-456-7890
|
||||
Is "+1-123-456-7890" correct? (y/n): y
|
||||
Enter phone code: 12345
|
||||
Logged in successfully
|
||||
|
||||
After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing Pyrogram to
|
||||
execute API calls with your identity. This file will be loaded again when you restart your app, and as long as you
|
||||
keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
||||
|
||||
.. important::
|
||||
|
||||
Your ``*.session`` file is personal and must be kept secret.
|
||||
execute API calls with your identity. This file is personal and will be loaded again when you restart your app, and as
|
||||
long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
Error Handling
|
||||
==============
|
||||
|
||||
Errors are inevitable when working with the API, and they can be correctly handled with ``try...except`` blocks in order
|
||||
to control the behaviour of your application. Pyrogram errors all live inside the ``errors`` package:
|
||||
Errors can be correctly handled with ``try...except`` blocks in order to control the behaviour of your application.
|
||||
Pyrogram errors all live inside the ``errors`` package:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -25,10 +25,10 @@ This error is raised every time a method call against Telegram's API was unsucce
|
||||
|
||||
from pyrogram.errors import RPCError
|
||||
|
||||
.. warning::
|
||||
.. note::
|
||||
|
||||
It must be noted that catching this error is bad practice, especially when no feedback is given (i.e. by
|
||||
logging/printing the full error traceback), because it makes it impossible to understand what went wrong.
|
||||
Avoid catching this error everywhere, especially when no feedback is given (i.e. by logging/printing the full error
|
||||
traceback), because it makes it impossible to understand what went wrong.
|
||||
|
||||
Error Categories
|
||||
----------------
|
||||
@ -84,9 +84,6 @@ whole category of errors and be sure to also handle these unknown errors.
|
||||
In case a whole class of errors is unknown (that is, an error code that is unknown), Pyrogram will raise a special
|
||||
``520 UnknownError`` exception.
|
||||
|
||||
In both cases, Pyrogram will log them in the ``unknown_errors.txt`` file. Users are invited to report
|
||||
these unknown errors in the `discussion group <https://t.me/pyrogram>`_.
|
||||
|
||||
Errors with Values
|
||||
------------------
|
||||
|
||||
|
@ -19,7 +19,7 @@ like send_audio(), send_document(), send_location(), etc...
|
||||
|
||||
with app:
|
||||
app.send_message(
|
||||
"haskell", # Edit this
|
||||
"me", # Edit this
|
||||
"This is a ReplyKeyboardMarkup example",
|
||||
reply_markup=ReplyKeyboardMarkup(
|
||||
[
|
||||
@ -33,7 +33,7 @@ like send_audio(), send_document(), send_location(), etc...
|
||||
)
|
||||
|
||||
app.send_message(
|
||||
"haskell", # Edit this
|
||||
"me", # Edit this
|
||||
"This is a InlineKeyboardMarkup example",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
|
@ -15,7 +15,7 @@ It uses the ``@on_message`` decorator to register a ``MessageHandler`` and appli
|
||||
|
||||
@app.on_message(filters.text & filters.private)
|
||||
def echo(client, message):
|
||||
message.reply_text(message.text)
|
||||
message.reply(message.text)
|
||||
|
||||
|
||||
app.run() # Automatically start() and idle()
|
@ -13,9 +13,3 @@ This example demonstrates a basic API usage
|
||||
with app:
|
||||
# Send a message, Markdown is enabled by default
|
||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
||||
|
||||
# Send a location
|
||||
app.send_location("me", 51.500729, -0.124583)
|
||||
|
||||
# Send a sticker
|
||||
app.send_sticker("me", "CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE")
|
@ -26,7 +26,6 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||
),
|
||||
url="https://docs.pyrogram.org/intro/install",
|
||||
description="How to install Pyrogram",
|
||||
thumb_url="https://i.imgur.com/JyxrStE.png",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[InlineKeyboardButton(
|
||||
@ -43,7 +42,6 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||
),
|
||||
url="https://docs.pyrogram.org/start/invoking",
|
||||
description="How to use Pyrogram",
|
||||
thumb_url="https://i.imgur.com/JyxrStE.png",
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[InlineKeyboardButton(
|
||||
|
@ -11,8 +11,8 @@ This example shows how to query an inline bot (as user).
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
# Get bot results for "Fuzz Universe" from the inline bot @vid
|
||||
bot_results = app.get_inline_bot_results("vid", "Fuzz Universe")
|
||||
# Get bot results for "hello" from the inline bot @vid
|
||||
bot_results = app.get_inline_bot_results("vid", "hello")
|
||||
|
||||
# Send the first result (bot_results.results[0]) to your own chat (Saved Messages)
|
||||
app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id)
|
@ -8,7 +8,7 @@ to make it only work for specific messages in a specific chat.
|
||||
|
||||
from pyrogram import Client, emoji, filters
|
||||
|
||||
TARGET = "PyrogramChat" # Target chat. Can also be a list of multiple chat ids/usernames
|
||||
TARGET = -100123456789 # Target chat. Can also be a list of multiple chat ids/usernames
|
||||
MENTION = "[{}](tg://user?id={})" # User mention markup
|
||||
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.org/)'s group chat {}!" # Welcome message
|
||||
|
||||
|
@ -2,7 +2,7 @@ Calling Methods
|
||||
===============
|
||||
|
||||
At this point, we have successfully :doc:`installed Pyrogram <../intro/install>` and :doc:`authorized <auth>` our
|
||||
account; we are now aiming towards the core of the library. It's time to start playing with the API!
|
||||
account; we are now aiming towards the core of the framework.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -22,60 +22,53 @@ Making API method calls with Pyrogram is very simple. Here's a basic example we
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
app.send_message("me", "Hi!")
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
Basic step-by-step
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
app.run(main())
|
||||
|
||||
#. Let's begin by importing the Client class:
|
||||
Step-by-step
|
||||
^^^^^^^^^^^^
|
||||
|
||||
#. Let's begin by importing the Client class.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
#. Now instantiate a new Client object, "my_account" is a session name of your choice:
|
||||
#. Now instantiate a new Client object, "my_account" is a session name of your choice.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
#. The ``with`` context manager is a shortcut for starting, executing and stopping the Client:
|
||||
#. Async methods can't be executed at the top level, because they must be inside an async context.
|
||||
Here we define an async function and put our code inside. Also notice the ``await`` keyword in front of the method
|
||||
call; this is required for all asynchronous methods.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with app:
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
#. Now, you can call any method you like:
|
||||
#. Finally, we tell Python to schedule our ``main()`` async function by using Pyrogram's :meth:`~pyrogram.Client.run`
|
||||
method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.send_message("me", "Hi!")
|
||||
app.run(main())
|
||||
|
||||
Context Manager
|
||||
---------------
|
||||
|
||||
The ``with`` statement starts a context manager used as a shortcut to automatically call :meth:`~pyrogram.Client.start`
|
||||
and :meth:`~pyrogram.Client.stop`, which are methods required for Pyrogram to work properly. The context manager does
|
||||
also gracefully stop the client, even in case of unhandled exceptions in your code.
|
||||
The ``async with`` statement starts a context manager, which is used as a shortcut for starting, executing and stopping
|
||||
the Client, asynchronously. It does so by automatically calling :meth:`~pyrogram.Client.start` and
|
||||
:meth:`~pyrogram.Client.stop` in a more convenient way which also gracefully stops the client, even in case of
|
||||
unhandled exceptions in your code.
|
||||
|
||||
This is how Pyrogram looks without the context manager:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
app.start()
|
||||
app.send_message("me", "Hi!")
|
||||
app.stop()
|
||||
|
||||
Asynchronous Calls
|
||||
------------------
|
||||
|
||||
In case you want Pyrogram to run asynchronously (e.g.: if you are using third party libraries that require you to call
|
||||
them with ``await``), use the asynchronous context manager:
|
||||
Below there's the same example as above, but without the use of the context manager:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -84,36 +77,48 @@ them with ``await``), use the asynchronous context manager:
|
||||
app = Client("my_account")
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
await app.start()
|
||||
await app.send_message("me", "Hi!")
|
||||
await app.stop()
|
||||
|
||||
app.run(main())
|
||||
|
||||
Asynchronous step-by-step
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Using asyncio.run()
|
||||
-------------------
|
||||
|
||||
#. Import the Client class and create an instance:
|
||||
Alternatively to the :meth:`~pyrogram.Client.run` method, you can use Python's ``asyncio.run()`` to execute the main
|
||||
function, with one little caveat: the Client instance (and possibly other asyncio resources you are going to use) must
|
||||
be instantiated inside the main function.
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
import asyncio
|
||||
from pyrogram import Client
|
||||
|
||||
async def main():
|
||||
app = Client("my_account")
|
||||
|
||||
#. Async methods can't normally be executed at the top level, because they must be inside an async-defined function;
|
||||
here we define one and put our code inside; the context manager is also being used differently in asyncio and
|
||||
method calls require the await keyword:
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
|
||||
.. code-block:: python
|
||||
asyncio.run(main())
|
||||
|
||||
async def main():
|
||||
async with app:
|
||||
await app.send_message("me", "Hi!")
|
||||
Synchronous Calls
|
||||
------------------
|
||||
|
||||
#. Finally, we tell Python to schedule our ``main()`` async function, which in turn will execute Pyrogram's methods.
|
||||
Using :meth:`~pyrogram.Client.run` this way is a friendly alternative for the much more verbose
|
||||
``asyncio.get_event_loop().run_until_complete(main())``:
|
||||
Pyrogram is an asynchronous framework, but it also provides a convenience way for calling methods without the need
|
||||
of async/await keywords and the extra boilerplate. In case you want Pyrogram to run synchronously, simply use the
|
||||
synchronous context manager:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
app.run(main())
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
app.send_message("me", "Hi!")
|
||||
|
||||
As you can see, the non-async example becomes less cluttered. Use Pyrogram in this non-asynchronous way only when you
|
||||
want to write something without the boilerplate or in case you want to combine Pyrogram with other libraries that are
|
||||
not async.
|
@ -1,8 +1,8 @@
|
||||
Handling Updates
|
||||
================
|
||||
|
||||
Calling :doc:`API methods <invoking>` sequentially is cool, but how to react when, for example, a new message arrives?
|
||||
This page deals with updates and how to handle such events in Pyrogram. Let's have a look at how they work.
|
||||
Calling :doc:`API methods <invoking>` sequentially is one way to use Pyrogram, but how to react when, for example, a
|
||||
new message arrives? This page deals with updates and how to handle such events in Pyrogram.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -14,10 +14,9 @@ This page deals with updates and how to handle such events in Pyrogram. Let's ha
|
||||
Defining Updates
|
||||
----------------
|
||||
|
||||
First, let's define what are these updates. As hinted already, updates are simply events that happen in your Telegram
|
||||
account (incoming messages, new members join, bot button presses, etc...), which are meant to notify you about a new
|
||||
specific state that has changed. These updates are handled by registering one or more callback functions in your app
|
||||
using :doc:`Handlers <../api/handlers>`.
|
||||
As hinted already, updates are simply events that happen in your Telegram account (incoming messages, new members join,
|
||||
bot button presses, etc.), which are meant to notify you about a new specific state that has changed. These updates are
|
||||
handled by registering one or more callback functions in your app using :doc:`Handlers <../api/handlers>`.
|
||||
|
||||
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
|
||||
function will be called back by the framework and its body executed.
|
||||
@ -40,50 +39,51 @@ The most elegant way to register a message handler is by using the :meth:`~pyrog
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
|
||||
@app.on_message()
|
||||
def my_handler(client, message):
|
||||
message.forward("me")
|
||||
|
||||
async def my_handler(client, message):
|
||||
await message.forward("me")
|
||||
|
||||
app.run()
|
||||
|
||||
The defined function ``my_handler``, which accepts the two arguments *(client, message)*, will be the function that gets
|
||||
executed every time a new message arrives.
|
||||
|
||||
Asynchronous handlers
|
||||
In the last line we see again the :meth:`~pyrogram.Client.run` method, this time used without any argument.
|
||||
Its purpose here is simply to automatically :meth:`~pyrogram.Client.start`, keep the Client online so that it can listen
|
||||
for updates and :meth:`~pyrogram.Client.stop` it once you hit ``CTRL+C``.
|
||||
|
||||
Synchronous handlers
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can also have asynchronous handlers; you only need to define the callback function using ``async def`` and call API
|
||||
methods by placing ``await`` in front of them:
|
||||
You can also have synchronous handlers; you only need to define the callback function without using ``async def`` and
|
||||
call API methods by not placing ``await`` in front of them:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_message()
|
||||
async def my_handler(client, message):
|
||||
await message.forward("me")
|
||||
def my_handler(client, message):
|
||||
message.forward("me")
|
||||
|
||||
.. note::
|
||||
|
||||
You can mix ``def`` and ``async def`` handlers as much as you need, Pyrogram will still work concurrently and
|
||||
efficiently regardless of what you choose.
|
||||
You can mix ``def`` and ``async def`` handlers as much as you like, Pyrogram will still work concurrently and
|
||||
efficiently regardless of what you choose. However, it is recommended to use Pyrogram in its native, asynchronous
|
||||
form at all times, unless you want to write something without the boilerplate or in case you want to combine
|
||||
Pyrogram with other libraries that are not async.
|
||||
|
||||
Using add_handler()
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback
|
||||
function and registers it in your Client. It is useful in case you want to programmatically add handlers (or in case,
|
||||
for some reason, you don't like to use decorators).
|
||||
function and registers it in your Client. It is useful in case you want to programmatically add handlers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.handlers import MessageHandler
|
||||
|
||||
|
||||
def my_function(client, message):
|
||||
message.forward("me")
|
||||
|
||||
async def my_function(client, message):
|
||||
await message.forward("me")
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
@ -92,12 +92,12 @@ for some reason, you don't like to use decorators).
|
||||
|
||||
app.run()
|
||||
|
||||
The same about asynchronous handlers applies for :meth:`~pyrogram.Client.add_handler`:
|
||||
The same about synchronous handlers applies for :meth:`~pyrogram.Client.add_handler`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
async def my_function(client, message):
|
||||
await message.forward("me")
|
||||
def my_function(client, message):
|
||||
message.forward("me")
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -1,66 +1,62 @@
|
||||
Support Pyrogram
|
||||
================
|
||||
|
||||
As a developer, you probably understand that "open source" doesn't mean "free work". If you wish to tip me for Pyrogram
|
||||
-- or any of my `other works`_ -- you can do so by the ways shown below. Your appreciation means a lot and helps
|
||||
staying motivated!
|
||||
.. raw:: html
|
||||
|
||||
--- `Dan`_
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
|
||||
<div style="float: right; margin-bottom: 10px">
|
||||
<a class="github-button"
|
||||
href="https://github.com/pyrogram/pyrogram/fork"
|
||||
data-icon="octicon-repo-forked" data-size="large" data-show-count="true"
|
||||
aria-label="Fork pyrogram/pyrogram on GitHub">Fork</a>
|
||||
|
||||
<a class="github-button"
|
||||
href="https://github.com/pyrogram/pyrogram"
|
||||
data-icon="octicon-star" data-size="large"
|
||||
data-show-count="true" aria-label="Star pyrogram/pyrogram on GitHub">Star</a>
|
||||
</div>
|
||||
|
||||
<br style="clear: both"/>
|
||||
|
||||
Pyrogram is a free and open source project.
|
||||
If you enjoy Pyrogram and would like to show your appreciation, consider donating or becoming
|
||||
a sponsor of the project. You can support Pyrogram via the ways shown below:
|
||||
|
||||
-----
|
||||
|
||||
Star
|
||||
----
|
||||
GitHub Sponsor
|
||||
--------------
|
||||
|
||||
Pyrogram is free and open source software, and thus powered by your love and support! If you like the project and have
|
||||
found it to be useful, give Pyrogram a `Star on GitHub`_.
|
||||
`Become a GitHub sponsor <https://github.com/sponsors/delivrance>`_.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<a class="github-button" href="https://github.com/pyrogram/pyrogram" data-size="large" data-show-count="true" aria-label="Star pyrogram/pyrogram on GitHub">Star</a>
|
||||
<br><br>
|
||||
<a class="github-button"
|
||||
href="https://github.com/sponsors/delivrance"
|
||||
data-icon="octicon-heart"
|
||||
data-size="large"
|
||||
aria-label="Sponsor @delivrance on GitHub">
|
||||
Sponsor</a>
|
||||
|
||||
-----
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
LiberaPay Patron
|
||||
----------------
|
||||
|
||||
You can become a GitHub sponsor:
|
||||
`Become a LiberaPay patron <https://liberapay.com/delivrance>`_.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe
|
||||
src="https://github.com/sponsors/delivrance/button"
|
||||
title="Sponsor delivrance"
|
||||
height="40" width="120"
|
||||
style="border: 0px; padding-top: 5px; margin-top: -5px">
|
||||
</iframe>
|
||||
<script src="https://liberapay.com/delivrance/widgets/button.js"></script>
|
||||
|
||||
-----
|
||||
|
||||
Donate
|
||||
------
|
||||
OpenCollective Backer
|
||||
---------------------
|
||||
|
||||
You can donate via PayPal using the button below:
|
||||
`Become an OpenCollective backer <https://opencollective.com/pyrogram>`_
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
||||
<input type="hidden" name="hosted_button_id" value="WMKAVFE47XEML" />
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
|
||||
<img alt="" border="0" src="https://www.paypal.com/en_IT/i/scr/pixel.gif" width="1" height="1" />
|
||||
</form>
|
||||
|
||||
-----
|
||||
|
||||
Cloud Credits
|
||||
-------------
|
||||
|
||||
If you need a cloud server to host your applications, try **Hetzner Cloud**. You can sign up with
|
||||
`this link <https://hetzner.cloud/?ref=9CyT92gZEINU>`_ to get €20 in cloud credits and help support Pyrogram and
|
||||
my `other projects`_.
|
||||
|
||||
.. _Star on GitHub: https://github.com/pyrogram/pyrogram
|
||||
.. _other projects: https://github.com/delivrance
|
||||
.. _other works: https://github.com/delivrance
|
||||
.. _Dan: https://t.me/haskell
|
||||
<script src="https://opencollective.com/pyrogram/banner.js"></script>
|
@ -1,9 +1,8 @@
|
||||
Advanced Usage
|
||||
==============
|
||||
|
||||
Pyrogram's API, which consists of well documented convenience :doc:`methods <../api/methods/index>` and facade
|
||||
:doc:`types <../api/types/index>`, exists to provide a much easier interface to the undocumented and often confusing
|
||||
Telegram API.
|
||||
Pyrogram's API -- which consists of well documented :doc:`methods <../api/methods/index>` and
|
||||
:doc:`types <../api/types/index>` -- exists to provide an easier interface to the more complex Telegram API.
|
||||
|
||||
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main "raw"
|
||||
Telegram API with its functions and types.
|
||||
@ -21,25 +20,18 @@ Telegram Raw API
|
||||
If you can't find a high-level method for your needs or if you want complete, low-level access to the whole
|
||||
Telegram API, you have to use the raw :mod:`~pyrogram.raw.functions` and :mod:`~pyrogram.raw.types`.
|
||||
|
||||
As already hinted, raw functions and types can be really confusing, mainly because people don't realize soon enough they
|
||||
accept *only* the right types and that all required parameters must be filled in. This section will therefore explain
|
||||
some pitfalls to take into consideration when working with the raw API.
|
||||
As already hinted, raw functions and types can be less convenient. This section will therefore explain some pitfalls to
|
||||
take into consideration when working with the raw API.
|
||||
|
||||
.. hint::
|
||||
.. tip::
|
||||
|
||||
Every available high-level methods in Pyrogram is built on top of these raw functions.
|
||||
|
||||
Nothing stops you from using the raw functions only, but they are rather complex and
|
||||
:doc:`plenty of them <../api/methods/index>` are already re-implemented by providing a much simpler and cleaner
|
||||
interface which is very similar to the Bot API (yet much more powerful).
|
||||
|
||||
If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
|
||||
Every available high-level method in Pyrogram is built on top of these raw functions.
|
||||
|
||||
Invoking Functions
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
------------------
|
||||
|
||||
Unlike the :doc:`methods <../api/methods/index>` found in Pyrogram's API, which can be called in the usual simple way,
|
||||
functions to be invoked from the raw Telegram API have a different way of usage and are more complex.
|
||||
functions to be invoked from the raw Telegram API have a different way of usage.
|
||||
|
||||
First of all, both :doc:`raw functions <../telegram/functions/index>` and :doc:`raw types <../telegram/types/index>`
|
||||
live in their respective packages (and sub-packages): ``pyrogram.raw.functions``, ``pyrogram.raw.types``. They all exist
|
||||
@ -61,12 +53,12 @@ Here's some examples:
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.UpdateProfile(
|
||||
first_name="Dan", last_name="Tès",
|
||||
about="Bio written from Pyrogram"
|
||||
first_name="First Name", last_name="Last Name",
|
||||
about="New bio text"
|
||||
)
|
||||
)
|
||||
|
||||
- Disable links to your account when someone forwards your messages:
|
||||
- Set online/offline status:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -74,14 +66,13 @@ Here's some examples:
|
||||
from pyrogram.raw import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.SetPrivacy(
|
||||
key=types.PrivacyKeyForwards(),
|
||||
rules=[types.InputPrivacyValueDisallowAll()]
|
||||
)
|
||||
)
|
||||
# Set online status
|
||||
app.send(functions.account.UpdateStatus(offline=False))
|
||||
|
||||
- Invite users to your channel/supergroup:
|
||||
# Set offline status
|
||||
app.send(functions.account.UpdateStatus(offline=True))
|
||||
|
||||
- Get chat info:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -89,21 +80,18 @@ Here's some examples:
|
||||
from pyrogram.raw import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.channels.InviteToChannel(
|
||||
channel=app.resolve_peer(123456789), # ID or Username
|
||||
users=[ # The users you want to invite
|
||||
app.resolve_peer(23456789), # By ID
|
||||
app.resolve_peer("username"), # By username
|
||||
app.resolve_peer("+393281234567"), # By phone number
|
||||
]
|
||||
r = app.send(
|
||||
functions.channels.GetFullChannel(
|
||||
channel=app.resolve_peer("username")
|
||||
)
|
||||
)
|
||||
|
||||
print(r)
|
||||
|
||||
Chat IDs
|
||||
^^^^^^^^
|
||||
--------
|
||||
|
||||
The way Telegram works makes it impossible to directly send a message to a user or a chat by using their IDs only.
|
||||
The way Telegram works makes it not possible to directly send a message to a user or a chat by using their IDs only.
|
||||
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed. Pyrogram allows
|
||||
sending messages with IDs only thanks to cached access hashes.
|
||||
|
||||
@ -112,18 +100,17 @@ Whenever an InputPeer is needed you must pass one of these:
|
||||
|
||||
- :class:`~pyrogram.raw.types.InputPeerUser` - Users
|
||||
- :class:`~pyrogram.raw.types.InputPeerChat` - Basic Chats
|
||||
- :class:`~pyrogram.raw.types.InputPeerChannel` - Either Channels or Supergroups
|
||||
- :class:`~pyrogram.raw.types.InputPeerChannel` - Channels & Supergroups
|
||||
|
||||
But you don't necessarily have to manually instantiate each object because, luckily for you, Pyrogram already provides
|
||||
But you don't necessarily have to manually instantiate each object because Pyrogram already provides
|
||||
:meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer
|
||||
by accepting a peer ID only.
|
||||
|
||||
Another thing to take into consideration about chat IDs is the way they are represented: they are all integers and
|
||||
all positive within their respective raw types.
|
||||
|
||||
Things are different when working with Pyrogram's API because having them in the same space can theoretically lead to
|
||||
collisions, and that's why Pyrogram (as well as the official Bot API) uses a slightly different representation for each
|
||||
kind of ID.
|
||||
Things are different when working with Pyrogram's API because having them in the same space could lead to
|
||||
collisions, and that's why Pyrogram uses a slightly different representation for each kind of ID.
|
||||
|
||||
For example, given the ID *123456789*, here's how Pyrogram can tell entities apart:
|
||||
|
||||
|
@ -1,50 +0,0 @@
|
||||
Bots Interaction
|
||||
================
|
||||
|
||||
Users can interact with other bots via plain text messages as well as inline queries.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
:depth: 1
|
||||
:local:
|
||||
|
||||
-----
|
||||
|
||||
Inline Bots
|
||||
-----------
|
||||
|
||||
- If a bot accepts inline queries, you can call it by using
|
||||
:meth:`~pyrogram.Client.get_inline_bot_results` to get the list of its inline results for a query:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Get bot results for "Fuzz Universe" from the inline bot @vid
|
||||
bot_results = app.get_inline_bot_results("vid", "Fuzz Universe")
|
||||
|
||||
.. figure:: https://i.imgur.com/IAqLs54.png
|
||||
:width: 90%
|
||||
:align: center
|
||||
:figwidth: 60%
|
||||
|
||||
``get_inline_bot_results()`` is the equivalent action of writing ``@vid Fuzz Universe`` and getting the
|
||||
results list.
|
||||
|
||||
- After you retrieved the bot results, you can use
|
||||
:meth:`~pyrogram.Client.send_inline_bot_result` to send a chosen result to any chat:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Send the first result to your own chat
|
||||
app.send_inline_bot_result(
|
||||
"me",
|
||||
bot_results.query_id,
|
||||
bot_results.results[0].id
|
||||
)
|
||||
|
||||
.. figure:: https://i.imgur.com/wwxr7B7.png
|
||||
:width: 90%
|
||||
:align: center
|
||||
:figwidth: 60%
|
||||
|
||||
``send_inline_bot_result()`` is the equivalent action of choosing a result from the list and sending it
|
||||
to a chat.
|
@ -1,24 +1,12 @@
|
||||
Session Settings
|
||||
================
|
||||
Client Settings
|
||||
===============
|
||||
|
||||
As you may probably know, Telegram allows users (and bots) having more than one session (authorizations) registered
|
||||
in the system at the same time.
|
||||
You can control the way your client appears in the Active Sessions menu of an official client by changing some client
|
||||
settings. By default you will see something like the following:
|
||||
|
||||
Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official
|
||||
app (or by invoking :class:`~pyrogram.api.functions.account.GetAuthorizations` with Pyrogram). They
|
||||
store some useful information such as the client who's using them and from which country and IP address.
|
||||
|
||||
.. figure:: https://i.imgur.com/YaqtMLO.png
|
||||
:width: 600
|
||||
:align: center
|
||||
|
||||
**A Pyrogram session running on Linux, Python 3.7.**
|
||||
|
||||
That's how a session looks like on the Android app, showing the three main pieces of information.
|
||||
|
||||
- ``app_version``: **Pyrogram 0.13.0**
|
||||
- ``device_model``: **CPython 3.7.2**
|
||||
- ``system_version``: **Linux 4.15.0-23-generic**
|
||||
- Device Model: ``CPython x.y.z``
|
||||
- Application: ``Pyrogram x.y.z``
|
||||
- System Version: ``Linux x.y.z``
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
@ -15,7 +15,7 @@ Introduction
|
||||
------------
|
||||
|
||||
The idea behind using a configuration file is to help keeping your code free of private settings information such as
|
||||
the API Key and Proxy, without having you to even deal with how to load such settings. The configuration file, usually
|
||||
the API Key and Proxy, without having you to deal with how to load such settings. The configuration file, usually
|
||||
referred as ``config.ini`` file, is automatically loaded from the root of your working directory; all you need to do is
|
||||
fill in the necessary parts.
|
||||
|
||||
@ -23,7 +23,7 @@ fill in the necessary parts.
|
||||
|
||||
The configuration file is optional, but recommended. If, for any reason, you prefer not to use it, there's always an
|
||||
alternative way to configure Pyrogram via Client's parameters. Doing so, you can have full control on how to store
|
||||
and load your settings (e.g.: from environment variables).
|
||||
and load your settings.
|
||||
|
||||
Settings specified via Client's parameter have higher priority and will override any setting stored in the
|
||||
configuration file.
|
||||
|
@ -87,7 +87,7 @@ Finally, the filter usage remains the same:
|
||||
Filters with Arguments
|
||||
----------------------
|
||||
|
||||
A much cooler filter would be one that accepts "pyrogram" or any other string as argument at usage time.
|
||||
A more flexible filter would be one that accepts "pyrogram" or any other string as argument at usage time.
|
||||
A dynamic filter like this will make use of named arguments for the :meth:`~pyrogram.filters.create` method and the
|
||||
first argument of the callback function, which is a reference to the filter object itself holding the extra data passed
|
||||
via named arguments.
|
||||
|
@ -2,7 +2,7 @@ Debugging
|
||||
=========
|
||||
|
||||
When working with the API, chances are you'll stumble upon bugs, get stuck and start wondering how to continue. Nothing
|
||||
to actually worry about -- that's normal -- and luckily for you, Pyrogram provides some commodities to help you in this.
|
||||
to actually worry about since Pyrogram provides some commodities to help you in this.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -27,8 +27,8 @@ Consider the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dan = app.get_users("haskell")
|
||||
print(dan) # User
|
||||
me = app.get_users("me")
|
||||
print(me) # User
|
||||
|
||||
This will show a JSON representation of the object returned by :meth:`~pyrogram.Client.get_users`, which is a
|
||||
:class:`~pyrogram.types.User` instance, in this case. The output on your terminal will be something similar to this:
|
||||
@ -36,9 +36,9 @@ This will show a JSON representation of the object returned by :meth:`~pyrogram.
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_": "pyrogram.User",
|
||||
"id": 23122162,
|
||||
"is_self": false,
|
||||
"_": "User",
|
||||
"id": 123456789,
|
||||
"is_self": true,
|
||||
"is_contact": false,
|
||||
"is_mutual_contact": false,
|
||||
"is_deleted": false,
|
||||
@ -46,19 +46,13 @@ This will show a JSON representation of the object returned by :meth:`~pyrogram.
|
||||
"is_verified": false,
|
||||
"is_restricted": false,
|
||||
"is_support": false,
|
||||
"is_scam": false,
|
||||
"first_name": "Dan",
|
||||
"status": {
|
||||
"_": "pyrogram.UserStatus",
|
||||
"user_id": 23122162,
|
||||
"recently": true
|
||||
},
|
||||
"username": "haskell",
|
||||
"language_code": "en",
|
||||
"first_name": "Pyrogram",
|
||||
"photo": {
|
||||
"_": "pyrogram.ChatPhoto",
|
||||
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
|
||||
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
|
||||
"_": "ChatPhoto",
|
||||
"small_file_id": "AbCdE...EdCbA",
|
||||
"small_photo_unique_id": "VwXyZ...ZyXwV",
|
||||
"big_file_id": "AbCdE...EdCbA",
|
||||
"big_photo_unique_id": "VwXyZ...ZyXwV"
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,37 +63,23 @@ Accessing Attributes
|
||||
--------------------
|
||||
|
||||
Even though you see a JSON output, it doesn't mean we are dealing with dictionaries; in fact, all Pyrogram types are
|
||||
full-fledged Python objects and the correct way to access any attribute of them is by using the dot notation ``.``:
|
||||
fully-fledged Python objects and the correct way to access any attribute of them is by using the dot notation ``.``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dan_photo = dan.photo
|
||||
print(dan_photo) # ChatPhoto
|
||||
photo = me.photo
|
||||
print(photo) # ChatPhoto
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_": "pyrogram.ChatPhoto",
|
||||
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
|
||||
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
|
||||
"_": "ChatPhoto",
|
||||
"small_file_id": "AbCdE...EdCbA",
|
||||
"small_photo_unique_id": "VwXyZ...ZyXwV",
|
||||
"big_file_id": "AbCdE...EdCbA",
|
||||
"big_photo_unique_id": "VwXyZ...ZyXwV"
|
||||
}
|
||||
|
||||
However, the bracket notation ``[]`` is also supported, but its usage is discouraged:
|
||||
|
||||
.. warning::
|
||||
|
||||
Bracket notation in Python is not commonly used for getting/setting object attributes. While it works for Pyrogram
|
||||
objects, it might not work for anything else and you should not rely on this.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dan_photo_big = dan["photo"]["big_file_id"]
|
||||
print(dan_photo_big) # str
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg
|
||||
|
||||
Checking an Object's Type
|
||||
-------------------------
|
||||
|
||||
@ -111,8 +91,8 @@ error. The correct way to get the object type is by using the built-in function
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dan_status = dan.status
|
||||
print(type(dan_status))
|
||||
status = me.status
|
||||
print(type(status))
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@ -125,8 +105,8 @@ And to check if an object is an instance of a given class, you use the built-in
|
||||
|
||||
from pyrogram.types import UserStatus
|
||||
|
||||
dan_status = dan.status
|
||||
print(isinstance(dan_status, UserStatus))
|
||||
status = me.status
|
||||
print(isinstance(status, UserStatus))
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
|
@ -24,7 +24,6 @@ group. Dispatching groups hold one or more handlers and are processed sequential
|
||||
For example, take these two handlers:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 1, 6
|
||||
|
||||
@app.on_message(filters.text | filters.sticker)
|
||||
def text_or_sticker(client, message):
|
||||
|
@ -1,10 +1,10 @@
|
||||
MTProto vs. Bot API
|
||||
===================
|
||||
|
||||
Pyrogram is a framework that acts as a fully-fledged Telegram client based on MTProto, and this very feature makes it
|
||||
already superior to, what is usually called, the official Bot API, in many respects. This page will therefore show you
|
||||
why Pyrogram might be a better choice for your project by comparing the two APIs, but first, let's make it clear what
|
||||
actually is the MTProto and the Bot API.
|
||||
Pyrogram is a framework written from the ground up that acts as a fully-fledged Telegram client based on the MTProto
|
||||
API. This means that Pyrogram is able to execute any official client and bot API action and more. This page will
|
||||
therefore show you why Pyrogram might be a better choice for your project by comparing the two APIs, but first, let's
|
||||
make it clear what actually is the MTProto and the Bot API.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -19,10 +19,11 @@ What is the MTProto API?
|
||||
`MTProto`_, took alone, is the name of the custom-made, open and encrypted communication protocol created by Telegram
|
||||
itself --- it's the only protocol used to exchange information between a client and the actual Telegram servers.
|
||||
|
||||
The MTProto **API** on the other hand, is what people, for convenience, call the main Telegram API as a whole. This API
|
||||
is able to authorize both users and bots and is built on top of the MTProto encryption protocol by means of
|
||||
`binary data serialized`_ in a specific way, as described by the `TL language`_, and delivered using UDP, TCP or even
|
||||
HTTP as transport-layer protocol.
|
||||
The MTProto API on the other hand, is what people for convenience call the main Telegram API in order to distinguish it
|
||||
from the Bot API. The main Telegram API is able to authorize both users and bots and is built on top of the MTProto
|
||||
encryption protocol by means of `binary data serialized`_ in a specific way, as described by the `TL language`_, and
|
||||
delivered using UDP, TCP or even HTTP as transport-layer protocol. Clients that make use of Telegram's main API, such as
|
||||
Pyrogram, implement all these details.
|
||||
|
||||
.. _MTProto: https://core.telegram.org/mtproto
|
||||
.. _binary data serialized: https://core.telegram.org/mtproto/serialize
|
||||
@ -31,12 +32,12 @@ HTTP as transport-layer protocol.
|
||||
What is the Bot API?
|
||||
--------------------
|
||||
|
||||
The `Bot API`_ is an HTTP(S) interface for building normal bots using a sub-set of the main MTProto API. Bots are special
|
||||
accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the main
|
||||
Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram servers
|
||||
using MTProto.
|
||||
The `Bot API`_ is an HTTP(S) interface for building normal bots using a sub-set of the main Telegram API. Bots are
|
||||
special accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the
|
||||
main Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram
|
||||
servers using MTProto.
|
||||
|
||||
.. figure:: https://i.imgur.com/WvwBoZo.png
|
||||
.. figure:: //_static/img/mtproto-vs-bot-api.png
|
||||
:align: center
|
||||
|
||||
.. _Bot API: https://core.telegram.org/bots/api
|
||||
@ -44,8 +45,8 @@ using MTProto.
|
||||
Advantages of the MTProto API
|
||||
-----------------------------
|
||||
|
||||
Here is a list of all the advantages in using MTProto-based libraries -- such as Pyrogram -- instead of the official
|
||||
HTTP Bot API. Using Pyrogram you can:
|
||||
Here is a non-exhaustive list of all the advantages in using MTProto-based libraries -- such as Pyrogram -- instead of
|
||||
the official HTTP Bot API. Using Pyrogram you can:
|
||||
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
@ -69,7 +70,7 @@ HTTP Bot API. Using Pyrogram you can:
|
||||
.. hlist::
|
||||
:columns: 1
|
||||
|
||||
- :guilabel:`+` **Run multiple sessions at once, up to 10 per account (either bot or user)**
|
||||
- :guilabel:`+` **Run multiple sessions at once (for both user and bot identities)**
|
||||
- :guilabel:`--` The Bot API intermediate server will terminate any other session in case you try to use the same
|
||||
bot again in a parallel connection.
|
||||
|
||||
|
@ -14,8 +14,8 @@ non-asynchronous contexts. For more detailed information, you can visit and lear
|
||||
|
||||
-----
|
||||
|
||||
Using ``apscheduler``
|
||||
---------------------
|
||||
Using apscheduler
|
||||
-----------------
|
||||
|
||||
- Install with ``pip3 install apscheduler``
|
||||
- Documentation: https://apscheduler.readthedocs.io
|
||||
|
@ -24,8 +24,7 @@ If you want a nicely formatted, human readable JSON representation of any object
|
||||
...
|
||||
|
||||
with app:
|
||||
r = app.get_chat("haskell")
|
||||
|
||||
r = app.get_chat("me")
|
||||
print(str(r))
|
||||
|
||||
.. tip::
|
||||
@ -48,7 +47,7 @@ as the process requires the package to be in scope.
|
||||
...
|
||||
|
||||
with app:
|
||||
r = app.get_chat("haskell")
|
||||
r = app.get_chat("me")
|
||||
|
||||
print(repr(r))
|
||||
print(eval(repr(r)) == r) # True
|
||||
|
@ -1,9 +1,9 @@
|
||||
Smart Plugins
|
||||
=============
|
||||
|
||||
Pyrogram embeds a **smart**, lightweight yet powerful plugin system that is meant to further simplify the organization
|
||||
of large projects and to provide a way for creating pluggable (modular) components that can be **easily shared** across
|
||||
different Pyrogram applications with **minimal boilerplate code**.
|
||||
Pyrogram embeds a smart, lightweight yet powerful plugin system that is meant to further simplify the organization
|
||||
of large projects and to provide a way for creating pluggable (modular) components that can be easily shared across
|
||||
different Pyrogram applications with minimal boilerplate code.
|
||||
|
||||
.. tip::
|
||||
|
||||
@ -74,8 +74,8 @@ after importing your modules, like this:
|
||||
|
||||
This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
|
||||
manually ``import``, manually :meth:`~pyrogram.Client.add_handler` and manually instantiate each
|
||||
:class:`~pyrogram.handlers.MessageHandler` object because **you can't use those cool decorators** for your
|
||||
functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
|
||||
:class:`~pyrogram.handlers.MessageHandler` object because you can't use decorators for your functions.
|
||||
So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
|
||||
|
||||
Using Smart Plugins
|
||||
-------------------
|
||||
@ -91,7 +91,6 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
|
||||
This is the same example application as shown above, written using the Smart Plugin system.
|
||||
|
||||
.. code-block:: text
|
||||
:emphasize-lines: 2, 3
|
||||
|
||||
myproject/
|
||||
plugins/
|
||||
@ -102,7 +101,6 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
|
||||
- ``plugins/handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4, 9
|
||||
|
||||
from pyrogram import Client, filters
|
||||
|
||||
@ -164,7 +162,7 @@ found inside each module will be, instead, loaded in the order they are defined,
|
||||
.. note::
|
||||
|
||||
Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping
|
||||
filters included a second time will not work. Learn more at :doc:`More on Updates <more-on-updates>`.
|
||||
filters included a second time will not work, by design. Learn more at :doc:`More on Updates <more-on-updates>`.
|
||||
|
||||
This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or
|
||||
exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude``
|
||||
@ -300,32 +298,30 @@ In the previous section we've explained how to specify which plugins to load and
|
||||
starts. Here we'll show, instead, how to unload and load again a previously registered plugin at runtime.
|
||||
|
||||
Each function decorated with the usual ``on_message`` decorator (or any other decorator that deals with Telegram
|
||||
updates) will be modified in such a way that a special ``handler`` attribute pointing to a tuple of
|
||||
updates) will be modified in such a way that a special ``handlers`` attribute pointing to a list of tuples of
|
||||
*(handler: Handler, group: int)* is attached to the function object itself.
|
||||
|
||||
- ``plugins/handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 5, 6
|
||||
|
||||
@Client.on_message(filters.text & filters.private)
|
||||
def echo(client, message):
|
||||
message.reply(message.text)
|
||||
|
||||
print(echo)
|
||||
print(echo.handler)
|
||||
print(echo.handlers)
|
||||
|
||||
- Printing ``echo`` will show something like ``<function echo at 0x10e3b6598>``.
|
||||
|
||||
- Printing ``echo.handler`` will reveal the handler, that is, a tuple containing the actual handler and the group it
|
||||
was registered on ``(<MessageHandler object at 0x10e3abc50>, 0)``.
|
||||
- Printing ``echo.handlers`` will reveal the handlers, that is, a list of tuples containing the actual handlers and
|
||||
the groups they were registered on ``[(<MessageHandler object at 0x10e3abc50>, 0)]``.
|
||||
|
||||
Unloading
|
||||
^^^^^^^^^
|
||||
|
||||
In order to unload a plugin, all you need to do is obtain a reference to it by importing the relevant module and call
|
||||
:meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* special attribute preceded by the
|
||||
star ``*`` operator as argument. Example:
|
||||
:meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* instance:
|
||||
|
||||
- ``main.py``
|
||||
|
||||
@ -333,16 +329,19 @@ star ``*`` operator as argument. Example:
|
||||
|
||||
from plugins.handlers import echo
|
||||
|
||||
...
|
||||
handlers = echo.handlers
|
||||
|
||||
app.remove_handler(*echo.handler)
|
||||
for h in handlers:
|
||||
app.remove_handler(*h)
|
||||
|
||||
The star ``*`` operator is used to unpack the tuple into positional arguments so that *remove_handler* will receive
|
||||
exactly what is needed. The same could have been achieved with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
handler, group = echo.handler
|
||||
handlers = echo.handlers
|
||||
handler, group = handlers[0]
|
||||
|
||||
app.remove_handler(handler, group)
|
||||
|
||||
Loading
|
||||
@ -359,4 +358,7 @@ using :meth:`~pyrogram.Client.add_handler` instead. Example:
|
||||
|
||||
...
|
||||
|
||||
app.add_handler(*echo.handler)
|
||||
handlers = echo.handlers
|
||||
|
||||
for h in handlers:
|
||||
app.add_handler(*h)
|
@ -18,28 +18,18 @@ Persisting Sessions
|
||||
In order to make a client reconnect successfully between restarts, that is, without having to start a new
|
||||
authorization process from scratch each time, Pyrogram needs to store the generated session data somewhere.
|
||||
|
||||
Other useful data being stored is peers' cache. In short, peers are all those entities you can chat with, such as users
|
||||
or bots, basic groups, but also channels and supergroups. Because of how Telegram works, a unique pair of **id** and
|
||||
**access_hash** is needed to contact a peer. This, plus other useful info such as the peer type, is what is stored
|
||||
inside a session storage.
|
||||
|
||||
So, if you ever wondered how is Pyrogram able to contact peers just by asking for their ids, it's because of this very
|
||||
reason: the peer *id* is looked up in the internal database and the available *access_hash* is retrieved, which is then
|
||||
used to correctly invoke API methods.
|
||||
|
||||
Different Storage Engines
|
||||
-------------------------
|
||||
|
||||
Let's now talk about how Pyrogram actually stores all the relevant data. Pyrogram offers two different types of storage
|
||||
engines: a **File Storage** and a **Memory Storage**. These engines are well integrated in the library and require a
|
||||
minimal effort to set up. Here's how they work:
|
||||
Pyrogram offers two different types of storage engines: a **File Storage** and a **Memory Storage**.
|
||||
These engines are well integrated in the framework and require a minimal effort to set up. Here's how they work:
|
||||
|
||||
File Storage
|
||||
^^^^^^^^^^^^
|
||||
|
||||
This is the most common storage engine. It is implemented by using **SQLite**, which will store the session and peers
|
||||
details. The database will be saved to disk as a single portable file and is designed to efficiently store and retrieve
|
||||
peers whenever they are needed.
|
||||
This is the most common storage engine. It is implemented by using **SQLite**, which will store the session details.
|
||||
The database will be saved to disk as a single portable file and is designed to efficiently store and retrieve
|
||||
data whenever they are needed.
|
||||
|
||||
To use this type of engine, simply pass any name of your choice to the ``session_name`` parameter of the
|
||||
:obj:`~pyrogram.Client` constructor, as usual:
|
||||
@ -68,8 +58,8 @@ session name "**:memory:**" to the ``session_name`` parameter of the :obj:`~pyro
|
||||
with Client(":memory:") as app:
|
||||
print(app.get_me())
|
||||
|
||||
This storage engine is still backed by SQLite, but the database exists purely in memory. This means that, once you stop a
|
||||
client, the entire database is discarded and the session details used for logging in again will be lost forever.
|
||||
This storage engine is still backed by SQLite, but the database exists purely in memory. This means that, once you stop
|
||||
a client, the entire database is discarded and the session details used for logging in again will be lost forever.
|
||||
|
||||
Session Strings
|
||||
---------------
|
||||
@ -84,8 +74,8 @@ In case you want to use an in-memory storage, but also want to keep access to th
|
||||
with Client(":memory:") as app:
|
||||
print(app.export_session_string())
|
||||
|
||||
...and save the resulting (quite long) string somewhere. You can use this string as session name the next time you want
|
||||
to login using the same session; the storage used will still be completely in-memory:
|
||||
...and save the resulting string. You can use this string as session name the next time you want to login
|
||||
using the same session; the storage used will still be in-memory:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -96,11 +86,5 @@ to login using the same session; the storage used will still be completely in-me
|
||||
with Client(session_string) as app:
|
||||
print(app.get_me())
|
||||
|
||||
Session strings are useful when you want to run authorized Pyrogram clients on platforms like
|
||||
`Heroku <https://www.heroku.com/>`_, where their ephemeral filesystems makes it much harder for a file-based storage
|
||||
engine to properly work as intended.
|
||||
|
||||
But, why is the session string so long? Can't it be shorter? No, it can't. The session string already packs the bare
|
||||
minimum data Pyrogram needs to successfully reconnect to an authorized session, and the 2048-bits auth key is the major
|
||||
contributor to the overall length. Needless to say that this string, as well as any other session storage, represent
|
||||
strictly personal data. Keep them safe.
|
||||
Session strings are useful when you want to run authorized Pyrogram clients on platforms where their ephemeral
|
||||
filesystems makes it harder for a file-based storage engine to properly work as intended.
|
||||
|
@ -15,8 +15,7 @@ Telegram's test servers without hassle. All you need to do is start a new sessio
|
||||
.. note::
|
||||
|
||||
If this is the first time you login into test servers, you will be asked to register your account first.
|
||||
Don't worry about your contacts and chats, they will be kept untouched inside the production environment;
|
||||
accounts authorized on test servers reside in a different, parallel instance of a Telegram database.
|
||||
Accounts registered on test servers reside in a different, parallel instance of a Telegram server.
|
||||
|
||||
.. contents:: Contents
|
||||
:backlinks: none
|
||||
@ -28,19 +27,15 @@ Telegram's test servers without hassle. All you need to do is start a new sessio
|
||||
Test Mode in Official Apps
|
||||
--------------------------
|
||||
|
||||
You can also login yourself into test servers using official desktop apps, such as Webogram and TDesktop:
|
||||
You can also login yourself into test servers using official desktop apps, such as Telegram Web and Telegram Desktop:
|
||||
|
||||
- **Webogram**: Login here: https://web.telegram.org/?test=1
|
||||
- **TDesktop**: Hold ``Alt+Shift`` and right click on "Add account", then choose "Test server".
|
||||
- **Telegram Web**: Login here: https://web.telegram.org/?test=1
|
||||
- **Telegram Desktop**: Hold ``Alt+Shift`` and right click on "Add account", then choose "Test server".
|
||||
|
||||
Test Numbers
|
||||
------------
|
||||
|
||||
Beside normal numbers, the test environment allows you to login with reserved test numbers.
|
||||
Valid phone numbers follow the pattern ``99966XYYYY``, where ``X`` is the DC number (1 to 3) and ``YYYY`` are random
|
||||
numbers. Users with such numbers always get ``XXXXX`` as the confirmation code (the DC number, repeated five times).
|
||||
|
||||
.. important::
|
||||
|
||||
Do not store any important or private information in such test users' accounts; anyone can make use of the
|
||||
simplified authorization mechanism and login at any time.
|
||||
numbers. Users with such numbers always get ``XXXXX`` or ``XXXXXX`` as the confirmation code (the DC number, repeated
|
||||
five or six times).
|
@ -14,7 +14,7 @@ Text Formatting
|
||||
:class: strike-italic
|
||||
|
||||
Pyrogram uses a custom Markdown dialect for text formatting which adds some unique features that make writing styled
|
||||
texts easier in both Markdown and HTML. You can send sophisticated text messages and media captions using a great
|
||||
texts easier in both Markdown and HTML. You can send sophisticated text messages and media captions using a
|
||||
variety of decorations that can also be nested in order to combine multiple styles together.
|
||||
|
||||
.. contents:: Contents
|
||||
@ -36,7 +36,7 @@ list of the basic styles currently supported by Pyrogram.
|
||||
- :underline:`underline`
|
||||
- spoiler
|
||||
- `text URL <https://pyrogram.org>`_
|
||||
- `user text mention <https://t.me/haskell>`_
|
||||
- `user text mention <tg://user?id=123456789>`_
|
||||
- ``inline fixed-width code``
|
||||
- .. code-block:: text
|
||||
|
||||
@ -66,9 +66,9 @@ To strictly use this mode, pass "markdown" to the *parse_mode* parameter when us
|
||||
|
||||
||spoiler||
|
||||
|
||||
[text URL](https://docs.pyrogram.org/)
|
||||
[text URL](https://pyrogram.org/)
|
||||
|
||||
[text user mention](tg://user?id=23122162)
|
||||
[text user mention](tg://user?id=123456789)
|
||||
|
||||
`inline fixed-width code`
|
||||
|
||||
@ -83,14 +83,13 @@ To strictly use this mode, pass "markdown" to the *parse_mode* parameter when us
|
||||
.. code-block:: python
|
||||
|
||||
app.send_message(
|
||||
"haskell",
|
||||
"me",
|
||||
(
|
||||
"**bold**, "
|
||||
"__italic__, "
|
||||
"--underline--, "
|
||||
"~~strike~~, "
|
||||
"||spoiler||, "
|
||||
"[mention](tg://user?id=23122162), "
|
||||
"[URL](https://pyrogram.org), "
|
||||
"`code`, "
|
||||
"```"
|
||||
@ -119,9 +118,9 @@ The following tags are currently supported:
|
||||
|
||||
<spoiler>spoiler</spoiler>
|
||||
|
||||
<a href="http://docs.pyrogram.org/">text URL</a>
|
||||
<a href="https://pyrogram.org/">text URL</a>
|
||||
|
||||
<a href="tg://user?id=23122162">inline mention</a>
|
||||
<a href="tg://user?id=123456789">inline mention</a>
|
||||
|
||||
<code>inline fixed-width code</code>
|
||||
|
||||
@ -136,14 +135,13 @@ The following tags are currently supported:
|
||||
.. code-block:: python
|
||||
|
||||
app.send_message(
|
||||
"haskell",
|
||||
"me",
|
||||
(
|
||||
"<b>bold</b>, "
|
||||
"<i>italic</i>, "
|
||||
"<u>underline</u>, "
|
||||
"<s>strike</s>, "
|
||||
"<spoiler>spoiler</spoiler>, "
|
||||
"<a href=\"tg://user?id=23122162\">mention</a>, "
|
||||
"<a href=\"https://pyrogram.org/\">URL</a>, "
|
||||
"<code>code</code>\n\n"
|
||||
"<pre>"
|
||||
@ -181,7 +179,7 @@ This means you can combine together both syntaxes in the same text:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.send_message("haskell", "**bold**, <i>italic</i>")
|
||||
app.send_message("me", "**bold**, <i>italic</i>")
|
||||
|
||||
Result:
|
||||
|
||||
@ -192,8 +190,8 @@ If you don't like this behaviour you can always choose to only enable either Mar
|
||||
|
||||
.. code-block::
|
||||
|
||||
app.send_message("haskell", "**bold**, <i>italic</i>", parse_mode="markdown")
|
||||
app.send_message("haskell", "**bold**, <i>italic</i>", parse_mode="html")
|
||||
app.send_message("me", "**bold**, <i>italic</i>", parse_mode="markdown")
|
||||
app.send_message("me", "**bold**, <i>italic</i>", parse_mode="html")
|
||||
|
||||
Result:
|
||||
|
||||
@ -206,7 +204,7 @@ as-is.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.send_message("haskell", "**bold**, <i>italic</i>", parse_mode=None)
|
||||
app.send_message("me", "**bold**, <i>italic</i>", parse_mode=None)
|
||||
|
||||
Result:
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
Fast Crypto
|
||||
===========
|
||||
|
||||
Pyrogram's speed can be *dramatically* boosted up by TgCrypto_, a high-performance, easy-to-install Telegram Crypto
|
||||
Library specifically written in C for Pyrogram [1]_ as a Python extension.
|
||||
Pyrogram's speed can be boosted up by TgCrypto_, a high-performance, easy-to-install cryptography library specifically
|
||||
written in C for Pyrogram as a Python extension.
|
||||
|
||||
TgCrypto is a replacement for the much slower PyAES and implements the crypto algorithms Telegram requires, namely
|
||||
**AES-IGE 256 bit** (used in MTProto v2.0) and **AES-CTR 256 bit** (used for CDN encrypted files).
|
||||
TgCrypto is a replacement for a slower Python-only alternative and implements the cryptographic algorithms Telegram
|
||||
requires, namely: AES-256-IGE, AES-256-CTR and AES-256-CBC.
|
||||
|
||||
Installation
|
||||
------------
|
||||
@ -14,10 +14,10 @@ Installation
|
||||
|
||||
$ pip3 install -U tgcrypto
|
||||
|
||||
.. note:: Being a C extension for Python, TgCrypto is an optional but *highly recommended* dependency; when TgCrypto is
|
||||
not detected in your system, Pyrogram will automatically fall back to PyAES and will show you a warning.
|
||||
.. note:: When TgCrypto is not detected in your system, Pyrogram will automatically fall back to a slower Python-only
|
||||
implementation and will show you a warning.
|
||||
|
||||
The reason about being an optional package is that TgCrypto requires some extra system tools in order to be compiled.
|
||||
The reason about being an optional package is that TgCrypto requires extra system tools in order to be compiled.
|
||||
The errors you receive when trying to install TgCrypto are system dependent, but also descriptive enough to understand
|
||||
what you should do next:
|
||||
|
||||
@ -26,7 +26,4 @@ what you should do next:
|
||||
- **Linux**: Install a proper C compiler (``gcc``, ``clang``) and the Python header files (``python3-dev``).
|
||||
- **Termux**: Install ``clang`` package.
|
||||
|
||||
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
|
||||
|
||||
.. [1] Although TgCrypto is intended for Pyrogram, it is shipped as a standalone package and can thus be used for
|
||||
other Python projects too.
|
||||
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
|
@ -19,16 +19,15 @@ Single Filters
|
||||
|
||||
Let's start right away with a simple example:
|
||||
|
||||
- This example will show you how to **only** handle messages containing an :class:`~pyrogram.Audio` object and
|
||||
- This example will show you how to **only** handle messages containing a :class:`~pyrogram.types.Sticker` object and
|
||||
ignore any other message. Filters are passed as the first argument of the decorator:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4
|
||||
|
||||
from pyrogram import filters
|
||||
|
||||
|
||||
@app.on_message(filters.audio)
|
||||
@app.on_message(filters.sticker)
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
@ -36,7 +35,6 @@ Let's start right away with a simple example:
|
||||
callback function itself:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 9
|
||||
|
||||
from pyrogram import filters
|
||||
from pyrogram.handlers import MessageHandler
|
||||
@ -46,12 +44,12 @@ Let's start right away with a simple example:
|
||||
print(message)
|
||||
|
||||
|
||||
app.add_handler(MessageHandler(my_handler, filters.audio))
|
||||
app.add_handler(MessageHandler(my_handler, filters.sticker))
|
||||
|
||||
Combining Filters
|
||||
-----------------
|
||||
|
||||
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
|
||||
Filters can be used in a more advanced way by inverting and combining more filters together using bitwise
|
||||
operators ``~``, ``&`` and ``|``:
|
||||
|
||||
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
||||
|
@ -1,8 +1,8 @@
|
||||
Voice Calls
|
||||
===========
|
||||
|
||||
Both private voice calls and group voice calls are currently supported by third-party libraries that integrate with
|
||||
Pyrogram.
|
||||
Both private voice calls and group voice calls are currently supported by third-party, external libraries that integrate
|
||||
with Pyrogram.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
@ -32,6 +32,7 @@ from pathlib import Path
|
||||
from typing import Union, List, Optional
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import __version__, __license__
|
||||
from pyrogram import raw
|
||||
from pyrogram import utils
|
||||
from pyrogram.crypto import aes
|
||||
@ -281,6 +282,10 @@ class Client(Methods, Scaffold):
|
||||
if self.bot_token:
|
||||
return await self.sign_in_bot(self.bot_token)
|
||||
|
||||
print(f"Welcome to Pyrogram (version {__version__})")
|
||||
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
||||
f"under the terms of the {__license__}.\n")
|
||||
|
||||
while True:
|
||||
try:
|
||||
if not self.phone_number:
|
||||
@ -428,7 +433,6 @@ class Client(Methods, Scaffold):
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 10,14,18,22
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
@ -436,23 +440,23 @@ class Client(Methods, Scaffold):
|
||||
|
||||
with app:
|
||||
# Default combined mode: Markdown + HTML
|
||||
app.send_message("haskell", "1. **markdown** and <i>html</i>")
|
||||
app.send_message("me", "1. **markdown** and <i>html</i>")
|
||||
|
||||
# Force Markdown-only, HTML is disabled
|
||||
app.set_parse_mode("markdown")
|
||||
app.send_message("haskell", "2. **markdown** and <i>html</i>")
|
||||
app.send_message("me", "2. **markdown** and <i>html</i>")
|
||||
|
||||
# Force HTML-only, Markdown is disabled
|
||||
app.set_parse_mode("html")
|
||||
app.send_message("haskell", "3. **markdown** and <i>html</i>")
|
||||
app.send_message("me", "3. **markdown** and <i>html</i>")
|
||||
|
||||
# Disable the parser completely
|
||||
app.set_parse_mode(None)
|
||||
app.send_message("haskell", "4. **markdown** and <i>html</i>")
|
||||
app.send_message("me", "4. **markdown** and <i>html</i>")
|
||||
|
||||
# Bring back the default combined mode
|
||||
app.set_parse_mode()
|
||||
app.send_message("haskell", "5. **markdown** and <i>html</i>")
|
||||
app.send_message("me", "5. **markdown** and <i>html</i>")
|
||||
"""
|
||||
|
||||
self.parse_mode = parse_mode
|
||||
@ -937,8 +941,8 @@ class Client(Methods, Scaffold):
|
||||
await self.loop.run_in_executor(self.executor, func)
|
||||
|
||||
if len(chunk) < limit:
|
||||
break
|
||||
|
||||
break
|
||||
|
||||
r = await session.send(
|
||||
raw.functions.upload.GetFile(
|
||||
location=location,
|
||||
|
@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .tcp import TCP
|
||||
|
@ -17,9 +17,9 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
from binascii import crc32
|
||||
from struct import pack, unpack
|
||||
from typing import Optional
|
||||
|
||||
from .tcp import TCP
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
from struct import pack, unpack
|
||||
from typing import Optional
|
||||
|
||||
from .tcp import TCP
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional
|
||||
from struct import pack, unpack
|
||||
from typing import Optional
|
||||
|
||||
from pyrogram.crypto import aes
|
||||
from .tcp import TCP
|
||||
|
@ -39,7 +39,7 @@ class RPCError(Exception):
|
||||
is_unknown: bool = False,
|
||||
is_signed: bool = False
|
||||
):
|
||||
super().__init__("[{}{} {}]: {} {}".format(
|
||||
super().__init__("Telegram says: [{}{} {}] - {} {}".format(
|
||||
"-" if is_signed else "",
|
||||
self.CODE,
|
||||
self.ID or self.NAME,
|
||||
|
@ -934,12 +934,3 @@ class chat(Filter, set):
|
||||
and message.from_user
|
||||
and message.from_user.is_self
|
||||
and not message.outgoing)))
|
||||
|
||||
|
||||
# region dan_filter
|
||||
async def dan_filter(_, __, m: Message):
|
||||
return bool(m.from_user and m.from_user.id == 23122162)
|
||||
|
||||
|
||||
dan = create(dan_filter)
|
||||
# endregion
|
||||
|
@ -23,8 +23,8 @@ from .get_inline_bot_results import GetInlineBotResults
|
||||
from .request_callback_answer import RequestCallbackAnswer
|
||||
from .send_game import SendGame
|
||||
from .send_inline_bot_result import SendInlineBotResult
|
||||
from .set_game_score import SetGameScore
|
||||
from .set_bot_commands import SetBotCommands
|
||||
from .set_game_score import SetGameScore
|
||||
|
||||
|
||||
class Bots(
|
||||
|
@ -47,8 +47,8 @@ class GetChatMember(Scaffold):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
dan = app.get_chat_member("pyrogramchat", "haskell")
|
||||
print(dan)
|
||||
member = app.get_chat_member(chat_id, "me")
|
||||
print(member)
|
||||
"""
|
||||
chat = await self.resolve_peer(chat_id)
|
||||
user = await self.resolve_peer(user_id)
|
||||
|
@ -57,16 +57,17 @@ class GetChatMembers(Scaffold):
|
||||
|
||||
offset (``int``, *optional*):
|
||||
Sequential number of the first member to be returned.
|
||||
Only applicable to supergroups and channels. Defaults to 0 [1]_.
|
||||
Only applicable to supergroups and channels. Defaults to 0.
|
||||
|
||||
limit (``int``, *optional*):
|
||||
Limits the number of members to be retrieved.
|
||||
Only applicable to supergroups and channels.
|
||||
Defaults to 200, which is also the maximum server limit allowed per method call.
|
||||
Defaults to 200.
|
||||
|
||||
query (``str``, *optional*):
|
||||
Query string to filter members based on their display names and usernames.
|
||||
Only applicable to supergroups and channels. Defaults to "" (empty string) [2]_.
|
||||
Only applicable to supergroups and channels. Defaults to "" (empty string).
|
||||
A query string is applicable only for *"all"*, *"banned"* and *"restricted"* filters only
|
||||
|
||||
filter (``str``, *optional*):
|
||||
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
|
||||
@ -80,11 +81,6 @@ class GetChatMembers(Scaffold):
|
||||
Only applicable to supergroups and channels.
|
||||
Defaults to *"recent"*.
|
||||
|
||||
.. [1] Server limit: on supergroups, you can get up to 10,000 members for a single query and up to 200 members
|
||||
on channels.
|
||||
|
||||
.. [2] A query string is applicable only for *"all"*, *"banned"* and *"restricted"* filters only.
|
||||
|
||||
Returns:
|
||||
List of :obj:`~pyrogram.types.ChatMember`: On success, a list of chat members is returned.
|
||||
|
||||
@ -95,13 +91,13 @@ class GetChatMembers(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Get first 200 recent members
|
||||
app.get_chat_members("pyrogramchat")
|
||||
app.get_chat_members(chat_id)
|
||||
|
||||
# Get all administrators
|
||||
app.get_chat_members("pyrogramchat", filter="administrators")
|
||||
app.get_chat_members(chat_id, filter="administrators")
|
||||
|
||||
# Get all bots
|
||||
app.get_chat_members("pyrogramchat", filter="bots")
|
||||
app.get_chat_members(chat_id, filter="bots")
|
||||
"""
|
||||
peer = await self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -42,7 +42,7 @@ class GetChatMembersCount(Scaffold):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
count = app.get_chat_members_count("pyrogramchat")
|
||||
count = app.get_chat_members_count(chat_id)
|
||||
print(count)
|
||||
"""
|
||||
peer = await self.resolve_peer(chat_id)
|
||||
|
@ -16,7 +16,6 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from string import ascii_lowercase
|
||||
from typing import Union, AsyncGenerator, Optional
|
||||
|
||||
from pyrogram import raw
|
||||
@ -33,10 +32,6 @@ class Filters:
|
||||
ADMINISTRATORS = "administrators"
|
||||
|
||||
|
||||
QUERIES = [""] + [str(i) for i in range(10)] + list(ascii_lowercase)
|
||||
QUERYABLE_FILTERS = (Filters.ALL, Filters.BANNED, Filters.RESTRICTED)
|
||||
|
||||
|
||||
class IterChatMembers(Scaffold):
|
||||
async def iter_chat_members(
|
||||
self,
|
||||
@ -57,11 +52,11 @@ class IterChatMembers(Scaffold):
|
||||
|
||||
limit (``int``, *optional*):
|
||||
Limits the number of members to be retrieved.
|
||||
By default, no limit is applied and all members are returned [1]_.
|
||||
|
||||
query (``str``, *optional*):
|
||||
Query string to filter members based on their display names and usernames.
|
||||
Defaults to "" (empty string) [2]_.
|
||||
Defaults to "" (empty string).
|
||||
A query string is applicable only for *"all"*, *"banned"* and *"restricted"* filters only.
|
||||
|
||||
filter (``str``, *optional*):
|
||||
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
|
||||
@ -74,11 +69,6 @@ class IterChatMembers(Scaffold):
|
||||
*"administrators"* - chat administrators only.
|
||||
Defaults to *"recent"*.
|
||||
|
||||
.. [1] Server limit: on supergroups, you can get up to 10,000 members for a single query and up to 200 members
|
||||
on channels.
|
||||
|
||||
.. [2] A query string is applicable only for *"all"*, *"banned"* and *"restricted"* filters only.
|
||||
|
||||
Returns:
|
||||
``Generator``: A generator yielding :obj:`~pyrogram.types.ChatMember` objects.
|
||||
|
||||
@ -86,58 +76,52 @@ class IterChatMembers(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Iterate though all chat members
|
||||
for member in app.iter_chat_members("pyrogramchat"):
|
||||
for member in app.iter_chat_members(chat_id):
|
||||
print(member.user.first_name)
|
||||
|
||||
# Iterate though all administrators
|
||||
for member in app.iter_chat_members("pyrogramchat", filter="administrators"):
|
||||
for member in app.iter_chat_members(chat_id, filter="administrators"):
|
||||
print(member.user.first_name)
|
||||
|
||||
# Iterate though all bots
|
||||
for member in app.iter_chat_members("pyrogramchat", filter="bots"):
|
||||
for member in app.iter_chat_members(chat_id, filter="bots"):
|
||||
print(member.user.first_name)
|
||||
"""
|
||||
current = 0
|
||||
yielded = set()
|
||||
queries = [query] if query else QUERIES
|
||||
total = limit or (1 << 31) - 1
|
||||
limit = min(200, total)
|
||||
resolved_chat_id = await self.resolve_peer(chat_id)
|
||||
offset = 0
|
||||
|
||||
if filter not in QUERYABLE_FILTERS:
|
||||
queries = [""]
|
||||
while True:
|
||||
chat_members = await self.get_chat_members(
|
||||
chat_id=chat_id,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
query=query,
|
||||
filter=filter
|
||||
)
|
||||
|
||||
for q in queries:
|
||||
offset = 0
|
||||
if not chat_members:
|
||||
break
|
||||
|
||||
while True:
|
||||
chat_members = await self.get_chat_members(
|
||||
chat_id=chat_id,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
query=q,
|
||||
filter=filter
|
||||
)
|
||||
if isinstance(resolved_chat_id, raw.types.InputPeerChat):
|
||||
total = len(chat_members)
|
||||
|
||||
if not chat_members:
|
||||
break
|
||||
offset += len(chat_members)
|
||||
|
||||
if isinstance(resolved_chat_id, raw.types.InputPeerChat):
|
||||
total = len(chat_members)
|
||||
for chat_member in chat_members:
|
||||
user_id = chat_member.user.id
|
||||
|
||||
offset += len(chat_members)
|
||||
if user_id in yielded:
|
||||
continue
|
||||
|
||||
for chat_member in chat_members:
|
||||
user_id = chat_member.user.id
|
||||
yield chat_member
|
||||
|
||||
if user_id in yielded:
|
||||
continue
|
||||
yielded.add(chat_member.user.id)
|
||||
|
||||
yield chat_member
|
||||
current += 1
|
||||
|
||||
yielded.add(chat_member.user.id)
|
||||
|
||||
current += 1
|
||||
|
||||
if current >= total:
|
||||
return
|
||||
if current >= total:
|
||||
return
|
||||
|
@ -52,7 +52,7 @@ class SetAdministratorTitle(Scaffold):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
app.set_administrator_title(chat_id, user_id, "ฅ^•ﻌ•^ฅ")
|
||||
app.set_administrator_title(chat_id, user_id, "Admin Title")
|
||||
"""
|
||||
chat_id = await self.resolve_peer(chat_id)
|
||||
user_id = await self.resolve_peer(user_id)
|
||||
|
@ -45,10 +45,10 @@ class SetSlowMode(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Set slow mode to 60 seconds
|
||||
app.set_slow_mode("pyrogramchat", 60)
|
||||
app.set_slow_mode(chat_id, 60)
|
||||
|
||||
# Disable slow mode
|
||||
app.set_slow_mode("pyrogramchat", None)
|
||||
app.set_slow_mode(chat_id, None)
|
||||
"""
|
||||
|
||||
await self.send(
|
||||
|
@ -38,7 +38,7 @@ class AddContact(Scaffold):
|
||||
user_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target user.
|
||||
|
||||
first_name (``str``, *optional*):
|
||||
first_name (``str``):
|
||||
User's first name.
|
||||
|
||||
last_name (``str``, *optional*):
|
||||
|
@ -43,9 +43,9 @@ class ImportContacts(Scaffold):
|
||||
from pyrogram.types import InputPhoneContact
|
||||
|
||||
app.import_contacts([
|
||||
InputPhoneContact("39123456789", "Foo"),
|
||||
InputPhoneContact("38987654321", "Bar"),
|
||||
InputPhoneContact("01234567891", "Baz")])
|
||||
InputPhoneContact("+1-123-456-7890", "Foo"),
|
||||
InputPhoneContact("+1-456-789-0123", "Bar"),
|
||||
InputPhoneContact("+1-789-012-3456", "Baz")])
|
||||
"""
|
||||
imported_contacts = await self.send(
|
||||
raw.functions.contacts.ImportContacts(
|
||||
|
@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union, List, Optional
|
||||
from typing import Union, List
|
||||
|
||||
from pyrogram import types, utils, raw
|
||||
from pyrogram.scaffold import Scaffold
|
||||
@ -103,7 +103,8 @@ class CopyMediaGroup(Scaffold):
|
||||
**await self.parser.parse(
|
||||
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
||||
captions if isinstance(captions, str) and i == 0 else
|
||||
message.caption if message.caption and message.caption != "None" and not type(captions) is str else "")
|
||||
message.caption if message.caption and message.caption != "None" and not type(
|
||||
captions) is str else "")
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -92,7 +92,7 @@ class DownloadMedia(Scaffold):
|
||||
app.download_media(message)
|
||||
|
||||
# Download from file id
|
||||
app.download_media("CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE")
|
||||
app.download_media(message.photo.file_id)
|
||||
|
||||
# Keep track of the progress while downloading
|
||||
def progress(current, total):
|
||||
|
@ -67,7 +67,6 @@ class ForwardMessages(Scaffold):
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 2,5
|
||||
|
||||
# Forward a single message
|
||||
app.forward_messages("me", "pyrogram", 20)
|
||||
|
@ -72,13 +72,13 @@ class GetHistory(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Get the last 100 messages of a chat
|
||||
app.get_history("pyrogramchat")
|
||||
app.get_history(chat_id)
|
||||
|
||||
# Get the last 3 messages of a chat
|
||||
app.get_history("pyrogramchat", limit=3)
|
||||
app.get_history(chat_id, limit=3)
|
||||
|
||||
# Get 3 messages after skipping the first 5
|
||||
app.get_history("pyrogramchat", offset=5, limit=3)
|
||||
app.get_history(chat_id, offset=5, limit=3)
|
||||
"""
|
||||
|
||||
offset_id = offset_id or (1 if reverse else 0)
|
||||
|
@ -48,7 +48,7 @@ class GetHistoryCount(Scaffold):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
app.get_history_count("pyrogramchat")
|
||||
app.get_history_count(chat_id)
|
||||
"""
|
||||
|
||||
r = await self.send(
|
||||
|
@ -50,7 +50,7 @@ class GetMediaGroup(Scaffold):
|
||||
In case the passed message_id is negative or equal 0.
|
||||
In case target message doesn't belong to a media group.
|
||||
"""
|
||||
|
||||
|
||||
# There can be maximum 10 items in a media group.
|
||||
messages = await self.get_messages(chat_id, [msg_id for msg_id in range(message_id - 9, message_id + 10)],
|
||||
replies=0)
|
||||
@ -66,7 +66,7 @@ class GetMediaGroup(Scaffold):
|
||||
|
||||
# There can be maximum 10 items in a media group.
|
||||
# The if/else condition to fix the problem of getting correct `media_group_id` when it has `message_id` less then 10.
|
||||
media_group_id = messages[9].media_group_id if len(messages) == 19 else messages[message_id-1].media_group_id
|
||||
media_group_id = messages[9].media_group_id if len(messages) == 19 else messages[message_id - 1].media_group_id
|
||||
|
||||
if media_group_id is None:
|
||||
raise ValueError("The message doesn't belong to a media group")
|
||||
|
@ -71,10 +71,10 @@ class GetMessages(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Get one message
|
||||
app.get_messages("pyrogramchat", 51110)
|
||||
app.get_messages(chat_id, 12345)
|
||||
|
||||
# Get more than one message (list of messages)
|
||||
app.get_messages("pyrogramchat", [44625, 51110])
|
||||
app.get_messages(chat_id, [12345, 12346])
|
||||
|
||||
# Get message by ignoring any replied-to message
|
||||
app.get_messages(chat_id, message_id, replies=0)
|
||||
|
@ -47,10 +47,10 @@ class ReadHistory(Scaffold):
|
||||
.. code-block:: python
|
||||
|
||||
# Mark the whole chat as read
|
||||
app.read_history("pyrogramlounge")
|
||||
app.read_history(chat_id)
|
||||
|
||||
# Mark messages as read only up to the given message id
|
||||
app.read_history("pyrogramlounge", 123456)
|
||||
app.read_history(chat_id, 123456)
|
||||
"""
|
||||
|
||||
peer = await self.resolve_peer(chat_id)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user