Merge branch 'develop' into inline-mode

# Conflicts:
#	compiler/api/compiler.py
This commit is contained in:
Dan 2018-11-09 08:52:26 +01:00
commit 8d50b86bc6
110 changed files with 5364 additions and 4651 deletions

View File

@ -97,13 +97,13 @@ Copyright & License
<a href="https://t.me/PyrogramChat">
Community
</a>
<br><br>
<br>
<a href="compiler/api/source/main_api.tl">
<img src="https://img.shields.io/badge/SCHEME-LAYER%2082-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
alt="Scheme Layer">
<img src="https://img.shields.io/badge/schema-layer%2082-eda738.svg?longCache=true&colorA=262b30"
alt="Schema Layer">
</a>
<a href="https://github.com/pyrogram/tgcrypto">
<img src="https://img.shields.io/badge/TGCRYPTO-V1.1.1-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
<img src="https://img.shields.io/badge/tgcrypto-v1.1.1-eda738.svg?longCache=true&colorA=262b30"
alt="TgCrypto">
</a>
</p>

View File

@ -507,6 +507,7 @@ def start():
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
f.write("\n 0xb0700031: \"pyrogram.client.types.UserStatus\"")
f.write("\n 0xb0700032: \"pyrogram.client.types.InlineQuery\"")
f.write("\n}\n")

View File

@ -68,3 +68,4 @@ USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
USER_NOT_PARTICIPANT The user is not a member of this chat
CHANNEL_PRIVATE The channel/supergroup is not accessible
MESSAGE_IDS_EMPTY The requested message doesn't exist
1 id message
68 API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
69 USER_NOT_PARTICIPANT The user is not a member of this chat
70 CHANNEL_PRIVATE The channel/supergroup is not accessible
71 MESSAGE_IDS_EMPTY The requested message doesn't exist

View File

@ -2,3 +2,4 @@ id message
CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup)
CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat
1 id message
2 CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
3 RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup)
4 CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
5 MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat

View File

@ -84,6 +84,7 @@ To get started, press the Next button.
resources/UpdateHandling
resources/UsingFilters
resources/SmartPlugins
resources/AutoAuthorization
resources/CustomizeSessions
resources/TgCrypto

View File

@ -30,6 +30,7 @@ Decorators
on_message
on_callback_query
on_deleted_messages
on_user_status
on_disconnect
on_raw_update
@ -96,7 +97,8 @@ Users
get_me
get_users
get_user_profile_photos
delete_profile_photos
set_user_profile_photo
delete_user_profile_photos
Contacts
--------

View File

@ -3,4 +3,3 @@ Filters
.. autoclass:: pyrogram.Filters
:members:
:undoc-members:

View File

@ -9,6 +9,7 @@ Handlers
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
UserStatusHandler
DisconnectHandler
RawUpdateHandler
@ -21,6 +22,9 @@ Handlers
.. autoclass:: CallbackQueryHandler
:members:
.. autoclass:: UserStatusHandler
:members:
.. autoclass:: DisconnectHandler
:members:

View File

@ -10,6 +10,7 @@ Users & Chats
:nosignatures:
User
UserStatus
Chat
ChatPhoto
ChatMember
@ -73,6 +74,9 @@ Input Media
.. autoclass:: User
:members:
.. autoclass:: UserStatus
:members:
.. autoclass:: Chat
:members:

View File

@ -35,11 +35,8 @@ Example:
password="password" # (if you have one)
)
app.start()
print(app.get_me())
app.stop()
with app:
print(app.get_me())
Sign Up
-------
@ -67,8 +64,5 @@ Example:
last_name="" # Can be an empty string
)
app.start()
print(app.get_me())
app.stop()
with app:
print(app.get_me())

View File

@ -0,0 +1,126 @@
Smart Plugins
=============
Pyrogram embeds a **smart** (automatic) and lightweight plugin system that is meant to further simplify the organization
of large projects and to provide a way for creating pluggable components that can be **easily shared** across different
Pyrogram applications with **minimal boilerplate code**.
.. tip::
Smart Plugins are completely optional and disabled by default.
Introduction
------------
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
your applications, you had to do something like this...
.. note::
This is an example application that replies in private chats with two messages: one containing the same
text message you sent and the other containing the reversed text message.
Example: *"Pyrogram"* replies with *"Pyrogram"* and *"margoryP"*
.. code-block:: text
myproject/
config.ini
handlers.py
main.py
- ``handlers.py``
.. code-block:: python
def echo(client, message):
message.reply(message.text)
def echo_reversed(client, message):
message.reply(message.text[::-1])
- ``main.py``
.. code-block:: python
from pyrogram import Client, MessageHandler, Filters
from handlers import echo, echo_reversed
app = Client("my_account")
app.add_handler(
MessageHandler(
echo,
Filters.text & Filters.private))
app.add_handler(
MessageHandler(
echo_reversed,
Filters.text & Filters.private),
group=1)
app.run()
...which is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
manually ``import``, manually :meth:`add_handler <pyrogram.Client.add_handler>` and manually instantiate each
:obj:`MessageHandler <pyrogram.MessageHandler>` object because **you can't use those cool decorators** for your
functions. So... What if you could?
Using Smart Plugins
-------------------
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
#. Create a new folder to store all the plugins (e.g.: "plugins").
#. Put your files full of plugins inside.
#. Enable plugins in your Client.
.. note::
This is the same example application `as shown above <#introduction>`_, written using the Smart Plugin system.
.. code-block:: text
:emphasize-lines: 2, 3
myproject/
plugins/
handlers.py
config.ini
main.py
- ``plugins/handlers.py``
.. code-block:: python
:emphasize-lines: 4, 9
from pyrogram import Client, Filters
@Client.on_message(Filters.text & Filters.private)
def echo(client, message):
message.reply(message.text)
@Client.on_message(Filters.text & Filters.private, group=1)
def echo_reversed(client, message):
message.reply(message.text[::-1])
- ``main.py``
.. code-block:: python
from pyrogram import Client
Client("my_account", plugins_dir="plugins").run()
The first important thing to note is the new ``plugins`` folder, whose name is passed to the the ``plugins_dir``
parameter when creating a :obj:`Client <pyrogram.Client>` in the ``main.py`` file — you can put *any python file* in
there and each file can contain *any decorated function* (handlers) with only one limitation: within a single plugin
file you must use different names for each decorated function. Your Pyrogram Client instance will **automatically**
scan the folder upon creation to search for valid handlers and register them for you.
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
functions in a static way, i.e. **without having the Client instance around**: simply use ``@Client`` (Client class)
instead of the usual ``@app`` (Client instance) namespace and things will work just the same.

View File

