diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst
index a18e01a6..66d409c4 100644
--- a/docs/source/api/types.rst
+++ b/docs/source/api/types.rst
@@ -40,7 +40,6 @@ Messages & Media
:columns: 5
- :class:`Message`
- - :class:`Messages`
- :class:`MessageEntity`
- :class:`Photo`
- :class:`Thumbnail`
@@ -125,7 +124,6 @@ Details
.. Messages & Media
.. autoclass:: Message()
-.. autoclass:: Messages()
.. autoclass:: MessageEntity()
.. autoclass:: Photo()
.. autoclass:: Thumbnail()
diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/client/ext/dispatcher.py
index 2f1ec2b9..12d5a5de 100644
--- a/pyrogram/client/ext/dispatcher.py
+++ b/pyrogram/client/ext/dispatcher.py
@@ -21,6 +21,7 @@ import threading
from collections import OrderedDict
from queue import Queue
from threading import Thread
+from . import utils
import pyrogram
from pyrogram.api import types
@@ -68,7 +69,7 @@ class Dispatcher:
lambda upd, usr, cht: (pyrogram.Message._parse(self.client, upd.message, usr, cht), MessageHandler),
Dispatcher.DELETE_MESSAGES_UPDATES:
- lambda upd, usr, cht: (pyrogram.Messages._parse_deleted(self.client, upd), DeletedMessagesHandler),
+ lambda upd, usr, cht: (utils.parse_deleted_messages(self.client, upd), DeletedMessagesHandler),
Dispatcher.CALLBACK_QUERY_UPDATES:
lambda upd, usr, cht: (pyrogram.CallbackQuery._parse(self.client, upd, usr), CallbackQueryHandler),
diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py
index e1959309..41270d39 100644
--- a/pyrogram/client/ext/utils.py
+++ b/pyrogram/client/ext/utils.py
@@ -18,8 +18,9 @@
import struct
from base64 import b64decode, b64encode
-from typing import Union
+from typing import Union, List
+import pyrogram
from . import BaseClient
from ...api import types
@@ -135,3 +136,58 @@ def get_input_media_from_file_id(
)
raise ValueError("Unknown media type: {}".format(file_id_str))
+
+
+def parse_messages(client, messages: types.messages.Messages, replies: int = 1) -> List["pyrogram.Message"]:
+ users = {i.id: i for i in messages.users}
+ chats = {i.id: i for i in messages.chats}
+
+ if not messages.messages:
+ return pyrogram.List()
+
+ parsed_messages = [
+ pyrogram.Message._parse(client, message, users, chats, replies=0)
+ for message in messages.messages
+ ]
+
+ if replies:
+ messages_with_replies = {i.id: getattr(i, "reply_to_msg_id", None) for i in messages.messages}
+ reply_message_ids = [i[0] for i in filter(lambda x: x[1] is not None, messages_with_replies.items())]
+
+ if reply_message_ids:
+ reply_messages = client.get_messages(
+ parsed_messages[0].chat.id,
+ reply_to_message_ids=reply_message_ids,
+ replies=replies - 1
+ )
+
+ for message in parsed_messages:
+ reply_id = messages_with_replies[message.message_id]
+
+ for reply in reply_messages:
+ if reply.message_id == reply_id:
+ message.reply_to_message = reply
+
+ return pyrogram.List(parsed_messages)
+
+
+def parse_deleted_messages(client, update) -> List["pyrogram.Message"]:
+ messages = update.messages
+ channel_id = getattr(update, "channel_id", None)
+
+ parsed_messages = []
+
+ for message in messages:
+ parsed_messages.append(
+ pyrogram.Message(
+ message_id=message,
+ chat=pyrogram.Chat(
+ id=int("-100" + str(channel_id)),
+ type="channel",
+ client=client
+ ) if channel_id is not None else None,
+ client=client
+ )
+ )
+
+ return pyrogram.List(parsed_messages)
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index b6651fba..3230b9bd 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -20,16 +20,15 @@ from .handler import Handler
class DeletedMessagesHandler(Handler):
- """The deleted Messages handler class. Used to handle deleted messages coming from any chat
- (private, group, channel). It is intended to be used with
- :meth:`~Client.add_handler`
+ """The deleted messages handler class. Used to handle deleted messages coming from any chat
+ (private, group, channel). It is intended to be used with :meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`~Client.on_deleted_messages` decorator.
Parameters:
callback (``callable``):
- Pass a function that will be called when one or more Messages have been deleted.
+ Pass a function that will be called when one or more messages have been deleted.
It takes *(client, messages)* as positional arguments (look at the section below for a detailed description).
filters (:obj:`Filters`):
@@ -40,12 +39,12 @@ class DeletedMessagesHandler(Handler):
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the message handler.
- messages (:obj:`Messages`):
- The deleted messages.
+ messages (List of :obj:`Message`):
+ The deleted messages, as list.
"""
def __init__(self, callback: callable, filters=None):
super().__init__(callback, filters)
def check(self, messages):
- return super().check(messages.messages[0])
+ return super().check(messages[0])
diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/client/methods/messages/forward_messages.py
index bc9ad331..c69df608 100644
--- a/pyrogram/client/methods/messages/forward_messages.py
+++ b/pyrogram/client/methods/messages/forward_messages.py
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see .
-from typing import Union, Iterable
+from typing import Union, Iterable, List
import pyrogram
from pyrogram.api import functions, types
@@ -32,7 +32,7 @@ class ForwardMessages(BaseClient):
disable_notification: bool = None,
as_copy: bool = False,
remove_caption: bool = False
- ) -> "pyrogram.Messages":
+ ) -> List["pyrogram.Message"]:
"""Forward messages of any kind.
Parameters:
@@ -64,9 +64,9 @@ class ForwardMessages(BaseClient):
Defaults to False.
Returns:
- :obj:`Message` | :obj:`Messages`: In case *message_ids* was an integer, the single forwarded message is
- returned, otherwise, in case *message_ids* was an iterable, the returned value will be an object containing
- a list of messages, even if such iterable contained just a single element.
+ :obj:`Message` | List of :obj:`Message`: In case *message_ids* was an integer, the single forwarded message
+ is returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of
+ messages, even if such iterable contained just a single element.
Raises:
RPCError: In case of a Telegram RPC error.
@@ -79,9 +79,9 @@ class ForwardMessages(BaseClient):
forwarded_messages = []
for chunk in [message_ids[i:i + 200] for i in range(0, len(message_ids), 200)]:
- messages = self.get_messages(chat_id=from_chat_id, message_ids=chunk) # type: pyrogram.Messages
+ messages = self.get_messages(chat_id=from_chat_id, message_ids=chunk)
- for message in messages.messages:
+ for message in messages:
forwarded_messages.append(
message.forward(
chat_id,
@@ -91,11 +91,7 @@ class ForwardMessages(BaseClient):
)
)
- return pyrogram.Messages(
- client=self,
- total_count=len(forwarded_messages),
- messages=forwarded_messages
- ) if is_iterable else forwarded_messages[0]
+ return pyrogram.List(forwarded_messages) if is_iterable else forwarded_messages[0]
else:
r = self.send(
functions.messages.ForwardMessages(
@@ -121,8 +117,4 @@ class ForwardMessages(BaseClient):
)
)
- return pyrogram.Messages(
- client=self,
- total_count=len(forwarded_messages),
- messages=forwarded_messages
- ) if is_iterable else forwarded_messages[0]
+ return pyrogram.List(forwarded_messages) if is_iterable else forwarded_messages[0]
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index c0810474..8adafe22 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -18,10 +18,11 @@
import logging
import time
-from typing import Union
+from typing import Union, List
import pyrogram
from pyrogram.api import functions
+from pyrogram.client.ext import utils
from pyrogram.errors import FloodWait
from ...ext import BaseClient
@@ -37,7 +38,7 @@ class GetHistory(BaseClient):
offset_id: int = 0,
offset_date: int = 0,
reverse: bool = False
- ) -> "pyrogram.Messages":
+ ) -> List["pyrogram.Message"]:
"""Retrieve a chunk of the history of a chat.
You can get up to 100 messages at once.
@@ -67,15 +68,17 @@ class GetHistory(BaseClient):
Pass True to retrieve the messages in reversed order (from older to most recent).
Returns:
- :obj:`Messages` - On success, an object containing a list of the retrieved messages.
+ List of :obj:`Message` - On success, a list of the retrieved messages is returned.
Raises:
RPCError: In case of a Telegram RPC error.
"""
+ offset_id = offset_id or (1 if reverse else 0)
+
while True:
try:
- messages = pyrogram.Messages._parse(
+ messages = utils.parse_messages(
self,
self.send(
functions.messages.GetHistory(
@@ -97,6 +100,6 @@ class GetHistory(BaseClient):
break
if reverse:
- messages.messages.reverse()
+ messages.reverse()
return messages
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index 7a60f276..0f901174 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -18,12 +18,12 @@
import logging
import time
-from typing import Union, Iterable
+from typing import Union, Iterable, List
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FloodWait
-from ...ext import BaseClient
+from ...ext import BaseClient, utils
log = logging.getLogger(__name__)
@@ -35,7 +35,7 @@ class GetMessages(BaseClient):
message_ids: Union[int, Iterable[int]] = None,
reply_to_message_ids: Union[int, Iterable[int]] = None,
replies: int = 1
- ) -> Union["pyrogram.Message", "pyrogram.Messages"]:
+ ) -> Union["pyrogram.Message", List["pyrogram.Message"]]:
"""Get one or more messages that belong to a specific chat.
You can retrieve up to 200 messages at once.
@@ -60,9 +60,9 @@ class GetMessages(BaseClient):
Defaults to 1.
Returns:
- :obj:`Message` | :obj:`Messages`: In case *message_ids* was an integer, the single requested message is
- returned, otherwise, in case *message_ids* was an iterable, the returned value will be an object containing
- a list of messages, even if such iterable contained just a single element.
+ :obj:`Message` | List of :obj:`Message`: In case *message_ids* was an integer, the single requested message is
+ returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of messages,
+ even if such iterable contained just a single element.
Raises:
RPCError: In case of a Telegram RPC error.
@@ -99,6 +99,6 @@ class GetMessages(BaseClient):
else:
break
- messages = pyrogram.Messages._parse(self, r, replies=replies)
+ messages = utils.parse_messages(self, r, replies=replies)
- return messages if is_iterable else messages.messages[0]
+ return messages if is_iterable else messages[0]
diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py
index 57da3da5..15c48c95 100644
--- a/pyrogram/client/methods/messages/iter_history.py
+++ b/pyrogram/client/methods/messages/iter_history.py
@@ -80,7 +80,7 @@ class IterHistory(BaseClient):
offset_id=offset_id,
offset_date=offset_date,
reverse=reverse
- ).messages
+ )
if not messages:
return
diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
index fb029a66..194a2202 100644
--- a/pyrogram/client/methods/messages/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -38,7 +38,7 @@ class SendMediaGroup(BaseClient):
media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]],
disable_notification: bool = None,
reply_to_message_id: int = None
- ):
+ ) -> List["pyrogram.Message"]:
"""Send a group of photos or videos as an album.
Parameters:
@@ -58,7 +58,7 @@ class SendMediaGroup(BaseClient):
If the message is a reply, ID of the original message.
Returns:
- :obj:`Messages`: On success, an object is returned containing all the single messages sent.
+ List of :obj:`Message`: On success, a list of the sent messages is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@@ -158,7 +158,7 @@ class SendMediaGroup(BaseClient):
else:
break
- return pyrogram.Messages._parse(
+ return utils.parse_messages(
self,
types.messages.Messages(
messages=[m.message for m in filter(
diff --git a/pyrogram/client/methods/users/get_profile_photos.py b/pyrogram/client/methods/users/get_profile_photos.py
index 32e7e513..eaf632e2 100644
--- a/pyrogram/client/methods/users/get_profile_photos.py
+++ b/pyrogram/client/methods/users/get_profile_photos.py
@@ -20,6 +20,7 @@ from typing import Union, List
import pyrogram
from pyrogram.api import functions, types
+from pyrogram.client.ext import utils
from ...ext import BaseClient
@@ -66,7 +67,7 @@ class GetProfilePhotos(BaseClient):
return pyrogram.List(pyrogram.Photo._parse(self, photo) for photo in r.photos)
else:
- new_chat_photos = pyrogram.Messages._parse(
+ r = utils.parse_messages(
self,
self.send(
functions.messages.Search(
@@ -85,4 +86,4 @@ class GetProfilePhotos(BaseClient):
)
)
- return pyrogram.List([m.new_chat_photo for m in new_chat_photos.messages][:limit])
+ return pyrogram.List([message.new_chat_photo for message in r][:limit])
diff --git a/pyrogram/client/types/messages_and_media/__init__.py b/pyrogram/client/types/messages_and_media/__init__.py
index 2de2c6a3..b9bcb460 100644
--- a/pyrogram/client/types/messages_and_media/__init__.py
+++ b/pyrogram/client/types/messages_and_media/__init__.py
@@ -24,7 +24,6 @@ from .game import Game
from .location import Location
from .message import Message
from .message_entity import MessageEntity
-from .messages import Messages
from .photo import Photo
from .poll import Poll
from .poll_option import PollOption
@@ -37,6 +36,6 @@ from .video_note import VideoNote
from .voice import Voice
__all__ = [
- "Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Messages", "Photo",
- "Thumbnail", "StrippedThumbnail", "Poll", "PollOption", "Sticker", "Venue", "Video", "VideoNote", "Voice"
+ "Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Photo", "Thumbnail",
+ "StrippedThumbnail", "Poll", "PollOption", "Sticker", "Venue", "Video", "VideoNote", "Voice"
]
diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py
index f7dff7b5..f7e99d0a 100644
--- a/pyrogram/client/types/messages_and_media/message.py
+++ b/pyrogram/client/types/messages_and_media/message.py
@@ -2617,7 +2617,7 @@ class Message(Object, Update):
)
if self.photo:
- file_id = self.photo.sizes[-1].file_id
+ file_id = self.photo.file_id
elif self.audio:
file_id = self.audio.file_id
elif self.document:
diff --git a/pyrogram/client/types/messages_and_media/messages.py b/pyrogram/client/types/messages_and_media/messages.py
deleted file mode 100644
index ee516f20..00000000
--- a/pyrogram/client/types/messages_and_media/messages.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2019 Dan Tès
-#
-# 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 .
-
-from typing import List, Union
-
-import pyrogram
-from pyrogram.api import types
-from .message import Message
-from ..object import Object
-from ..update import Update
-from ..user_and_chats import Chat
-
-
-class Messages(Object, Update):
- """Contains a chat's messages.
-
- Parameters:
- total_count (``int``):
- Total number of messages the target chat has.
-
- messages (List of :obj:`Message`):
- Requested messages.
- """
-
- __slots__ = ["total_count", "messages"]
-
- def __init__(
- self,
- *,
- client: "pyrogram.BaseClient" = None,
- total_count: int,
- messages: List[Message]
- ):
- super().__init__(client)
-
- self.total_count = total_count
- self.messages = messages
-
- @staticmethod
- def _parse(client, messages: types.messages.Messages, replies: int = 1) -> "Messages":
- users = {i.id: i for i in messages.users}
- chats = {i.id: i for i in messages.chats}
-
- total_count = getattr(messages, "count", len(messages.messages))
-
- if not messages.messages:
- return Messages(
- total_count=total_count,
- messages=[],
- client=client
- )
-
- parsed_messages = [Message._parse(client, message, users, chats, replies=0) for message in messages.messages]
-
- if replies:
- messages_with_replies = {i.id: getattr(i, "reply_to_msg_id", None) for i in messages.messages}
- reply_message_ids = [i[0] for i in filter(lambda x: x[1] is not None, messages_with_replies.items())]
-
- if reply_message_ids:
- reply_messages = client.get_messages(
- parsed_messages[0].chat.id,
- reply_to_message_ids=reply_message_ids,
- replies=replies - 1
- ).messages
-
- for message in parsed_messages:
- reply_id = messages_with_replies[message.message_id]
-
- for reply in reply_messages:
- if reply.message_id == reply_id:
- message.reply_to_message = reply
-
- return Messages(
- total_count=total_count,
- messages=parsed_messages,
- client=client
- )
-
- @staticmethod
- def _parse_deleted(client, update) -> "Messages":
- messages = update.messages
- channel_id = getattr(update, "channel_id", None)
-
- parsed_messages = []
-
- for message in messages:
- parsed_messages.append(
- Message(
- message_id=message,
- chat=Chat(
- id=int("-100" + str(channel_id)),
- type="channel",
- client=client
- ) if channel_id is not None else None,
- client=client
- )
- )
-
- return Messages(
- total_count=len(parsed_messages),
- messages=parsed_messages,
- client=client
- )
-
- def forward(
- self,
- chat_id: Union[int, str],
- disable_notification: bool = None,
- as_copy: bool = False,
- remove_caption: bool = False
- ):
- """Bound method *forward* of :obj:`Message`.
-
- Parameters:
- chat_id (``int`` | ``str``):
- Unique identifier (int) or username (str) of the target chat.
- 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).
-
- disable_notification (``bool``, *optional*):
- Sends messages silently.
- Users will receive a notification with no sound.
-
- as_copy (``bool``, *optional*):
- Pass True to forward messages without the forward header (i.e.: send a copy of the message content).
- Defaults to False.
-
- remove_caption (``bool``, *optional*):
- If set to True and *as_copy* is enabled as well, media captions are not preserved when copying the
- message. Has no effect if *as_copy* is not enabled.
- Defaults to False.
-
- Returns:
- On success, a :obj:`Messages` containing forwarded messages is returned.
-
- Raises:
- RPCError: In case of a Telegram RPC error.
- """
- forwarded_messages = []
-
- for message in self.messages:
- forwarded_messages.append(
- message.forward(
- chat_id=chat_id,
- as_copy=as_copy,
- disable_notification=disable_notification,
- remove_caption=remove_caption
- )
- )
-
- return Messages(
- total_count=len(forwarded_messages),
- messages=forwarded_messages,
- client=self._client
- )