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' 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}}", ) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 0ac13702..390548b5 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -310,8 +310,9 @@ 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) @@ -410,9 +411,10 @@ 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: + 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) @@ -473,8 +475,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -557,8 +560,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -641,8 +645,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -726,8 +731,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -815,8 +821,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -889,8 +896,9 @@ 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: + if self.parse_mode and caption_entities is not None: payload.setdefault('parse_mode', self.parse_mode) files = {} @@ -1413,10 +1421,11 @@ 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()) - 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) @@ -2199,8 +2208,9 @@ 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: + 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) @@ -2250,8 +2260,9 @@ 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: + 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) 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, 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 “🎰”. 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