@ -14,17 +14,17 @@ by following the instructions at https://pip.pypa.io/en/latest/installing/.
Install Pyrogram
----------------
- The easiest way to install and upgrade Pyrogram is by using **pip**:
- The easiest way to install and upgrade Pyrogram to its latest stable version is by using **pip**:
.. code-block:: bash
.. code-block:: text
$ pip3 install --upgrade pyrogram
- or, with TgCrypto_ (recommended):
- or, with TgCrypto_ as extra requirement (recommended):
.. code-block:: bash
.. code-block:: text
$ pip3 install --upgrade pyrogram[tgcrypto]
$ pip3 install --upgrade pyrogram[fast]
Bleeding Edge
-------------
@ -32,21 +32,57 @@ Bleeding Edge
If you want the latest development version of Pyrogram, you can install it straight from the develop_
branch using this command (you might need to install **git** first):
.. code-block:: bash
.. code-block:: text
$ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git
Asynchronous
------------
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging client library after all), and here's
where asyncio shines the most by providing extra performance while running on a single OS-level thread only.
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5+ required).
Use this command to install:
.. code-block:: text
$ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git@asyncio
Pyrogram API remains the same and features are kept up to date from the non-async, default develop branch, but you
are obviously required Python asyncio knowledge in order to take full advantage of it.
.. tip::
The idea to turn Pyrogram fully asynchronous is still under consideration, but is wise to expect that in future this
would be the one and only way to work with Pyrogram.
You can start using Pyrogram Async variant right now as an excuse to learn more about asynchronous programming and
do experiments with it!
.. raw:: html
<script async
src="https://telegram.org/js/telegram-widget.js?4"
data-telegram-post="Pyrogram/4"
data-width="100%">
</script>
.. centered:: Subscribe to `@Pyrogram <https://t.me/Pyrogram>`_ for news and announcements
Verifying
---------
To verify that Pyrogram is correctly installed, open a Python shell and import it.
If no error shows up you are good to go.
.. code-block:: bash
.. code-block:: python
>>> import pyrogram
>>> pyrogram.__version__
'0.8.0'
'0.9.1'
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
.. _develop: http://github.com/pyrogram/pyrogram

View File

