Adapt the rest of the library to layer 119

This commit is contained in:
Lonami Exo 2020-10-01 12:22:55 +02:00
parent 62737c1caf
commit d5e4398ace
14 changed files with 78 additions and 98 deletions

View File

@ -60,7 +60,7 @@ class _DialogsIter(RequestIter):
messages = {} messages = {}
for m in r.messages: for m in r.messages:
m._finish_init(self.client, entities, None) m._finish_init(self.client, entities, None)
messages[_dialog_message_key(m.to_id, m.id)] = m messages[_dialog_message_key(m.peer_id, m.id)] = m
for d in r.dialogs: for d in r.dialogs:
# We check the offset date here because Telegram may ignore it # We check the offset date here because Telegram may ignore it

View File

@ -157,7 +157,7 @@ class MessageParseMethods:
elif (isinstance(update, types.UpdateEditChannelMessage) elif (isinstance(update, types.UpdateEditChannelMessage)
and utils.get_peer_id(request.peer) == and utils.get_peer_id(request.peer) ==
utils.get_peer_id(update.message.to_id)): utils.get_peer_id(update.message.peer_id)):
if request.id == update.message.id: if request.id == update.message.id:
update.message._finish_init(self, entities, input_chat) update.message._finish_init(self, entities, input_chat)
return update.message return update.message
@ -170,7 +170,7 @@ class MessageParseMethods:
if request.media.poll.id == update.poll_id: if request.media.poll.id == update.poll_id:
m = types.Message( m = types.Message(
id=request.id, id=request.id,
to_id=utils.get_peer(request.peer), peer_id=utils.get_peer(request.peer),
media=types.MessageMediaPoll( media=types.MessageMediaPoll(
poll=update.poll, poll=update.poll,
results=update.results results=update.results

View File

@ -1,6 +1,7 @@
import inspect import inspect
import itertools import itertools
import typing import typing
import warnings
from .. import helpers, utils, errors, hints from .. import helpers, utils, errors, hints
from ..requestiter import RequestIter from ..requestiter import RequestIter
@ -62,7 +63,7 @@ class _MessagesIter(RequestIter):
from_user = None # Ignore from_user unless it's a user from_user = None # Ignore from_user unless it's a user
if from_user: if from_user:
self.from_id = await self.client.get_peer_id(from_user) self.from_id = utils.get_peer(from_user)
else: else:
self.from_id = None self.from_id = None
@ -76,7 +77,9 @@ class _MessagesIter(RequestIter):
if not self.entity: if not self.entity:
self.request = functions.messages.SearchGlobalRequest( self.request = functions.messages.SearchGlobalRequest(
q=search or '', q=search or '',
offset_rate=offset_date, min_date=None,
max_date=offset_date,
offset_rate=None,
offset_peer=types.InputPeerEmpty(), offset_peer=types.InputPeerEmpty(),
offset_id=offset_id, offset_id=offset_id,
limit=1 limit=1
@ -270,7 +273,7 @@ class _IDsIter(RequestIter):
else: else:
r = await self.client(functions.messages.GetMessagesRequest(ids)) r = await self.client(functions.messages.GetMessagesRequest(ids))
if self._entity: if self._entity:
from_id = await self.client.get_peer_id(self._entity) from_id = utils.get_peer(self._entity)
if isinstance(r, types.messages.MessagesNotModified): if isinstance(r, types.messages.MessagesNotModified):
self.buffer.extend(None for _ in ids) self.buffer.extend(None for _ in ids)
@ -289,7 +292,7 @@ class _IDsIter(RequestIter):
# arbitrary chats. Validate these unless ``from_id is None``. # arbitrary chats. Validate these unless ``from_id is None``.
for message in r.messages: for message in r.messages:
if isinstance(message, types.MessageEmpty) or ( if isinstance(message, types.MessageEmpty) or (
from_id and message.chat_id != from_id): from_id and message.peer_id != from_id):
self.buffer.append(None) self.buffer.append(None)
else: else:
message._finish_init(self.client, entities, self._entity) message._finish_init(self.client, entities, self._entity)
@ -753,7 +756,7 @@ class MessageMethods:
if isinstance(result, types.UpdateShortSentMessage): if isinstance(result, types.UpdateShortSentMessage):
message = types.Message( message = types.Message(
id=result.id, id=result.id,
to_id=utils.get_peer(entity), peer_id=utils.get_peer(entity),
message=message, message=message,
date=result.date, date=result.date,
out=result.out, out=result.out,
@ -805,15 +808,7 @@ class MessageMethods:
this behaviour. this behaviour.
as_album (`bool`, optional): as_album (`bool`, optional):
Whether several image messages should be forwarded as an This flag no longer has any effect.
album (grouped) or not. The default behaviour is to treat
albums specially and send outgoing requests with
``as_album=True`` only for the albums if message objects
are used. If IDs are used it will group by default.
In short, the default should do what you expect,
`True` will group always (even converting separate
images into albums), and `False` will never group.
schedule (`hints.DateLike`, optional): schedule (`hints.DateLike`, optional):
If set, the message(s) won't forward immediately, and If set, the message(s) won't forward immediately, and
@ -846,6 +841,9 @@ class MessageMethods:
# Forwarding as a copy # Forwarding as a copy
await client.send_message(chat, message) await client.send_message(chat, message)
""" """
if as_album is not None:
warnings.warn('the as_album argument is deprecated and no longer has any effect')
single = not utils.is_list_like(messages) single = not utils.is_list_like(messages)
if single: if single:
messages = (messages,) messages = (messages,)
@ -858,44 +856,24 @@ class MessageMethods:
else: else:
from_peer_id = None from_peer_id = None
def _get_key(m): def get_key(m):
if isinstance(m, int): if isinstance(m, int):
if from_peer_id is not None: if from_peer_id is not None:
return from_peer_id, None return from_peer_id
raise ValueError('from_peer must be given if integer IDs are used') raise ValueError('from_peer must be given if integer IDs are used')
elif isinstance(m, types.Message): elif isinstance(m, types.Message):
return m.chat_id, m.grouped_id return m.chat_id
else: else:
raise TypeError('Cannot forward messages of type {}'.format(type(m))) raise TypeError('Cannot forward messages of type {}'.format(type(m)))
# We want to group outgoing chunks differently if we are "smart"
# about sending as album.
#
# Why? We need separate requests for ``as_album=True/False``, so
# if we want that behaviour, when we group messages to create the
# chunks, we need to consider the grouped ID too. But if we don't
# care about that, we don't need to consider it for creating the
# chunks, so we can make less requests.
if as_album is None:
get_key = _get_key
else:
def get_key(m):
return _get_key(m)[0] # Ignore grouped_id
sent = [] sent = []
for chat_id, chunk in itertools.groupby(messages, key=get_key): for _chat_id, chunk in itertools.groupby(messages, key=get_key):
chunk = list(chunk) chunk = list(chunk)
if isinstance(chunk[0], int): if isinstance(chunk[0], int):
chat = from_peer chat = from_peer
grouped = True if as_album is None else as_album
else: else:
chat = await chunk[0].get_input_chat() chat = await chunk[0].get_input_chat()
if as_album is None:
grouped = any(m.grouped_id is not None for m in chunk)
else:
grouped = as_album
chunk = [m.id for m in chunk] chunk = [m.id for m in chunk]
req = functions.messages.ForwardMessagesRequest( req = functions.messages.ForwardMessagesRequest(
@ -903,10 +881,6 @@ class MessageMethods:
id=chunk, id=chunk,
to_peer=entity, to_peer=entity,
silent=silent, silent=silent,
# Trying to send a single message as grouped will cause
# GROUPED_MEDIA_INVALID. If more than one message is forwarded
# (even without media...), this error goes away.
grouped=len(chunk) > 1 and grouped,
schedule_date=schedule schedule_date=schedule
) )
result = await self(req) result = await self(req)
@ -1018,7 +992,7 @@ class MessageMethods:
elif isinstance(entity, types.Message): elif isinstance(entity, types.Message):
text = message # Shift the parameters to the right text = message # Shift the parameters to the right
message = entity message = entity
entity = entity.to_id entity = entity.peer_id
text, msg_entities = await self._parse_message_text(text, parse_mode) text, msg_entities = await self._parse_message_text(text, parse_mode)
file_handle, media, image = await self._file_to_media(file, file_handle, media, image = await self._file_to_media(file,

View File

@ -127,12 +127,12 @@ class EntityCache:
if cid in has_message: if cid in has_message:
x = update.message x = update.message
y = getattr(x, 'to_id', None) # handle MessageEmpty y = getattr(x, 'peer_id', None) # handle MessageEmpty
if y and utils.get_peer_id(y) not in dct: if y and utils.get_peer_id(y) not in dct:
return False return False
y = getattr(x, 'from_id', None) y = getattr(x, 'from_id', None)
if y and y not in dct: if y and utils.get_peer_id(y) not in dct:
return False return False
# We don't quite worry about entities anywhere else. # We don't quite worry about entities anywhere else.

View File

@ -150,12 +150,12 @@ class Album(EventBuilder):
""" """
def __init__(self, messages): def __init__(self, messages):
message = messages[0] message = messages[0]
if not message.out and isinstance(message.to_id, types.PeerUser): if not message.out and isinstance(message.peer_id, types.PeerUser):
# Incoming message (e.g. from a bot) has to_id=us, and # Incoming message (e.g. from a bot) has peer_id=us, and
# from_id=bot (the actual "chat" from a user's perspective). # from_id=bot (the actual "chat" from a user's perspective).
chat_peer = types.PeerUser(message.from_id) chat_peer = message.from_id
else: else:
chat_peer = message.to_id chat_peer = message.peer_id
super().__init__(chat_peer=chat_peer, super().__init__(chat_peer=chat_peer,
msg_id=message.id, broadcast=bool(message.post)) msg_id=message.id, broadcast=bool(message.post))

View File

@ -78,7 +78,7 @@ class ChatAction(EventBuilder):
users=msg.from_id) users=msg.from_id)
elif isinstance(action, types.MessageActionChatAddUser): elif isinstance(action, types.MessageActionChatAddUser):
# If a user adds itself, it means they joined # If a user adds itself, it means they joined
added_by = ([msg.from_id] == action.users) or msg.from_id added_by = ([utils.get_peer_id(msg.from_id)] == action.users) or msg.from_id
return cls.Event(msg, return cls.Event(msg,
added_by=added_by, added_by=added_by,
users=action.users) users=action.users)
@ -108,12 +108,12 @@ class ChatAction(EventBuilder):
return cls.Event(msg, return cls.Event(msg,
users=msg.from_id, users=msg.from_id,
new_photo=True) new_photo=True)
elif isinstance(action, types.MessageActionPinMessage) and msg.reply_to_msg_id: elif isinstance(action, types.MessageActionPinMessage) and msg.reply_to:
# Seems to not be reliable on unpins, but when pinning # Seems to not be reliable on unpins, but when pinning
# we prefer this because we know who caused it. # we prefer this because we know who caused it.
return cls.Event(msg, return cls.Event(msg,
users=msg.from_id, users=msg.from_id,
new_pin=msg.reply_to_msg_id) new_pin=msg.reply_to.reply_to_msg_id)
class Event(EventCommon): class Event(EventCommon):
""" """
@ -158,7 +158,7 @@ class ChatAction(EventBuilder):
users=None, new_title=None, unpin=None): users=None, new_title=None, unpin=None):
if isinstance(where, types.MessageService): if isinstance(where, types.MessageService):
self.action_message = where self.action_message = where
where = where.to_id where = where.peer_id
else: else:
self.action_message = None self.action_message = None
@ -193,9 +193,9 @@ class ChatAction(EventBuilder):
self.created = bool(created) self.created = bool(created)
if isinstance(users, list): if isinstance(users, list):
self._user_ids = users self._user_ids = [utils.get_peer_id(u) for u in users]
elif users: elif users:
self._user_ids = [users] self._user_ids = [utils.get_peer_id(users)]
else: else:
self._user_ids = [] self._user_ids = []

View File

@ -1,6 +1,7 @@
import re import re
from .common import EventBuilder, EventCommon, name_inner_event, _into_id_set from .common import EventBuilder, EventCommon, name_inner_event, _into_id_set
from .. import utils
from ..tl import types from ..tl import types
@ -106,15 +107,15 @@ class NewMessage(EventBuilder):
media_unread=update.media_unread, media_unread=update.media_unread,
silent=update.silent, silent=update.silent,
id=update.id, id=update.id,
# Note that to_id/from_id complement each other in private # Note that peer_id/from_id complement each other in private
# messages, depending on whether the message was outgoing. # messages, depending on whether the message was outgoing.
to_id=types.PeerUser(update.user_id if update.out else self_id), peer_id=types.PeerUser(update.user_id if update.out else self_id),
from_id=self_id if update.out else update.user_id, from_id=types.PeerUser(self_id if update.out else update.user_id),
message=update.message, message=update.message,
date=update.date, date=update.date,
fwd_from=update.fwd_from, fwd_from=update.fwd_from,
via_bot_id=update.via_bot_id, via_bot_id=update.via_bot_id,
reply_to_msg_id=update.reply_to_msg_id, reply_to=update.reply_to,
entities=update.entities entities=update.entities
)) ))
elif isinstance(update, types.UpdateShortChatMessage): elif isinstance(update, types.UpdateShortChatMessage):
@ -124,13 +125,13 @@ class NewMessage(EventBuilder):
media_unread=update.media_unread, media_unread=update.media_unread,
silent=update.silent, silent=update.silent,
id=update.id, id=update.id,
from_id=update.from_id, from_id=types.PeerUser(update.from_id),
to_id=types.PeerChat(update.chat_id), peer_id=types.PeerChat(update.chat_id),
message=update.message, message=update.message,
date=update.date, date=update.date,
fwd_from=update.fwd_from, fwd_from=update.fwd_from,
via_bot_id=update.via_bot_id, via_bot_id=update.via_bot_id,
reply_to_msg_id=update.reply_to_msg_id, reply_to=update.reply_to,
entities=update.entities entities=update.entities
)) ))
else: else:
@ -139,8 +140,8 @@ class NewMessage(EventBuilder):
# Make messages sent to ourselves outgoing unless they're forwarded. # Make messages sent to ourselves outgoing unless they're forwarded.
# This makes it consistent with official client's appearance. # This makes it consistent with official client's appearance.
ori = event.message ori = event.message
if isinstance(ori.to_id, types.PeerUser): if isinstance(ori.peer_id, types.PeerUser):
if ori.from_id == ori.to_id.user_id and not ori.fwd_from: if ori.from_id == ori.peer_id and not ori.fwd_from:
event.message.out = True event.message.out = True
return event return event
@ -158,7 +159,7 @@ class NewMessage(EventBuilder):
return return
if self.from_users is not None: if self.from_users is not None:
if event.message.from_id not in self.from_users: if utils.get_peer_id(event.message.from_id) not in self.from_users:
return return
if self.pattern: if self.pattern:
@ -204,12 +205,12 @@ class NewMessage(EventBuilder):
""" """
def __init__(self, message): def __init__(self, message):
self.__dict__['_init'] = False self.__dict__['_init'] = False
if not message.out and isinstance(message.to_id, types.PeerUser): if not message.out and isinstance(message.peer_id, types.PeerUser):
# Incoming message (e.g. from a bot) has to_id=us, and # Incoming message (e.g. from a bot) has peer_id=us, and
# from_id=bot (the actual "chat" from a user's perspective). # from_id=bot (the actual "chat" from a user's perspective).
chat_peer = types.PeerUser(message.from_id) chat_peer = message.from_id
else: else:
chat_peer = message.to_id chat_peer = message.peer_id
super().__init__(chat_peer=chat_peer, super().__init__(chat_peer=chat_peer,
msg_id=message.id, broadcast=bool(message.post)) msg_id=message.id, broadcast=bool(message.post))

