mirror of
https://github.com/TeamPGM/pyrogram.git
synced 2024-11-23 23:34:28 +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
|
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
|
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 -->
|
<!-- 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:
|
contact_links:
|
||||||
- name: Ask Pyrogram related questions
|
- name: Ask Pyrogram related questions
|
||||||
url: https://stackoverflow.com/questions/tagged/pyrogram
|
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.
|
about: This place is only for reporting issues about Pyrogram. You can ask questions at StackOverflow.
|
||||||
- name: Join the Telegram community
|
- name: Join the Telegram channel
|
||||||
url: https://t.me/pyrogram
|
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 -->
|
<!-- WARNING: Ignoring or altering this template could lead to the issue being closed as invalid -->
|
||||||
|
|
||||||
## Checklist
|
## 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.
|
- [ ] I have searched in the issue tracker for similar requests, including closed ones.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
60
README.md
60
README.md
@ -1,6 +1,6 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/pyrogram/pyrogram">
|
<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>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<b>Telegram MTProto API Framework for Python</b>
|
<b>Telegram MTProto API Framework for Python</b>
|
||||||
@ -9,17 +9,19 @@
|
|||||||
Documentation
|
Documentation
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://github.com/pyrogram/pyrogram/releases">
|
<a href="https://docs.pyrogram.org/releases">
|
||||||
Releases
|
Releases
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://t.me/Pyrogram">
|
<a href="https://t.me/pyrogram">
|
||||||
Community
|
News
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Pyrogram
|
## Pyrogram
|
||||||
|
|
||||||
|
> Elegant, modern and asynchronous Telegram MTProto API framework in Python for users and bots
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
|
|
||||||
@ -28,34 +30,33 @@ app = Client("my_account")
|
|||||||
|
|
||||||
@app.on_message(filters.private)
|
@app.on_message(filters.private)
|
||||||
async def hello(client, message):
|
async def hello(client, message):
|
||||||
await message.reply_text(f"Hello {message.from_user.mention}")
|
await message.reply("Hello from Pyrogram!")
|
||||||
|
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pyrogram** is a modern, elegant and easy-to-use [Telegram](https://telegram.org/) client library framework written
|
**Pyrogram** is a modern, elegant and asynchronous [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi)
|
||||||
from the ground up in Python and C. It enables you to easily create custom Telegram client applications for both user
|
framework. It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot
|
||||||
and bot identities (bot API alternative) via the [MTProto API](https://docs.pyrogram.org/topics/mtproto-vs-botapi).
|
identity (bot API alternative) using Python.
|
||||||
|
|
||||||
### Features
|
### Support
|
||||||
|
|
||||||
- **Easy**: You can install Pyrogram with pip and start building your applications right away.
|
If you'd like to support Pyrogram, you can consider:
|
||||||
- **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
|
- [Become a GitHub sponsor](https://github.com/sponsors/delivrance).
|
||||||
written in pure C.
|
- [Become a LiberaPay patron](https://liberapay.com/delivrance).
|
||||||
- **Asynchronous**: Allows both synchronous and asynchronous models to fit all usage needs.
|
- [Become an OpenCollective backer](https://opencollective.com/pyrogram>).
|
||||||
- **Documented**: API methods, types and public interfaces are all [well documented](https://docs.pyrogram.org).
|
|
||||||
|
### 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.
|
- **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.
|
- **Async**: Fully asynchronous (also usable synchronously if wanted, for convenience).
|
||||||
- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed.
|
- **Powerful**: Full access to Telegram's API to execute any official client action and more.
|
||||||
- **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).
|
|
||||||
|
|
||||||
### Installing
|
### Installing
|
||||||
|
|
||||||
@ -65,11 +66,6 @@ pip3 install pyrogram
|
|||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
- The docs contain lots of resources to help you get started with Pyrogram: https://docs.pyrogram.org.
|
- Check out the docs at https://docs.pyrogram.org to learn more about Pyrogram, get started right
|
||||||
- Seeking extra help? Come join and ask our community: https://t.me/pyrogram.
|
away and discover more in-depth material for building your client applications.
|
||||||
- For other kind of inquiries, you can send a [message](https://t.me/haskell) or an [e-mail](mailto:dan@pyrogram.org).
|
- Join the official channel at https://t.me/pyrogram and stay tuned for news, updates and announcements.
|
||||||
|
|
||||||
### 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)
|
|
||||||
|
@ -158,6 +158,7 @@ def pyrogram_api():
|
|||||||
send_venue
|
send_venue
|
||||||
send_contact
|
send_contact
|
||||||
send_cached_media
|
send_cached_media
|
||||||
|
send_reaction
|
||||||
edit_message_text
|
edit_message_text
|
||||||
edit_message_caption
|
edit_message_caption
|
||||||
edit_message_media
|
edit_message_media
|
||||||
@ -180,7 +181,9 @@ def pyrogram_api():
|
|||||||
retract_vote
|
retract_vote
|
||||||
send_dice
|
send_dice
|
||||||
search_messages
|
search_messages
|
||||||
|
search_messages_count
|
||||||
search_global
|
search_global
|
||||||
|
search_global_count
|
||||||
download_media
|
download_media
|
||||||
get_discussion_message
|
get_discussion_message
|
||||||
""",
|
""",
|
||||||
@ -284,6 +287,7 @@ def pyrogram_api():
|
|||||||
send_game
|
send_game
|
||||||
set_game_score
|
set_game_score
|
||||||
get_game_high_scores
|
get_game_high_scores
|
||||||
|
set_bot_commands
|
||||||
""",
|
""",
|
||||||
authorization="""
|
authorization="""
|
||||||
Authorization
|
Authorization
|
||||||
@ -360,6 +364,7 @@ def pyrogram_api():
|
|||||||
ChatEvent
|
ChatEvent
|
||||||
ChatEventFilter
|
ChatEventFilter
|
||||||
ChatMemberUpdated
|
ChatMemberUpdated
|
||||||
|
ChatJoinRequest
|
||||||
Dialog
|
Dialog
|
||||||
Restriction
|
Restriction
|
||||||
""",
|
""",
|
||||||
@ -384,6 +389,7 @@ def pyrogram_api():
|
|||||||
Poll
|
Poll
|
||||||
PollOption
|
PollOption
|
||||||
Dice
|
Dice
|
||||||
|
Reaction
|
||||||
VoiceChatScheduled
|
VoiceChatScheduled
|
||||||
VoiceChatStarted
|
VoiceChatStarted
|
||||||
VoiceChatEnded
|
VoiceChatEnded
|
||||||
@ -420,6 +426,8 @@ def pyrogram_api():
|
|||||||
InlineQueryResultArticle
|
InlineQueryResultArticle
|
||||||
InlineQueryResultPhoto
|
InlineQueryResultPhoto
|
||||||
InlineQueryResultAnimation
|
InlineQueryResultAnimation
|
||||||
|
InlineQueryResultAudio
|
||||||
|
InlineQueryResultVideo
|
||||||
ChosenInlineResult
|
ChosenInlineResult
|
||||||
""",
|
""",
|
||||||
input_message_content="""
|
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
|
Bound Methods
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Some Pyrogram types define what are called bound methods. Bound methods are functions attached to a class which are
|
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 class. They make it even easier to call specific methods by automatically inferring
|
accessed via an instance of that type. They make it even easier to call specific methods by automatically inferring
|
||||||
some of the required arguments.
|
some of the required arguments.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 8
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
@ -15,7 +14,7 @@ some of the required arguments.
|
|||||||
|
|
||||||
@app.on_message()
|
@app.on_message()
|
||||||
def hello(client, message)
|
def hello(client, message)
|
||||||
message.reply_text("hi")
|
message.reply("hi")
|
||||||
|
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
|
7
compiler/docs/template/methods.rst
vendored
7
compiler/docs/template/methods.rst
vendored
@ -1,18 +1,17 @@
|
|||||||
Available Methods
|
Available Methods
|
||||||
=================
|
=================
|
||||||
|
|
||||||
This page is about Pyrogram methods. All the methods listed here are bound to a :class:`~pyrogram.Client` instance,
|
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.
|
Some other utility functions can instead be found in the main package directly.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 6
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
with app:
|
with app:
|
||||||
app.send_message("haskell", "hi")
|
app.send_message("me", "hi")
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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.
|
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
|
.. code-block:: python
|
||||||
:emphasize-lines: 1
|
|
||||||
|
|
||||||
from pyrogram.types import User, Message, ...
|
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_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_SEND_INLINE_FORBIDDEN You cannot use inline bots to send messages in this chat
|
||||||
CHAT_TITLE_EMPTY The chat title is empty
|
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_EMPTY The provided code is empty
|
||||||
CODE_HASH_INVALID The provided code hash invalid
|
CODE_HASH_INVALID The provided code hash invalid
|
||||||
CODE_INVALID The provided code is invalid (i.e. from email)
|
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
|
WEBDOCUMENT_URL_INVALID The web document URL is invalid
|
||||||
WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL
|
WEBPAGE_CURL_FAILED Telegram server could not fetch the provided URL
|
||||||
WEBPAGE_MEDIA_EMPTY The URL doesn't contain any valid media
|
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
|
ACTIVE_USER_REQUIRED The method is only available to already activated users
|
||||||
AUTH_KEY_INVALID The key is invalid
|
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_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_EXPIRED The authorization has expired
|
||||||
SESSION_PASSWORD_NEEDED The two-step verification is enabled and a password is required
|
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
|
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
|
||||||
sphinx_rtd_theme
|
sphinx_rtd_theme==1.0.0
|
||||||
sphinx_copybutton
|
sphinx_copybutton
|
||||||
pypandoc
|
pypandoc
|
||||||
requests
|
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.
|
This page is about the Client class, which exposes high-level methods for an easy access to the API.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 1-3
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
Decorators
|
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
|
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
|
: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
|
:meth:`~pyrogram.Client.add_handler` automatically. All you need to do is adding the decorators on top of your
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 6
|
|
||||||
|
|
||||||
from pyrogram import Client
|
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.
|
For a much more convenient way of registering callback functions have a look at :doc:`Decorators <decorators>` instead.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 2, 11
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
from pyrogram.handlers import MessageHandler
|
from pyrogram.handlers import MessageHandler
|
||||||
|
@ -29,35 +29,37 @@ from pygments.styles.friendly import FriendlyStyle
|
|||||||
FriendlyStyle.background_color = "#f3f2f1"
|
FriendlyStyle.background_color = "#f3f2f1"
|
||||||
|
|
||||||
project = "Pyrogram"
|
project = "Pyrogram"
|
||||||
copyright = f"2017-{datetime.now().year}, Dan"
|
copyright = f"2017-present, Dan"
|
||||||
author = "Dan"
|
author = "Dan"
|
||||||
|
|
||||||
|
version = ".".join(__version__.split(".")[:-1])
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
"sphinx.ext.autodoc",
|
"sphinx.ext.autodoc",
|
||||||
"sphinx.ext.napoleon",
|
"sphinx.ext.napoleon",
|
||||||
"sphinx.ext.autosummary",
|
"sphinx.ext.autosummary",
|
||||||
"sphinx_copybutton",
|
"sphinx_copybutton"
|
||||||
"sphinx_tabs.tabs"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
master_doc = "index"
|
master_doc = "index"
|
||||||
source_suffix = ".rst"
|
source_suffix = ".rst"
|
||||||
autodoc_member_order = "bysource"
|
autodoc_member_order = "bysource"
|
||||||
|
|
||||||
version = __version__
|
templates_path = ["_resources/templates"]
|
||||||
release = version
|
html_copy_source = False
|
||||||
|
|
||||||
templates_path = ["_templates"]
|
|
||||||
|
|
||||||
napoleon_use_rtype = False
|
napoleon_use_rtype = False
|
||||||
|
napoleon_use_param = False
|
||||||
|
|
||||||
pygments_style = "friendly"
|
pygments_style = "friendly"
|
||||||
|
|
||||||
copybutton_prompt_text = "$ "
|
copybutton_prompt_text = "$ "
|
||||||
|
|
||||||
|
suppress_warnings = ["image.not_readable"]
|
||||||
|
|
||||||
html_title = "Pyrogram Documentation"
|
html_title = "Pyrogram Documentation"
|
||||||
html_theme = "sphinx_rtd_theme"
|
html_theme = "sphinx_rtd_theme"
|
||||||
html_static_path = ["_static"]
|
html_static_path = ["_resources/static"]
|
||||||
html_show_sourcelink = True
|
html_show_sourcelink = True
|
||||||
html_show_copyright = False
|
html_show_copyright = False
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
@ -65,17 +67,15 @@ html_theme_options = {
|
|||||||
"collapse_navigation": True,
|
"collapse_navigation": True,
|
||||||
"sticky_navigation": False,
|
"sticky_navigation": False,
|
||||||
"logo_only": True,
|
"logo_only": True,
|
||||||
"display_version": True,
|
"display_version": False,
|
||||||
"style_external_links": True
|
"style_external_links": True
|
||||||
}
|
}
|
||||||
|
|
||||||
napoleon_use_param = False
|
html_logo = "_resources/static/img/pyrogram.png"
|
||||||
|
html_favicon = "_resources/static/img/favicon.ico"
|
||||||
html_logo = "_images/pyrogram.png"
|
|
||||||
html_favicon = "_images/favicon.ico"
|
|
||||||
|
|
||||||
latex_engine = "xelatex"
|
latex_engine = "xelatex"
|
||||||
latex_logo = "_images/pyrogram.png"
|
latex_logo = "_resources/static/img/pyrogram.png"
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
"pointsize": "12pt",
|
"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">
|
<div align="center">
|
||||||
<a href="/">
|
<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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -14,15 +15,15 @@ Welcome to Pyrogram
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/pyrogram/pyrogram">
|
<a href="https://github.com/pyrogram/pyrogram">
|
||||||
Source Code
|
Development
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://github.com/pyrogram/pyrogram/releases">
|
<a href="https://docs.pyrogram.org/releases">
|
||||||
Releases
|
Releases
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://t.me/Pyrogram">
|
<a href="https://t.me/pyrogram">
|
||||||
Community
|
News
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -35,16 +36,34 @@ Welcome to Pyrogram
|
|||||||
|
|
||||||
@app.on_message(filters.private)
|
@app.on_message(filters.private)
|
||||||
async def hello(client, message):
|
async def hello(client, message):
|
||||||
await message.reply_text(f"Hello {message.from_user.mention}")
|
await message.reply("Hello from Pyrogram!")
|
||||||
|
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
**Pyrogram** is a modern, elegant and easy-to-use Telegram_ framework written from the ground up in Python and C.
|
**Pyrogram** is a modern, elegant and asynchronous :doc:`MTProto API <topics/mtproto-vs-botapi>` framework.
|
||||||
It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the
|
It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot identity
|
||||||
:doc:`MTProto API <topics/mtproto-vs-botapi>`.
|
(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
|
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
|
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.
|
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
|
First Steps
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 2
|
:columns: 1
|
||||||
|
|
||||||
- :doc:`Quick Start <intro/quickstart>`: Overview to get you started quickly.
|
- :doc:`Quick Start <intro/quickstart>`: Overview to get you started quickly.
|
||||||
- :doc:`Calling Methods <start/invoking>`: How to call Pyrogram's methods.
|
- :doc:`Calling Methods <start/invoking>`: How to call Pyrogram's methods.
|
||||||
@ -75,7 +87,7 @@ API Reference
|
|||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 2
|
:columns: 1
|
||||||
|
|
||||||
- :doc:`Pyrogram Client <api/client>`: Reference details about the Client class.
|
- :doc:`Pyrogram Client <api/client>`: Reference details about the Client class.
|
||||||
- :doc:`Available Methods <api/methods/index>`: List of available high-level methods.
|
- :doc:`Available Methods <api/methods/index>`: List of available high-level methods.
|
||||||
@ -86,16 +98,12 @@ Meta
|
|||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 2
|
:columns: 1
|
||||||
|
|
||||||
- :doc:`Pyrogram FAQ <faq>`: Answers to common Pyrogram questions.
|
- :doc:`Pyrogram FAQ <faq/index>`: Answers to common Pyrogram questions.
|
||||||
- :doc:`Pyrogram Glossary <glossary>`: List of words with brief explanations.
|
|
||||||
- :doc:`Support Pyrogram <support>`: Ways to show your appreciation.
|
- :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.
|
- :doc:`Release Notes <releases/index>`: Release notes for Pyrogram releases.
|
||||||
|
|
||||||
Last updated on |today|
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:hidden:
|
:hidden:
|
||||||
:caption: Introduction
|
:caption: Introduction
|
||||||
@ -136,14 +144,13 @@ Last updated on |today|
|
|||||||
topics/more-on-updates
|
topics/more-on-updates
|
||||||
topics/config-file
|
topics/config-file
|
||||||
topics/smart-plugins
|
topics/smart-plugins
|
||||||
topics/session-settings
|
topics/client-settings
|
||||||
topics/tgcrypto
|
topics/tgcrypto
|
||||||
topics/storage-engines
|
topics/storage-engines
|
||||||
topics/text-formatting
|
topics/text-formatting
|
||||||
topics/serializing
|
topics/serializing
|
||||||
topics/proxy
|
topics/proxy
|
||||||
topics/scheduling
|
topics/scheduling
|
||||||
topics/bots-interaction
|
|
||||||
topics/mtproto-vs-botapi
|
topics/mtproto-vs-botapi
|
||||||
topics/debugging
|
topics/debugging
|
||||||
topics/test-servers
|
topics/test-servers
|
||||||
@ -154,10 +161,8 @@ Last updated on |today|
|
|||||||
:hidden:
|
:hidden:
|
||||||
:caption: Meta
|
:caption: Meta
|
||||||
|
|
||||||
faq
|
faq/index
|
||||||
glossary
|
|
||||||
support
|
support
|
||||||
license
|
|
||||||
releases/index
|
releases/index
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
Install Guide
|
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.
|
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
|
.. contents:: Contents
|
||||||
:backlinks: none
|
:backlinks: none
|
||||||
:depth: 1
|
:depth: 1
|
||||||
@ -36,12 +29,7 @@ Install Pyrogram
|
|||||||
Bleeding Edge
|
Bleeding Edge
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Pyrogram is always evolving, although new releases on PyPI are published only when enough changes are added, but this
|
You can install the development version from the git ``master`` branch using this command:
|
||||||
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):
|
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
@ -57,6 +45,6 @@ If no error shows up you are good to go.
|
|||||||
|
|
||||||
>>> import pyrogram
|
>>> import pyrogram
|
||||||
>>> pyrogram.__version__
|
>>> pyrogram.__version__
|
||||||
'|version|'
|
'x.y.z'
|
||||||
|
|
||||||
.. _`Github repo`: http://github.com/pyrogram/pyrogram
|
.. _`Github repo`: http://github.com/pyrogram/pyrogram
|
||||||
|
@ -1,49 +1,54 @@
|
|||||||
Quick Start
|
Quick Start
|
||||||
===========
|
===========
|
||||||
|
|
||||||
The next few steps serve as a quick start for all new :term:`Pyrogrammers <Pyrogrammer>` that want to see Pyrogram in
|
The next few steps serve as a quick start to see Pyrogram in action as fast as possible.
|
||||||
action as fast as possible. Let's go!
|
|
||||||
|
|
||||||
Get Pyrogram Real Fast
|
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``.
|
1. Install Pyrogram with ``pip3 install -U pyrogram``.
|
||||||
|
|
||||||
2. Get your own Telegram API key from https://my.telegram.org/apps.
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
api_id = 12345
|
api_id = 12345
|
||||||
api_hash = "0123456789abcdef0123456789abcdef"
|
api_hash = "0123456789abcdef0123456789abcdef"
|
||||||
|
|
||||||
with Client("my_account", api_id, api_hash) as app:
|
async def main():
|
||||||
app.send_message("me", "Greetings from **Pyrogram**!")
|
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.
|
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.
|
7. Follow the instructions on your terminal to login.
|
||||||
|
|
||||||
8. Watch Pyrogram send a message to yourself.
|
8. Watch Pyrogram send a message to yourself.
|
||||||
|
|
||||||
9. Join our `community`_.
|
|
||||||
|
|
||||||
10. Say, "hi!".
|
|
||||||
|
|
||||||
Enjoy the API
|
Enjoy the API
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
That was just a quick overview that barely scratched the surface!
|
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
|
||||||
In the next few pages of the introduction, we'll take a much more in-depth look of what we have just done above.
|
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
|
If you are feeling eager to continue you can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back
|
||||||
learn some more details.
|
later to learn some more details.
|
||||||
|
|
||||||
.. _community: https://t.me/Pyrogram
|
.. _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
|
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
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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):
|
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.
|
#. Visit https://my.telegram.org/apps and log in with your Telegram Account.
|
||||||
#. Fill out the form to register a new Telegram application.
|
#. 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**.
|
#. Done. The API key consists of two parts: **api_id** and **api_hash**. Keep it secret.
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
The API key is personal and must be kept secret.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The API key is unique for each user, but defines a token for a Telegram *application* you are going to build. This
|
The API key defines a token for a Telegram *application* you are going to build.
|
||||||
means that you are able to authorize multiple users (and bots too) to access the Telegram database through the
|
This means that you are able to authorize multiple users or bots with a single API key.
|
||||||
MTProto API by a single API key.
|
|
||||||
|
|
||||||
Configuration
|
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.
|
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:
|
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
|
- 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 is the preferred method because allows you to
|
replace the *api_id* and *api_hash* values with your own. This method allows you to keep your credentials out of
|
||||||
keep your credentials out of your code without having to deal with how to load them:
|
your code without having to deal with how to load them.
|
||||||
|
|
||||||
.. code-block:: ini
|
.. 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
|
api_hash = 0123456789abcdef0123456789abcdef
|
||||||
|
|
||||||
- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* parameters of the
|
- 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
|
Client class. This way you can have full control on how to store and load your credentials:
|
||||||
credentials from the environment variables and directly pass the values into Pyrogram):
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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 = Client("my_account")
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_) and the
|
This starts an interactive shell asking you to input your **phone number**, including your `Country Code`_ (the plus
|
||||||
**phone code** you will receive in your devices that are already authorized or via SMS:
|
``+`` 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
|
.. code-block:: text
|
||||||
|
|
||||||
Enter phone number: +39**********
|
Enter phone number: +1-123-456-7890
|
||||||
Is "+39**********" correct? (y/n): y
|
Is "+1-123-456-7890" correct? (y/n): y
|
||||||
Enter phone code: 32768
|
Enter phone code: 12345
|
||||||
Logged in successfully as Dan
|
Logged in successfully
|
||||||
|
|
||||||
After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing Pyrogram to
|
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
|
execute API calls with your identity. This file is personal and will be loaded again when you restart your app, and as
|
||||||
keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
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.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
Error Handling
|
Error Handling
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Errors are inevitable when working with the API, and they can be correctly handled with ``try...except`` blocks in order
|
Errors can be correctly handled with ``try...except`` blocks in order to control the behaviour of your application.
|
||||||
to control the behaviour of your application. Pyrogram errors all live inside the ``errors`` package:
|
Pyrogram errors all live inside the ``errors`` package:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
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
|
Avoid catching this error everywhere, especially when no feedback is given (i.e. by logging/printing the full error
|
||||||
logging/printing the full error traceback), because it makes it impossible to understand what went wrong.
|
traceback), because it makes it impossible to understand what went wrong.
|
||||||
|
|
||||||
Error Categories
|
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
|
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.
|
``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
|
Errors with Values
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ like send_audio(), send_document(), send_location(), etc...
|
|||||||
|
|
||||||
with app:
|
with app:
|
||||||
app.send_message(
|
app.send_message(
|
||||||
"haskell", # Edit this
|
"me", # Edit this
|
||||||
"This is a ReplyKeyboardMarkup example",
|
"This is a ReplyKeyboardMarkup example",
|
||||||
reply_markup=ReplyKeyboardMarkup(
|
reply_markup=ReplyKeyboardMarkup(
|
||||||
[
|
[
|
||||||
@ -33,7 +33,7 @@ like send_audio(), send_document(), send_location(), etc...
|
|||||||
)
|
)
|
||||||
|
|
||||||
app.send_message(
|
app.send_message(
|
||||||
"haskell", # Edit this
|
"me", # Edit this
|
||||||
"This is a InlineKeyboardMarkup example",
|
"This is a InlineKeyboardMarkup example",
|
||||||
reply_markup=InlineKeyboardMarkup(
|
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)
|
@app.on_message(filters.text & filters.private)
|
||||||
def echo(client, message):
|
def echo(client, message):
|
||||||
message.reply_text(message.text)
|
message.reply(message.text)
|
||||||
|
|
||||||
|
|
||||||
app.run() # Automatically start() and idle()
|
app.run() # Automatically start() and idle()
|
@ -13,9 +13,3 @@ This example demonstrates a basic API usage
|
|||||||
with app:
|
with app:
|
||||||
# Send a message, Markdown is enabled by default
|
# Send a message, Markdown is enabled by default
|
||||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
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",
|
url="https://docs.pyrogram.org/intro/install",
|
||||||
description="How to install Pyrogram",
|
description="How to install Pyrogram",
|
||||||
thumb_url="https://i.imgur.com/JyxrStE.png",
|
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
@ -43,7 +42,6 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
|||||||
),
|
),
|
||||||
url="https://docs.pyrogram.org/start/invoking",
|
url="https://docs.pyrogram.org/start/invoking",
|
||||||
description="How to use Pyrogram",
|
description="How to use Pyrogram",
|
||||||
thumb_url="https://i.imgur.com/JyxrStE.png",
|
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
|
@ -11,8 +11,8 @@ This example shows how to query an inline bot (as user).
|
|||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
with app:
|
with app:
|
||||||
# Get bot results for "Fuzz Universe" from the inline bot @vid
|
# Get bot results for "hello" from the inline bot @vid
|
||||||
bot_results = app.get_inline_bot_results("vid", "Fuzz Universe")
|
bot_results = app.get_inline_bot_results("vid", "hello")
|
||||||
|
|
||||||
# Send the first result (bot_results.results[0]) to your own chat (Saved Messages)
|
# 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)
|
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
|
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
|
MENTION = "[{}](tg://user?id={})" # User mention markup
|
||||||
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.org/)'s group chat {}!" # Welcome message
|
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
|
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
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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")
|
app = Client("my_account")
|
||||||
|
|
||||||
with app:
|
async def main():
|
||||||
app.send_message("me", "Hi!")
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
from pyrogram import Client
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
app = Client("my_account")
|
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
|
.. 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
|
.. code-block:: python
|
||||||
|
|
||||||
app.send_message("me", "Hi!")
|
app.run(main())
|
||||||
|
|
||||||
Context Manager
|
Context Manager
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
The ``with`` statement starts a context manager used as a shortcut to automatically call :meth:`~pyrogram.Client.start`
|
The ``async with`` statement starts a context manager, which is used as a shortcut for starting, executing and stopping
|
||||||
and :meth:`~pyrogram.Client.stop`, which are methods required for Pyrogram to work properly. The context manager does
|
the Client, asynchronously. It does so by automatically calling :meth:`~pyrogram.Client.start` and
|
||||||
also gracefully stop the client, even in case of unhandled exceptions in your code.
|
: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:
|
Below there's the same example as above, but without the use of 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:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -84,36 +77,48 @@ them with ``await``), use the asynchronous context manager:
|
|||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
async with app:
|
await app.start()
|
||||||
await app.send_message("me", "Hi!")
|
await app.send_message("me", "Hi!")
|
||||||
|
await app.stop()
|
||||||
|
|
||||||
app.run(main())
|
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")
|
app = Client("my_account")
|
||||||
|
|
||||||
#. Async methods can't normally be executed at the top level, because they must be inside an async-defined function;
|
async with app:
|
||||||
here we define one and put our code inside; the context manager is also being used differently in asyncio and
|
await app.send_message("me", "Hi!")
|
||||||
method calls require the await keyword:
|
|
||||||
|
|
||||||
.. code-block:: python
|
asyncio.run(main())
|
||||||
|
|
||||||
async def main():
|
Synchronous Calls
|
||||||
async with app:
|
------------------
|
||||||
await app.send_message("me", "Hi!")
|
|
||||||
|
|
||||||
#. Finally, we tell Python to schedule our ``main()`` async function, which in turn will execute Pyrogram's methods.
|
Pyrogram is an asynchronous framework, but it also provides a convenience way for calling methods without the need
|
||||||
Using :meth:`~pyrogram.Client.run` this way is a friendly alternative for the much more verbose
|
of async/await keywords and the extra boilerplate. In case you want Pyrogram to run synchronously, simply use the
|
||||||
``asyncio.get_event_loop().run_until_complete(main())``:
|
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
|
Handling Updates
|
||||||
================
|
================
|
||||||
|
|
||||||
Calling :doc:`API methods <invoking>` sequentially is cool, but how to react when, for example, a new message arrives?
|
Calling :doc:`API methods <invoking>` sequentially is one way to use Pyrogram, but how to react when, for example, a
|
||||||
This page deals with updates and how to handle such events in Pyrogram. Let's have a look at how they work.
|
new message arrives? This page deals with updates and how to handle such events in Pyrogram.
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
:backlinks: none
|
:backlinks: none
|
||||||
@ -14,10 +14,9 @@ This page deals with updates and how to handle such events in Pyrogram. Let's ha
|
|||||||
Defining Updates
|
Defining Updates
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
First, let's define what are these updates. As hinted already, updates are simply events that happen in your Telegram
|
As hinted already, updates are simply events that happen in your Telegram account (incoming messages, new members join,
|
||||||
account (incoming messages, new members join, bot button presses, etc...), which are meant to notify you about a new
|
bot button presses, etc.), which are meant to notify you about a new specific state that has changed. These updates are
|
||||||
specific state that has changed. These updates are handled by registering one or more callback functions in your app
|
handled by registering one or more callback functions in your app using :doc:`Handlers <../api/handlers>`.
|
||||||
using :doc:`Handlers <../api/handlers>`.
|
|
||||||
|
|
||||||
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
|
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.
|
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 = Client("my_account")
|
||||||
|
|
||||||
|
|
||||||
@app.on_message()
|
@app.on_message()
|
||||||
def my_handler(client, message):
|
async def my_handler(client, message):
|
||||||
message.forward("me")
|
await message.forward("me")
|
||||||
|
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
The defined function ``my_handler``, which accepts the two arguments *(client, message)*, will be the function that gets
|
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.
|
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
|
You can also have synchronous handlers; you only need to define the callback function without using ``async def`` and
|
||||||
methods by placing ``await`` in front of them:
|
call API methods by not placing ``await`` in front of them:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@app.on_message()
|
@app.on_message()
|
||||||
async def my_handler(client, message):
|
def my_handler(client, message):
|
||||||
await message.forward("me")
|
message.forward("me")
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
You can mix ``def`` and ``async def`` handlers as much as you need, Pyrogram will still work concurrently and
|
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.
|
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()
|
Using add_handler()
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback
|
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,
|
function and registers it in your Client. It is useful in case you want to programmatically add handlers.
|
||||||
for some reason, you don't like to use decorators).
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
from pyrogram.handlers import MessageHandler
|
from pyrogram.handlers import MessageHandler
|
||||||
|
|
||||||
|
async def my_function(client, message):
|
||||||
def my_function(client, message):
|
await message.forward("me")
|
||||||
message.forward("me")
|
|
||||||
|
|
||||||
|
|
||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
@ -92,12 +92,12 @@ for some reason, you don't like to use decorators).
|
|||||||
|
|
||||||
app.run()
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
async def my_function(client, message):
|
def my_function(client, message):
|
||||||
await message.forward("me")
|
message.forward("me")
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -1,66 +1,62 @@
|
|||||||
Support Pyrogram
|
Support Pyrogram
|
||||||
================
|
================
|
||||||
|
|
||||||
As a developer, you probably understand that "open source" doesn't mean "free work". If you wish to tip me for Pyrogram
|
.. raw:: html
|
||||||
-- or any of my `other works`_ -- you can do so by the ways shown below. Your appreciation means a lot and helps
|
|
||||||
staying motivated!
|
|
||||||
|
|
||||||
--- `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
|
`Become a GitHub sponsor <https://github.com/sponsors/delivrance>`_.
|
||||||
found it to be useful, give Pyrogram a `Star on GitHub`_.
|
|
||||||
|
|
||||||
.. raw:: html
|
.. 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>
|
<a class="github-button"
|
||||||
<br><br>
|
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
|
.. raw:: html
|
||||||
|
|
||||||
<iframe
|
<script src="https://liberapay.com/delivrance/widgets/button.js"></script>
|
||||||
src="https://github.com/sponsors/delivrance/button"
|
|
||||||
title="Sponsor delivrance"
|
|
||||||
height="40" width="120"
|
|
||||||
style="border: 0px; padding-top: 5px; margin-top: -5px">
|
|
||||||
</iframe>
|
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Donate
|
OpenCollective Backer
|
||||||
------
|
---------------------
|
||||||
|
|
||||||
You can donate via PayPal using the button below:
|
`Become an OpenCollective backer <https://opencollective.com/pyrogram>`_
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
<script src="https://opencollective.com/pyrogram/banner.js"></script>
|
||||||
<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
|
|
@ -1,9 +1,8 @@
|
|||||||
Advanced Usage
|
Advanced Usage
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Pyrogram's API, which consists of well documented convenience :doc:`methods <../api/methods/index>` and facade
|
Pyrogram's API -- which consists of well documented :doc:`methods <../api/methods/index>` and
|
||||||
:doc:`types <../api/types/index>`, exists to provide a much easier interface to the undocumented and often confusing
|
:doc:`types <../api/types/index>` -- exists to provide an easier interface to the more complex Telegram API.
|
||||||
Telegram API.
|
|
||||||
|
|
||||||
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main "raw"
|
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.
|
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
|
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`.
|
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
|
As already hinted, raw functions and types can be less convenient. This section will therefore explain some pitfalls to
|
||||||
accept *only* the right types and that all required parameters must be filled in. This section will therefore explain
|
take into consideration when working with the raw API.
|
||||||
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.
|
Every available high-level method 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_!
|
|
||||||
|
|
||||||
Invoking Functions
|
Invoking Functions
|
||||||
^^^^^^^^^^^^^^^^^^
|
------------------
|
||||||
|
|
||||||
Unlike the :doc:`methods <../api/methods/index>` found in Pyrogram's API, which can be called in the usual simple way,
|
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>`
|
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
|
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:
|
with Client("my_account") as app:
|
||||||
app.send(
|
app.send(
|
||||||
functions.account.UpdateProfile(
|
functions.account.UpdateProfile(
|
||||||
first_name="Dan", last_name="Tès",
|
first_name="First Name", last_name="Last Name",
|
||||||
about="Bio written from Pyrogram"
|
about="New bio text"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
- Disable links to your account when someone forwards your messages:
|
- Set online/offline status:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -74,14 +66,13 @@ Here's some examples:
|
|||||||
from pyrogram.raw import functions, types
|
from pyrogram.raw import functions, types
|
||||||
|
|
||||||
with Client("my_account") as app:
|
with Client("my_account") as app:
|
||||||
app.send(
|
# Set online status
|
||||||
functions.account.SetPrivacy(
|
app.send(functions.account.UpdateStatus(offline=False))
|
||||||
key=types.PrivacyKeyForwards(),
|
|
||||||
rules=[types.InputPrivacyValueDisallowAll()]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
- Invite users to your channel/supergroup:
|
# Set offline status
|
||||||
|
app.send(functions.account.UpdateStatus(offline=True))
|
||||||
|
|
||||||
|
- Get chat info:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@ -89,21 +80,18 @@ Here's some examples:
|
|||||||
from pyrogram.raw import functions, types
|
from pyrogram.raw import functions, types
|
||||||
|
|
||||||
with Client("my_account") as app:
|
with Client("my_account") as app:
|
||||||
app.send(
|
r = app.send(
|
||||||
functions.channels.InviteToChannel(
|
functions.channels.GetFullChannel(
|
||||||
channel=app.resolve_peer(123456789), # ID or Username
|
channel=app.resolve_peer("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
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print(r)
|
||||||
|
|
||||||
Chat IDs
|
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
|
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.
|
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.InputPeerUser` - Users
|
||||||
- :class:`~pyrogram.raw.types.InputPeerChat` - Basic Chats
|
- :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
|
:meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer
|
||||||
by accepting a peer ID only.
|
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
|
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.
|
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
|
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 (as well as the official Bot API) uses a slightly different representation for each
|
collisions, and that's why Pyrogram uses a slightly different representation for each kind of ID.
|
||||||
kind of ID.
|
|
||||||
|
|
||||||
For example, given the ID *123456789*, here's how Pyrogram can tell entities apart:
|
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
|
You can control the way your client appears in the Active Sessions menu of an official client by changing some client
|
||||||
in the system at the same time.
|
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
|
- Device Model: ``CPython x.y.z``
|
||||||
app (or by invoking :class:`~pyrogram.api.functions.account.GetAuthorizations` with Pyrogram). They
|
- Application: ``Pyrogram x.y.z``
|
||||||
store some useful information such as the client who's using them and from which country and IP address.
|
- System Version: ``Linux x.y.z``
|
||||||
|
|
||||||
.. 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**
|
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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 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
|
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.
|
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
|
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
|
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
|
Settings specified via Client's parameter have higher priority and will override any setting stored in the
|
||||||
configuration file.
|
configuration file.
|
||||||
|
@ -87,7 +87,7 @@ Finally, the filter usage remains the same:
|
|||||||
Filters with Arguments
|
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
|
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
|
first argument of the callback function, which is a reference to the filter object itself holding the extra data passed
|
||||||
via named arguments.
|
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
|
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
|
.. contents:: Contents
|
||||||
:backlinks: none
|
:backlinks: none
|
||||||
@ -27,8 +27,8 @@ Consider the following code:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
dan = app.get_users("haskell")
|
me = app.get_users("me")
|
||||||
print(dan) # User
|
print(me) # User
|
||||||
|
|
||||||
This will show a JSON representation of the object returned by :meth:`~pyrogram.Client.get_users`, which is a
|
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:
|
: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
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"_": "pyrogram.User",
|
"_": "User",
|
||||||
"id": 23122162,
|
"id": 123456789,
|
||||||
"is_self": false,
|
"is_self": true,
|
||||||
"is_contact": false,
|
"is_contact": false,
|
||||||
"is_mutual_contact": false,
|
"is_mutual_contact": false,
|
||||||
"is_deleted": 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_verified": false,
|
||||||
"is_restricted": false,
|
"is_restricted": false,
|
||||||
"is_support": false,
|
"is_support": false,
|
||||||
"is_scam": false,
|
"first_name": "Pyrogram",
|
||||||
"first_name": "Dan",
|
|
||||||
"status": {
|
|
||||||
"_": "pyrogram.UserStatus",
|
|
||||||
"user_id": 23122162,
|
|
||||||
"recently": true
|
|
||||||
},
|
|
||||||
"username": "haskell",
|
|
||||||
"language_code": "en",
|
|
||||||
"photo": {
|
"photo": {
|
||||||
"_": "pyrogram.ChatPhoto",
|
"_": "ChatPhoto",
|
||||||
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
|
"small_file_id": "AbCdE...EdCbA",
|
||||||
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
|
"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
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
dan_photo = dan.photo
|
photo = me.photo
|
||||||
print(dan_photo) # ChatPhoto
|
print(photo) # ChatPhoto
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"_": "pyrogram.ChatPhoto",
|
"_": "ChatPhoto",
|
||||||
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
|
"small_file_id": "AbCdE...EdCbA",
|
||||||
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
|
"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
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
dan_status = dan.status
|
status = me.status
|
||||||
print(type(dan_status))
|
print(type(status))
|
||||||
|
|
||||||
.. code-block:: text
|
.. 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
|
from pyrogram.types import UserStatus
|
||||||
|
|
||||||
dan_status = dan.status
|
status = me.status
|
||||||
print(isinstance(dan_status, UserStatus))
|
print(isinstance(status, UserStatus))
|
||||||
|
|
||||||
.. code-block:: text
|
.. 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:
|
For example, take these two handlers:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 1, 6
|
|
||||||
|
|
||||||
@app.on_message(filters.text | filters.sticker)
|
@app.on_message(filters.text | filters.sticker)
|
||||||
def text_or_sticker(client, message):
|
def text_or_sticker(client, message):
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
MTProto vs. Bot API
|
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
|
Pyrogram is a framework written from the ground up that acts as a fully-fledged Telegram client based on the MTProto
|
||||||
already superior to, what is usually called, the official Bot API, in many respects. This page will therefore show you
|
API. This means that Pyrogram is able to execute any official client and bot API action and more. This page will
|
||||||
why Pyrogram might be a better choice for your project by comparing the two APIs, but first, let's make it clear what
|
therefore show you why Pyrogram might be a better choice for your project by comparing the two APIs, but first, let's
|
||||||
actually is the MTProto and the Bot API.
|
make it clear what actually is the MTProto and the Bot API.
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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
|
`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.
|
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
|
The MTProto API on the other hand, is what people for convenience call the main Telegram API in order to distinguish it
|
||||||
is able to authorize both users and bots and is built on top of the MTProto encryption protocol by means of
|
from the Bot API. The main Telegram API is able to authorize both users and bots and is built on top of the MTProto
|
||||||
`binary data serialized`_ in a specific way, as described by the `TL language`_, and delivered using UDP, TCP or even
|
encryption protocol by means of `binary data serialized`_ in a specific way, as described by the `TL language`_, and
|
||||||
HTTP as transport-layer protocol.
|
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
|
.. _MTProto: https://core.telegram.org/mtproto
|
||||||
.. _binary data serialized: https://core.telegram.org/mtproto/serialize
|
.. _binary data serialized: https://core.telegram.org/mtproto/serialize
|
||||||
@ -31,12 +32,12 @@ HTTP as transport-layer protocol.
|
|||||||
What is the Bot API?
|
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
|
The `Bot API`_ is an HTTP(S) interface for building normal bots using a sub-set of the main Telegram API. Bots are
|
||||||
accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the main
|
special accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the
|
||||||
Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram servers
|
main Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram
|
||||||
using MTProto.
|
servers using MTProto.
|
||||||
|
|
||||||
.. figure:: https://i.imgur.com/WvwBoZo.png
|
.. figure:: //_static/img/mtproto-vs-bot-api.png
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
.. _Bot API: https://core.telegram.org/bots/api
|
.. _Bot API: https://core.telegram.org/bots/api
|
||||||
@ -44,8 +45,8 @@ using MTProto.
|
|||||||
Advantages of the MTProto API
|
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
|
Here is a non-exhaustive list of all the advantages in using MTProto-based libraries -- such as Pyrogram -- instead of
|
||||||
HTTP Bot API. Using Pyrogram you can:
|
the official HTTP Bot API. Using Pyrogram you can:
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 1
|
:columns: 1
|
||||||
@ -69,7 +70,7 @@ HTTP Bot API. Using Pyrogram you can:
|
|||||||
.. hlist::
|
.. hlist::
|
||||||
:columns: 1
|
: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
|
- :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.
|
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``
|
- Install with ``pip3 install apscheduler``
|
||||||
- Documentation: https://apscheduler.readthedocs.io
|
- Documentation: https://apscheduler.readthedocs.io
|
||||||
|
@ -24,8 +24,7 @@ If you want a nicely formatted, human readable JSON representation of any object
|
|||||||
...
|
...
|
||||||
|
|
||||||
with app:
|
with app:
|
||||||
r = app.get_chat("haskell")
|
r = app.get_chat("me")
|
||||||
|
|
||||||
print(str(r))
|
print(str(r))
|
||||||
|
|
||||||
.. tip::
|
.. tip::
|
||||||
@ -48,7 +47,7 @@ as the process requires the package to be in scope.
|
|||||||
...
|
...
|
||||||
|
|
||||||
with app:
|
with app:
|
||||||
r = app.get_chat("haskell")
|
r = app.get_chat("me")
|
||||||
|
|
||||||
print(repr(r))
|
print(repr(r))
|
||||||
print(eval(repr(r)) == r) # True
|
print(eval(repr(r)) == r) # True
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
Smart Plugins
|
Smart Plugins
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Pyrogram embeds a **smart**, lightweight yet powerful plugin system that is meant to further simplify the organization
|
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
|
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**.
|
different Pyrogram applications with minimal boilerplate code.
|
||||||
|
|
||||||
.. tip::
|
.. 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
|
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
|
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
|
:class:`~pyrogram.handlers.MessageHandler` object because you can't use decorators for your functions.
|
||||||
functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
|
So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
|
||||||
|
|
||||||
Using Smart Plugins
|
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.
|
This is the same example application as shown above, written using the Smart Plugin system.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
:emphasize-lines: 2, 3
|
|
||||||
|
|
||||||
myproject/
|
myproject/
|
||||||
plugins/
|
plugins/
|
||||||
@ -102,7 +101,6 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
|
|||||||
- ``plugins/handlers.py``
|
- ``plugins/handlers.py``
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 4, 9
|
|
||||||
|
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
|
|
||||||
@ -164,7 +162,7 @@ found inside each module will be, instead, loaded in the order they are defined,
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping
|
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
|
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``
|
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.
|
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
|
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.
|
*(handler: Handler, group: int)* is attached to the function object itself.
|
||||||
|
|
||||||
- ``plugins/handlers.py``
|
- ``plugins/handlers.py``
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 5, 6
|
|
||||||
|
|
||||||
@Client.on_message(filters.text & filters.private)
|
@Client.on_message(filters.text & filters.private)
|
||||||
def echo(client, message):
|
def echo(client, message):
|
||||||
message.reply(message.text)
|
message.reply(message.text)
|
||||||
|
|
||||||
print(echo)
|
print(echo)
|
||||||
print(echo.handler)
|
print(echo.handlers)
|
||||||
|
|
||||||
- Printing ``echo`` will show something like ``<function echo at 0x10e3b6598>``.
|
- 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
|
- Printing ``echo.handlers`` will reveal the handlers, that is, a list of tuples containing the actual handlers and
|
||||||
was registered on ``(<MessageHandler object at 0x10e3abc50>, 0)``.
|
the groups they were registered on ``[(<MessageHandler object at 0x10e3abc50>, 0)]``.
|
||||||
|
|
||||||
Unloading
|
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
|
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
|
:meth:`~pyrogram.Client.remove_handler` Client's method with your function's *handler* instance:
|
||||||
star ``*`` operator as argument. Example:
|
|
||||||
|
|
||||||
- ``main.py``
|
- ``main.py``
|
||||||
|
|
||||||
@ -333,16 +329,19 @@ star ``*`` operator as argument. Example:
|
|||||||
|
|
||||||
from plugins.handlers import echo
|
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
|
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:
|
exactly what is needed. The same could have been achieved with:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
handler, group = echo.handler
|
handlers = echo.handlers
|
||||||
|
handler, group = handlers[0]
|
||||||
|
|
||||||
app.remove_handler(handler, group)
|
app.remove_handler(handler, group)
|
||||||
|
|
||||||
Loading
|
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
|
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.
|
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
|
Different Storage Engines
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Let's now talk about how Pyrogram actually stores all the relevant data. Pyrogram offers two different types of storage
|
Pyrogram offers two different types of storage engines: a **File Storage** and a **Memory Storage**.
|
||||||
engines: a **File Storage** and a **Memory Storage**. These engines are well integrated in the library and require a
|
These engines are well integrated in the framework and require a minimal effort to set up. Here's how they work:
|
||||||
minimal effort to set up. Here's how they work:
|
|
||||||
|
|
||||||
File Storage
|
File Storage
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
This is the most common storage engine. It is implemented by using **SQLite**, which will store the session and peers
|
This is the most common storage engine. It is implemented by using **SQLite**, which will store the session details.
|
||||||
details. The database will be saved to disk as a single portable file and is designed to efficiently store and retrieve
|
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.
|
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
|
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:
|
: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:
|
with Client(":memory:") as app:
|
||||||
print(app.get_me())
|
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
|
This storage engine is still backed by SQLite, but the database exists purely in memory. This means that, once you stop
|
||||||
client, the entire database is discarded and the session details used for logging in again will be lost forever.
|
a client, the entire database is discarded and the session details used for logging in again will be lost forever.
|
||||||
|
|
||||||
Session Strings
|
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:
|
with Client(":memory:") as app:
|
||||||
print(app.export_session_string())
|
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
|
...and save the resulting string. You can use this string as session name the next time you want to login
|
||||||
to login using the same session; the storage used will still be completely in-memory:
|
using the same session; the storage used will still be in-memory:
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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:
|
with Client(session_string) as app:
|
||||||
print(app.get_me())
|
print(app.get_me())
|
||||||
|
|
||||||
Session strings are useful when you want to run authorized Pyrogram clients on platforms like
|
Session strings are useful when you want to run authorized Pyrogram clients on platforms where their ephemeral
|
||||||
`Heroku <https://www.heroku.com/>`_, where their ephemeral filesystems makes it much harder for a file-based storage
|
filesystems makes it harder for a file-based storage engine to properly work as intended.
|
||||||
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.
|
|
||||||
|
@ -15,8 +15,7 @@ Telegram's test servers without hassle. All you need to do is start a new sessio
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If this is the first time you login into test servers, you will be asked to register your account first.
|
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 registered on test servers reside in a different, parallel instance of a Telegram server.
|
||||||
accounts authorized on test servers reside in a different, parallel instance of a Telegram database.
|
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
:backlinks: none
|
: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
|
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
|
- **Telegram Web**: Login here: https://web.telegram.org/?test=1
|
||||||
- **TDesktop**: Hold ``Alt+Shift`` and right click on "Add account", then choose "Test server".
|
- **Telegram Desktop**: Hold ``Alt+Shift`` and right click on "Add account", then choose "Test server".
|
||||||
|
|
||||||
Test Numbers
|
Test Numbers
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Beside normal numbers, the test environment allows you to login with reserved 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
|
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).
|
numbers. Users with such numbers always get ``XXXXX`` or ``XXXXXX`` as the confirmation code (the DC number, repeated
|
||||||
|
five or six 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.
|
|
@ -14,7 +14,7 @@ Text Formatting
|
|||||||
:class: strike-italic
|
:class: strike-italic
|
||||||
|
|
||||||
Pyrogram uses a custom Markdown dialect for text formatting which adds some unique features that make writing styled
|
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.
|
variety of decorations that can also be nested in order to combine multiple styles together.
|
||||||
|
|
||||||
.. contents:: Contents
|
.. contents:: Contents
|
||||||
@ -36,7 +36,7 @@ list of the basic styles currently supported by Pyrogram.
|
|||||||
- :underline:`underline`
|
- :underline:`underline`
|
||||||
- spoiler
|
- spoiler
|
||||||
- `text URL <https://pyrogram.org>`_
|
- `text URL <https://pyrogram.org>`_
|
||||||
- `user text mention <https://t.me/haskell>`_
|
- `user text mention <tg://user?id=123456789>`_
|
||||||
- ``inline fixed-width code``
|
- ``inline fixed-width code``
|
||||||
- .. code-block:: text
|
- .. code-block:: text
|
||||||
|
|
||||||
@ -66,9 +66,9 @@ To strictly use this mode, pass "markdown" to the *parse_mode* parameter when us
|
|||||||
|
|
||||||
||spoiler||
|
||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`
|
`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
|
.. code-block:: python
|
||||||
|
|
||||||
app.send_message(
|
app.send_message(
|
||||||
"haskell",
|
"me",
|
||||||
(
|
(
|
||||||
"**bold**, "
|
"**bold**, "
|
||||||
"__italic__, "
|
"__italic__, "
|
||||||
"--underline--, "
|
"--underline--, "
|
||||||
"~~strike~~, "
|
"~~strike~~, "
|
||||||
"||spoiler||, "
|
"||spoiler||, "
|
||||||
"[mention](tg://user?id=23122162), "
|
|
||||||
"[URL](https://pyrogram.org), "
|
"[URL](https://pyrogram.org), "
|
||||||
"`code`, "
|
"`code`, "
|
||||||
"```"
|
"```"
|
||||||
@ -119,9 +118,9 @@ The following tags are currently supported:
|
|||||||
|
|
||||||
<spoiler>spoiler</spoiler>
|
<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>
|
<code>inline fixed-width code</code>
|
||||||
|
|
||||||
@ -136,14 +135,13 @@ The following tags are currently supported:
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
app.send_message(
|
app.send_message(
|
||||||
"haskell",
|
"me",
|
||||||
(
|
(
|
||||||
"<b>bold</b>, "
|
"<b>bold</b>, "
|
||||||
"<i>italic</i>, "
|
"<i>italic</i>, "
|
||||||
"<u>underline</u>, "
|
"<u>underline</u>, "
|
||||||
"<s>strike</s>, "
|
"<s>strike</s>, "
|
||||||
"<spoiler>spoiler</spoiler>, "
|
"<spoiler>spoiler</spoiler>, "
|
||||||
"<a href=\"tg://user?id=23122162\">mention</a>, "
|
|
||||||
"<a href=\"https://pyrogram.org/\">URL</a>, "
|
"<a href=\"https://pyrogram.org/\">URL</a>, "
|
||||||
"<code>code</code>\n\n"
|
"<code>code</code>\n\n"
|
||||||
"<pre>"
|
"<pre>"
|
||||||
@ -181,7 +179,7 @@ This means you can combine together both syntaxes in the same text:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
app.send_message("haskell", "**bold**, <i>italic</i>")
|
app.send_message("me", "**bold**, <i>italic</i>")
|
||||||
|
|
||||||
Result:
|
Result:
|
||||||
|
|
||||||
@ -192,8 +190,8 @@ If you don't like this behaviour you can always choose to only enable either Mar
|
|||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
app.send_message("haskell", "**bold**, <i>italic</i>", parse_mode="markdown")
|
app.send_message("me", "**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="html")
|
||||||
|
|
||||||
Result:
|
Result:
|
||||||
|
|
||||||
@ -206,7 +204,7 @@ as-is.
|
|||||||
|
|
||||||
.. code-block:: python
|
.. 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:
|
Result:
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Fast Crypto
|
Fast Crypto
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Pyrogram's speed can be *dramatically* boosted up by TgCrypto_, a high-performance, easy-to-install Telegram Crypto
|
Pyrogram's speed can be boosted up by TgCrypto_, a high-performance, easy-to-install cryptography library specifically
|
||||||
Library specifically written in C for Pyrogram [1]_ as a Python extension.
|
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
|
TgCrypto is a replacement for a slower Python-only alternative and implements the cryptographic algorithms Telegram
|
||||||
**AES-IGE 256 bit** (used in MTProto v2.0) and **AES-CTR 256 bit** (used for CDN encrypted files).
|
requires, namely: AES-256-IGE, AES-256-CTR and AES-256-CBC.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
@ -14,10 +14,10 @@ Installation
|
|||||||
|
|
||||||
$ pip3 install -U tgcrypto
|
$ pip3 install -U tgcrypto
|
||||||
|
|
||||||
.. note:: Being a C extension for Python, TgCrypto is an optional but *highly recommended* dependency; when TgCrypto is
|
.. note:: When TgCrypto is not detected in your system, Pyrogram will automatically fall back to a slower Python-only
|
||||||
not detected in your system, Pyrogram will automatically fall back to PyAES and will show you a warning.
|
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
|
The errors you receive when trying to install TgCrypto are system dependent, but also descriptive enough to understand
|
||||||
what you should do next:
|
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``).
|
- **Linux**: Install a proper C compiler (``gcc``, ``clang``) and the Python header files (``python3-dev``).
|
||||||
- **Termux**: Install ``clang`` package.
|
- **Termux**: Install ``clang`` package.
|
||||||
|
|
||||||
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
|
.. _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.
|
|
@ -19,16 +19,15 @@ Single Filters
|
|||||||
|
|
||||||
Let's start right away with a simple example:
|
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:
|
ignore any other message. Filters are passed as the first argument of the decorator:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 4
|
|
||||||
|
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
|
|
||||||
|
|
||||||
@app.on_message(filters.audio)
|
@app.on_message(filters.sticker)
|
||||||
def my_handler(client, message):
|
def my_handler(client, message):
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ Let's start right away with a simple example:
|
|||||||
callback function itself:
|
callback function itself:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 9
|
|
||||||
|
|
||||||
from pyrogram import filters
|
from pyrogram import filters
|
||||||
from pyrogram.handlers import MessageHandler
|
from pyrogram.handlers import MessageHandler
|
||||||
@ -46,12 +44,12 @@ Let's start right away with a simple example:
|
|||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
|
|
||||||
app.add_handler(MessageHandler(my_handler, filters.audio))
|
app.add_handler(MessageHandler(my_handler, filters.sticker))
|
||||||
|
|
||||||
Combining Filters
|
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 ``|``:
|
operators ``~``, ``&`` and ``|``:
|
||||||
|
|
||||||
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
Voice Calls
|
Voice Calls
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Both private voice calls and group voice calls are currently supported by third-party libraries that integrate with
|
Both private voice calls and group voice calls are currently supported by third-party, external libraries that integrate
|
||||||
Pyrogram.
|
with Pyrogram.
|
||||||
|
|
||||||
Libraries
|
Libraries
|
||||||
---------
|
---------
|
||||||
|
@ -32,6 +32,7 @@ from pathlib import Path
|
|||||||
from typing import Union, List, Optional
|
from typing import Union, List, Optional
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
|
from pyrogram import __version__, __license__
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import utils
|
from pyrogram import utils
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
@ -281,6 +282,10 @@ class Client(Methods, Scaffold):
|
|||||||
if self.bot_token:
|
if self.bot_token:
|
||||||
return await self.sign_in_bot(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:
|
while True:
|
||||||
try:
|
try:
|
||||||
if not self.phone_number:
|
if not self.phone_number:
|
||||||
@ -428,7 +433,6 @@ class Client(Methods, Scaffold):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 10,14,18,22
|
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
@ -436,23 +440,23 @@ class Client(Methods, Scaffold):
|
|||||||
|
|
||||||
with app:
|
with app:
|
||||||
# Default combined mode: Markdown + HTML
|
# 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
|
# Force Markdown-only, HTML is disabled
|
||||||
app.set_parse_mode("markdown")
|
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
|
# Force HTML-only, Markdown is disabled
|
||||||
app.set_parse_mode("html")
|
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
|
# Disable the parser completely
|
||||||
app.set_parse_mode(None)
|
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
|
# Bring back the default combined mode
|
||||||
app.set_parse_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
|
self.parse_mode = parse_mode
|
||||||
@ -937,8 +941,8 @@ class Client(Methods, Scaffold):
|
|||||||
await self.loop.run_in_executor(self.executor, func)
|
await self.loop.run_in_executor(self.executor, func)
|
||||||
|
|
||||||
if len(chunk) < limit:
|
if len(chunk) < limit:
|
||||||
break
|
break
|
||||||
|
|
||||||
r = await session.send(
|
r = await session.send(
|
||||||
raw.functions.upload.GetFile(
|
raw.functions.upload.GetFile(
|
||||||
location=location,
|
location=location,
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
|
||||||
from binascii import crc32
|
from binascii import crc32
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from .tcp import TCP
|
from .tcp import TCP
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import Optional
|
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
from .tcp import TCP
|
from .tcp import TCP
|
||||||
|
@ -39,7 +39,7 @@ class RPCError(Exception):
|
|||||||
is_unknown: bool = False,
|
is_unknown: bool = False,
|
||||||
is_signed: bool = False
|
is_signed: bool = False
|
||||||
):
|
):
|
||||||
super().__init__("[{}{} {}]: {} {}".format(
|
super().__init__("Telegram says: [{}{} {}] - {} {}".format(
|
||||||
"-" if is_signed else "",
|
"-" if is_signed else "",
|
||||||
self.CODE,
|
self.CODE,
|
||||||
self.ID or self.NAME,
|
self.ID or self.NAME,
|
||||||
|
@ -934,12 +934,3 @@ class chat(Filter, set):
|
|||||||
and message.from_user
|
and message.from_user
|
||||||
and message.from_user.is_self
|
and message.from_user.is_self
|
||||||
and not message.outgoing)))
|
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 .request_callback_answer import RequestCallbackAnswer
|
||||||
from .send_game import SendGame
|
from .send_game import SendGame
|
||||||
from .send_inline_bot_result import SendInlineBotResult
|
from .send_inline_bot_result import SendInlineBotResult
|
||||||
from .set_game_score import SetGameScore
|
|
||||||
from .set_bot_commands import SetBotCommands
|
from .set_bot_commands import SetBotCommands
|
||||||
|
from .set_game_score import SetGameScore
|
||||||
|
|
||||||
|
|
||||||
class Bots(
|
class Bots(
|
||||||
|
@ -47,8 +47,8 @@ class GetChatMember(Scaffold):
|
|||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
dan = app.get_chat_member("pyrogramchat", "haskell")
|
member = app.get_chat_member(chat_id, "me")
|
||||||
print(dan)
|
print(member)
|
||||||
"""
|
"""
|
||||||
chat = await self.resolve_peer(chat_id)
|
chat = await self.resolve_peer(chat_id)
|
||||||
user = await self.resolve_peer(user_id)
|
user = await self.resolve_peer(user_id)
|
||||||
|
@ -57,16 +57,17 @@ class GetChatMembers(Scaffold):
|
|||||||
|
|
||||||
offset (``int``, *optional*):
|
offset (``int``, *optional*):
|
||||||
Sequential number of the first member to be returned.
|
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*):
|
limit (``int``, *optional*):
|
||||||
Limits the number of members to be retrieved.
|
Limits the number of members to be retrieved.
|
||||||
Only applicable to supergroups and channels.
|
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 (``str``, *optional*):
|
||||||
Query string to filter members based on their display names and usernames.
|
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 (``str``, *optional*):
|
||||||
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
|
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.
|
Only applicable to supergroups and channels.
|
||||||
Defaults to *"recent"*.
|
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:
|
Returns:
|
||||||
List of :obj:`~pyrogram.types.ChatMember`: On success, a list of chat members is returned.
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
# Get first 200 recent members
|
# Get first 200 recent members
|
||||||
app.get_chat_members("pyrogramchat")
|
app.get_chat_members(chat_id)
|
||||||
|
|
||||||
# Get all administrators
|
# Get all administrators
|
||||||
app.get_chat_members("pyrogramchat", filter="administrators")
|
app.get_chat_members(chat_id, filter="administrators")
|
||||||
|
|
||||||
# Get all bots
|
# 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)
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class GetChatMembersCount(Scaffold):
|
|||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
count = app.get_chat_members_count("pyrogramchat")
|
count = app.get_chat_members_count(chat_id)
|
||||||
print(count)
|
print(count)
|
||||||
"""
|
"""
|
||||||
peer = await self.resolve_peer(chat_id)
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from string import ascii_lowercase
|
|
||||||
from typing import Union, AsyncGenerator, Optional
|
from typing import Union, AsyncGenerator, Optional
|
||||||
|
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
@ -33,10 +32,6 @@ class Filters:
|
|||||||
ADMINISTRATORS = "administrators"
|
ADMINISTRATORS = "administrators"
|
||||||
|
|
||||||
|
|
||||||
QUERIES = [""] + [str(i) for i in range(10)] + list(ascii_lowercase)
|
|
||||||
QUERYABLE_FILTERS = (Filters.ALL, Filters.BANNED, Filters.RESTRICTED)
|
|
||||||
|
|
||||||
|
|
||||||
class IterChatMembers(Scaffold):
|
class IterChatMembers(Scaffold):
|
||||||
async def iter_chat_members(
|
async def iter_chat_members(
|
||||||
self,
|
self,
|
||||||
@ -57,11 +52,11 @@ class IterChatMembers(Scaffold):
|
|||||||
|
|
||||||
limit (``int``, *optional*):
|
limit (``int``, *optional*):
|
||||||
Limits the number of members to be retrieved.
|
Limits the number of members to be retrieved.
|
||||||
By default, no limit is applied and all members are returned [1]_.
|
|
||||||
|
|
||||||
query (``str``, *optional*):
|
query (``str``, *optional*):
|
||||||
Query string to filter members based on their display names and usernames.
|
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 (``str``, *optional*):
|
||||||
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
|
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.
|
*"administrators"* - chat administrators only.
|
||||||
Defaults to *"recent"*.
|
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:
|
Returns:
|
||||||
``Generator``: A generator yielding :obj:`~pyrogram.types.ChatMember` objects.
|
``Generator``: A generator yielding :obj:`~pyrogram.types.ChatMember` objects.
|
||||||
|
|
||||||
@ -86,58 +76,52 @@ class IterChatMembers(Scaffold):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Iterate though all chat members
|
# 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)
|
print(member.user.first_name)
|
||||||
|
|
||||||
# Iterate though all administrators
|
# 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)
|
print(member.user.first_name)
|
||||||
|
|
||||||
# Iterate though all bots
|
# 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)
|
print(member.user.first_name)
|
||||||
"""
|
"""
|
||||||
current = 0
|
current = 0
|
||||||
yielded = set()
|
yielded = set()
|
||||||
queries = [query] if query else QUERIES
|
|
||||||
total = limit or (1 << 31) - 1
|
total = limit or (1 << 31) - 1
|
||||||
limit = min(200, total)
|
limit = min(200, total)
|
||||||
resolved_chat_id = await self.resolve_peer(chat_id)
|
resolved_chat_id = await self.resolve_peer(chat_id)
|
||||||
|
offset = 0
|
||||||
|
|
||||||
if filter not in QUERYABLE_FILTERS:
|
while True:
|
||||||
queries = [""]
|
chat_members = await self.get_chat_members(
|
||||||
|
chat_id=chat_id,
|
||||||
|
offset=offset,
|
||||||
|
limit=limit,
|
||||||
|
query=query,
|
||||||
|
filter=filter
|
||||||
|
)
|
||||||
|
|
||||||
for q in queries:
|
if not chat_members:
|
||||||
offset = 0
|
break
|
||||||
|
|
||||||
while True:
|
if isinstance(resolved_chat_id, raw.types.InputPeerChat):
|
||||||
chat_members = await self.get_chat_members(
|
total = len(chat_members)
|
||||||
chat_id=chat_id,
|
|
||||||
offset=offset,
|
|
||||||
limit=limit,
|
|
||||||
query=q,
|
|
||||||
filter=filter
|
|
||||||
)
|
|
||||||
|
|
||||||
if not chat_members:
|
offset += len(chat_members)
|
||||||
break
|
|
||||||
|
|
||||||
if isinstance(resolved_chat_id, raw.types.InputPeerChat):
|
for chat_member in chat_members:
|
||||||
total = len(chat_members)
|
user_id = chat_member.user.id
|
||||||
|
|
||||||
offset += len(chat_members)
|
if user_id in yielded:
|
||||||
|
continue
|
||||||
|
|
||||||
for chat_member in chat_members:
|
yield chat_member
|
||||||
user_id = chat_member.user.id
|
|
||||||
|
|
||||||
if user_id in yielded:
|
yielded.add(chat_member.user.id)
|
||||||
continue
|
|
||||||
|
|
||||||
yield chat_member
|
current += 1
|
||||||
|
|
||||||
yielded.add(chat_member.user.id)
|
if current >= total:
|
||||||
|
return
|
||||||
current += 1
|
|
||||||
|
|
||||||
if current >= total:
|
|
||||||
return
|
|
||||||
|
@ -52,7 +52,7 @@ class SetAdministratorTitle(Scaffold):
|
|||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. 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)
|
chat_id = await self.resolve_peer(chat_id)
|
||||||
user_id = await self.resolve_peer(user_id)
|
user_id = await self.resolve_peer(user_id)
|
||||||
|
@ -45,10 +45,10 @@ class SetSlowMode(Scaffold):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Set slow mode to 60 seconds
|
# Set slow mode to 60 seconds
|
||||||
app.set_slow_mode("pyrogramchat", 60)
|
app.set_slow_mode(chat_id, 60)
|
||||||
|
|
||||||
# Disable slow mode
|
# Disable slow mode
|
||||||
app.set_slow_mode("pyrogramchat", None)
|
app.set_slow_mode(chat_id, None)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
await self.send(
|
await self.send(
|
||||||
|
@ -38,7 +38,7 @@ class AddContact(Scaffold):
|
|||||||
user_id (``int`` | ``str``):
|
user_id (``int`` | ``str``):
|
||||||
Unique identifier (int) or username (str) of the target user.
|
Unique identifier (int) or username (str) of the target user.
|
||||||
|
|
||||||
first_name (``str``, *optional*):
|
first_name (``str``):
|
||||||
User's first name.
|
User's first name.
|
||||||
|
|
||||||
last_name (``str``, *optional*):
|
last_name (``str``, *optional*):
|
||||||
|
@ -43,9 +43,9 @@ class ImportContacts(Scaffold):
|
|||||||
from pyrogram.types import InputPhoneContact
|
from pyrogram.types import InputPhoneContact
|
||||||
|
|
||||||
app.import_contacts([
|
app.import_contacts([
|
||||||
InputPhoneContact("39123456789", "Foo"),
|
InputPhoneContact("+1-123-456-7890", "Foo"),
|
||||||
InputPhoneContact("38987654321", "Bar"),
|
InputPhoneContact("+1-456-789-0123", "Bar"),
|
||||||
InputPhoneContact("01234567891", "Baz")])
|
InputPhoneContact("+1-789-012-3456", "Baz")])
|
||||||
"""
|
"""
|
||||||
imported_contacts = await self.send(
|
imported_contacts = await self.send(
|
||||||
raw.functions.contacts.ImportContacts(
|
raw.functions.contacts.ImportContacts(
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# 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 import types, utils, raw
|
||||||
from pyrogram.scaffold import Scaffold
|
from pyrogram.scaffold import Scaffold
|
||||||
@ -103,7 +103,8 @@ class CopyMediaGroup(Scaffold):
|
|||||||
**await self.parser.parse(
|
**await self.parser.parse(
|
||||||
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
||||||
captions if isinstance(captions, str) and i == 0 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)
|
app.download_media(message)
|
||||||
|
|
||||||
# Download from file id
|
# Download from file id
|
||||||
app.download_media("CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE")
|
app.download_media(message.photo.file_id)
|
||||||
|
|
||||||
# Keep track of the progress while downloading
|
# Keep track of the progress while downloading
|
||||||
def progress(current, total):
|
def progress(current, total):
|
||||||
|
@ -67,7 +67,6 @@ class ForwardMessages(Scaffold):
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:emphasize-lines: 2,5
|
|
||||||
|
|
||||||
# Forward a single message
|
# Forward a single message
|
||||||
app.forward_messages("me", "pyrogram", 20)
|
app.forward_messages("me", "pyrogram", 20)
|
||||||
|
@ -72,13 +72,13 @@ class GetHistory(Scaffold):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Get the last 100 messages of a chat
|
# 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
|
# 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
|
# 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)
|
offset_id = offset_id or (1 if reverse else 0)
|
||||||
|
@ -48,7 +48,7 @@ class GetHistoryCount(Scaffold):
|
|||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
app.get_history_count("pyrogramchat")
|
app.get_history_count(chat_id)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
r = await self.send(
|
r = await self.send(
|
||||||
|
@ -50,7 +50,7 @@ class GetMediaGroup(Scaffold):
|
|||||||
In case the passed message_id is negative or equal 0.
|
In case the passed message_id is negative or equal 0.
|
||||||
In case target message doesn't belong to a media group.
|
In case target message doesn't belong to a media group.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# There can be maximum 10 items in 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)],
|
messages = await self.get_messages(chat_id, [msg_id for msg_id in range(message_id - 9, message_id + 10)],
|
||||||
replies=0)
|
replies=0)
|
||||||
@ -66,7 +66,7 @@ class GetMediaGroup(Scaffold):
|
|||||||
|
|
||||||
# There can be maximum 10 items in a media group.
|
# 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.
|
# 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:
|
if media_group_id is None:
|
||||||
raise ValueError("The message doesn't belong to a media group")
|
raise ValueError("The message doesn't belong to a media group")
|
||||||
|
@ -71,10 +71,10 @@ class GetMessages(Scaffold):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Get one message
|
# Get one message
|
||||||
app.get_messages("pyrogramchat", 51110)
|
app.get_messages(chat_id, 12345)
|
||||||
|
|
||||||
# Get more than one message (list of messages)
|
# 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
|
# Get message by ignoring any replied-to message
|
||||||
app.get_messages(chat_id, message_id, replies=0)
|
app.get_messages(chat_id, message_id, replies=0)
|
||||||
|
@ -47,10 +47,10 @@ class ReadHistory(Scaffold):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# Mark the whole chat as read
|
# 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
|
# 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)
|
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