@ -23,13 +23,13 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
)
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__version__ = "0.8.1dev1"
__version__ = "0.9.2.dev1"
from .api.errors import Error
from .client.types import (
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User,
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserStatus,
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove,
InlineQuery, InlineQueryResultArticle, InlineQueryResultPhoto, InputTextMessageContent, InlineQueryResultCachedAudio
@ -37,5 +37,5 @@ from .client.types import (
from .client import (
Client, ChatAction, ParseMode, Emoji,
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
RawUpdateHandler, DisconnectHandler, Filters
RawUpdateHandler, DisconnectHandler, UserStatusHandler, Filters
)

View File

@ -22,5 +22,5 @@ from .filters import Filters
from .handlers import (
MessageHandler, DeletedMessagesHandler,
CallbackQueryHandler, RawUpdateHandler,
DisconnectHandler
DisconnectHandler, UserStatusHandler
)

View File

@ -33,6 +33,8 @@ import time
from configparser import ConfigParser
from datetime import datetime
from hashlib import sha256, md5
from importlib import import_module
from pathlib import Path
from signal import signal, SIGINT, SIGTERM, SIGABRT
from threading import Thread
@ -45,6 +47,7 @@ from pyrogram.api.errors import (
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate)
from pyrogram.client.handlers import DisconnectHandler
from pyrogram.client.handlers.handler import Handler
from pyrogram.crypto import AES
from pyrogram.session import Auth, Session
from .dispatcher import Dispatcher
@ -140,6 +143,11 @@ class Client(Methods, BaseClient):
config_file (``str``, *optional*):
Path of the configuration file. Defaults to ./config.ini
plugins_dir (``str``, *optional*):
Define a custom directory for your plugins. The plugins directory is the location in your
filesystem where Pyrogram will automatically load your update handlers.
Defaults to None (plugins disabled).
"""
def __init__(self,
@ -161,7 +169,8 @@ class Client(Methods, BaseClient):
last_name: str = None,
workers: int = BaseClient.WORKERS,
workdir: str = BaseClient.WORKDIR,
config_file: str = BaseClient.CONFIG_FILE):
config_file: str = BaseClient.CONFIG_FILE,
plugins_dir: str = None):
super().__init__()
self.session_name = session_name
@ -184,6 +193,7 @@ class Client(Methods, BaseClient):
self.workers = workers
self.workdir = workdir
self.config_file = config_file
self.plugins_dir = plugins_dir
self.dispatcher = Dispatcher(self, workers)
@ -208,7 +218,8 @@ class Client(Methods, BaseClient):
Requires no parameters.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ConnectionError`` in case you try to start an already started Client.
"""
if self.is_started:
raise ConnectionError("Client has already been started")
@ -219,6 +230,7 @@ class Client(Methods, BaseClient):
self.load_config()
self.load_session()
self.load_plugins()
self.session = Session(
self,
@ -285,6 +297,9 @@ class Client(Methods, BaseClient):
def stop(self):
"""Use this method to manually stop the Client.
Requires no parameters.
Raises:
``ConnectionError`` in case you try to stop an already stopped Client.
"""
if not self.is_started:
raise ConnectionError("Client is already stopped")
@ -344,7 +359,7 @@ class Client(Methods, BaseClient):
Requires no parameters.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
self.start()
self.idle()
@ -876,7 +891,7 @@ class Client(Methods, BaseClient):
Args:
data (``Object``):
The API Scheme function filled with proper arguments.
The API Schema function filled with proper arguments.
retries (``int``):
Number of retries.
@ -885,7 +900,7 @@ class Client(Methods, BaseClient):
Timeout in seconds.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
if not self.is_started:
raise ConnectionError("Client has not been started")
@ -968,6 +983,45 @@ class Client(Methods, BaseClient):
if peer:
self.peers_by_phone[k] = peer
def load_plugins(self):
if self.plugins_dir is not None:
plugins_count = 0
for path in Path(self.plugins_dir).rglob("*.py"):
file_path = os.path.splitext(str(path))[0]
import_path = []
while file_path:
file_path, tail = os.path.split(file_path)
import_path.insert(0, tail)
import_path = ".".join(import_path)
module = import_module(import_path)
for name in dir(module):
# noinspection PyBroadException
try:
handler, group = getattr(module, name)
if isinstance(handler, Handler) and isinstance(group, int):
self.add_handler(handler, group)
log.info('{}("{}") from "{}" loaded in group {}'.format(
type(handler).__name__, name, import_path, group))
plugins_count += 1
except Exception:
pass
if plugins_count > 0:
log.warning('Successfully loaded {} plugin{} from "{}"'.format(
plugins_count,
"s" if plugins_count > 1 else "",
self.plugins_dir
))
else:
log.warning('No plugin loaded: "{}" doesn\'t contain any valid plugin'.format(self.plugins_dir))
def save_session(self):
auth_key = base64.b64encode(self.auth_key).decode()
auth_key = [auth_key[i: i + 43] for i in range(0, len(auth_key), 43)]
@ -1035,7 +1089,8 @@ class Client(Methods, BaseClient):
On success, the resolved peer id is returned in form of an InputPeer object.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``KeyError`` in case the peer doesn't exist in the internal database.
"""
if type(peer_id) is str:
if peer_id in ("self", "me"):
@ -1075,6 +1130,13 @@ class Client(Methods, BaseClient):
progress_args: tuple = ()):
part_size = 512 * 1024
file_size = os.path.getsize(path)
if file_size == 0:
raise ValueError("File size equals to 0 B")
if file_size > 1500 * 1024 * 1024:
raise ValueError("Telegram doesn't support uploading files bigger than 1500 MiB")
file_total_parts = int(math.ceil(file_size / part_size))
is_big = True if file_size > 10 * 1024 * 1024 else False
is_missing_part = True if file_id is not None else False

View File

@ -25,7 +25,7 @@ from threading import Thread
import pyrogram
from pyrogram.api import types
from ..ext import utils
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler
log = logging.getLogger(__name__)
@ -108,6 +108,8 @@ class Dispatcher:
callback_query = update.callback_query
user_status = update.user_status
if message and isinstance(handler, MessageHandler):
if not handler.check(message):
continue
@ -123,6 +125,11 @@ class Dispatcher:
continue
args = (self.client, callback_query)
elif user_status and isinstance(handler, UserStatusHandler):
if not handler.check(user_status):
continue
args = (self.client, user_status)
else:
continue
@ -209,6 +216,14 @@ class Dispatcher:
)
)
)
elif isinstance(update, types.UpdateUserStatus):
self.dispatch(
pyrogram.Update(
user_status=utils.parse_user_status(
update.status, update.user_id
)
)
)
else:
continue
except Exception as e:

View File

@ -119,7 +119,8 @@ class BaseClient:
def get_messages(
self,
chat_id: int or str,
message_ids,
message_ids: int or list = None,
reply_to_message_ids: int or list = None,
replies: int = 1
):
pass

File diff suppressed because it is too large Load Diff

View File

@ -17,15 +17,13 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import logging
import time
from base64 import b64decode, b64encode
from struct import pack
from weakref import proxy
from pyrogram.api.errors import FloodWait
from pyrogram.client import types as pyrogram_types
from ...api import types, functions
from ...api.errors import StickersetInvalid
from ...api.errors import StickersetInvalid, MessageIdsEmpty
log = logging.getLogger(__name__)
@ -129,6 +127,30 @@ def parse_chat_photo(photo):
)
def parse_user_status(user_status, user_id: int = None, is_bot: bool = False) -> pyrogram_types.UserStatus or None:
if is_bot:
return None
status = pyrogram_types.UserStatus(user_id)
if isinstance(user_status, types.UserStatusOnline):
status.online = True
status.date = user_status.expires
elif isinstance(user_status, types.UserStatusOffline):
status.offline = True
status.date = user_status.was_online
elif isinstance(user_status, types.UserStatusRecently):
status.recently = True
elif isinstance(user_status, types.UserStatusLastWeek):
status.within_week = True
elif isinstance(user_status, types.UserStatusLastMonth):
status.within_month = True
else:
status.long_time_ago = True
return status
def parse_user(user: types.User) -> pyrogram_types.User or None:
return pyrogram_types.User(
id=user.id,
@ -142,7 +164,9 @@ def parse_user(user: types.User) -> pyrogram_types.User or None:
username=user.username,
language_code=user.lang_code,
phone_number=user.phone,
photo=parse_chat_photo(user.photo)
photo=parse_chat_photo(user.photo),
status=parse_user_status(user.status, is_bot=user.bot),
restriction_reason=user.restriction_reason
) if user else None
@ -162,7 +186,8 @@ def parse_user_chat(user: types.User) -> pyrogram_types.Chat:
username=user.username,
first_name=user.first_name,
last_name=user.last_name,
photo=parse_chat_photo(user.photo)
photo=parse_chat_photo(user.photo),
restriction_reason=user.restriction_reason
)
@ -187,7 +212,8 @@ def parse_channel_chat(channel: types.Channel) -> pyrogram_types.Chat:
type="supergroup" if channel.megagroup else "channel",
title=channel.title,
username=getattr(channel, "username", None),
photo=parse_chat_photo(getattr(channel, "photo", None))
photo=parse_chat_photo(getattr(channel, "photo", None)),
restriction_reason=getattr(channel, "restriction_reason", None)
)
@ -580,6 +606,8 @@ def parse_messages(
forward_from_message_id=forward_from_message_id,
forward_signature=forward_signature,
forward_date=forward_date,
mentioned=message.mentioned,
media=bool(media) or None,
edit_date=message.edit_date,
media_group_id=message.grouped_id,
photo=photo,
@ -607,18 +635,14 @@ def parse_messages(
m.caption.init(m._client, m.caption_entities or [])
if message.reply_to_msg_id and replies:
while True:
try:
m.reply_to_message = client.get_messages(
m.chat.id, message.reply_to_msg_id,
replies=replies - 1
)
except FloodWait as e:
log.warning("get_messages flood: waiting {} seconds".format(e.x))
time.sleep(e.x)
continue
else:
break
try:
m.reply_to_message = client.get_messages(
m.chat.id,
reply_to_message_ids=message.id,
replies=replies - 1
)
except MessageIdsEmpty:
pass
elif isinstance(message, types.MessageService):
action = message.action
@ -705,6 +729,7 @@ def parse_messages(
date=message.date,
chat=parse_chat(message, users, chats),
from_user=parse_user(users.get(message.from_id, None)),
service=True,
new_chat_members=new_chat_members,
left_chat_member=left_chat_member,
new_chat_title=new_chat_title,
@ -719,20 +744,16 @@ def parse_messages(
)
if isinstance(action, types.MessageActionPinMessage):
while True:
try:
m.pinned_message = client.get_messages(
m.chat.id, message.reply_to_msg_id,
replies=0
)
except FloodWait as e:
log.warning("get_messages flood: waiting {} seconds".format(e.x))
time.sleep(e.x)
continue
else:
break
try:
m.pinned_message = client.get_messages(
m.chat.id,
reply_to_message_ids=message.id,
replies=0
)
except MessageIdsEmpty:
pass
else:
m = pyrogram_types.Message(message_id=message.id, client=proxy(client))
m = pyrogram_types.Message(message_id=message.id, client=proxy(client), empty=True)
parsed_messages.append(m)
@ -934,7 +955,7 @@ def parse_chat_full(
if full_chat.pinned_msg_id:
parsed_chat.pinned_message = client.get_messages(
parsed_chat.id,
full_chat.pinned_msg_id
message_ids=full_chat.pinned_msg_id
)
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
@ -957,6 +978,7 @@ def parse_chat_members(members: types.channels.ChannelParticipants or types.mess
parsed_members = []
if isinstance(members, types.channels.ChannelParticipants):
count = members.count
members = members.participants
for member in members:
@ -1015,7 +1037,7 @@ def parse_chat_members(members: types.channels.ChannelParticipants or types.mess
parsed_members.append(chat_member)
return pyrogram_types.ChatMembers(
total_count=members.count,
total_count=count,
chat_members=parsed_members
)
else:

View File

@ -166,9 +166,41 @@ class Filters:
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
"""Filter messages containing inline keyboard markups"""
mentioned = create("Mentioned", lambda _, m: bool(m.mentioned))
"""Filter messages containing mentions"""
service = create("Service", lambda _, m: bool(m.service))
"""Filter service messages. A service message contains any of the following fields set
- left_chat_member
- new_chat_title
- new_chat_photo
- delete_chat_photo
- group_chat_created
- supergroup_chat_created
- channel_chat_created
- migrate_to_chat_id
- migrate_from_chat_id
- pinned_message"""
media = create("Media", lambda _, m: bool(m.media))
"""Filter media messages. A media message contains any of the following fields set
- audio
- document
- photo
- sticker
- video
- animation
- voice
- video_note
- contact
- location
- venue"""
@staticmethod
def command(command: str or list,
prefix: str = "/",
prefix: str or list = "/",
separator: str = " ",
case_sensitive: bool = False):
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
@ -180,9 +212,10 @@ class Filters:
a command arrives, the command itself and its arguments will be stored in the *command*
field of the :class:`Message <pyrogram.Message>`.
prefix (``str``, *optional*):
The command prefix. Defaults to "/" (slash).
Examples: /start, .help, !settings.
prefix (``str`` | ``list``, *optional*):
A prefix or a list of prefixes as string the filter should look for.
Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."].
Can be None or "" (empty string) to allow commands with no prefix at all.
separator (``str``, *optional*):
The command arguments separator. Defaults to " " (white space).
@ -194,11 +227,14 @@ class Filters:
"""
def f(_, m):
if m.text and m.text.startswith(_.p):
t = m.text.split(_.s)
c, a = t[0][len(_.p):], t[1:]
c = c if _.cs else c.lower()
m.command = ([c] + a) if c in _.c else None
if m.text:
for i in _.p:
if m.text.startswith(i):
t = m.text.split(_.s)
c, a = t[0][len(i):], t[1:]
c = c if _.cs else c.lower()
m.command = ([c] + a) if c in _.c else None
break
return bool(m.command)
@ -211,7 +247,7 @@ class Filters:
else {c if case_sensitive
else c.lower()
for c in command},
p=prefix,
p=set(prefix) if prefix else {""},
s=separator,
cs=case_sensitive
)
@ -246,15 +282,16 @@ class Filters:
Args:
users (``int`` | ``str`` | ``list``):
Pass one or more user ids/usernames to filter users.
For you yourself, "me" or "self" can be used as well.
Defaults to None (no users).
"""
def __init__(self, users: int or str or list = None):
users = [] if users is None else users if type(users) is list else [users]
super().__init__(
{i.lower().strip("@") if type(i) is str else i for i in users}
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in users}
if type(users) is list else
{users.lower().strip("@") if type(users) is str else users}
{"me" if users in ["me", "self"] else users.lower().strip("@") if type(users) is str else users}
)
def __call__(self, message):
@ -262,7 +299,9 @@ class Filters:
message.from_user
and (message.from_user.id in self
or (message.from_user.username
and message.from_user.username.lower() in self))
and message.from_user.username.lower() in self)
or ("me" in self
and message.from_user.is_self))
)
# noinspection PyPep8Naming
@ -275,15 +314,16 @@ class Filters:
Args:
chats (``int`` | ``str`` | ``list``):
Pass one or more chat ids/usernames to filter chats.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
Defaults to None (no chats).
"""
def __init__(self, chats: int or str or list = None):
chats = [] if chats is None else chats if type(chats) is list else [chats]
super().__init__(
{i.lower().strip("@") if type(i) is str else i for i in chats}
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in chats}
if type(chats) is list else
{chats.lower().strip("@") if type(chats) is str else chats}
{"me" if chats in ["me", "self"] else chats.lower().strip("@") if type(chats) is str else chats}
)
def __call__(self, message):
@ -291,41 +331,10 @@ class Filters:
message.chat
and (message.chat.id in self
or (message.chat.username
and message.chat.username.lower() in self))
and message.chat.username.lower() in self)
or ("me" in self and message.from_user
and message.from_user.is_self
and not message.outgoing))
)
service = create(
"Service",
lambda _, m: bool(
Filters.new_chat_members(m)
or Filters.left_chat_member(m)
or Filters.new_chat_title(m)
or Filters.new_chat_photo(m)
or Filters.delete_chat_photo(m)
or Filters.group_chat_created(m)
or Filters.supergroup_chat_created(m)
or Filters.channel_chat_created(m)
or Filters.migrate_to_chat_id(m)
or Filters.migrate_from_chat_id(m)
or Filters.pinned_message(m)
)
)
"""Filter all service messages."""
media = create(
"Media",
lambda _, m: bool(
Filters.audio(m)
or Filters.document(m)
or Filters.photo(m)
or Filters.sticker(m)
or Filters.video(m)
or Filters.animation(m)
or Filters.voice(m)
or Filters.video_note(m)
or Filters.contact(m)
or Filters.location(m)
or Filters.venue(m)
)
)
"""Filter all media messages."""
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))