View File

@ -134,10 +134,10 @@ class StateCache:
if cid in has_channel_id: if cid in has_channel_id:
return update.channel_id return update.channel_id
elif cid in has_message: elif cid in has_message:
if update.message.to_id is None: if update.message.peer_id is None:
self._logger.info('Update has None to_id %s', update) self._logger.info('Update has None peer_id %s', update)
else: else:
return update.message.to_id.channel_id return update.message.peer_id.channel_id
return None return None

View File

@ -95,7 +95,7 @@ class ChatGetter(abc.ABC):
def chat_id(self): def chat_id(self):
""" """
Returns the marked chat integer ID. Note that this value **will Returns the marked chat integer ID. Note that this value **will
be different** from ``to_id`` for incoming private messages, since be different** from ``peer_id`` for incoming private messages, since
the chat *to* which the messages go is to your own person, but the chat *to* which the messages go is to your own person, but
the *chat* itself is with the one who sent the message. the *chat* itself is with the one who sent the message.

View File

@ -165,7 +165,7 @@ class Conversation(ChatGetter):
""" """
return self._get_message( return self._get_message(
message, self._reply_indices, self._pending_replies, timeout, message, self._reply_indices, self._pending_replies, timeout,
lambda x, y: x.reply_to_msg_id == y lambda x, y: x.reply_to and x.reply_to.reply_to_msg_id == y
) )
def _get_message( def _get_message(
@ -374,7 +374,7 @@ class Conversation(ChatGetter):
del self._pending_responses[msg_id] del self._pending_responses[msg_id]
for msg_id, future in list(self._pending_replies.items()): for msg_id, future in list(self._pending_replies.items()):
if msg_id == response.reply_to_msg_id: if response.reply_to and msg_id == response.reply_to.reply_to_msg_id:
self._reply_indices[msg_id] = len(self._incoming) self._reply_indices[msg_id] = len(self._incoming)
future.set_result(response) future.set_result(response)
del self._pending_replies[msg_id] del self._pending_replies[msg_id]

View File

@ -1,6 +1,6 @@
from .chatgetter import ChatGetter from .chatgetter import ChatGetter
from .sendergetter import SenderGetter from .sendergetter import SenderGetter
from ... import utils from ... import utils, helpers
from ...tl import types from ...tl import types
@ -30,19 +30,24 @@ class Forward(ChatGetter, SenderGetter):
self.__dict__.update(original.__dict__) self.__dict__.update(original.__dict__)
self.original_fwd = original self.original_fwd = original
sender, input_sender = utils._get_entity_pair( sender_id = sender = input_sender = peer = chat = input_chat = None
original.from_id, entities, client._entity_cache) if not original.from_id:
pass
if not original.channel_id:
peer = chat = input_chat = None
else: else:
peer = types.PeerChannel(original.channel_id) ty = helpers._entity_type(original.from_id)
chat, input_chat = utils._get_entity_pair( if ty == helpers._EntityType.USER:
utils.get_peer_id(peer), entities, client._entity_cache) sender_id = utils.get_peer_id(original.from_id)
sender, input_sender = utils._get_entity_pair(
sender_id, entities, client._entity_cache)
elif ty in (helpers._EntityType.CHAT, helpers._EntityType.CHANNEL):
peer = original.from_id
chat, input_chat = utils._get_entity_pair(
utils.get_peer_id(peer), entities, client._entity_cache)
# This call resets the client # This call resets the client
ChatGetter.__init__(self, peer, chat=chat, input_chat=input_chat) ChatGetter.__init__(self, peer, chat=chat, input_chat=input_chat)
SenderGetter.__init__(self, original.from_id, sender=sender, input_sender=input_sender) SenderGetter.__init__(self, sender_id, sender=sender, input_sender=input_sender)
self._client = client self._client = client
# TODO We could reload the message # TODO We could reload the message

View File

@ -85,7 +85,7 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
The peer who sent this message, which is either The peer who sent this message, which is either
:tl:`PeerUser`, :tl:`PeerChat` or :tl:`PeerChannel`. :tl:`PeerUser`, :tl:`PeerChat` or :tl:`PeerChannel`.
reply_to (`int`): reply_to (:tl:`MessageReplyHeader`):
The original reply header if this message is replying to another. The original reply header if this message is replying to another.
fwd_from (:tl:`MessageFwdHeader`): fwd_from (:tl:`MessageFwdHeader`):
@ -210,15 +210,15 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
self._action_entities = None self._action_entities = None
if not out and isinstance(peer_id, types.PeerUser): if not out and isinstance(peer_id, types.PeerUser):
chat_peer = types.PeerUser(from_id) chat_peer = from_id
if from_id == peer_id.user_id: if from_id == peer_id:
self.out = not self.fwd_from # Patch out in our chat self.out = not self.fwd_from # Patch out in our chat
else: else:
chat_peer = peer_id chat_peer = peer_id
# Note that these calls would reset the client # Note that these calls would reset the client
ChatGetter.__init__(self, chat_peer, broadcast=post) ChatGetter.__init__(self, chat_peer, broadcast=post)
SenderGetter.__init__(self, from_id) SenderGetter.__init__(self, utils.get_peer_id(from_id) if from_id else None)
if post and not from_id and chat_peer: if post and not from_id and chat_peer:
# If the message comes from a Channel, let the sender be it # If the message comes from a Channel, let the sender be it
@ -329,10 +329,10 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
`True` if the message is a reply to some other message. `True` if the message is a reply to some other message.
Remember that you can access the ID of the message Remember that you can access the ID of the message
this one is replying to through `reply_to_msg_id`, this one is replying to through `reply_to.reply_to_msg_id`,
and the `Message` object with `get_reply_message()`. and the `Message` object with `get_reply_message()`.
""" """
return bool(self.reply_to_msg_id) return self.reply_to is not None
@property @property
def forward(self): def forward(self):
@ -647,7 +647,7 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
The result will be cached after its first use. The result will be cached after its first use.
""" """
if self._reply_message is None and self._client: if self._reply_message is None and self._client:
if not self.reply_to_msg_id: if not self.reply_to:
return None return None
# Bots cannot access other bots' messages by their ID. # Bots cannot access other bots' messages by their ID.
@ -663,7 +663,7 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
# directly by its ID. # directly by its ID.
self._reply_message = await self._client.get_messages( self._reply_message = await self._client.get_messages(
self._input_chat if self.is_channel else None, self._input_chat if self.is_channel else None,
ids=self.reply_to_msg_id ids=self.reply_to.reply_to_msg_id
) )
return self._reply_message return self._reply_message

View File

@ -76,7 +76,7 @@ async def handler(event):
# If we sent the message, we are replying to someone, # If we sent the message, we are replying to someone,
# and we said "save pic" in the message # and we said "save pic" in the message
if event.out and event.reply_to_msg_id and 'save pic' in event.raw_text: if event.out and event.is_reply and 'save pic' in event.raw_text:
reply_msg = await event.get_reply_message() reply_msg = await event.get_reply_message()
replied_to_user = await reply_msg.get_input_sender() replied_to_user = await reply_msg.get_input_sender()

View File

@ -156,7 +156,7 @@ class TLArg:
# treated as a "date" object. Note that this is not a valid # treated as a "date" object. Note that this is not a valid
# Telegram object, but it's easier to work with # Telegram object, but it's easier to work with
if self.type == 'int' and ( if self.type == 'int' and (
re.search(r'(\b|_)([dr]ate|until|since)(\b|_)', name) or re.search(r'(\b|_)(date|until|since)(\b|_)', name) or
name in ('expires', 'expires_at', 'was_online')): name in ('expires', 'expires_at', 'was_online')):
self.type = 'date' self.type = 'date'