diff --git a/aiogram/__init__.py b/aiogram/__init__.py index 9a11b7a2..1c66de7e 100644 --- a/aiogram/__init__.py +++ b/aiogram/__init__.py @@ -44,4 +44,4 @@ __all__ = ( ) __version__ = '2.10' -__api_version__ = '4.9' +__api_version__ = '5.0' diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index cb258cdf..c83b7ede 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -153,7 +153,7 @@ class Methods(Helper): """ Helper for Telegram API Methods listed on https://core.telegram.org/bots/api - List is updated to Bot API 4.9 + List is updated to Bot API 5.0 """ mode = HelperMode.lowerCamelCase @@ -165,8 +165,11 @@ class Methods(Helper): # Available methods GET_ME = Item() # getMe + LOG_OUT = Item() # logOut + CLOSE = Item() # close SEND_MESSAGE = Item() # sendMessage FORWARD_MESSAGE = Item() # forwardMessage + COPY_MESSAGE = Item() # copyMessage SEND_PHOTO = Item() # sendPhoto SEND_AUDIO = Item() # sendAudio SEND_DOCUMENT = Item() # sendDocument @@ -198,6 +201,7 @@ class Methods(Helper): SET_CHAT_DESCRIPTION = Item() # setChatDescription PIN_CHAT_MESSAGE = Item() # pinChatMessage UNPIN_CHAT_MESSAGE = Item() # unpinChatMessage + UNPIN_ALL_CHAT_MESSAGES = Item() # unpinAllChatMessages LEAVE_CHAT = Item() # leaveChat GET_CHAT = Item() # getChat GET_CHAT_ADMINISTRATORS = Item() # getChatAdministrators diff --git a/aiogram/bot/base.py b/aiogram/bot/base.py index f45546c3..71e4effc 100644 --- a/aiogram/bot/base.py +++ b/aiogram/bot/base.py @@ -15,6 +15,7 @@ from . import api from ..types import ParseMode, base from ..utils import json from ..utils.auth_widget import check_integrity +from ..utils.deprecated import deprecated class BaseBot: @@ -173,6 +174,8 @@ class BaseBot: finally: self._ctx_token.reset(token) + @deprecated("This method's behavior will be changed in aiogram v3.0. " + "More info: https://core.telegram.org/bots/api#close") async def close(self): """ Close all client sessions diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 3b886cc0..a9008f9c 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -7,6 +7,8 @@ import warnings from .base import BaseBot, api from .. import types from ..types import base +from ..utils.deprecated import deprecated +from ..utils.exceptions import ValidationError from ..utils.mixins import DataMixin, ContextInstanceMixin from ..utils.payload import generate_payload, prepare_arg, prepare_attachment, prepare_file @@ -95,27 +97,61 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.GET_UPDATES, payload) return [types.Update(**update) for update in result] - async def set_webhook(self, url: base.String, - certificate: typing.Union[base.InputFile, None] = None, - max_connections: typing.Union[base.Integer, None] = None, - allowed_updates: typing.Union[typing.List[base.String], None] = None) -> base.Boolean: + async def set_webhook(self, + url: base.String, + certificate: typing.Optional[base.InputFile] = None, + ip_address: typing.Optional[base.String] = None, + max_connections: typing.Optional[base.Integer] = None, + allowed_updates: typing.Optional[typing.List[base.String]] = None, + drop_pending_updates: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ - Use this method to specify a url and receive incoming updates via an outgoing webhook. - Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, - containing a JSON-serialized Update. In case of an unsuccessful request, - we will give up after a reasonable amount of attempts. + Use this method to specify a url and receive incoming updates via an outgoing + webhook. Whenever there is an update for the bot, we will send an HTTPS POST + request to the specified url, containing a JSON-serialized Update. In case + of an unsuccessful request, we will give up after a reasonable amount of + attempts. Returns True on success. + + If you'd like to make sure that the Webhook request comes from Telegram, + we recommend using a secret path in the URL, e.g. + `https://www.example.com/`. + Since nobody else knows your bot's token, you can be pretty sure it's us. Source: https://core.telegram.org/bots/api#setwebhook - :param url: HTTPS url to send updates to. Use an empty string to remove webhook integration + :param url: HTTPS url to send updates to. Use an empty string to remove + webhook integration :type url: :obj:`base.String` - :param certificate: Upload your public key certificate so that the root certificate in use can be checked - :type certificate: :obj:`typing.Union[base.InputFile, None]` - :param max_connections: Maximum allowed number of simultaneous HTTPS connections to the webhook - for update delivery, 1-100. - :type max_connections: :obj:`typing.Union[base.Integer, None]` - :param allowed_updates: List the types of updates you want your bot to receive - :type allowed_updates: :obj:`typing.Union[typing.List[base.String], None]` + + :param certificate: Upload your public key certificate so that the root + certificate in use can be checked. See our self-signed guide for details: + https://core.telegram.org/bots/self-signed + :type certificate: :obj:`typing.Optional[base.InputFile]` + + :param ip_address: The fixed IP address which will be used to send webhook + requests instead of the IP address resolved through DNS + :type ip_address: :obj:`typing.Optional[base.String]` + + :param max_connections: Maximum allowed number of simultaneous HTTPS + connections to the webhook for update delivery, 1-100. Defaults to 40. + Use lower values to limit the load on your bot's server, and higher + values to increase your bot's throughput. + :type max_connections: :obj:`typing.Optional[base.Integer]` + + :param allowed_updates: A list of the update types you want your bot to + receive. For example, specify [“message”, “edited_channel_post”, + “callback_query”] to only receive updates of these types. See Update for + a complete list of available update types. Specify an empty list to + receive all updates regardless of type (default). If not specified, the + previous setting will be used. + Please note that this parameter doesn't affect updates created before the + call to the setWebhook, so unwanted updates may be received for a short + period of time. + :type allowed_updates: :obj:`typing.Optional[typing.List[base.String]]` + + :param drop_pending_updates: Pass True to drop all pending updates + :type drop_pending_updates: :obj:`typing.Optional[base.Boolean]` + :return: Returns true :rtype: :obj:`base.Boolean` """ @@ -128,13 +164,18 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SET_WEBHOOK, payload, files) return result - async def delete_webhook(self) -> base.Boolean: + async def delete_webhook(self, + drop_pending_updates: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ - Use this method to remove webhook integration if you decide to switch back to getUpdates. - Returns True on success. Requires no parameters. + Use this method to remove webhook integration if you decide to switch back + to getUpdates. Returns True on success. Source: https://core.telegram.org/bots/api#deletewebhook + :param drop_pending_updates: Pass True to drop all pending updates + :type drop_pending_updates: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ @@ -176,15 +217,57 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.GET_ME, payload) return types.User(**result) - async def send_message(self, chat_id: typing.Union[base.Integer, base.String], text: base.String, - parse_mode: typing.Union[base.String, None] = None, - disable_web_page_preview: typing.Union[base.Boolean, None] = None, - disable_notification: typing.Union[base.Boolean, None] = None, - reply_to_message_id: typing.Union[base.Integer, None] = None, + async def log_out(self) -> base.Boolean: + """ + Use this method to log out from the cloud Bot API server before launching + the bot locally. You **must** log out the bot before running it locally, + otherwise there is no guarantee that the bot will receive updates. + After a successful call, you will not be able to log in again using the + same token for 10 minutes. Returns True on success. Requires no parameters. + + Source: https://core.telegram.org/bots/api#logout + + :return: Returns True on success + :rtype: :obj:`base.Boolean` + """ + payload = generate_payload(**locals()) + + result = await self.request(api.Methods.LOG_OUT, payload) + return result + + @deprecated("This method will be renamed to `close` in aiogram v3.0") + async def close_bot(self) -> base.Boolean: + """ + Use this method to close the bot instance before moving it from one local + server to another. You need to delete the webhook before calling this method + to ensure that the bot isn't launched again after server restart. The method + will return error 429 in the first 10 minutes after the bot is launched. + Returns True on success. Requires no parameters. + + Source: https://core.telegram.org/bots/api#close + + :return: Returns True on success + :rtype: :obj:`base.Boolean` + """ + payload = generate_payload(**locals()) + + result = await self.request(api.Methods.CLOSE, payload) + return result + + async def send_message(self, + chat_id: typing.Union[base.Integer, base.String], + text: base.String, + parse_mode: typing.Optional[base.String] = None, + entities: typing.Optional[typing.List[types.MessageEntity]] = None, + disable_web_page_preview: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ Use this method to send text messages. @@ -192,21 +275,36 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param text: Text of the message to be sent :type text: :obj:`base.String` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. - :type parse_mode: :obj:`typing.Union[base.String, None]` + :type parse_mode: :obj:`typing.Optional[base.String]` + + :param entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param disable_web_page_preview: Disables link previews for links in this message - :type disable_web_page_preview: :obj:`typing.Union[base.Boolean, None]` + :type disable_web_page_preview: :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.Union[base.Boolean, None]` + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + :param reply_to_message_id: If the message is a reply, ID of the original message - :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -243,16 +341,97 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.FORWARD_MESSAGE, payload) return types.Message(**result) - async def send_photo(self, chat_id: typing.Union[base.Integer, base.String], + async def copy_message(self, + chat_id: typing.Union[base.Integer, base.String], + from_chat_id: typing.Union[base.Integer, base.String], + message_id: base.Integer, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[types.InlineKeyboardMarkup, + types.ReplyKeyboardMarkup, + types.ReplyKeyboardRemove, + types.ForceReply, None] = None, + ) -> types.Message: + """ + Use this method to copy messages of any kind. The method is analogous to the + method forwardMessages, but the copied message doesn't have a link to the + original message. Returns the MessageId of the sent message on success. + + Source: https://core.telegram.org/bots/api#copymessage + + :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 from_chat_id: Unique identifier for the chat where the original + message was sent (or channel username in the format @channelusername) + :type from_chat_id: :obj:`typing.Union[base.Integer, base.String]` + + :param message_id: Message identifier in the chat specified in from_chat_id + :type message_id: :obj:`base.Integer` + + :param caption: New caption for media, 0-1024 characters after entities + parsing. If not specified, the original caption is kept + :type caption: :obj:`typing.Optional[base.String]` + + :param parse_mode: Mode for parsing entities in the new caption. See + formatting options for more details: + https://core.telegram.org/bots/api#formatting-options + :type parse_mode: :obj:`typing.Optional[base.String]` + + :param caption_entities: List of special entities that appear in the new + caption, which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + + :param disable_notification: Sends the message silently. Users will receive + a notification with no sound + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply_to_message_id: If the message is a reply, ID of the original + message + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user. + :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, + None]` + + :return: On success, the sent Message is returned + :rtype: :obj:`types.Message` + """ + reply_markup = prepare_arg(reply_markup) + payload = generate_payload(**locals()) + + if self.parse_mode: + payload.setdefault('parse_mode', self.parse_mode) + + result = await self.request(api.Methods.COPY_MESSAGE, payload) + return types.Message(**result) + + async def send_photo(self, + chat_id: typing.Union[base.Integer, base.String], photo: typing.Union[base.InputFile, base.String], caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ Use this method to send photos. @@ -260,21 +439,36 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param photo: Photo to send :type photo: :obj:`typing.Union[base.InputFile, base.String]` + :param caption: Photo caption (may also be used when resending photos by file_id), 0-1024 characters :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -289,20 +483,24 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_PHOTO, payload, files) return types.Message(**result) - async def send_audio(self, chat_id: typing.Union[base.Integer, base.String], + async def send_audio(self, + chat_id: typing.Union[base.Integer, base.String], audio: typing.Union[base.InputFile, base.String], caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, duration: typing.Union[base.Integer, None] = None, performer: typing.Union[base.String, None] = None, title: typing.Union[base.String, None] = None, thumb: typing.Union[base.InputFile, base.String, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format. @@ -313,29 +511,48 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param audio: Audio file to send :type audio: :obj:`typing.Union[base.InputFile, base.String]` + :param caption: Audio caption, 0-1024 characters :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param duration: Duration of the audio in seconds :type duration: :obj:`typing.Union[base.Integer, None]` + :param performer: Performer :type performer: :obj:`typing.Union[base.String, None]` + :param title: Track name :type title: :obj:`typing.Union[base.String, None]` + :param thumb: Thumbnail of the file sent :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -351,43 +568,75 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_AUDIO, payload, files) return types.Message(**result) - async def send_document(self, chat_id: typing.Union[base.Integer, base.String], + async def send_document(self, + chat_id: typing.Union[base.Integer, base.String], document: typing.Union[base.InputFile, base.String], thumb: typing.Union[base.InputFile, base.String, None] = None, - caption: typing.Union[base.String, None] = None, - parse_mode: typing.Union[base.String, None] = None, - disable_notification: typing.Union[base.Boolean, None] = None, - reply_to_message_id: typing.Union[base.Integer, None] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, + None] = None, + ) -> types.Message: """ - Use this method to send general files. - - Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. + Use this method to send general files. On success, the sent Message is + returned. Bots can currently send files of any type of up to 50 MB in size, + this limit may be changed in the future. Source: https://core.telegram.org/bots/api#senddocument - :param chat_id: Unique identifier for the target chat or username of the target channel + :param chat_id: Unique identifier for the target chat or username of the + target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param document: File to send :type document: :obj:`typing.Union[base.InputFile, base.String]` + :param thumb: Thumbnail of the file sent :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` - :param caption: Document caption (may also be used when resending documents by file_id), 0-1024 characters - :type caption: :obj:`typing.Union[base.String, None]` - :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, - fixed-width text or inline URLs in your bot's message. - :type parse_mode: :obj:`typing.Union[base.String, None]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :param reply_to_message_id: If the message is a reply, ID of the original message - :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user - :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, - types.ReplyKeyboardRemove, types.ForceReply], None]` + + :param caption: Document caption (may also be used when resending documents + by file_id), 0-1024 characters + :type caption: :obj:`typing.Optional[base.String]` + + :param disable_content_type_detection: Disables automatic server-side content + type detection for files uploaded using multipart/form-data + :type disable_content_type_detection: :obj:`typing.Optional[base.Boolean]` + + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in your bot's message. + :type parse_mode: :obj:`typing.Optional[base.String]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + + :param disable_notification: Sends the message silently. Users will receive a + notification with no sound + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply_to_message_id: If the message is a reply, ID of the original + message + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user + :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], + None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -411,9 +660,11 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): thumb: typing.Union[base.InputFile, base.String, None] = None, caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, supports_streaming: typing.Union[base.Boolean, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, @@ -426,31 +677,51 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param video: Video to send :type video: :obj:`typing.Union[base.InputFile, base.String]` + :param duration: Duration of sent video in seconds :type duration: :obj:`typing.Union[base.Integer, None]` + :param width: Video width :type width: :obj:`typing.Union[base.Integer, None]` + :param height: Video height :type height: :obj:`typing.Union[base.Integer, None]` + :param thumb: Thumbnail of the file sent :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` + :param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param supports_streaming: Pass True, if the uploaded video is suitable for streaming :type supports_streaming: :obj:`typing.Union[base.Boolean, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -475,12 +746,14 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply], None] = None + types.ForceReply], None] = None, ) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). @@ -493,32 +766,51 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :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 animation: Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data :type animation: :obj:`typing.Union[base.InputFile, base.String]` + :param duration: Duration of sent animation in seconds :type duration: :obj:`typing.Union[base.Integer, None]` + :param width: Animation width :type width: :obj:`typing.Union[base.Integer, None]` + :param height: Animation height :type height: :obj:`typing.Union[base.Integer, None]` + :param thumb: Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail‘s width and height should not exceed 320. :type thumb: :obj:`typing.Union[typing.Union[base.InputFile, base.String], None]` + :param caption: Animation caption (may also be used when resending animation by file_id), 0-1024 characters :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -534,17 +826,21 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_ANIMATION, payload, files) return types.Message(**result) - async def send_voice(self, chat_id: typing.Union[base.Integer, base.String], + async def send_voice(self, + chat_id: typing.Union[base.Integer, base.String], voice: typing.Union[base.InputFile, base.String], caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, duration: typing.Union[base.Integer, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. @@ -556,23 +852,39 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param voice: Audio file to send :type voice: :obj:`typing.Union[base.InputFile, base.String]` + :param caption: Voice message caption, 0-1024 characters :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param duration: Duration of the voice message in seconds :type duration: :obj:`typing.Union[base.Integer, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -594,6 +906,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): thumb: typing.Union[base.InputFile, base.String, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, @@ -606,22 +919,34 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param video_note: Video note to send :type video_note: :obj:`typing.Union[base.InputFile, base.String]` + :param duration: Duration of sent video in seconds :type duration: :obj:`typing.Union[base.Integer, None]` + :param length: Video width and height :type length: :obj:`typing.Union[base.Integer, None]` + :param thumb: Thumbnail of the file sent :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -634,24 +959,41 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_VIDEO_NOTE, payload, files) return types.Message(**result) - async def send_media_group(self, chat_id: typing.Union[base.Integer, base.String], + async def send_media_group(self, + chat_id: typing.Union[base.Integer, base.String], media: typing.Union[types.MediaGroup, typing.List], - disable_notification: typing.Union[base.Boolean, None] = None, - reply_to_message_id: typing.Union[base.Integer, - None] = None) -> typing.List[types.Message]: + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + ) -> typing.List[types.Message]: """ - Use this method to send a group of photos or videos as an album. + Use this method to send a group of photos, videos, documents or audios as + an album. Documents and audio files can be only group in an album with + messages of the same type. On success, an array of Messages that were sent + is returned. Source: https://core.telegram.org/bots/api#sendmediagroup - :param chat_id: Unique identifier for the target chat or username of the target channel + :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 media: A JSON-serialized array describing photos and videos to be sent + + :param media: A JSON-serialized array describing messages to be sent, must + include 2-10 items :type media: :obj:`typing.Union[types.MediaGroup, typing.List]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :param reply_to_message_id: If the message is a reply, ID of the original message - :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param disable_notification: Sends messages silently. Users will receive a + notification with no sound. + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply_to_message_id: If the messages are a reply, ID of the original + message + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :return: On success, an array of the sent Messages is returned :rtype: typing.List[types.Message] """ @@ -659,6 +1001,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): if isinstance(media, list): media = types.MediaGroup(media) + # check MediaGroup quantity + if 2 > len(media.media) > 10: + raise ValidationError("Media group must include 2-10 items") + files = dict(media.get_files()) media = prepare_arg(media) @@ -669,9 +1015,13 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): async def send_location(self, chat_id: typing.Union[base.Integer, base.String], latitude: base.Float, longitude: base.Float, - live_period: typing.Union[base.Integer, None] = None, - disable_notification: typing.Union[base.Boolean, None] = None, - reply_to_message_id: typing.Union[base.Integer, None] = None, + horizontal_accuracy: typing.Optional[base.Float] = None, + live_period: typing.Optional[base.Integer] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, @@ -683,20 +1033,44 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param latitude: Latitude of the location :type latitude: :obj:`base.Float` + :param longitude: Longitude of the location :type longitude: :obj:`base.Float` + + :param horizontal_accuracy: The radius of uncertainty for the location, + measured in meters; 0-1500 + :type horizontal_accuracy: :obj:`typing.Optional[base.Float]` + :param live_period: Period in seconds for which the location will be updated - :type live_period: :obj:`typing.Union[base.Integer, None]` + :type live_period: :obj:`typing.Optional[base.Integer]` + + :param heading: For live locations, a direction in which the user is moving, + in degrees. Must be between 1 and 360 if specified. + :type heading: :obj:`typing.Optional[base.Integer]` + + :param proximity_alert_radius: For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. Must + be between 1 and 100000 if specified. + :type proximity_alert_radius: :obj:`typing.Optional[base.Integer]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + :param reply_to_message_id: If the message is a reply, ID of the original message - :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -706,12 +1080,17 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_LOCATION, payload) return types.Message(**result) - async def edit_message_live_location(self, latitude: base.Float, longitude: base.Float, + async def edit_message_live_location(self, + latitude: base.Float, + longitude: base.Float, chat_id: typing.Union[base.Integer, base.String, None] = None, - message_id: typing.Union[base.Integer, None] = None, - inline_message_id: typing.Union[base.String, None] = None, - reply_markup: typing.Union[types.InlineKeyboardMarkup, - None] = None) -> types.Message or base.Boolean: + message_id: typing.Optional[base.Integer] = None, + inline_message_id: typing.Optional[base.String] = None, + horizontal_accuracy: typing.Optional[base.Float] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, + reply_markup: typing.Optional[types.InlineKeyboardMarkup] = None, + ) -> types.Message or base.Boolean: """ Use this method to edit live location messages sent by the bot or via the bot (for inline bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call @@ -721,16 +1100,35 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Required if inline_message_id is not specified :type chat_id: :obj:`typing.Union[base.Integer, base.String, None]` + :param message_id: Required if inline_message_id is not specified. Identifier of the sent message - :type message_id: :obj:`typing.Union[base.Integer, None]` + :type message_id: :obj:`typing.Optional[base.Integer]` + :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the inline message - :type inline_message_id: :obj:`typing.Union[base.String, None]` + :type inline_message_id: :obj:`typing.Optional[base.String]` + :param latitude: Latitude of new location :type latitude: :obj:`base.Float` + :param longitude: Longitude of new location :type longitude: :obj:`base.Float` + + :param horizontal_accuracy: The radius of uncertainty for the location, + measured in meters; 0-1500 + :type horizontal_accuracy: :obj:`typing.Optional[base.Float]` + + :param heading: Direction in which the user is moving, in degrees. Must be + between 1 and 360 if specified. + :type heading: :obj:`typing.Optional[base.Integer]` + + :param proximity_alert_radius: For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. Must + be between 1 and 100000 if specified. + :type proximity_alert_radius: :obj:`typing.Optional[base.Integer]` + :param reply_markup: A JSON-serialized object for a new inline keyboard - :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]` + :type reply_markup: :obj:`typing.Optional[types.InlineKeyboardMarkup]` + :return: On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`typing.Union[types.Message, base.Boolean]` @@ -775,44 +1173,77 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return result return types.Message(**result) - async def send_venue(self, chat_id: typing.Union[base.Integer, base.String], - latitude: base.Float, longitude: base.Float, - title: base.String, address: base.String, - foursquare_id: typing.Union[base.String, None] = None, - foursquare_type: typing.Union[base.String, None] = None, - disable_notification: typing.Union[base.Boolean, None] = None, - reply_to_message_id: typing.Union[base.Integer, None] = None, + async def send_venue(self, + chat_id: typing.Union[base.Integer, base.String], + latitude: base.Float, + longitude: base.Float, + title: base.String, + address: base.String, + foursquare_id: typing.Optional[base.String] = None, + foursquare_type: typing.Optional[base.String] = None, + google_place_id: typing.Optional[base.String] = None, + google_place_type: typing.Optional[base.String] = None, + disable_notification: typing.Optional[base.Boolean] = None, + reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ Use this method to send information about a venue. Source: https://core.telegram.org/bots/api#sendvenue - :param chat_id: Unique identifier for the target chat or username of the target channel + :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` + :param longitude: Longitude of the venue :type longitude: :obj:`base.Float` + :param title: Name of the venue :type title: :obj:`base.String` + :param address: Address of the venue :type address: :obj:`base.String` + :param foursquare_id: Foursquare identifier of the venue - :type foursquare_id: :obj:`typing.Union[base.String, None]` + :type foursquare_id: :obj:`typing.Optional[base.String]` + :param foursquare_type: Foursquare type of the venue, if known - :type foursquare_type: :obj:`typing.Union[base.String, None]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :param reply_to_message_id: If the message is a reply, ID of the original message - :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user + :type foursquare_type: :obj:`typing.Optional[base.String]` + + :param google_place_id: Google Places identifier of the venue + :type google_place_id: :obj:`typing.Optional[base.String]` + + :param google_place_type: Google Places type of the venue. See supported + types: https://developers.google.com/places/web-service/supported_types + :type google_place_type: :obj:`typing.Optional[base.String]` + + :param disable_notification: Sends the message silently. Users will receive + a notification with no sound + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply_to_message_id: If the message is a reply, ID of the original + message + :type reply_to_message_id: :obj:`typing.Optional[base.Integer]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, - types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, + None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -828,6 +1259,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): vcard: typing.Union[base.String, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, @@ -839,22 +1271,34 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param phone_number: Contact's phone number :type phone_number: :obj:`base.String` + :param first_name: Contact's first name :type first_name: :obj:`base.String` + :param last_name: Contact's last name :type last_name: :obj:`typing.Union[base.String, None]` + :param vcard: vcard :type vcard: :obj:`typing.Union[base.String, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -864,7 +1308,8 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_CONTACT, payload) return types.Message(**result) - async def send_poll(self, chat_id: typing.Union[base.Integer, base.String], + async def send_poll(self, + chat_id: typing.Union[base.Integer, base.String], question: base.String, options: typing.List[base.String], is_anonymous: typing.Optional[base.Boolean] = None, @@ -873,56 +1318,97 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): correct_option_id: typing.Optional[base.Integer] = None, explanation: typing.Optional[base.String] = None, explanation_parse_mode: typing.Optional[base.String] = None, + explanation_entities: typing.Optional[typing.List[types.MessageEntity]] = None, open_period: typing.Union[base.Integer, None] = None, close_date: typing.Union[ - base.Integer, datetime.datetime, datetime.timedelta, None] = None, + base.Integer, + datetime.datetime, + datetime.timedelta, + None] = None, is_closed: typing.Optional[base.Boolean] = None, disable_notification: typing.Optional[base.Boolean] = None, reply_to_message_id: typing.Optional[base.Integer] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ - Use this method to send a native poll. A native poll can't be sent to a private chat. - On success, the sent Message is returned. + Use this method to send a native poll. On success, the sent Message is + returned. Source: https://core.telegram.org/bots/api#sendpoll - :param chat_id: Unique identifier for the target chat - or username of the target channel (in the format @channelusername). - A native poll can't be sent to a private chat. + :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 question: Poll question, 1-255 characters + + :param question: Poll question, 1-300 characters :type question: :obj:`base.String` - :param options: List of answer options, 2-10 strings 1-100 characters each + + :param options: A list of answer options, 2-10 strings 1-100 characters each :type options: :obj:`typing.List[base.String]` + :param is_anonymous: True, if the poll needs to be anonymous, defaults to True :type is_anonymous: :obj:`typing.Optional[base.Boolean]` + :param type: Poll type, “quiz” or “regular”, defaults to “regular” :type type: :obj:`typing.Optional[base.String]` - :param allows_multiple_answers: True, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to False + + :param allows_multiple_answers: True, if the poll allows multiple answers, + ignored for polls in quiz mode, defaults to False :type allows_multiple_answers: :obj:`typing.Optional[base.Boolean]` - :param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode + + :param correct_option_id: 0-based identifier of the correct answer option, + required for polls in quiz mode :type correct_option_id: :obj:`typing.Optional[base.Integer]` - :param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing + + :param explanation: Text that is shown when a user chooses an incorrect + answer or taps on the lamp icon in a quiz-style poll, 0-200 characters + with at most 2 line feeds after entities parsing :type explanation: :obj:`typing.Optional[base.String]` - :param explanation_parse_mode: Mode for parsing entities in the explanation. See formatting options for more details. + + :param explanation_parse_mode: Mode for parsing entities in the explanation. + See formatting options for more details. :type explanation_parse_mode: :obj:`typing.Optional[base.String]` - :param open_period: Amount of time in seconds the poll will be active after creation, 5-600. Can't be used together with close_date. + + :param explanation_entities: List of special entities that appear in message + text, which can be specified instead of parse_mode + :type explanation_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + + :param open_period: Amount of time in seconds the poll will be active after + creation, 5-600. Can't be used together with close_date. :type open_period: :obj:`typing.Union[base.Integer, None]` - :param close_date: Point in time (Unix timestamp) when the poll will be automatically closed. Must be at least 5 and no more than 600 seconds in the future. Can't be used together with open_period. - :type close_date: :obj:`typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None]` + + :param close_date: Point in time (Unix timestamp) when the poll will be + automatically closed. Must be at least 5 and no more than 600 seconds in + the future. Can't be used together with open_period. + :type close_date: :obj:`typing.Union[base.Integer, datetime.datetime, + datetime.timedelta, None]` + :param is_closed: Pass True, if the poll needs to be immediately closed :type is_closed: :obj:`typing.Optional[base.Boolean]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + + :param disable_notification: Sends the message silently. Users will receive + a notification with no sound. :type disable_notification: :obj:`typing.Optional[Boolean]` - :param reply_to_message_id: If the message is a reply, ID of the original message + + :param reply_to_message_id: If the message is a reply, ID of the original + message :type reply_to_message_id: :obj:`typing.Optional[Integer]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, - types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, + None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -936,34 +1422,49 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SEND_POLL, payload) return types.Message(**result) - async def send_dice(self, chat_id: typing.Union[base.Integer, base.String], + async def send_dice(self, + chat_id: typing.Union[base.Integer, base.String], disable_notification: typing.Union[base.Boolean, None] = None, emoji: typing.Union[base.String, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, - types.ForceReply, None] = None) -> types.Message: + types.ForceReply, None] = None, + ) -> types.Message: """ - Use this method to send a dice, which will have a random value from 1 to 6. + Use this method to send an animated emoji that will display a random value. On success, the sent Message is returned. - (Yes, we're aware of the “proper” singular of die. - But it's awkward, and we decided to help it change. One dice at a time!) Source: https://core.telegram.org/bots/api#senddice - :param chat_id: Unique identifier for the target chat or username of the target channel + :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 "🎰". Defauts to “🎲” + :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 “🎰”. + Defaults to “🎲” :type emoji: :obj:`typing.Union[base.String, None]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound + + :param disable_notification: Sends the message silently. Users will receive + a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -1070,20 +1571,32 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.KICK_CHAT_MEMBER, payload) return result - async def unban_chat_member(self, chat_id: typing.Union[base.Integer, base.String], - user_id: base.Integer) -> base.Boolean: + async def unban_chat_member(self, + chat_id: typing.Union[base.Integer, base.String], + user_id: base.Integer, + only_if_banned: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ - Use this method to unban a previously kicked user in a supergroup or channel. ` - The user will not return to the group or channel automatically, but will be able to join via link, etc. - - The bot must be an administrator for this to work. + Use this method to unban a previously kicked user in a supergroup or channel. + The user will not return to the group or channel automatically, but will be + able to join via link, etc. The bot must be an administrator for this to + work. By default, this method guarantees that after the call the user is not + a member of the chat, but will be able to join it. So if the user is a member + of the chat they will also be removed from the chat. If you don't want this, + use the parameter only_if_banned. Returns True on success. Source: https://core.telegram.org/bots/api#unbanchatmember - :param chat_id: Unique identifier for the target group or username of the target supergroup or channel + :param chat_id: Unique identifier for the target group or username of the + target supergroup or channel (in the format @username) :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param user_id: Unique identifier of the target user :type user_id: :obj:`base.Integer` + + :param only_if_banned: Do nothing if the user is not banned + :type only_if_banned: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ @@ -1148,16 +1661,19 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.RESTRICT_CHAT_MEMBER, payload) return result - async def promote_chat_member(self, chat_id: typing.Union[base.Integer, base.String], + async def promote_chat_member(self, + chat_id: typing.Union[base.Integer, base.String], user_id: base.Integer, - can_change_info: typing.Union[base.Boolean, None] = None, - can_post_messages: typing.Union[base.Boolean, None] = None, - can_edit_messages: typing.Union[base.Boolean, None] = None, - can_delete_messages: typing.Union[base.Boolean, None] = None, - can_invite_users: typing.Union[base.Boolean, None] = None, - can_restrict_members: typing.Union[base.Boolean, None] = None, - can_pin_messages: typing.Union[base.Boolean, None] = None, - can_promote_members: typing.Union[base.Boolean, None] = None) -> base.Boolean: + 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, + can_delete_messages: typing.Optional[base.Boolean] = None, + can_invite_users: typing.Optional[base.Boolean] = None, + can_restrict_members: typing.Optional[base.Boolean] = None, + can_pin_messages: typing.Optional[base.Boolean] = None, + can_promote_members: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. @@ -1167,26 +1683,39 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :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.Union[base.Boolean, None]` + :type can_promote_members: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ @@ -1339,21 +1868,31 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.SET_CHAT_DESCRIPTION, payload) return result - async def pin_chat_message(self, chat_id: typing.Union[base.Integer, base.String], message_id: base.Integer, - disable_notification: typing.Union[base.Boolean, None] = None) -> base.Boolean: + async def pin_chat_message(self, + chat_id: typing.Union[base.Integer, base.String], + message_id: base.Integer, + disable_notification: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ - Use this method to pin a message in a supergroup. - The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Use this method to add a message to the list of pinned messages in a chat. + If the chat is not a private chat, the bot must be an administrator in the + chat for this to work and must have the 'can_pin_messages' admin right in a + supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. Source: https://core.telegram.org/bots/api#pinchatmessage - :param chat_id: Unique identifier for the target chat or username of the target supergroup + :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 message_id: Identifier of a message to pin :type message_id: :obj:`base.Integer` - :param disable_notification: Pass True, if it is not necessary to send a notification to - all group members about the new pinned message - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + + :param disable_notification: Pass True, if it is not necessary to send a + notification to all group members about the new pinned message + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ @@ -1362,15 +1901,27 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.PIN_CHAT_MESSAGE, payload) return result - async def unpin_chat_message(self, chat_id: typing.Union[base.Integer, base.String]) -> base.Boolean: + async def unpin_chat_message(self, + chat_id: typing.Union[base.Integer, base.String], + message_id: typing.Optional[base.Integer] = None, + ) -> base.Boolean: """ - Use this method to unpin a message in a supergroup chat. - The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Use this method to remove a message from the list of pinned messages in a + chat. If the chat is not a private chat, the bot must be an administrator in + the chat for this to work and must have the 'can_pin_messages' admin right in + a supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. Source: https://core.telegram.org/bots/api#unpinchatmessage - :param chat_id: Unique identifier for the target chat or username of the target supergroup + :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 message_id: Identifier of a message to unpin. If not specified, the + most recent pinned message (by sending date) will be unpinned. + :type message_id: :obj:`typing.Optional[base.Integer]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ @@ -1379,6 +1930,29 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.UNPIN_CHAT_MESSAGE, payload) return result + async def unpin_all_chat_messages(self, + chat_id: typing.Union[base.Integer, base.String], + ) -> base.Boolean: + """ + Use this method to clear the list of pinned messages in a chat. If the chat + is not a private chat, the bot must be an administrator in the chat for this + to work and must have the 'can_pin_messages' admin right in a supergroup or + 'can_edit_messages' admin right in a channel. Returns True on success. + + Source: https://core.telegram.org/bots/api#unpinallchatmessages + + :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]` + + :return: Returns True on success + :rtype: :obj:`base.Boolean` + """ + payload = generate_payload(**locals()) + + result = await self.request(api.Methods.UNPIN_ALL_CHAT_MESSAGES, payload) + return result + async def leave_chat(self, chat_id: typing.Union[base.Integer, base.String]) -> base.Boolean: """ Use this method for your bot to leave a group, supergroup or channel. @@ -1576,14 +2150,17 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): result = await self.request(api.Methods.GET_MY_COMMANDS, payload) return [types.BotCommand(**bot_command_data) for bot_command_data in result] - async def edit_message_text(self, text: base.String, + async def edit_message_text(self, + text: base.String, chat_id: typing.Union[base.Integer, base.String, None] = None, message_id: typing.Union[base.Integer, None] = None, inline_message_id: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + entities: typing.Optional[typing.List[types.MessageEntity]] = None, disable_web_page_preview: typing.Union[base.Boolean, None] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, - None] = None) -> types.Message or base.Boolean: + None] = None, + ) -> types.Message or base.Boolean: """ Use this method to edit text and game messages sent by the bot or via the bot (for inline bots). @@ -1592,19 +2169,30 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Required if inline_message_id is not specified Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String, None]` + :param message_id: Required if inline_message_id is not specified. Identifier of the sent message :type message_id: :obj:`typing.Union[base.Integer, None]` + :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the inline message :type inline_message_id: :obj:`typing.Union[base.String, None]` + :param text: New text of the message :type text: :obj:`base.String` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param disable_web_page_preview: Disables link previews for links in this message :type disable_web_page_preview: :obj:`typing.Union[base.Boolean, None]` + :param reply_markup: A JSON-serialized object for an inline keyboard :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`typing.Union[types.Message, base.Boolean]` @@ -1624,6 +2212,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): inline_message_id: typing.Union[base.String, None] = None, caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, None] = None) -> types.Message or base.Boolean: """ @@ -1634,17 +2223,27 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Required if inline_message_id is not specified Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String, None]` + :param message_id: Required if inline_message_id is not specified. Identifier of the sent message :type message_id: :obj:`typing.Union[base.Integer, None]` + :param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the inline message :type inline_message_id: :obj:`typing.Union[base.String, None]` + :param caption: New caption of the message :type caption: :obj:`typing.Union[base.String, None]` + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. :type parse_mode: :obj:`typing.Union[base.String, None]` + + :param caption_entities: List of special entities that appear in message text, + which can be specified instead of parse_mode + :type caption_entities: :obj:`typing.Optional[typing.List[types.MessageEntity]]` + :param reply_markup: A JSON-serialized object for an inline keyboard :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`typing.Union[types.Message, base.Boolean]` @@ -1790,6 +2389,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): sticker: typing.Union[base.InputFile, base.String], disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, @@ -1801,16 +2401,25 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target channel :type chat_id: :obj:`typing.Union[base.Integer, base.String]` + :param sticker: Sticker to send :type sticker: :obj:`typing.Union[base.InputFile, base.String]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -2093,6 +2702,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): is_flexible: typing.Union[base.Boolean, None] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, + allow_sending_without_reply: typing.Optional[base.Boolean] = None, reply_markup: typing.Union[types.InlineKeyboardMarkup, None] = None) -> types.Message: """ Use this method to send invoices. @@ -2101,54 +2711,81 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target private chat :type chat_id: :obj:`base.Integer` + :param title: Product name, 1-32 characters :type title: :obj:`base.String` + :param description: Product description, 1-255 characters :type description: :obj:`base.String` + :param payload: Bot-defined invoice payload, 1-128 bytes This will not be displayed to the user, use for your internal processes. :type payload: :obj:`base.String` + :param provider_token: Payments provider token, obtained via Botfather :type provider_token: :obj:`base.String` + :param start_parameter: Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter :type start_parameter: :obj:`base.String` + :param currency: Three-letter ISO 4217 currency code, see more on currencies :type currency: :obj:`base.String` + :param prices: Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) :type prices: :obj:`typing.List[types.LabeledPrice]` + :param provider_data: JSON-encoded data about the invoice, which will be shared with the payment provider :type provider_data: :obj:`typing.Union[typing.Dict, None]` + :param photo_url: URL of the product photo for the invoice :type photo_url: :obj:`typing.Union[base.String, None]` + :param photo_size: Photo size :type photo_size: :obj:`typing.Union[base.Integer, None]` + :param photo_width: Photo width :type photo_width: :obj:`typing.Union[base.Integer, None]` + :param photo_height: Photo height :type photo_height: :obj:`typing.Union[base.Integer, None]` + :param need_name: Pass True, if you require the user's full name to complete the order :type need_name: :obj:`typing.Union[base.Boolean, None]` + :param need_phone_number: Pass True, if you require the user's phone number to complete the order :type need_phone_number: :obj:`typing.Union[base.Boolean, None]` + :param need_email: Pass True, if you require the user's email to complete the order :type need_email: :obj:`typing.Union[base.Boolean, None]` + :param need_shipping_address: Pass True, if you require the user's shipping address to complete the order :type need_shipping_address: :obj:`typing.Union[base.Boolean, None]` + :param send_phone_number_to_provider: Pass True, if user's phone number should be sent to provider :type send_phone_number_to_provider: :obj:`typing.Union[base.Boolean, None]` + :param send_email_to_provider: Pass True, if user's email address should be sent to provider :type send_email_to_provider: :obj:`typing.Union[base.Boolean, None]` + :param is_flexible: Pass True, if the final price depends on the shipping method :type is_flexible: :obj:`typing.Union[base.Boolean, None]` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: A JSON-serialized object for an inline keyboard If empty, one 'Pay total price' button will be shown. If not empty, the first button must be a Pay button. :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ @@ -2256,10 +2893,14 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): # === Games === # https://core.telegram.org/bots/api#games - async def send_game(self, chat_id: base.Integer, game_short_name: base.String, + async def send_game(self, + chat_id: base.Integer, + game_short_name: base.String, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, - reply_markup: typing.Union[types.InlineKeyboardMarkup, None] = None) -> types.Message: + allow_sending_without_reply: typing.Optional[base.Boolean] = None, + reply_markup: typing.Union[types.InlineKeyboardMarkup, None] = None, + ) -> types.Message: """ Use this method to send a game. @@ -2267,16 +2908,25 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat :type chat_id: :obj:`base.Integer` - :param game_short_name: Short name of the game, serves as the unique identifier for the game. \ + + :param game_short_name: Short name of the game, serves as the unique identifier for the game. Set up your games via Botfather. :type game_short_name: :obj:`base.String` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param reply_to_message_id: If the message is a reply, ID of the original message :type reply_to_message_id: :obj:`typing.Union[base.Integer, None]` + + :param allow_sending_without_reply: Pass True, if the message should be sent + even if the specified replied-to message is not found + :type allow_sending_without_reply: :obj:`typing.Optional[base.Boolean]` + :param reply_markup: A JSON-serialized object for an inline keyboard If empty, one ‘Play game_title’ button will be shown. If not empty, the first button must launch the game. :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]` + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ diff --git a/aiogram/types/audio.py b/aiogram/types/audio.py index 6859668f..1657c9cc 100644 --- a/aiogram/types/audio.py +++ b/aiogram/types/audio.py @@ -15,6 +15,7 @@ class Audio(base.TelegramObject, mixins.Downloadable): duration: base.Integer = fields.Field() performer: base.String = fields.Field() title: base.String = fields.Field() + file_name: base.String = fields.Field() mime_type: base.String = fields.Field() file_size: base.Integer = fields.Field() thumb: PhotoSize = fields.Field(base=PhotoSize) diff --git a/aiogram/types/chat.py b/aiogram/types/chat.py index 28cc5ed0..901e2052 100644 --- a/aiogram/types/chat.py +++ b/aiogram/types/chat.py @@ -4,12 +4,13 @@ import asyncio import datetime import typing -from ..utils import helper, markdown from . import base, fields +from .chat_location import ChatLocation from .chat_member import ChatMember from .chat_permissions import ChatPermissions from .chat_photo import ChatPhoto from .input_file import InputFile +from ..utils import helper, markdown from ..utils.deprecated import deprecated @@ -27,6 +28,7 @@ class Chat(base.TelegramObject): last_name: base.String = fields.Field() all_members_are_administrators: base.Boolean = fields.Field() photo: ChatPhoto = fields.Field(base=ChatPhoto) + bio: typing.Optional[base.String] = fields.Field() description: base.String = fields.Field() invite_link: base.String = fields.Field() pinned_message: 'Message' = fields.Field(base='Message') @@ -34,6 +36,8 @@ class Chat(base.TelegramObject): slow_mode_delay: base.Integer = fields.Field() sticker_set_name: base.String = fields.Field() can_set_sticker_set: base.Boolean = fields.Field() + linked_chat_id: typing.Optional[base.Integer] = fields.Field() + location: typing.Optional[ChatLocation] = fields.Field() def __hash__(self): return self.id @@ -182,7 +186,8 @@ class Chat(base.TelegramObject): return await self.bot.set_chat_description(self.id, description) async def kick(self, user_id: base.Integer, - until_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean: + until_date: typing.Union[ + base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean: """ Use this method to kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group @@ -205,21 +210,35 @@ class Chat(base.TelegramObject): """ return await self.bot.kick_chat_member(self.id, user_id=user_id, until_date=until_date) - async def unban(self, user_id: base.Integer) -> base.Boolean: + async def unban(self, + user_id: base.Integer, + only_if_banned: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ - Use this method to unban a previously kicked user in a supergroup or channel. ` - The user will not return to the group or channel automatically, but will be able to join via link, etc. - - The bot must be an administrator for this to work. + Use this method to unban a previously kicked user in a supergroup or channel. + The user will not return to the group or channel automatically, but will be + able to join via link, etc. The bot must be an administrator for this to + work. By default, this method guarantees that after the call the user is not + a member of the chat, but will be able to join it. So if the user is a member + of the chat they will also be removed from the chat. If you don't want this, + use the parameter only_if_banned. Returns True on success. Source: https://core.telegram.org/bots/api#unbanchatmember :param user_id: Unique identifier of the target user :type user_id: :obj:`base.Integer` + + :param only_if_banned: Do nothing if the user is not banned + :type only_if_banned: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success. :rtype: :obj:`base.Boolean` """ - return await self.bot.unban_chat_member(self.id, user_id=user_id) + return await self.bot.unban_chat_member( + chat_id=self.id, + user_id=user_id, + only_if_banned=only_if_banned, + ) async def restrict(self, user_id: base.Integer, permissions: typing.Optional[ChatPermissions] = None, @@ -338,36 +357,73 @@ class Chat(base.TelegramObject): :param custom_title: New custom title for the administrator; 0-16 characters, emoji are not allowed :return: True on success. """ - return await self.bot.set_chat_administrator_custom_title(chat_id=self.id, user_id=user_id, custom_title=custom_title) + return await self.bot.set_chat_administrator_custom_title(chat_id=self.id, user_id=user_id, + custom_title=custom_title) - async def pin_message(self, message_id: base.Integer, disable_notification: base.Boolean = False) -> base.Boolean: + async def pin_message(self, + message_id: base.Integer, + disable_notification: typing.Optional[base.Boolean] = False, + ) -> base.Boolean: """ - Use this method to pin a message in a supergroup. - The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Use this method to add a message to the list of pinned messages in a chat. + If the chat is not a private chat, the bot must be an administrator in the + chat for this to work and must have the 'can_pin_messages' admin right in a + supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. Source: https://core.telegram.org/bots/api#pinchatmessage :param message_id: Identifier of a message to pin :type message_id: :obj:`base.Integer` - :param disable_notification: Pass True, if it is not necessary to send a notification to - all group members about the new pinned message - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :return: Returns True on success. + + :param disable_notification: Pass True, if it is not necessary to send a + notification to all group members about the new pinned message + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :return: Returns True on success :rtype: :obj:`base.Boolean` """ return await self.bot.pin_chat_message(self.id, message_id, disable_notification) - async def unpin_message(self) -> base.Boolean: + async def unpin_message(self, + message_id: typing.Optional[base.Integer] = None, + ) -> base.Boolean: """ - Use this method to unpin a message in a supergroup chat. - The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Use this method to remove a message from the list of pinned messages in a + chat. If the chat is not a private chat, the bot must be an administrator in + the chat for this to work and must have the 'can_pin_messages' admin right in + a supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. Source: https://core.telegram.org/bots/api#unpinchatmessage - :return: Returns True on success. + :param message_id: Identifier of a message to unpin. If not specified, the + most recent pinned message (by sending date) will be unpinned. + :type message_id: :obj:`typing.Optional[base.Integer]` + + :return: Returns True on success :rtype: :obj:`base.Boolean` """ - return await self.bot.unpin_chat_message(self.id) + return await self.bot.unpin_chat_message( + chat_id=self.id, + message_id=message_id, + ) + + async def unpin_all_messages(self): + """ + Use this method to clear the list of pinned messages in a chat. If the chat + is not a private chat, the bot must be an administrator in the chat for this + to work and must have the 'can_pin_messages' admin right in a supergroup or + 'can_edit_messages' admin right in a channel. Returns True on success. + + Source: https://core.telegram.org/bots/api#unpinallchatmessages + + :return: Returns True on success + :rtype: :obj:`base.Boolean` + """ + return await self.bot.unpin_all_chat_messages( + chat_id=self.id, + ) async def leave(self) -> base.Boolean: """ diff --git a/aiogram/types/chat_location.py b/aiogram/types/chat_location.py new file mode 100644 index 00000000..0438c544 --- /dev/null +++ b/aiogram/types/chat_location.py @@ -0,0 +1,16 @@ +from . import base +from . import fields +from .location import Location + + +class ChatLocation(base.TelegramObject): + """ + Represents a location to which a chat is connected. + + https://core.telegram.org/bots/api#chatlocation + """ + location: Location = fields.Field() + address: base.String = fields.Field() + + def __init__(self, location: Location, address: base.String): + super().__init__(location=location, address=address) diff --git a/aiogram/types/chat_member.py b/aiogram/types/chat_member.py index 274c8a26..4aa52b80 100644 --- a/aiogram/types/chat_member.py +++ b/aiogram/types/chat_member.py @@ -1,6 +1,4 @@ import datetime -import warnings -from typing import Optional from . import base from . import fields @@ -17,6 +15,7 @@ class ChatMember(base.TelegramObject): user: User = fields.Field(base=User) status: base.String = fields.Field() custom_title: base.String = fields.Field() + is_anonymous: base.Boolean = fields.Field() until_date: datetime.datetime = fields.DateTimeField() can_be_edited: base.Boolean = fields.Field() can_change_info: base.Boolean = fields.Field() diff --git a/aiogram/types/dice.py b/aiogram/types/dice.py index cae3e2b3..70c50e09 100644 --- a/aiogram/types/dice.py +++ b/aiogram/types/dice.py @@ -17,5 +17,5 @@ class DiceEmoji: DICE = '🎲' DART = '🎯' BASKETBALL = '🏀' - SOCCER = '⚽️' + FOOTBALL = '⚽' SLOT_MACHINE = '🎰' diff --git a/aiogram/types/inline_query_result.py b/aiogram/types/inline_query_result.py index fccaa2a1..af7dd3dd 100644 --- a/aiogram/types/inline_query_result.py +++ b/aiogram/types/inline_query_result.py @@ -1,6 +1,6 @@ import typing -from . import base +from . import base, MessageEntity from . import fields from .inline_keyboard import InlineKeyboardMarkup from .input_message_content import InputMessageContent @@ -83,23 +83,29 @@ class InlineQueryResultPhoto(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - photo_url: base.String, - thumb_url: base.String, - photo_width: typing.Optional[base.Integer] = None, - photo_height: typing.Optional[base.Integer] = None, - title: typing.Optional[base.String] = None, - description: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultPhoto, self).__init__(id=id, photo_url=photo_url, thumb_url=thumb_url, - photo_width=photo_width, photo_height=photo_height, title=title, - description=description, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + photo_url: base.String, + thumb_url: base.String, + photo_width: typing.Optional[base.Integer] = None, + photo_height: typing.Optional[base.Integer] = None, + title: typing.Optional[base.String] = None, + description: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, photo_url=photo_url, thumb_url=thumb_url, + photo_width=photo_width, photo_height=photo_height, title=title, + description=description, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultGif(InlineQueryResult): @@ -123,23 +129,29 @@ class InlineQueryResultGif(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - gif_url: base.String, - gif_width: typing.Optional[base.Integer] = None, - gif_height: typing.Optional[base.Integer] = None, - gif_duration: typing.Optional[base.Integer] = None, - thumb_url: typing.Optional[base.String] = None, - title: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultGif, self).__init__(id=id, gif_url=gif_url, gif_width=gif_width, - gif_height=gif_height, gif_duration=gif_duration, - thumb_url=thumb_url, title=title, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + gif_url: base.String, + gif_width: typing.Optional[base.Integer] = None, + gif_height: typing.Optional[base.Integer] = None, + gif_duration: typing.Optional[base.Integer] = None, + thumb_url: typing.Optional[base.String] = None, + title: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, gif_url=gif_url, gif_width=gif_width, gif_height=gif_height, + gif_duration=gif_duration, thumb_url=thumb_url, title=title, + caption=caption, parse_mode=parse_mode, reply_markup=reply_markup, + caption_entities=caption_entities, + input_message_content=input_message_content, + ) class InlineQueryResultMpeg4Gif(InlineQueryResult): @@ -163,23 +175,30 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - mpeg4_url: base.String, - thumb_url: base.String, - mpeg4_width: typing.Optional[base.Integer] = None, - mpeg4_height: typing.Optional[base.Integer] = None, - mpeg4_duration: typing.Optional[base.Integer] = None, - title: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultMpeg4Gif, self).__init__(id=id, mpeg4_url=mpeg4_url, mpeg4_width=mpeg4_width, - mpeg4_height=mpeg4_height, mpeg4_duration=mpeg4_duration, - thumb_url=thumb_url, title=title, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + mpeg4_url: base.String, + thumb_url: base.String, + mpeg4_width: typing.Optional[base.Integer] = None, + mpeg4_height: typing.Optional[base.Integer] = None, + mpeg4_duration: typing.Optional[base.Integer] = None, + title: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, mpeg4_url=mpeg4_url, mpeg4_width=mpeg4_width, + mpeg4_height=mpeg4_height, mpeg4_duration=mpeg4_duration, + thumb_url=thumb_url, title=title, caption=caption, + parse_mode=parse_mode, reply_markup=reply_markup, + caption_entities=caption_entities, + input_message_content=input_message_content, + ) class InlineQueryResultVideo(InlineQueryResult): @@ -207,26 +226,32 @@ class InlineQueryResultVideo(InlineQueryResult): description: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - video_url: base.String, - mime_type: base.String, - thumb_url: base.String, - title: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - video_width: typing.Optional[base.Integer] = None, - video_height: typing.Optional[base.Integer] = None, - video_duration: typing.Optional[base.Integer] = None, - description: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultVideo, self).__init__(id=id, video_url=video_url, mime_type=mime_type, - thumb_url=thumb_url, title=title, caption=caption, - video_width=video_width, video_height=video_height, - video_duration=video_duration, description=description, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + video_url: base.String, + mime_type: base.String, + thumb_url: base.String, + title: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + video_width: typing.Optional[base.Integer] = None, + video_height: typing.Optional[base.Integer] = None, + video_duration: typing.Optional[base.Integer] = None, + description: typing.Optional[base.String] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, video_url=video_url, mime_type=mime_type, thumb_url=thumb_url, + title=title, caption=caption, video_width=video_width, + video_height=video_height, video_duration=video_duration, + description=description, parse_mode=parse_mode, + reply_markup=reply_markup, caption_entities=caption_entities, + input_message_content=input_message_content, + ) class InlineQueryResultAudio(InlineQueryResult): @@ -248,21 +273,27 @@ class InlineQueryResultAudio(InlineQueryResult): audio_duration: base.Integer = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - audio_url: base.String, - title: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - performer: typing.Optional[base.String] = None, - audio_duration: typing.Optional[base.Integer] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultAudio, self).__init__(id=id, audio_url=audio_url, title=title, - caption=caption, parse_mode=parse_mode, - performer=performer, audio_duration=audio_duration, - reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + audio_url: base.String, + title: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + performer: typing.Optional[base.String] = None, + audio_duration: typing.Optional[base.Integer] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, audio_url=audio_url, title=title, + caption=caption, parse_mode=parse_mode, + performer=performer, audio_duration=audio_duration, + reply_markup=reply_markup, caption_entities=caption_entities, + input_message_content=input_message_content, + ) class InlineQueryResultVoice(InlineQueryResult): @@ -285,19 +316,25 @@ class InlineQueryResultVoice(InlineQueryResult): voice_duration: base.Integer = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - voice_url: base.String, - title: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - voice_duration: typing.Optional[base.Integer] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultVoice, self).__init__(id=id, voice_url=voice_url, title=title, - caption=caption, voice_duration=voice_duration, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + voice_url: base.String, + title: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + voice_duration: typing.Optional[base.Integer] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, voice_url=voice_url, title=title, caption=caption, + voice_duration=voice_duration, parse_mode=parse_mode, + reply_markup=reply_markup, caption_entities=caption_entities, + input_message_content=input_message_content, + ) class InlineQueryResultDocument(InlineQueryResult): @@ -323,25 +360,31 @@ class InlineQueryResultDocument(InlineQueryResult): thumb_width: base.Integer = fields.Field() thumb_height: base.Integer = fields.Field() - def __init__(self, *, - id: base.String, - title: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - document_url: typing.Optional[base.String] = None, - mime_type: typing.Optional[base.String] = None, - description: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None, - thumb_url: typing.Optional[base.String] = None, - thumb_width: typing.Optional[base.Integer] = None, - thumb_height: typing.Optional[base.Integer] = None): - super(InlineQueryResultDocument, self).__init__(id=id, title=title, caption=caption, - document_url=document_url, mime_type=mime_type, - description=description, reply_markup=reply_markup, - input_message_content=input_message_content, - thumb_url=thumb_url, thumb_width=thumb_width, - thumb_height=thumb_height, parse_mode=parse_mode) + def __init__( + self, + *, + id: base.String, + title: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + document_url: typing.Optional[base.String] = None, + mime_type: typing.Optional[base.String] = None, + description: typing.Optional[base.String] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + thumb_url: typing.Optional[base.String] = None, + thumb_width: typing.Optional[base.Integer] = None, + thumb_height: typing.Optional[base.Integer] = None, + ): + super().__init__( + id=id, title=title, caption=caption, parse_mode=parse_mode, + caption_entities=caption_entities, document_url=document_url, + mime_type=mime_type, description=description, reply_markup=reply_markup, + input_message_content=input_message_content, + thumb_url=thumb_url, thumb_width=thumb_width, + thumb_height=thumb_height, + ) class InlineQueryResultLocation(InlineQueryResult): @@ -352,16 +395,16 @@ class InlineQueryResultLocation(InlineQueryResult): Alternatively, you can use input_message_content to send a message with the specified content instead of the location. - Note: This will only work in Telegram versions released after 9 April, 2016. - Older clients will ignore them. - https://core.telegram.org/bots/api#inlinequeryresultlocation """ type: base.String = fields.Field(alias='type', default='location') latitude: base.Float = fields.Field() longitude: base.Float = fields.Field() title: base.String = fields.Field() + horizontal_accuracy: typing.Optional[base.Float] = fields.Field() live_period: base.Integer = fields.Field() + heading: typing.Optional[base.Integer] = fields.Field() + proximity_alert_radius: typing.Optional[base.Integer] = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) thumb_url: base.String = fields.Field() thumb_width: base.Integer = fields.Field() @@ -372,18 +415,31 @@ class InlineQueryResultLocation(InlineQueryResult): latitude: base.Float, longitude: base.Float, title: base.String, + horizontal_accuracy: typing.Optional[base.Float] = None, live_period: typing.Optional[base.Integer] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, reply_markup: typing.Optional[InlineKeyboardMarkup] = None, input_message_content: typing.Optional[InputMessageContent] = None, thumb_url: typing.Optional[base.String] = None, thumb_width: typing.Optional[base.Integer] = None, - thumb_height: typing.Optional[base.Integer] = None): - super(InlineQueryResultLocation, self).__init__(id=id, latitude=latitude, longitude=longitude, - title=title, live_period=live_period, - reply_markup=reply_markup, - input_message_content=input_message_content, - thumb_url=thumb_url, thumb_width=thumb_width, - thumb_height=thumb_height) + thumb_height: typing.Optional[base.Integer] = None, + ): + super().__init__( + id=id, + latitude=latitude, + longitude=longitude, + title=title, + horizontal_accuracy=horizontal_accuracy, + live_period=live_period, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + reply_markup=reply_markup, + input_message_content=input_message_content, + thumb_url=thumb_url, + thumb_width=thumb_width, + thumb_height=thumb_height + ) class InlineQueryResultVenue(InlineQueryResult): @@ -404,31 +460,40 @@ class InlineQueryResultVenue(InlineQueryResult): title: base.String = fields.Field() address: base.String = fields.Field() foursquare_id: base.String = fields.Field() + foursquare_type: base.String = fields.Field() + google_place_id: base.String = fields.Field() + google_place_type: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) thumb_url: base.String = fields.Field() thumb_width: base.Integer = fields.Field() thumb_height: base.Integer = fields.Field() - foursquare_type: base.String = fields.Field() - def __init__(self, *, - id: base.String, - latitude: base.Float, - longitude: base.Float, - title: base.String, - address: base.String, - foursquare_id: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None, - thumb_url: typing.Optional[base.String] = None, - thumb_width: typing.Optional[base.Integer] = None, - thumb_height: typing.Optional[base.Integer] = None, - foursquare_type: typing.Optional[base.String] = None): - super(InlineQueryResultVenue, self).__init__(id=id, latitude=latitude, longitude=longitude, - title=title, address=address, foursquare_id=foursquare_id, - reply_markup=reply_markup, - input_message_content=input_message_content, thumb_url=thumb_url, - thumb_width=thumb_width, thumb_height=thumb_height, - foursquare_type=foursquare_type) + def __init__( + self, + *, + id: base.String, + latitude: base.Float, + longitude: base.Float, + title: base.String, + address: base.String, + foursquare_id: typing.Optional[base.String] = None, + foursquare_type: typing.Optional[base.String] = None, + google_place_id: typing.Optional[base.String] = None, + google_place_type: typing.Optional[base.String] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + thumb_url: typing.Optional[base.String] = None, + thumb_width: typing.Optional[base.Integer] = None, + thumb_height: typing.Optional[base.Integer] = None, + ): + super().__init__( + id=id, latitude=latitude, longitude=longitude, title=title, + address=address, foursquare_id=foursquare_id, + foursquare_type=foursquare_type, google_place_id=google_place_id, + google_place_type=google_place_type, reply_markup=reply_markup, + input_message_content=input_message_content, thumb_url=thumb_url, + thumb_width=thumb_width, thumb_height=thumb_height, + ) class InlineQueryResultContact(InlineQueryResult): @@ -510,19 +575,24 @@ class InlineQueryResultCachedPhoto(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - photo_file_id: base.String, - title: typing.Optional[base.String] = None, - description: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedPhoto, self).__init__(id=id, photo_file_id=photo_file_id, title=title, - description=description, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + photo_file_id: base.String, + title: typing.Optional[base.String] = None, + description: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, photo_file_id=photo_file_id, title=title, description=description, + caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultCachedGif(InlineQueryResult): @@ -541,18 +611,23 @@ class InlineQueryResultCachedGif(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - gif_file_id: base.String, - title: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedGif, self).__init__(id=id, gif_file_id=gif_file_id, - title=title, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + gif_file_id: base.String, + title: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, gif_file_id=gif_file_id, title=title, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): @@ -571,18 +646,23 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - mpeg4_file_id: base.String, - title: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedMpeg4Gif, self).__init__(id=id, mpeg4_file_id=mpeg4_file_id, - title=title, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + mpeg4_file_id: base.String, + title: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, mpeg4_file_id=mpeg4_file_id, title=title, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultCachedSticker(InlineQueryResult): @@ -631,20 +711,25 @@ class InlineQueryResultCachedDocument(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - title: base.String, - document_file_id: base.String, - description: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedDocument, self).__init__(id=id, title=title, - document_file_id=document_file_id, - description=description, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + title: base.String, + document_file_id: base.String, + description: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, title=title, document_file_id=document_file_id, + description=description, caption=caption, parse_mode=parse_mode, + caption_entities=caption_entities, reply_markup=reply_markup, + input_message_content=input_message_content, + ) class InlineQueryResultCachedVideo(InlineQueryResult): @@ -664,19 +749,24 @@ class InlineQueryResultCachedVideo(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - video_file_id: base.String, - title: base.String, - description: typing.Optional[base.String] = None, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedVideo, self).__init__(id=id, video_file_id=video_file_id, title=title, - description=description, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + video_file_id: base.String, + title: base.String, + description: typing.Optional[base.String] = None, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, video_file_id=video_file_id, title=title, description=description, + caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultCachedVoice(InlineQueryResult): @@ -697,18 +787,23 @@ class InlineQueryResultCachedVoice(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - voice_file_id: base.String, - title: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedVoice, self).__init__(id=id, voice_file_id=voice_file_id, - title=title, caption=caption, - parse_mode=parse_mode, reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + voice_file_id: base.String, + title: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, voice_file_id=voice_file_id, title=title, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) class InlineQueryResultCachedAudio(InlineQueryResult): @@ -729,14 +824,19 @@ class InlineQueryResultCachedAudio(InlineQueryResult): caption: base.String = fields.Field() input_message_content: InputMessageContent = fields.Field(base=InputMessageContent) - def __init__(self, *, - id: base.String, - audio_file_id: base.String, - caption: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - reply_markup: typing.Optional[InlineKeyboardMarkup] = None, - input_message_content: typing.Optional[InputMessageContent] = None): - super(InlineQueryResultCachedAudio, self).__init__(id=id, audio_file_id=audio_file_id, - caption=caption, parse_mode=parse_mode, - reply_markup=reply_markup, - input_message_content=input_message_content) + def __init__( + self, + *, + id: base.String, + audio_file_id: base.String, + caption: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + reply_markup: typing.Optional[InlineKeyboardMarkup] = None, + input_message_content: typing.Optional[InputMessageContent] = None, + ): + super().__init__( + id=id, audio_file_id=audio_file_id, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + reply_markup=reply_markup, input_message_content=input_message_content, + ) diff --git a/aiogram/types/input_media.py b/aiogram/types/input_media.py index 25422df1..943a534c 100644 --- a/aiogram/types/input_media.py +++ b/aiogram/types/input_media.py @@ -5,6 +5,7 @@ import typing from . import base from . import fields from .input_file import InputFile +from .message_entity import MessageEntity ATTACHMENT_PREFIX = 'attach://' @@ -106,28 +107,48 @@ class InputMediaAnimation(InputMedia): height: base.Integer = fields.Field() duration: base.Integer = fields.Field() - def __init__(self, media: base.InputFile, - thumb: typing.Union[base.InputFile, base.String] = None, - caption: base.String = None, - width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None, - parse_mode: base.String = None, **kwargs): - super(InputMediaAnimation, self).__init__(type='animation', media=media, thumb=thumb, caption=caption, - width=width, height=height, duration=duration, - parse_mode=parse_mode, conf=kwargs) + def __init__( + self, + media: base.InputFile, + thumb: typing.Union[base.InputFile, base.String] = None, + caption: base.String = None, + width: base.Integer = None, + height: base.Integer = None, + duration: base.Integer = None, + parse_mode: base.String = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + **kwargs, + ): + super().__init__( + type='animation', media=media, thumb=thumb, caption=caption, width=width, + height=height, duration=duration, parse_mode=parse_mode, + caption_entities=caption_entities, conf=kwargs, + ) class InputMediaDocument(InputMedia): """ - Represents a photo to be sent. + Represents a general file to be sent. https://core.telegram.org/bots/api#inputmediadocument """ - def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None, - caption: base.String = None, parse_mode: base.String = None, **kwargs): - super(InputMediaDocument, self).__init__(type='document', media=media, thumb=thumb, - caption=caption, parse_mode=parse_mode, - conf=kwargs) + def __init__( + self, + media: base.InputFile, + thumb: typing.Union[base.InputFile, base.String, None] = None, + caption: base.String = None, + parse_mode: base.String = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, + **kwargs, + ): + super().__init__( + type='document', media=media, thumb=thumb, caption=caption, + parse_mode=parse_mode, caption_entities=caption_entities, + disable_content_type_detection=disable_content_type_detection, + conf=kwargs, + ) class InputMediaAudio(InputMedia): @@ -141,17 +162,23 @@ class InputMediaAudio(InputMedia): performer: base.String = fields.Field() title: base.String = fields.Field() - def __init__(self, media: base.InputFile, - thumb: typing.Union[base.InputFile, base.String] = None, - caption: base.String = None, - duration: base.Integer = None, - performer: base.String = None, - title: base.String = None, - parse_mode: base.String = None, **kwargs): - super(InputMediaAudio, self).__init__(type='audio', media=media, thumb=thumb, - caption=caption, duration=duration, - performer=performer, title=title, - parse_mode=parse_mode, conf=kwargs) + def __init__( + self, + media: base.InputFile, + thumb: typing.Union[base.InputFile, base.String] = None, + caption: base.String = None, + duration: base.Integer = None, + performer: base.String = None, + title: base.String = None, + parse_mode: base.String = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + **kwargs, + ): + super().__init__( + type='audio', media=media, thumb=thumb, caption=caption, + duration=duration, performer=performer, title=title, + parse_mode=parse_mode, caption_entities=caption_entities, conf=kwargs, + ) class InputMediaPhoto(InputMedia): @@ -161,11 +188,18 @@ class InputMediaPhoto(InputMedia): https://core.telegram.org/bots/api#inputmediaphoto """ - def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None, - caption: base.String = None, parse_mode: base.String = None, **kwargs): - super(InputMediaPhoto, self).__init__(type='photo', media=media, thumb=thumb, - caption=caption, parse_mode=parse_mode, - conf=kwargs) + def __init__( + self, + media: base.InputFile, + caption: base.String = None, + parse_mode: base.String = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + **kwargs, + ): + super().__init__( + type='photo', media=media, caption=caption, parse_mode=parse_mode, + caption_entities=caption_entities, conf=kwargs, + ) class InputMediaVideo(InputMedia): @@ -179,16 +213,25 @@ class InputMediaVideo(InputMedia): duration: base.Integer = fields.Field() supports_streaming: base.Boolean = fields.Field() - def __init__(self, media: base.InputFile, - thumb: typing.Union[base.InputFile, base.String] = None, - caption: base.String = None, - width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None, - parse_mode: base.String = None, - supports_streaming: base.Boolean = None, **kwargs): - super(InputMediaVideo, self).__init__(type='video', media=media, thumb=thumb, caption=caption, - width=width, height=height, duration=duration, - parse_mode=parse_mode, - supports_streaming=supports_streaming, conf=kwargs) + def __init__( + self, + media: base.InputFile, + thumb: typing.Union[base.InputFile, base.String] = None, + caption: base.String = None, + width: base.Integer = None, + height: base.Integer = None, + duration: base.Integer = None, + parse_mode: base.String = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + supports_streaming: base.Boolean = None, + **kwargs, + ): + super().__init__( + type='video', media=media, thumb=thumb, caption=caption, + width=width, height=height, duration=duration, + parse_mode=parse_mode, caption_entities=caption_entities, + supports_streaming=supports_streaming, conf=kwargs + ) class MediaGroup(base.TelegramObject): diff --git a/aiogram/types/input_message_content.py b/aiogram/types/input_message_content.py index 736a4454..a18d2b96 100644 --- a/aiogram/types/input_message_content.py +++ b/aiogram/types/input_message_content.py @@ -1,6 +1,6 @@ import typing -from . import base +from . import base, MessageEntity from . import fields @@ -40,17 +40,31 @@ class InputLocationMessageContent(InputMessageContent): """ Represents the content of a location message to be sent as the result of an inline query. - Note: This will only work in Telegram versions released after 9 April, 2016. - Older clients will ignore them. - https://core.telegram.org/bots/api#inputlocationmessagecontent """ latitude: base.Float = fields.Field() longitude: base.Float = fields.Field() + horizontal_accuracy: typing.Optional[base.Float] = fields.Field() + live_period: typing.Optional[base.Integer] = fields.Field() + heading: typing.Optional[base.Integer] = fields.Field() + proximity_alert_radius: typing.Optional[base.Integer] = fields.Field() - def __init__(self, latitude: base.Float, - longitude: base.Float): - super(InputLocationMessageContent, self).__init__(latitude=latitude, longitude=longitude) + def __init__(self, + latitude: base.Float, + longitude: base.Float, + horizontal_accuracy: typing.Optional[base.Float] = None, + live_period: typing.Optional[base.Integer] = None, + heading: typing.Optional[base.Integer] = None, + proximity_alert_radius: typing.Optional[base.Integer] = None, + ): + super().__init__( + latitude=latitude, + longitude=longitude, + horizontal_accuracy=horizontal_accuracy, + live_period=live_period, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + ) class InputTextMessageContent(InputMessageContent): @@ -69,14 +83,21 @@ class InputTextMessageContent(InputMessageContent): except RuntimeError: pass - def __init__(self, message_text: typing.Optional[base.String] = None, - parse_mode: typing.Optional[base.String] = None, - disable_web_page_preview: typing.Optional[base.Boolean] = None): + def __init__( + self, + message_text: typing.Optional[base.String] = None, + parse_mode: typing.Optional[base.String] = None, + caption_entities: typing.Optional[typing.List[MessageEntity]] = None, + disable_web_page_preview: typing.Optional[base.Boolean] = None, + ): if parse_mode is None: parse_mode = self.safe_get_parse_mode() - super(InputTextMessageContent, self).__init__(message_text=message_text, parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview) + super().__init__( + message_text=message_text, parse_mode=parse_mode, + caption_entities=caption_entities, + disable_web_page_preview=disable_web_page_preview, + ) class InputVenueMessageContent(InputMessageContent): @@ -93,11 +114,24 @@ class InputVenueMessageContent(InputMessageContent): title: base.String = fields.Field() address: base.String = fields.Field() foursquare_id: base.String = fields.Field() + foursquare_type: base.String = fields.Field() + google_place_id: base.String = fields.Field() + google_place_type: base.String = fields.Field() - def __init__(self, latitude: typing.Optional[base.Float] = None, - longitude: typing.Optional[base.Float] = None, - title: typing.Optional[base.String] = None, - address: typing.Optional[base.String] = None, - foursquare_id: typing.Optional[base.String] = None): - super(InputVenueMessageContent, self).__init__(latitude=latitude, longitude=longitude, title=title, - address=address, foursquare_id=foursquare_id) + def __init__( + self, + latitude: typing.Optional[base.Float] = None, + longitude: typing.Optional[base.Float] = None, + title: typing.Optional[base.String] = None, + address: typing.Optional[base.String] = None, + foursquare_id: typing.Optional[base.String] = None, + foursquare_type: typing.Optional[base.String] = None, + google_place_id: typing.Optional[base.String] = None, + google_place_type: typing.Optional[base.String] = None, + ): + super().__init__( + latitude=latitude, longitude=longitude, title=title, + address=address, foursquare_id=foursquare_id, + foursquare_type=foursquare_type, google_place_id=google_place_id, + google_place_type=google_place_type, + ) diff --git a/aiogram/types/location.py b/aiogram/types/location.py index ea2f81c4..5f159e33 100644 --- a/aiogram/types/location.py +++ b/aiogram/types/location.py @@ -1,3 +1,5 @@ +import typing + from . import base from . import fields @@ -10,3 +12,7 @@ class Location(base.TelegramObject): """ longitude: base.Float = fields.Field() latitude: base.Float = fields.Field() + horizontal_accuracy: typing.Optional[base.Float] = fields.Field() + live_period: typing.Optional[base.Integer] = fields.Field() + heading: typing.Optional[base.Integer] = fields.Field() + proximity_alert_radius: typing.Optional[base.Integer] = fields.Field() diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 54a11eb3..37d3d486 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -24,6 +24,7 @@ from .message_entity import MessageEntity from .passport_data import PassportData from .photo_size import PhotoSize from .poll import Poll +from .proximity_alert_triggered import ProximityAlertTriggered from .reply_keyboard import ReplyKeyboardMarkup, ReplyKeyboardRemove from .sticker import Sticker from .successful_payment import SuccessfulPayment @@ -43,6 +44,7 @@ class Message(base.TelegramObject): message_id: base.Integer = fields.Field() from_user: User = fields.Field(alias="from", base=User) + sender_chat: Chat = fields.Field(base=Chat) date: datetime.datetime = fields.DateTimeField() chat: Chat = fields.Field(base=Chat) forward_from: User = fields.Field(base=User) @@ -89,6 +91,7 @@ class Message(base.TelegramObject): successful_payment: SuccessfulPayment = fields.Field(base=SuccessfulPayment) connected_website: base.String = fields.Field() passport_data: PassportData = fields.Field(base=PassportData) + proximity_alert_triggered: typing.Optional[ProximityAlertTriggered] = fields.Field(base=ProximityAlertTriggered) reply_markup: InlineKeyboardMarkup = fields.Field(base=InlineKeyboardMarkup) @property @@ -150,6 +153,8 @@ class Message(base.TelegramObject): return ContentType.GROUP_CHAT_CREATED if self.passport_data: return ContentType.PASSPORT_DATA + if self.proximity_alert_triggered: + return ContentType.PROXIMITY_ALERT_TRIGGERED return ContentType.UNKNOWN @@ -513,6 +518,7 @@ class Message(base.TelegramObject): thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_markup: typing.Union[ InlineKeyboardMarkup, @@ -524,30 +530,45 @@ class Message(base.TelegramObject): reply: base.Boolean = False, ) -> Message: """ - Use this method to send general files. - - Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. + Use this method to send general files. On success, the sent Message is + returned. Bots can currently send files of any type of up to 50 MB in size, + this limit may be changed in the future. Source: https://core.telegram.org/bots/api#senddocument - :param document: File to send. + :param document: File to send :type document: :obj:`typing.Union[base.InputFile, base.String]` - :param thumb: Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 kB in size. - A thumbnail‘s width and height should not exceed 320. - :type thumb: :obj:`typing.Union[typing.Union[base.InputFile, base.String], None]` - :param caption: Document caption (may also be used when resending documents by file_id), 0-200 characters - :type caption: :obj:`typing.Union[base.String, None]` - :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, - fixed-width text or inline URLs in the media caption - :type parse_mode: :obj:`typing.Union[base.String, None]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound. - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user + + :param thumb: Thumbnail of the file sent + :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` + + :param caption: Document caption (may also be used when resending documents + by file_id), 0-1024 characters + :type caption: :obj:`typing.Optional[base.String]` + + :param disable_content_type_detection: Disables automatic server-side content + type detection for files uploaded using multipart/form-data + :type disable_content_type_detection: :obj:`typing.Optional[base.Boolean]` + + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in your bot's message. + :type parse_mode: :obj:`typing.Optional[base.String]` + + :param disable_notification: Sends the message silently. Users will receive a + notification with no sound + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply: True if the message is a reply + :type reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, - types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], None]` - :param reply: fill 'reply_to_message_id' - :return: On success, the sent Message is returned. + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], + None]` + + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ return await self.bot.send_document( @@ -556,6 +577,7 @@ class Message(base.TelegramObject): document=document, caption=caption, parse_mode=parse_mode, + disable_content_type_detection=disable_content_type_detection, disable_notification=disable_notification, reply_to_message_id=self.message_id if reply else None, reply_markup=reply_markup, @@ -1299,6 +1321,7 @@ class Message(base.TelegramObject): thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None, caption: typing.Union[base.String, None] = None, parse_mode: typing.Union[base.String, None] = None, + disable_content_type_detection: typing.Optional[base.Boolean] = None, disable_notification: typing.Union[base.Boolean, None] = None, reply_markup: typing.Union[ InlineKeyboardMarkup, @@ -1310,30 +1333,45 @@ class Message(base.TelegramObject): reply: base.Boolean = True, ) -> Message: """ - Use this method to send general files. - - Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. + Use this method to send general files. On success, the sent Message is + returned. Bots can currently send files of any type of up to 50 MB in size, + this limit may be changed in the future. Source: https://core.telegram.org/bots/api#senddocument - :param document: File to send. + :param document: File to send :type document: :obj:`typing.Union[base.InputFile, base.String]` - :param thumb: Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 kB in size. - A thumbnail‘s width and height should not exceed 320. - :type thumb: :obj:`typing.Union[typing.Union[base.InputFile, base.String], None]` - :param caption: Document caption (may also be used when resending documents by file_id), 0-200 characters - :type caption: :obj:`typing.Union[base.String, None]` - :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, - fixed-width text or inline URLs in the media caption - :type parse_mode: :obj:`typing.Union[base.String, None]` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound. - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` - :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, - custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user + + :param thumb: Thumbnail of the file sent + :type thumb: :obj:`typing.Union[base.InputFile, base.String, None]` + + :param caption: Document caption (may also be used when resending documents + by file_id), 0-1024 characters + :type caption: :obj:`typing.Optional[base.String]` + + :param disable_content_type_detection: Disables automatic server-side content + type detection for files uploaded using multipart/form-data + :type disable_content_type_detection: :obj:`typing.Optional[base.Boolean]` + + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in your bot's message. + :type parse_mode: :obj:`typing.Optional[base.String]` + + :param disable_notification: Sends the message silently. Users will receive a + notification with no sound + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + + :param reply: True if the message is a reply + :type reply: :obj:`typing.Optional[base.Boolean]` + + :param reply_markup: Additional interface options. A JSON-serialized object + for an inline keyboard, custom reply keyboard, instructions to remove + reply keyboard or to force a reply from the user :type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, - types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], None]` - :param reply: fill 'reply_to_message_id' - :return: On success, the sent Message is returned. + types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], + None]` + + :return: On success, the sent Message is returned :rtype: :obj:`types.Message` """ return await self.bot.send_document( @@ -1342,6 +1380,7 @@ class Message(base.TelegramObject): thumb=thumb, caption=caption, parse_mode=parse_mode, + disable_content_type_detection=disable_content_type_detection, disable_notification=disable_notification, reply_to_message_id=self.message_id if reply else None, reply_markup=reply_markup, @@ -2064,22 +2103,43 @@ class Message(base.TelegramObject): return await self.bot.delete_message(self.chat.id, self.message_id) async def pin( - self, disable_notification: typing.Union[base.Boolean, None] = None + self, disable_notification: typing.Optional[base.Boolean] = None, ) -> base.Boolean: """ - Use this method to pin a message in a supergroup. - The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Use this method to add a message to the list of pinned messages in a chat. + If the chat is not a private chat, the bot must be an administrator in the + chat for this to work and must have the 'can_pin_messages' admin right in a + supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. Source: https://core.telegram.org/bots/api#pinchatmessage - :param disable_notification: Pass True, if it is not necessary to send a notification to - all group members about the new pinned message - :type disable_notification: :obj:`typing.Union[base.Boolean, None]` + :param disable_notification: Pass True, if it is not necessary to send a + notification to all group members about the new pinned message + :type disable_notification: :obj:`typing.Optional[base.Boolean]` + :return: Returns True on success :rtype: :obj:`base.Boolean` """ return await self.chat.pin_message(self.message_id, disable_notification) + async def unpin(self) -> base.Boolean: + """ + Use this method to remove a message from the list of pinned messages in a + chat. If the chat is not a private chat, the bot must be an administrator in + the chat for this to work and must have the 'can_pin_messages' admin right in + a supergroup or 'can_edit_messages' admin right in a channel. Returns True on + success. + + Source: https://core.telegram.org/bots/api#unpinchatmessage + + :return: Returns True on success + :rtype: :obj:`base.Boolean` + """ + return await self.chat.unpin_message( + message_id=self.message_id, + ) + async def send_copy( self: Message, chat_id: typing.Union[str, int], @@ -2247,6 +2307,7 @@ class ContentType(helper.Helper): DELETE_CHAT_PHOTO = helper.Item() # delete_chat_photo GROUP_CHAT_CREATED = helper.Item() # group_chat_created PASSPORT_DATA = helper.Item() # passport_data + PROXIMITY_ALERT_TRIGGERED = helper.Item() # proximity_alert_triggered UNKNOWN = helper.Item() # unknown ANY = helper.Item() # any diff --git a/aiogram/types/proximity_alert_triggered.py b/aiogram/types/proximity_alert_triggered.py new file mode 100644 index 00000000..240854d8 --- /dev/null +++ b/aiogram/types/proximity_alert_triggered.py @@ -0,0 +1,15 @@ +from . import base +from . import fields +from .user import User + + +class ProximityAlertTriggered(base.TelegramObject): + """ + This object represents the content of a service message, sent whenever a user in + the chat triggers a proximity alert set by another user. + + https://core.telegram.org/bots/api#proximityalerttriggered + """ + traveler: User = fields.Field() + watcher: User = fields.Field() + distance: base.Integer = fields.Field() diff --git a/aiogram/types/venue.py b/aiogram/types/venue.py index f7b2a277..b851650b 100644 --- a/aiogram/types/venue.py +++ b/aiogram/types/venue.py @@ -14,3 +14,5 @@ class Venue(base.TelegramObject): address: base.String = fields.Field() foursquare_id: base.String = fields.Field() foursquare_type: base.String = fields.Field() + google_place_id: base.String = fields.Field() + google_place_type: base.String = fields.Field() diff --git a/aiogram/types/video.py b/aiogram/types/video.py index 97dbb90f..d4958761 100644 --- a/aiogram/types/video.py +++ b/aiogram/types/video.py @@ -16,5 +16,6 @@ class Video(base.TelegramObject, mixins.Downloadable): height: base.Integer = fields.Field() duration: base.Integer = fields.Field() thumb: PhotoSize = fields.Field(base=PhotoSize) + file_name: base.String = fields.Field() mime_type: base.String = fields.Field() file_size: base.Integer = fields.Field() diff --git a/aiogram/types/webhook_info.py b/aiogram/types/webhook_info.py index 995d3aaa..dc1a7cd9 100644 --- a/aiogram/types/webhook_info.py +++ b/aiogram/types/webhook_info.py @@ -13,6 +13,7 @@ class WebhookInfo(base.TelegramObject): url: base.String = fields.Field() has_custom_certificate: base.Boolean = fields.Field() pending_update_count: base.Integer = fields.Field() + ip_address: base.String = fields.Field() last_error_date: base.Integer = fields.Field() last_error_message: base.String = fields.Field() max_connections: base.Integer = fields.Field() diff --git a/tests/test_bot.py b/tests/test_bot.py index cf1c3c3b..45d3a3fa 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -24,6 +24,22 @@ async def test_get_me(bot: Bot, event_loop): assert result == user +async def test_log_out(bot: Bot, event_loop): + """ logOut method test """ + + async with FakeTelegram(message_data=True, loop=event_loop): + result = await bot.log_out() + assert result is True + + +async def test_close_bot(bot: Bot, event_loop): + """ close method test """ + + async with FakeTelegram(message_data=True, loop=event_loop): + result = await bot.close_bot() + assert result is True + + async def test_send_message(bot: Bot, event_loop): """ sendMessage method test """ from .types.dataset import MESSAGE