View File

@ -17,7 +17,8 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .callback_query_handler import CallbackQueryHandler
from .deleted_messages_handler import DeletedMessagesHandler
from .disconnect_handler import DisconnectHandler
from .message_handler import MessageHandler
from .deleted_messages_handler import DeletedMessagesHandler
from .raw_update_handler import RawUpdateHandler
from .user_status_handler import UserStatusHandler

View File

@ -0,0 +1,54 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <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/>.
from .handler import Handler
class UserStatusHandler(Handler):
"""The UserStatus handler class. Used to handle user status updates (user going online or offline).
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
For a nicer way to register this handler, have a look at the
:meth:`on_user_status() <pyrogram.Client.on_user_status>` decorator.
Args:
callback (``callable``):
Pass a function that will be called when a new UserStatus update arrives. It takes *(client, user_status)*
as positional arguments (look at the section below for a detailed description).
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of messages to be passed
in your callback function.
Other parameters:
client (:obj:`Client <pyrogram.Client>`):
The Client itself, useful when you want to call other API methods inside the user status handler.
user_status (:obj:`UserStatus <pyrogram.UserStatus>`):
The received UserStatus update.
"""
def __init__(self, callback: callable, filters=None):
super().__init__(callback, filters)
def check(self, user_status):
return (
self.filters(user_status)
if callable(self.filters)
else True
)

View File

