From d0bfa8a13bb5dc006908be4df447b656d175503b Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sun, 8 Nov 2020 18:58:06 +0200 Subject: [PATCH 1/6] Fix MessageEntity serialization for API calls #457 --- aiogram/bot/bot.py | 11 +++++++++ aiogram/types/message_entity.py | 41 +++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 0ac13702..8e7c1137 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -310,6 +310,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): """ reply_markup = prepare_arg(reply_markup) + entities = prepare_arg(entities) payload = generate_payload(**locals()) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -410,6 +411,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals()) if self.parse_mode: @@ -473,6 +475,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['photo']) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -557,6 +560,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['audio', 'thumb']) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -641,6 +645,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['document']) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -726,6 +731,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['video', 'thumb']) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -815,6 +821,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=["animation", "thumb"]) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -889,6 +896,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['voice']) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -1413,6 +1421,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`types.Message` """ options = prepare_arg(options) + explanation_entities = prepare_arg(explanation_entities) open_period = prepare_arg(open_period) close_date = prepare_arg(close_date) payload = generate_payload(**locals()) @@ -2199,6 +2208,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`typing.Union[types.Message, base.Boolean]` """ reply_markup = prepare_arg(reply_markup) + entities = prepare_arg(entities) payload = generate_payload(**locals()) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) @@ -2250,6 +2260,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :rtype: :obj:`typing.Union[types.Message, base.Boolean]` """ reply_markup = prepare_arg(reply_markup) + caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals()) if self.parse_mode: payload.setdefault('parse_mode', self.parse_mode) diff --git a/aiogram/types/message_entity.py b/aiogram/types/message_entity.py index 77b23c5c..58705265 100644 --- a/aiogram/types/message_entity.py +++ b/aiogram/types/message_entity.py @@ -1,10 +1,9 @@ import sys -from . import base -from . import fields -from .user import User from ..utils import helper, markdown from ..utils.deprecated import deprecated +from . import base, fields +from .user import User class MessageEntity(base.TelegramObject): @@ -13,6 +12,7 @@ class MessageEntity(base.TelegramObject): https://core.telegram.org/bots/api#messageentity """ + type: base.String = fields.Field() offset: base.Integer = fields.Field() length: base.Integer = fields.Field() @@ -20,6 +20,26 @@ class MessageEntity(base.TelegramObject): user: User = fields.Field(base=User) language: base.String = fields.Field() + def __init__( + self, + type: base.String, + offset: base.Integer, + length: base.Integer, + url: base.String = None, + user: User = None, + language: base.String = None, + **kwargs + ): + super().__init__( + type=type, + offset=offset, + length=length, + url=url, + user=user, + language=language, + **kwargs + ) + def get_text(self, text): """ Get value of entity @@ -27,18 +47,20 @@ class MessageEntity(base.TelegramObject): :param text: full text :return: part of text """ - if sys.maxunicode == 0xffff: - return text[self.offset:self.offset + self.length] + if sys.maxunicode == 0xFFFF: + return text[self.offset : self.offset + self.length] if not isinstance(text, bytes): - entity_text = text.encode('utf-16-le') + entity_text = text.encode("utf-16-le") else: entity_text = text - entity_text = entity_text[self.offset * 2:(self.offset + self.length) * 2] - return entity_text.decode('utf-16-le') + entity_text = entity_text[self.offset * 2 : (self.offset + self.length) * 2] + return entity_text.decode("utf-16-le") - @deprecated("This method doesn't work with nested entities and will be removed in aiogram 3.0") + @deprecated( + "This method doesn't work with nested entities and will be removed in aiogram 3.0" + ) def parse(self, text, as_html=True): """ Get entity value with markup @@ -95,6 +117,7 @@ class MessageEntityType(helper.Helper): :key: TEXT_LINK :key: TEXT_MENTION """ + mode = helper.HelperMode.snake_case MENTION = helper.Item() # mention - @username From c6a43c89c48dd6f2cc1860f926cb02eb8086f94a Mon Sep 17 00:00:00 2001 From: Daniil Kovalenko <40635760+WhiteMemory99@users.noreply.github.com> Date: Mon, 9 Nov 2020 01:35:09 +0700 Subject: [PATCH 2/6] Add missing parameter to promoteChatMember alias (#458) is_anonymous exists in the full method but is missing in its shortcut. --- aiogram/types/chat.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/aiogram/types/chat.py b/aiogram/types/chat.py index 0021eb23..1ff5dc75 100644 --- a/aiogram/types/chat.py +++ b/aiogram/types/chat.py @@ -282,7 +282,9 @@ class Chat(base.TelegramObject): can_send_other_messages=can_send_other_messages, can_add_web_page_previews=can_add_web_page_previews) - async def promote(self, user_id: base.Integer, + async def promote(self, + user_id: base.Integer, + is_anonymous: typing.Optional[base.Boolean] = None, can_change_info: typing.Optional[base.Boolean] = None, can_post_messages: typing.Optional[base.Boolean] = None, can_edit_messages: typing.Optional[base.Boolean] = None, @@ -300,29 +302,42 @@ class Chat(base.TelegramObject): :param user_id: Unique identifier of the target user :type user_id: :obj:`base.Integer` + + :param is_anonymous: Pass True, if the administrator's presence in the chat is hidden + :type is_anonymous: :obj:`typing.Optional[base.Boolean]` + :param can_change_info: Pass True, if the administrator can change chat title, photo and other settings :type can_change_info: :obj:`typing.Optional[base.Boolean]` + :param can_post_messages: Pass True, if the administrator can create channel posts, channels only :type can_post_messages: :obj:`typing.Optional[base.Boolean]` + :param can_edit_messages: Pass True, if the administrator can edit messages of other users, channels only :type can_edit_messages: :obj:`typing.Optional[base.Boolean]` + :param can_delete_messages: Pass True, if the administrator can delete messages of other users :type can_delete_messages: :obj:`typing.Optional[base.Boolean]` + :param can_invite_users: Pass True, if the administrator can invite new users to the chat :type can_invite_users: :obj:`typing.Optional[base.Boolean]` + :param can_restrict_members: Pass True, if the administrator can restrict, ban or unban chat members :type can_restrict_members: :obj:`typing.Optional[base.Boolean]` + :param can_pin_messages: Pass True, if the administrator can pin messages, supergroups only :type can_pin_messages: :obj:`typing.Optional[base.Boolean]` + :param can_promote_members: Pass True, if the administrator can add new administrators with a subset of his own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed by him) :type can_promote_members: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success. :rtype: :obj:`base.Boolean` """ return await self.bot.promote_chat_member(self.id, user_id=user_id, + is_anonymous=is_anonymous, can_change_info=can_change_info, can_post_messages=can_post_messages, can_edit_messages=can_edit_messages, From 44c1cc1f61d1badaf5d589788ef995457095652f Mon Sep 17 00:00:00 2001 From: Igor Date: Mon, 9 Nov 2020 00:59:16 +0300 Subject: [PATCH 3/6] Add parameter supports_streaming to reply_video, remove redundant docstrings (#459) --- aiogram/types/message.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 900b731c..ab56f363 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -1033,10 +1033,6 @@ class Message(base.TelegramObject): Source: https://core.telegram.org/bots/api#sendvenue - :param chat_id: Unique identifier for the target chat or username of the - target channel (in the format @channelusername) - :type chat_id: :obj:`typing.Union[base.Integer, base.String]` - :param latitude: Latitude of the venue :type latitude: :obj:`base.Float` @@ -1345,10 +1341,6 @@ class Message(base.TelegramObject): Source: https://core.telegram.org/bots/api#senddice - :param chat_id: Unique identifier for the target chat or username of the - target channel (in the format @channelusername) - :type chat_id: :obj:`typing.Union[base.Integer, base.String]` - :param emoji: Emoji on which the dice throw animation is based. Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, or “🎰”. Dice can have values 1-6 for “🎲” and “🎯”, values 1-5 for “🏀” and “⚽”, and values 1-64 for “🎰”. @@ -1790,6 +1782,7 @@ class Message(base.TelegramObject): caption: typing.Optional[base.String] = None, parse_mode: typing.Optional[base.String] = None, caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + supports_streaming: typing.Optional[base.Boolean] = None, disable_notification: typing.Optional[base.Boolean] = None, allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[ @@ -1834,6 +1827,9 @@ class Message(base.TelegramObject): which can be specified instead of parse_mode :type caption_entities: :obj:`typing.Optional[typing.List[MessageEntity]]` + :param supports_streaming: Pass True, if the uploaded video is suitable for streaming + :type supports_streaming: :obj:`typing.Optional[base.Boolean]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. :type disable_notification: :obj:`typing.Optional[base.Boolean]` @@ -1862,6 +1858,7 @@ class Message(base.TelegramObject): caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + supports_streaming=supports_streaming, disable_notification=disable_notification, reply_to_message_id=self.message_id if reply else None, allow_sending_without_reply=allow_sending_without_reply, @@ -2122,10 +2119,6 @@ class Message(base.TelegramObject): Source: https://core.telegram.org/bots/api#sendvenue - :param chat_id: Unique identifier for the target chat or username of the - target channel (in the format @channelusername) - :type chat_id: :obj:`typing.Union[base.Integer, base.String]` - :param latitude: Latitude of the venue :type latitude: :obj:`base.Float` @@ -2434,10 +2427,6 @@ class Message(base.TelegramObject): Source: https://core.telegram.org/bots/api#senddice - :param chat_id: Unique identifier for the target chat or username of the - target channel (in the format @channelusername) - :type chat_id: :obj:`typing.Union[base.Integer, base.String]` - :param emoji: Emoji on which the dice throw animation is based. Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, or “🎰”. Dice can have values 1-6 for “🎲” and “🎯”, values 1-5 for “🏀” and “⚽”, and values 1-64 for “🎰”. From 7f448b4d8e90f1da7f5f3a85ae40244b6ed7f180 Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Mon, 9 Nov 2020 11:39:19 +0200 Subject: [PATCH 4/6] Fix files URL template --- aiogram/bot/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index 03c7e209..9b86e7ca 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -47,7 +47,7 @@ class TelegramAPIServer: base = base.rstrip("/") return cls( base=f"{base}/bot{{token}}/{{method}}", - file=f"{base}/file/bot{{token}}/{{method}}", + file=f"{base}/file/bot{{token}}/{{path}}", ) From 89e52ae18b36d182b15d4b7a864fa2d8de093460 Mon Sep 17 00:00:00 2001 From: Oleg A Date: Mon, 9 Nov 2020 16:54:23 -0500 Subject: [PATCH 5/6] when entities are set, default parse_mode become disabled (#461) * when entities are set, default parse_mode become disabled * check entities is not None --- aiogram/bot/bot.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 8e7c1137..390548b5 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -312,7 +312,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) entities = prepare_arg(entities) payload = generate_payload(**locals()) - if self.parse_mode: + if self.parse_mode and entities is not None: payload.setdefault('parse_mode', self.parse_mode) result = await self.request(api.Methods.SEND_MESSAGE, payload) @@ -414,7 +414,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals()) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) result = await self.request(api.Methods.COPY_MESSAGE, payload) @@ -477,7 +477,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['photo']) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -562,7 +562,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['audio', 'thumb']) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -647,7 +647,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['document']) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -733,7 +733,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['video', 'thumb']) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -823,7 +823,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=["animation", "thumb"]) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -898,7 +898,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals(), exclude=['voice']) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -1425,7 +1425,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): open_period = prepare_arg(open_period) close_date = prepare_arg(close_date) payload = generate_payload(**locals()) - if self.parse_mode: + if self.parse_mode and explanation_entities is not None: payload.setdefault('explanation_parse_mode', self.parse_mode) result = await self.request(api.Methods.SEND_POLL, payload) @@ -2210,7 +2210,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) entities = prepare_arg(entities) payload = generate_payload(**locals()) - if self.parse_mode: + if self.parse_mode and entities is not None: payload.setdefault('parse_mode', self.parse_mode) result = await self.request(api.Methods.EDIT_MESSAGE_TEXT, payload) @@ -2262,7 +2262,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): reply_markup = prepare_arg(reply_markup) caption_entities = prepare_arg(caption_entities) payload = generate_payload(**locals()) - if self.parse_mode: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) result = await self.request(api.Methods.EDIT_MESSAGE_CAPTION, payload) From 0158f99deffcff4cd499b1d845218f8edb544a2b Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Tue, 10 Nov 2020 00:40:05 +0200 Subject: [PATCH 6/6] Bump version --- aiogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiogram/__init__.py b/aiogram/__init__.py index 03d29bf7..12aaed58 100644 --- a/aiogram/__init__.py +++ b/aiogram/__init__.py @@ -43,5 +43,5 @@ __all__ = ( 'utils', ) -__version__ = '2.11' +__version__ = '2.11.1' __api_version__ = '5.0'