@ -50,6 +50,12 @@ class AnswerCallbackQuery(BaseClient):
cache_time (``int``):
The maximum amount of time in seconds that the result of the callback query may be cached client-side.
Telegram apps will support caching starting in version 3.14. Defaults to 0.
Returns:
True, on success.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return self.send(
functions.messages.SetBotCallbackAnswer(

View File

@ -54,8 +54,8 @@ class GetInlineBotResults(BaseClient):
On Success, :obj:`BotResults <pyrogram.api.types.messages.BotResults>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
``TimeoutError``: If the bot fails to answer within 10 seconds
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``TimeoutError`` if the bot fails to answer within 10 seconds
"""
# TODO: Don't return the raw type

View File

@ -45,8 +45,8 @@ class RequestCallbackAnswer(BaseClient):
or as an alert.
Raises:
:class:`Error <pyrogram.Error>`
``TimeoutError``: If the bot fails to answer within 10 seconds
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``TimeoutError`` if the bot fails to answer within 10 seconds.
"""
return self.send(
functions.messages.GetBotCallbackAnswer(

View File

@ -53,7 +53,7 @@ class SendInlineBotResult(BaseClient):
On success, the sent Message is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return self.send(
functions.messages.SendInlineBotResult(

View File

@ -38,8 +38,8 @@ class DeleteChatPhoto(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)

View File

@ -35,7 +35,7 @@ class ExportChatInviteLink(BaseClient):
On success, the exported invite link as string is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
peer = self.resolve_peer(chat_id)

View File

@ -33,7 +33,7 @@ class GetChat(BaseClient):
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
peer = self.resolve_peer(chat_id)

View File

@ -39,7 +39,7 @@ class GetChatMember(BaseClient):
On success, a :obj:`ChatMember <pyrogram.ChatMember>` object is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
chat_id = self.resolve_peer(chat_id)
user_id = self.resolve_peer(user_id)

View File

@ -39,7 +39,7 @@ class GetChatMembers(BaseClient):
"""Use this method to get the members list of a chat.
A chat can be either a basic group, a supergroup or a channel.
You must be admin to retrieve the members (also known as "subscribers") list of a channel.
You must be admin to retrieve the members list of a channel (also known as "subscribers").
Args:
chat_id (``int`` | ``str``):
@ -51,7 +51,7 @@ class GetChatMembers(BaseClient):
limit (``int``, *optional*):
Limits the number of members to be retrieved.
Defaults to 200, which is also the maximum limit allowed per method call.
Defaults to 200, which is also the maximum server limit allowed per method call.
query (``str``, *optional*):
Query string to filter members based on their display names and usernames.
@ -68,9 +68,17 @@ class GetChatMembers(BaseClient):
*"administrators"* - chat administrators only.
Defaults to *"all"*.
.. [1] On supergroups and channels you can get up to 10,000 members for a single query string.
.. [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"*, *"kicked"* and *"restricted"* filters only.
Returns:
On success, a :obj:`ChatMembers` object is returned.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if you used an invalid filter or a chat_id that belongs to a user.
"""
peer = self.resolve_peer(chat_id)

View File

@ -32,8 +32,8 @@ class GetChatMembersCount(BaseClient):
On success, an integer is returned.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)

View File

@ -47,7 +47,7 @@ class GetDialogs(BaseClient):
On success, a :obj:`Dialogs` object is returned.
Raises:
:class:`Error`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
if pinned_only:

View File

@ -30,7 +30,7 @@ class JoinChat(BaseClient):
channel/supergroup (in the format @username).
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
match = self.INVITE_LINK_RE.match(chat_id)

View File

@ -17,6 +17,7 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api import functions, types
from pyrogram.client.ext import utils
from ...ext import BaseClient
@ -52,13 +53,13 @@ class KickChatMember(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
chat_peer = self.resolve_peer(chat_id)
user_peer = self.resolve_peer(user_id)
if isinstance(chat_peer, types.InputPeerChannel):
self.send(
r = self.send(
functions.channels.EditBanned(
channel=chat_peer,
user_id=user_peer,
@ -76,11 +77,17 @@ class KickChatMember(BaseClient):
)
)
else:
self.send(
r = self.send(
functions.messages.DeleteChatUser(
chat_id=abs(chat_id),
user_id=user_peer
)
)
return True
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
)

View File

@ -33,7 +33,7 @@ class LeaveChat(BaseClient):
Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
peer = self.resolve_peer(chat_id)

View File

@ -41,8 +41,8 @@ class PinChatMessage(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)

View File

@ -74,7 +74,7 @@ class PromoteChatMember(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
self.send(
functions.channels.EditAdmin(

View File

@ -64,7 +64,7 @@ class RestrictChatMember(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
send_messages = True
send_media = True

View File

@ -36,8 +36,8 @@ class SetChatDescription(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)

View File

@ -45,8 +45,8 @@ class SetChatPhoto(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)

View File

@ -41,8 +41,8 @@ class SetChatTitle(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id belongs to user.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id belongs to user.
"""
peer = self.resolve_peer(chat_id)

View File

@ -40,7 +40,7 @@ class UnbanChatMember(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
self.send(
functions.channels.EditBanned(

View File

@ -34,8 +34,8 @@ class UnpinChatMessage(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
"""
peer = self.resolve_peer(chat_id)

View File

@ -32,7 +32,7 @@ class AddContacts(BaseClient):
On success, the added contacts are returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
imported_contacts = self.send(
functions.contacts.ImportContacts(

View File

@ -34,7 +34,7 @@ class DeleteContacts(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
contacts = []

View File

@ -36,7 +36,7 @@ class GetContacts(BaseClient):
On success, the user's contacts are returned
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
while True:
try:

View File

@ -17,11 +17,19 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .on_callback_query import OnCallbackQuery
from .on_deleted_messages import OnDeletedMessages
from .on_disconnect import OnDisconnect
from .on_message import OnMessage
from .on_deleted_messages import OnDeletedMessages
from .on_raw_update import OnRawUpdate
from .on_user_status import OnUserStatus
class Decorators(OnMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, OnDisconnect):
class Decorators(
OnMessage,
OnDeletedMessages,
OnCallbackQuery,
OnRawUpdate,
OnDisconnect,
OnUserStatus
):
pass

View File

@ -17,6 +17,7 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
@ -36,7 +37,14 @@ class OnCallbackQuery(BaseClient):
"""
def decorator(func):
self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group)
return func
handler = pyrogram.CallbackQueryHandler(func, filters)
if isinstance(self, Filter):
return pyrogram.CallbackQueryHandler(func, self), group if filters is None else filters
if self is not None:
self.add_handler(handler, group)
return handler, group
return decorator

View File

@ -17,6 +17,7 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
@ -36,7 +37,14 @@ class OnDeletedMessages(BaseClient):
"""
def decorator(func):
self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group)
return func
handler = pyrogram.DeletedMessagesHandler(func, filters)
if isinstance(self, Filter):
return pyrogram.DeletedMessagesHandler(func, self), group if filters is None else filters
if self is not None:
self.add_handler(handler, group)
return handler, group
return decorator

View File

@ -28,7 +28,11 @@ class OnDisconnect(BaseClient):
"""
def decorator(func):
self.add_handler(pyrogram.DisconnectHandler(func))
return func
handler = pyrogram.DisconnectHandler(func)
if self is not None:
self.add_handler(handler)
return handler
return decorator

View File

@ -17,11 +17,12 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
class OnMessage(BaseClient):
def on_message(self, filters=None, group: int = 0):
def on_message(self=None, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
messages. This does the same thing as :meth:`add_handler` using the
:class:`MessageHandler`.
@ -36,7 +37,14 @@ class OnMessage(BaseClient):
"""
def decorator(func):
self.add_handler(pyrogram.MessageHandler(func, filters), group)
return func
handler = pyrogram.MessageHandler(func, filters)
if isinstance(self, Filter):
return pyrogram.MessageHandler(func, self), group if filters is None else filters
if self is not None:
self.add_handler(handler, group)
return handler, group
return decorator

View File

@ -21,7 +21,7 @@ from ...ext import BaseClient
class OnRawUpdate(BaseClient):
def on_raw_update(self, group: int = 0):
def on_raw_update(self=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
raw updates. This does the same thing as :meth:`add_handler` using the
:class:`RawUpdateHandler`.
@ -32,7 +32,14 @@ class OnRawUpdate(BaseClient):
"""
def decorator(func):
self.add_handler(pyrogram.RawUpdateHandler(func), group)
return func
handler = pyrogram.RawUpdateHandler(func)
if isinstance(self, int):
return handler, group if self is None else group
if self is not None:
self.add_handler(handler, group)
return handler, group
return decorator

View File

@ -0,0 +1,49 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <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 pyrogram
from pyrogram.client.filters.filter import Filter
from ...ext import BaseClient
class OnUserStatus(BaseClient):
def on_user_status(self=None, filters=None, group: int = 0):
"""Use this decorator to automatically register a function for handling
user status updates. This does the same thing as :meth:`add_handler` using the
:class:`UserStatusHandler`.
Args:
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function.
group (``int``, *optional*):
The group identifier, defaults to 0.
"""
def decorator(func):
handler = pyrogram.UserStatusHandler(func, filters)
if isinstance(self, Filter):
return pyrogram.UserStatusHandler(func, self), group if filters is None else filters
if self is not None:
self.add_handler(handler, group)
return handler, group
return decorator

View File

@ -53,7 +53,7 @@ class DeleteMessages(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
peer = self.resolve_peer(chat_id)
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]

View File

@ -53,7 +53,7 @@ class EditMessageCaption(BaseClient):
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -57,6 +57,12 @@ class EditMessageMedia(BaseClient):
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
An InlineKeyboardMarkup object.
Returns:
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
style = self.html if media.parse_mode.lower() == "html" else self.markdown
caption = media.caption

View File

@ -44,7 +44,7 @@ class EditMessageReplyMarkup(BaseClient):
:obj:`Message <pyrogram.Message>` is returned, otherwise True is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(

View File

@ -57,7 +57,7 @@ class EditMessageText(BaseClient):
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -54,7 +54,7 @@ class ForwardMessages(BaseClient):
is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
is_iterable = not isinstance(message_ids, int)
message_ids = list(message_ids) if is_iterable else [message_ids]

View File

@ -56,7 +56,7 @@ class GetHistory(BaseClient):
On success, a :obj:`Messages <pyrogram.Messages>` object is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(

View File

@ -23,9 +23,10 @@ from ...ext import BaseClient, utils
class GetMessages(BaseClient):
def get_messages(self,
chat_id: int or str,
message_ids,
message_ids: int or list = None,
reply_to_message_ids: int or list = None,
replies: int = 1):
"""Use this method to get messages that belong to a specific chat.
"""Use this method to get one or more messages that belong to a specific chat.
You can retrieve up to 200 messages at once.
Args:
@ -34,36 +35,46 @@ class GetMessages(BaseClient):
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
message_ids (``iterable``):
A list of Message identifiers in the chat specified in *chat_id* or a single message id, as integer.
Iterators and Generators are also accepted.
message_ids (``iterable``, *optional*):
Pass a single message identifier or a list of message ids (as integers) to get the content of the
message themselves. Iterators and Generators are also accepted.
reply_to_message_ids (``iterable``, *optional*):
Pass a single message identifier or a list of message ids (as integers) to get the content of
the previous message you replied to using this message. Iterators and Generators are also accepted.
If *message_ids* is set, this argument will be ignored.
replies (``int``, *optional*):
The number of subsequent replies to get for each message. Defaults to 1.
Returns:
On success and in case *message_ids* was a list, the returned value will be a list of the requested
:obj:`Messages <pyrogram.Messages>` even if a list contains just one element, otherwise if
*message_ids* was an integer, the single requested :obj:`Message <pyrogram.Message>`
is returned.
On success and in case *message_ids* or *reply_to_message_ids* was a list, the returned value will be a
list of the requested :obj:`Messages <pyrogram.Messages>` even if a list contains just one element,
otherwise if *message_ids* or *reply_to_message_ids* was an integer, the single requested
:obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
ids, ids_type = (
(message_ids, types.InputMessageID) if message_ids
else (reply_to_message_ids, types.InputMessageReplyTo) if reply_to_message_ids
else (None, None)
)
if ids is None:
raise ValueError("No argument supplied")
peer = self.resolve_peer(chat_id)
is_iterable = not isinstance(message_ids, int)
message_ids = list(message_ids) if is_iterable else [message_ids]
message_ids = [types.InputMessageID(i) for i in message_ids]
is_iterable = not isinstance(ids, int)
ids = list(ids) if is_iterable else [ids]
ids = [ids_type(i) for i in ids]
if isinstance(peer, types.InputPeerChannel):
rpc = functions.channels.GetMessages(
channel=peer,
id=message_ids
)
rpc = functions.channels.GetMessages(channel=peer, id=ids)
else:
rpc = functions.messages.GetMessages(
id=message_ids
)
rpc = functions.messages.GetMessages(id=ids)
r = self.send(rpc)

View File

@ -56,7 +56,7 @@ class SendAnimation(BaseClient):
pass a file path as string to upload a new animation that exists on your local machine.
caption (``str``, *optional*):
Animation caption, 0-200 characters.
Animation caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -116,7 +116,7 @@ class SendAnimation(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -58,7 +58,7 @@ class SendAudio(BaseClient):
pass a file path as string to upload a new audio file that exists on your local machine.
caption (``str``, *optional*):
Audio caption, 0-200 characters.
Audio caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -118,7 +118,7 @@ class SendAudio(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -47,8 +47,8 @@ class SendChatAction(BaseClient):
On success, True is returned.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If the provided string is not a valid ChatAction
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if the provided string is not a valid ChatAction.
"""
# Resolve Enum type

View File

@ -65,7 +65,7 @@ class SendContact(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(
functions.messages.SendMedia(

View File

@ -59,7 +59,7 @@ class SendDocument(BaseClient):
Thumbnails can't be reused and can be only uploaded as a new file.
caption (``str``, *optional*):
Document caption, 0-200 characters.
Document caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -104,7 +104,7 @@ class SendDocument(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -57,7 +57,7 @@ class SendLocation(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(
functions.messages.SendMedia(

View File

@ -64,7 +64,7 @@ class SendMessage(BaseClient):
On success, the sent :obj:`Message` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -52,7 +52,7 @@ class SendPhoto(BaseClient):
pass a file path as string to upload a new photo that exists on your local machine.
caption (``bool``, *optional*):
Photo caption, 0-200 characters.
Photo caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -102,7 +102,7 @@ class SendPhoto(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -86,7 +86,7 @@ class SendSticker(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None

View File

@ -74,7 +74,7 @@ class SendVenue(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(
functions.messages.SendMedia(

View File

@ -57,7 +57,7 @@ class SendVideo(BaseClient):
pass a file path as string to upload a new video that exists on your local machine.
caption (``str``, *optional*):
Video caption, 0-200 characters.
Video caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -120,7 +120,7 @@ class SendVideo(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -102,7 +102,7 @@ class SendVideoNote(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None

View File

@ -53,7 +53,7 @@ class SendVoice(BaseClient):
pass a file path as string to upload a new audio that exists on your local machine.
caption (``str``, *optional*):
Voice message caption, 0-200 characters.
Voice message caption, 0-1024 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -101,7 +101,7 @@ class SendVoice(BaseClient):
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown

View File

@ -41,7 +41,7 @@ class ChangeCloudPassword(BaseClient):
True on success, False otherwise.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(functions.account.GetPassword())

View File

@ -43,7 +43,7 @@ class EnableCloudPassword(BaseClient):
True on success, False otherwise.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(functions.account.GetPassword())

View File

@ -34,7 +34,7 @@ class RemoveCloudPassword(BaseClient):
True on success, False otherwise.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
r = self.send(functions.account.GetPassword())

View File

@ -16,15 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .delete_profile_photos import DeleteProfilePhotos
from .delete_user_profile_photos import DeleteUserProfilePhotos
from .get_me import GetMe
from .get_user_profile_photos import GetUserProfilePhotos
from .get_users import GetUsers
from .set_user_profile_photo import SetUserProfilePhoto
class Users(
GetUserProfilePhotos,
DeleteProfilePhotos,
SetUserProfilePhoto,
DeleteUserProfilePhotos,
GetUsers,
GetMe
):

View File

@ -23,8 +23,8 @@ from pyrogram.api import functions, types
from ...ext import BaseClient
class DeleteProfilePhotos(BaseClient):
def delete_profile_photos(self, id: str or list):
class DeleteUserProfilePhotos(BaseClient):
def delete_user_profile_photos(self, id: str or list):
"""Use this method to delete your own profile photos
Args:
@ -36,7 +36,7 @@ class DeleteProfilePhotos(BaseClient):
True on success.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
id = id if isinstance(id, list) else [id]
input_photos = []

View File

@ -28,7 +28,7 @@ class GetMe(BaseClient):
Basic information about the user or bot in form of a :obj:`User` object
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return utils.parse_user(
self.send(

View File

@ -45,7 +45,7 @@ class GetUserProfilePhotos(BaseClient):
On success, a :obj:`UserProfilePhotos` object is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return utils.parse_profile_photos(
self.send(

View File

@ -37,7 +37,7 @@ class GetUsers(BaseClient):
*user_ids* was an integer, the single requested :obj:`User` is returned.
Raises:
:class:`Error <pyrogram.Error>`
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
is_iterable = not isinstance(user_ids, (int, str))
user_ids = list(user_ids) if is_iterable else [user_ids]

View File

@ -0,0 +1,48 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <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/>.
from pyrogram.api import functions
from ...ext import BaseClient
class SetUserProfilePhoto(BaseClient):
def set_user_profile_photo(self, photo: str):
"""Use this method to set a new profile photo.
This method only works for Users.
Bots profile photos must be set using BotFather.
Args:
photo (``str``):
Profile photo to set.
Pass a file path as string to upload a new photo that exists on your local machine.
Returns:
True on success.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return bool(
self.send(
functions.photos.UploadProfilePhoto(
self.save_file(photo)
)
)
)

View File

@ -73,8 +73,8 @@ class DownloadMedia(BaseClient):
On success, the absolute path of the downloaded file as string is returned, None otherwise.
Raises:
:class:`Error <pyrogram.Error>`
``ValueError``: If the message doesn't contain any downloadable media
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
``ValueError`` if the message doesn't contain any downloadable media
"""
error_message = "This message doesn't contain any downloadable media"

View File

@ -37,5 +37,5 @@ from .messages_and_media import (
from .update import Update
from .user_and_chats import (
Chat, ChatMember, ChatMembers, ChatPhoto,
Dialog, Dialogs, User
Dialog, Dialogs, User, UserStatus
)

View File

@ -73,7 +73,9 @@ class CallbackQuery(Object):
self.game_short_name = game_short_name # flags.3?string
def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
"""Use this method as a shortcut for:
"""Bound method *answer* of :obj:`CallbackQuery <pyrogram.CallbackQuery>`.
Use this method as a shortcut for:
.. code-block:: python

View File

@ -31,7 +31,7 @@ class InlineKeyboardButton(Object):
text (``str``):
Label text on the button.
callback_data (``str``, *optional*):
callback_data (``bytes``, *optional*):
Data to be sent in a callback query to the bot when button is pressed, 1-64 bytes.
url (``str``, *optional*):
@ -50,35 +50,29 @@ class InlineKeyboardButton(Object):
chat's input field. Can be empty, in which case only the bot's username will be inserted.This offers a
quick way for the user to open your bot in inline mode in the same chat good for selecting something
from multiple options.
callback_game (:obj:`CallbackGame <pyrogram.CallbackGame>`, *optional*):
Description of the game that will be launched when the user presses the button.NOTE: This type of button
must always be the first button in the first row.
pay (``bool``, *optional*):
Specify True, to send a Pay button.NOTE: This type of button must always be the first button in the
first row.
"""
# TODO: Add callback_game and pay fields
ID = 0xb0700019
def __init__(
self,
text: str,
callback_data: str = None,
callback_data: bytes = None,
url: str = None,
switch_inline_query: str = None,
switch_inline_query_current_chat: str = None,
callback_game=None,
pay: bool = None
# callback_game=None,
# pay: bool = None
):
self.text = text
self.url = url
self.callback_data = callback_data
self.switch_inline_query = switch_inline_query
self.switch_inline_query_current_chat = switch_inline_query_current_chat
self.callback_game = callback_game
self.pay = pay
# self.callback_game = callback_game
# self.pay = pay
@staticmethod
def read(b, *args):
@ -91,7 +85,7 @@ class InlineKeyboardButton(Object):
if isinstance(b, KeyboardButtonCallback):
return InlineKeyboardButton(
text=b.text,
callback_data=b.data.decode()
callback_data=b.data
)
if isinstance(b, KeyboardButtonSwitchInline):
@ -108,7 +102,7 @@ class InlineKeyboardButton(Object):
def write(self):
if self.callback_data:
return KeyboardButtonCallback(self.text, self.callback_data.encode())
return KeyboardButtonCallback(self.text, self.callback_data)
if self.url:
return KeyboardButtonUrl(self.text, self.url)

View File

@ -27,7 +27,7 @@ class InlineKeyboardMarkup(Object):
Args:
inline_keyboard (List of List of :obj:`InlineKeyboardButton <pyrogram.InlineKeyboardButton>`):
Array of button rows, each represented by an Array of InlineKeyboardButton objects.
List of button rows, each represented by a List of InlineKeyboardButton objects.
"""
ID = 0xb0700020

View File

@ -25,11 +25,11 @@ from . import KeyboardButton
class ReplyKeyboardMarkup(Object):
"""This object represents a custom keyboard with reply options (see Introduction to bots for details and examples).
"""This object represents a custom keyboard with reply options.
Args:
keyboard (List of List of :obj:`KeyboardButton <pyrogram.KeyboardButton>`):
Array of button rows, each represented by an Array of KeyboardButton objects.
List of button rows, each represented by a List of KeyboardButton objects.
resize_keyboard (``bool``, *optional*):
Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if

View File

@ -35,7 +35,7 @@ class InputMediaAnimation(InputMedia):
Thumbnails can't be reused and can be only uploaded as a new file.
caption (``str``, *optional*):
Caption of the animation to be sent, 0-200 characters
Caption of the animation to be sent, 0-1024 characters
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`

View File

@ -36,7 +36,7 @@ class InputMediaAudio(InputMedia):
Thumbnails can't be reused and can be only uploaded as a new file.
caption (``str``, *optional*):
Caption of the audio to be sent, 0-200 characters
Caption of the audio to be sent, 0-1024 characters
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`

View File

@ -35,7 +35,7 @@ class InputMediaDocument(InputMedia):
Thumbnails can't be reused and can be only uploaded as a new file.
caption (``str``, *optional*):
Caption of the document to be sent, 0-200 characters
Caption of the document to be sent, 0-1024 characters
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`

View File

@ -31,7 +31,7 @@ class InputMediaPhoto(InputMedia):
Sending photo by a URL is currently unsupported.
caption (``str``, *optional*):
Caption of the photo to be sent, 0-200 characters
Caption of the photo to be sent, 0-1024 characters
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`

View File

@ -37,7 +37,7 @@ class InputMediaVideo(InputMedia):
Thumbnails can't be reused and can be only uploaded as a new file.
caption (``str``, *optional*):
Caption of the video to be sent, 0-200 characters
Caption of the video to be sent, 0-1024 characters
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`

View File

@ -48,7 +48,7 @@ class Animation(Object):
File size.
date (``int``, *optional*):
Date the Animation was sent in Unix time.
Date the animation was sent in Unix time.
"""
ID = 0xb0700025

View File

@ -36,7 +36,7 @@ class Contact(Object):
Contact's user identifier in Telegram.
vcard (``str``, *optional*):
Additional data about the contact in the form of a vCard
Additional data about the contact in the form of a vCard.
"""
ID = 0xb0700011

View File

@ -55,6 +55,24 @@ class Message(Object):
For replies, the original message. Note that the Message object in this field will not contain
further reply_to_message fields even if it itself is a reply.
mentioned (``bool``, *optional*):
The message contains a mention.
empty (``bool``, *optional*):
The message is empty.
A message can be empty in case it was deleted or you tried to retrieve a message that doesn't exist yet.
service (``bool``, *optional*):
The message is a service message.
A service message has one and only one of these fields set: left_chat_member, new_chat_title,
new_chat_photo, delete_chat_photo, group_chat_created, supergroup_chat_created, channel_chat_created,
migrate_to_chat_id, migrate_from_chat_id, pinned_message.
media (``bool``` *optional*):
The message is a media message.
A media message has one and only one of these fields set: audio, document, photo, sticker, video, animation,
voice, video_note, contact, location, venue.
edit_date (``int``, *optional*):
Date the message was last edited in Unix time.
@ -83,9 +101,6 @@ class Message(Object):
document (:obj:`Document <pyrogram.Document>`, *optional*):
Message is a general file, information about the file.
game (:obj:`Game <pyrogram.Game>`, *optional*):
Message is a game, information about the game. More about games.
photo (:obj:`Photo <pyrogram.Photo>`, *optional*):
Message is a photo, information about the photo.
@ -105,7 +120,7 @@ class Message(Object):
Message is a video note, information about the video message.
caption (``str``, *optional*):
Caption for the audio, document, photo, video or voice, 0-200 characters.
Caption for the audio, document, photo, video or voice, 0-1024 characters.
If the message contains caption entities (bold, italic, ...) you can access *caption.markdown* or
*caption.html* to get the marked up caption text. In case there is no caption entity, the fields
will contain the same text as *caption*.
@ -167,20 +182,11 @@ class Message(Object):
Note that the Message object in this field will not contain further reply_to_message fields even if it
is itself a reply.
invoice (:obj:`Invoice <pyrogram.Invoice>`, *optional*):
Message is an invoice for a payment, information about the invoice. More about payments.
successful_payment (:obj:`SuccessfulPayment <pyrogram.SuccessfulPayment>`, *optional*):
Message is a service message about a successful payment, information about the payment. More about payments.
connected_website (``str``, *optional*):
The domain name of the website on which the user has logged in. More about Telegram Login.
views (``int``, *optional*):
Channel post views.
via_bot (:obj:`User <pyrogram.User>`):
Via bot.
The information of the bot that generated the message from an inline query of a user.
outgoing (``bool``, *optional*):
Whether the message is incoming or outgoing.
@ -202,6 +208,7 @@ class Message(Object):
instructions to remove reply keyboard or to force a reply from the user.
"""
# TODO: Add game missing field. Also invoice, successful_payment, connected_website
ID = 0xb0700003
def __init__(
@ -217,6 +224,10 @@ class Message(Object):
forward_signature: str = None,
forward_date: int = None,
reply_to_message=None,
mentioned=None,
empty=None,
service=None,
media=None,
edit_date: int = None,
media_group_id: str = None,
author_signature: str = None,
@ -225,7 +236,6 @@ class Message(Object):
caption_entities: list = None,
audio=None,
document=None,
game=None,
photo=None,
sticker=None,
animation=None,
@ -247,9 +257,6 @@ class Message(Object):
migrate_to_chat_id: int = None,
migrate_from_chat_id: int = None,
pinned_message=None,
invoice=None,
successful_payment=None,
connected_website=None,
views: int = None,
via_bot=None,
outgoing: bool = None,
@ -268,6 +275,10 @@ class Message(Object):
self.forward_signature = forward_signature # flags.4?string
self.forward_date = forward_date # flags.5?int
self.reply_to_message = reply_to_message # flags.6?Message
self.mentioned = mentioned
self.empty = empty
self.service = service
self.media = media
self.edit_date = edit_date # flags.7?int
self.media_group_id = media_group_id # flags.8?string
self.author_signature = author_signature # flags.9?string
@ -276,7 +287,6 @@ class Message(Object):
self.caption_entities = caption_entities # flags.12?Vector<MessageEntity>
self.audio = audio # flags.13?Audio
self.document = document # flags.14?Document
self.game = game # flags.15?Game
self.photo = photo # flags.16?Vector<PhotoSize>
self.sticker = sticker # flags.17?Sticker
self.animation = animation
@ -298,9 +308,6 @@ class Message(Object):
self.migrate_to_chat_id = migrate_to_chat_id # flags.33?int
self.migrate_from_chat_id = migrate_from_chat_id # flags.34?int
self.pinned_message = pinned_message # flags.35?Message
self.invoice = invoice # flags.36?Invoice
self.successful_payment = successful_payment # flags.37?SuccessfulPayment
self.connected_website = connected_website # flags.38?string
self.views = views # flags.39?int
self.via_bot = via_bot # flags.40?User
self.outgoing = outgoing
@ -316,7 +323,9 @@ class Message(Object):
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None):
"""Use this method as a shortcut for:
"""Bound method *reply* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for:
.. code-block:: python
@ -381,10 +390,60 @@ class Message(Object):
reply_markup=reply_markup
)
def edit(self, text: str, parse_mode: str = "", disable_web_page_preview: bool = None, reply_markup=None):
"""Bound method *edit* of :obj:`Message <pyrogram.Message>
Use as a shortcut for:
.. code-block:: python
client.edit_message_text(
chat_id=message.chat.id,
message_id=message.message_id,
text="hello",
)
Example:
.. code-block:: python
message.edit("hello")
Args:
text (``str``):
New text of the message.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
Defaults to Markdown.
disable_web_page_preview (``bool``, *optional*):
Disables link previews for links in this message.
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
An InlineKeyboardMarkup object.
Returns:
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
Raises:
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
"""
return self._client.edit_message_text(
chat_id=self.chat.id,
message_id=self.message_id,
text=text,
parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview,
reply_markup=reply_markup
)
def forward(self,
chat_id: int or str,
disable_notification: bool = None):
"""Use this method as a shortcut for:
"""Bound method *forward* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for:
.. code-block:: python
@ -423,7 +482,9 @@ class Message(Object):
)
def delete(self, revoke: bool = True):
"""Use this method as a shortcut for:
"""Bound method *delete* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for:
.. code-block:: python
@ -459,8 +520,9 @@ class Message(Object):
return True
def click(self, x: int or str, y: int = None, quote: bool = None):
"""Use this method to click a button attached to the message.
It's a shortcut for:
"""Bound method *click* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for clicking a button attached to the message instead of.
- Clicking inline buttons:
@ -481,16 +543,17 @@ class Message(Object):
text=message.reply_markup[i][j].text
)
This method can be used in three different ways:
Example:
This method can be used in three different ways:
1. Pass one integer argument only (e.g.: ``.click(2)``, to click a button at index 2).
Buttons are counted left to right, starting from the top.
1. Pass one integer argument only (e.g.: ``.click(2)``, to click a button at index 2).
Buttons are counted left to right, starting from the top.
2. Pass two integer arguments (e.g.: ``.click(1, 0)``, to click a button at position (1, 0)).
The origin (0, 0) is top-left.
2. Pass two integer arguments (e.g.: ``.click(1, 0)``, to click a button at position (1, 0)).
The origin (0, 0) is top-left.
3. Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
Only the first matching button will be pressed.
3. Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
Only the first matching button will be pressed.
Args:
x (``int`` | ``str``):
@ -571,8 +634,10 @@ class Message(Object):
else:
raise ValueError("The message doesn't contain any keyboard")
def download(self, file_name: str = "", block: bool = True):
"""Use this method as a shortcut for:
def download(self, file_name: str = "", block: bool = True, progress: callable = None, progress_args: tuple = None):
"""Bound method *download* of :obj:`Message <pyrogram.Message>`.
Use as a shortcut for:
.. code-block:: python
@ -594,6 +659,15 @@ class Message(Object):
Blocks the code execution until the file has been downloaded.
Defaults to True.
progress (``callable``):
Pass a callback function to view the download progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
below for a detailed description).
progress_args (``tuple``):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass
a chat_id and a message_id in order to edit a message with the updated progress.
Returns:
On success, the absolute path of the downloaded file as string is returned, None otherwise.
@ -604,5 +678,7 @@ class Message(Object):
return self._client.download_media(
message=self,
file_name=file_name,
block=block
block=block,
progress=progress,
progress_args=progress_args,
)

View File

@ -20,7 +20,7 @@ from pyrogram.api.core import Object
class Photo(Object):
"""This object represents a Photo
"""This object represents a Photo.
Args:
id (``str``):

View File

@ -52,11 +52,9 @@ class Sticker(Object):
set_name (``str``, *optional*):
Name of the sticker set to which the sticker belongs.
mask_position (:obj:`MaskPosition <pyrogram.MaskPosition>`, *optional*):
For mask stickers, the position where the mask should be placed.
"""
# TODO: Add mask position
ID = 0xb0700017
def __init__(

Some files were not shown because too many files have changed in this diff Show More