From aec6d3badacdb919ac3a5305eff5db3926e94594 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Wed, 30 Dec 2020 13:41:07 +0100 Subject: [PATCH] Explicit Signatures for Shortcuts (#2240) * First POC * Actually get it to work * locals-less POC * pre-commit * Work on Message shortcuts, update some annotations in Bot methods * Tippity Tappity, coding stuff * CallbackQuery * InlineQuery & Some other stuff * Media Classes and PassportFile * Fix tests * PreCheckout- & ShippingQuery * User * Fix tests * Chat * Update rawapibot * Update annotations for answer_inline_query --- examples/rawapibot.py | 5 +- telegram/bot.py | 137 ++-- telegram/callbackquery.py | 340 ++++++++- telegram/chat.py | 892 ++++++++++++++++++++-- telegram/files/animation.py | 11 +- telegram/files/audio.py | 11 +- telegram/files/chatphoto.py | 25 +- telegram/files/document.py | 11 +- telegram/files/photosize.py | 11 +- telegram/files/sticker.py | 11 +- telegram/files/video.py | 11 +- telegram/files/videonote.py | 11 +- telegram/files/voice.py | 11 +- telegram/inline/inlinequery.py | 61 +- telegram/message.py | 1055 ++++++++++++++++++++++---- telegram/passport/passportfile.py | 11 +- telegram/payment/precheckoutquery.py | 28 +- telegram/payment/shippingquery.py | 34 +- telegram/user.py | 842 ++++++++++++++++++-- telegram/utils/helpers.py | 13 +- tests/conftest.py | 95 +++ tests/test_animation.py | 13 +- tests/test_audio.py | 13 +- tests/test_callbackquery.py | 280 ++++--- tests/test_chat.py | 520 +++++++++---- tests/test_chatphoto.py | 28 +- tests/test_document.py | 13 +- tests/test_inlinequery.py | 29 +- tests/test_message.py | 589 ++++++++++---- tests/test_passport.py | 4 +- tests/test_passportfile.py | 21 +- tests/test_photo.py | 14 +- tests/test_precheckoutquery.py | 19 +- tests/test_shippingquery.py | 19 +- tests/test_sticker.py | 13 +- tests/test_user.py | 379 ++++++--- tests/test_video.py | 13 +- tests/test_videonote.py | 15 +- tests/test_voice.py | 13 +- 39 files changed, 4544 insertions(+), 1077 deletions(-) diff --git a/examples/rawapibot.py b/examples/rawapibot.py index 60129fe6e..b25d72766 100644 --- a/examples/rawapibot.py +++ b/examples/rawapibot.py @@ -51,8 +51,9 @@ def echo(bot: telegram.Bot) -> None: UPDATE_ID = update.update_id + 1 if update.message: # your bot can receive updates without messages - # Reply to the message - update.message.reply_text(update.message.text) + if update.message.text: # not all messages contain text + # Reply to the message + update.message.reply_text(update.message.text) if __name__ == '__main__': diff --git a/telegram/bot.py b/telegram/bot.py index c74e40121..cc49c4d66 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -60,13 +60,9 @@ from telegram import ( Document, File, GameHighScore, - InlineQueryResult, - InputMedia, - LabeledPrice, Location, MaskPosition, Message, - MessageEntity, MessageId, PassportElementError, PhotoSize, @@ -84,10 +80,6 @@ from telegram import ( VideoNote, Voice, WebhookInfo, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, InlineKeyboardMarkup, ) from telegram.constants import MAX_INLINE_QUERY_RESULTS @@ -104,6 +96,16 @@ from telegram.utils.types import FileInput, JSONDict if TYPE_CHECKING: from telegram.ext import Defaults + from telegram import ( + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + InputMedia, + InlineQueryResult, + LabeledPrice, + MessageEntity, + ) RT = TypeVar('RT') @@ -253,7 +255,7 @@ class Bot(TelegramObject): allow_sending_without_reply: bool = None, timeout: float = None, api_kwargs: JSONDict = None, - ) -> Union[bool, Message, None]: + ) -> Union[bool, Message]: if reply_to_message_id is not None: data['reply_to_message_id'] = reply_to_message_id @@ -282,7 +284,7 @@ class Bot(TelegramObject): if result is True: return result - return Message.de_json(result, self) # type: ignore[arg-type] + return Message.de_json(result, self) # type: ignore[arg-type,return-value] @property def request(self) -> Request: @@ -370,7 +372,7 @@ class Bot(TelegramObject): return f'@{self.username}' @log - def get_me(self, timeout: int = None, api_kwargs: JSONDict = None) -> Optional[User]: + def get_me(self, timeout: int = None, api_kwargs: JSONDict = None) -> User: """A simple method for testing your bot's auth token. Requires no parameters. Args: @@ -392,7 +394,7 @@ class Bot(TelegramObject): self.bot = User.de_json(result, self) # type: ignore - return self.bot + return self.bot # type: ignore[return-value] @log def send_message( @@ -407,8 +409,8 @@ class Bot(TelegramObject): timeout: float = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - ) -> Optional[Message]: + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Message: """Use this method to send text messages. Args: @@ -519,7 +521,7 @@ class Bot(TelegramObject): disable_notification: bool = False, timeout: float = None, api_kwargs: JSONDict = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to forward messages of any kind. Args: @@ -564,7 +566,7 @@ class Bot(TelegramObject): def send_photo( self, chat_id: int, - photo: Union[FileInput, PhotoSize], + photo: Union[FileInput, 'PhotoSize'], caption: str = None, disable_notification: bool = False, reply_to_message_id: Union[int, str] = None, @@ -573,9 +575,9 @@ class Bot(TelegramObject): parse_mode: str = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to send photos. Note: @@ -654,7 +656,7 @@ class Bot(TelegramObject): def send_audio( self, chat_id: Union[int, str], - audio: Union[FileInput, Audio], + audio: Union[FileInput, 'Audio'], duration: int = None, performer: str = None, title: str = None, @@ -667,9 +669,9 @@ class Bot(TelegramObject): thumb: FileInput = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, - ) -> Optional[Message]: + ) -> 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 or .m4a format. @@ -775,7 +777,7 @@ class Bot(TelegramObject): def send_document( self, chat_id: Union[int, str], - document: Union[FileInput, Document], + document: Union[FileInput, 'Document'], filename: str = None, caption: str = None, disable_notification: bool = False, @@ -787,8 +789,8 @@ class Bot(TelegramObject): api_kwargs: JSONDict = None, disable_content_type_detection: bool = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - ) -> Optional[Message]: + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Message: """ Use this method to send general files. @@ -884,14 +886,14 @@ class Bot(TelegramObject): def send_sticker( self, chat_id: Union[int, str], - sticker: Union[FileInput, Sticker], + sticker: Union[FileInput, 'Sticker'], disable_notification: bool = False, reply_to_message_id: Union[int, str] = None, reply_markup: ReplyMarkup = None, timeout: float = 20, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - ) -> Optional[Message]: + ) -> Message: """ Use this method to send static .WEBP or animated .TGS stickers. @@ -948,7 +950,7 @@ class Bot(TelegramObject): def send_video( self, chat_id: Union[int, str], - video: Union[FileInput, Video], + video: Union[FileInput, 'Video'], duration: int = None, caption: str = None, disable_notification: bool = False, @@ -962,9 +964,9 @@ class Bot(TelegramObject): thumb: FileInput = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, - ) -> Optional[Message]: + ) -> Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -1075,7 +1077,7 @@ class Bot(TelegramObject): def send_video_note( self, chat_id: Union[int, str], - video_note: Union[FileInput, VideoNote], + video_note: Union[FileInput, 'VideoNote'], duration: int = None, length: int = None, disable_notification: bool = False, @@ -1086,7 +1088,7 @@ class Bot(TelegramObject): api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, filename: str = None, - ) -> Optional[Message]: + ) -> Message: """ As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send video messages. @@ -1174,7 +1176,7 @@ class Bot(TelegramObject): def send_animation( self, chat_id: Union[int, str], - animation: Union[FileInput, Animation], + animation: Union[FileInput, 'Animation'], duration: int = None, width: int = None, height: int = None, @@ -1187,9 +1189,9 @@ class Bot(TelegramObject): timeout: float = 20, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, - ) -> Optional[Message]: + ) -> Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). Bots can currently send animation files of up to 50 MB in size, this limit may be changed @@ -1292,7 +1294,7 @@ class Bot(TelegramObject): def send_voice( self, chat_id: Union[int, str], - voice: Union[FileInput, Voice], + voice: Union[FileInput, 'Voice'], duration: int = None, caption: str = None, disable_notification: bool = False, @@ -1302,9 +1304,9 @@ class Bot(TelegramObject): parse_mode: str = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, filename: str = None, - ) -> Optional[Message]: + ) -> Message: """ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .ogg file @@ -1390,13 +1392,15 @@ class Bot(TelegramObject): def send_media_group( self, chat_id: Union[int, str], - media: List[Union[InputMediaAudio, InputMediaDocument, InputMediaPhoto, InputMediaVideo]], + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], disable_notification: bool = None, reply_to_message_id: Union[int, str] = None, timeout: float = 20, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - ) -> List[Optional[Message]]: + ) -> List[Message]: """Use this method to send a group of photos or videos as an album. Args: @@ -1462,7 +1466,7 @@ class Bot(TelegramObject): heading: int = None, proximity_alert_radius: int = None, allow_sending_without_reply: bool = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to send point on the map. Note: @@ -1556,7 +1560,7 @@ class Bot(TelegramObject): horizontal_accuracy: float = None, heading: int = None, proximity_alert_radius: int = None, - ) -> Union[Optional[Message], bool]: + ) -> Union[Message, bool]: """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 :attr:`live_period` expires or editing is explicitly disabled by a call to :attr:`stop_message_live_location`. @@ -1639,7 +1643,7 @@ class Bot(TelegramObject): reply_markup: InlineKeyboardMarkup = None, timeout: float = None, api_kwargs: JSONDict = None, - ) -> Union[Optional[Message], bool]: + ) -> Union[Message, bool]: """Use this method to stop updating a live location message sent by the bot or via the bot (for inline bots) before live_period expires. @@ -1699,7 +1703,7 @@ class Bot(TelegramObject): google_place_id: str = None, google_place_type: str = None, allow_sending_without_reply: bool = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to send information about a venue. Note: @@ -1807,7 +1811,7 @@ class Bot(TelegramObject): vcard: str = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to send phone contacts. Note: @@ -1889,7 +1893,7 @@ class Bot(TelegramObject): timeout: float = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - ) -> Optional[Message]: + ) -> Message: """Use this method to send a game. Args: @@ -1975,7 +1979,9 @@ class Bot(TelegramObject): def answer_inline_query( self, inline_query_id: str, - results: List[InlineQueryResult], + results: Union[ + List['InlineQueryResult'], Callable[[int], Optional[List['InlineQueryResult']]] + ], cache_time: int = 300, is_personal: bool = None, next_offset: str = None, @@ -1998,9 +2004,9 @@ class Bot(TelegramObject): inline_query_id (:obj:`str`): Unique identifier for the answered query. results (List[:class:`telegram.InlineQueryResult`] | Callable): A list of results for the inline query. In case :attr:`current_offset` is passed, ``results`` may also be - a callable accepts the current page index starting from 0. It must return either a - list of :class:`telegram.InlineResult` instances or :obj:`None` if there are no - more results. + a callable that accepts the current page index starting from 0. It must return + either a list of :class:`telegram.InlineResult` instances or :obj:`None` if there + are no more results. cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300. is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on @@ -2083,10 +2089,11 @@ class Bot(TelegramObject): next_offset = '' if callable(results): - effective_results = results(current_offset_int) - if not effective_results: + callable_output = results(current_offset_int) + if not callable_output: effective_results = [] else: + effective_results = callable_output next_offset = str(current_offset_int + 1) else: if len(results) > (current_offset_int + 1) * MAX_INLINE_QUERY_RESULTS: @@ -2100,7 +2107,7 @@ class Bot(TelegramObject): else: effective_results = results[current_offset_int * MAX_INLINE_QUERY_RESULTS :] else: - effective_results = results + effective_results = results # type: ignore[assignment] for result in effective_results: _set_defaults(result) @@ -2397,8 +2404,8 @@ class Bot(TelegramObject): reply_markup: InlineKeyboardMarkup = None, timeout: float = None, api_kwargs: JSONDict = None, - entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - ) -> Union[Optional[Message], bool]: + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: """ Use this method to edit text and game messages. @@ -2468,7 +2475,7 @@ class Bot(TelegramObject): timeout: float = None, parse_mode: str = None, api_kwargs: JSONDict = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: """ Use this method to edit captions of messages. @@ -2526,7 +2533,7 @@ class Bot(TelegramObject): if inline_message_id: data['inline_message_id'] = inline_message_id - return self._message( # type: ignore[return-value] + return self._message( 'editMessageCaption', data, timeout=timeout, @@ -2540,7 +2547,7 @@ class Bot(TelegramObject): chat_id: Union[str, int] = None, message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, - media: InputMedia = None, + media: 'InputMedia' = None, reply_markup: InlineKeyboardMarkup = None, timeout: float = None, api_kwargs: JSONDict = None, @@ -2593,7 +2600,7 @@ class Bot(TelegramObject): if inline_message_id: data['inline_message_id'] = inline_message_id - return self._message( # type: ignore[return-value] + return self._message( 'editMessageMedia', data, timeout=timeout, @@ -2607,7 +2614,7 @@ class Bot(TelegramObject): chat_id: Union[str, int] = None, message_id: Union[str, int] = None, inline_message_id: Union[str, int] = None, - reply_markup: Optional[InlineKeyboardMarkup] = None, + reply_markup: Optional['InlineKeyboardMarkup'] = None, timeout: float = None, api_kwargs: JSONDict = None, ) -> Union[Message, bool]: @@ -2654,7 +2661,7 @@ class Bot(TelegramObject): if inline_message_id: data['inline_message_id'] = inline_message_id - return self._message( # type: ignore[return-value] + return self._message( 'editMessageReplyMarkup', data, timeout=timeout, @@ -3158,7 +3165,7 @@ class Bot(TelegramObject): if disable_edit_message is not None: data['disable_edit_message'] = disable_edit_message - return self._message( # type: ignore[return-value] + return self._message( 'setGameScore', data, timeout=timeout, @@ -3223,7 +3230,7 @@ class Bot(TelegramObject): provider_token: str, start_parameter: str, currency: str, - prices: List[LabeledPrice], + prices: List['LabeledPrice'], photo_url: str = None, photo_size: int = None, photo_width: int = None, @@ -4404,7 +4411,7 @@ class Bot(TelegramObject): close_date: Union[int, datetime] = None, api_kwargs: JSONDict = None, allow_sending_without_reply: bool = None, - explanation_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Message: """ Use this method to send a native poll. @@ -4724,14 +4731,14 @@ class Bot(TelegramObject): message_id: Union[str, int], caption: str = None, parse_mode: str = None, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, disable_notification: bool = False, reply_to_message_id: Union[int, str] = None, allow_sending_without_reply: bool = False, reply_markup: ReplyMarkup = None, timeout: float = None, api_kwargs: JSONDict = None, - ) -> Optional[MessageId]: + ) -> MessageId: """ 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. diff --git a/telegram/callbackquery.py b/telegram/callbackquery.py index f9e02a105..1ade06e89 100644 --- a/telegram/callbackquery.py +++ b/telegram/callbackquery.py @@ -18,13 +18,20 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. # pylint: disable=W0622 """This module contains an object that represents a Telegram CallbackQuery""" -from typing import TYPE_CHECKING, Any, List, Optional, Union +from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple -from telegram import Message, TelegramObject, User +from telegram import Message, TelegramObject, User, Location, ReplyMarkup from telegram.utils.types import JSONDict if TYPE_CHECKING: - from telegram import Bot, GameHighScore, InlineKeyboardMarkup, MessageId + from telegram import ( + Bot, + GameHighScore, + InlineKeyboardMarkup, + MessageId, + InputMedia, + MessageEntity, + ) class CallbackQuery(TelegramObject): @@ -117,18 +124,46 @@ class CallbackQuery(TelegramObject): return cls(bot=bot, **data) - def answer(self, *args: Any, **kwargs: Any) -> bool: + def answer( + self, + text: str = None, + show_alert: bool = False, + url: str = None, + cache_time: int = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.answer_callback_query(update.callback_query.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_callback_query`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.answer_callback_query(self.id, *args, **kwargs) + return self.bot.answer_callback_query( + callback_query_id=self.id, + text=text, + show_alert=show_alert, + url=url, + cache_time=cache_time, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def edit_message_text(self, text: str, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def edit_message_text( + self, + text: str, + parse_mode: str = None, + disable_web_page_preview: bool = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: """Shortcut for either:: update.callback_query.message.edit_text(text, *args, **kwargs) @@ -138,6 +173,9 @@ class CallbackQuery(TelegramObject): bot.edit_message_text(text, inline_message_id=update.callback_query.inline_message_id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_text`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -145,12 +183,35 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.edit_message_text( - text, inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + chat_id=None, + message_id=None, ) - return self.message.edit_text(text, *args, **kwargs) + return self.message.edit_text( + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + ) def edit_message_caption( - self, caption: str, *args: Any, **kwargs: Any + self, + caption: str = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + parse_mode: str = None, + api_kwargs: JSONDict = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -162,6 +223,9 @@ class CallbackQuery(TelegramObject): inline_message_id=update.callback_query.inline_message_id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_caption`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -169,12 +233,30 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.edit_message_caption( - caption=caption, inline_message_id=self.inline_message_id, *args, **kwargs + caption=caption, + inline_message_id=self.inline_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + chat_id=None, + message_id=None, ) - return self.message.edit_caption(caption=caption, *args, **kwargs) + return self.message.edit_caption( + caption=caption, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + ) def edit_message_reply_markup( - self, reply_markup: 'InlineKeyboardMarkup', *args: Any, **kwargs: Any + self, + reply_markup: Optional['InlineKeyboardMarkup'] = None, + timeout: float = None, + api_kwargs: JSONDict = None, ) -> Union[Message, bool]: """Shortcut for either:: @@ -193,6 +275,9 @@ class CallbackQuery(TelegramObject): **kwargs ) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_reply_markup`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -202,12 +287,24 @@ class CallbackQuery(TelegramObject): return self.bot.edit_message_reply_markup( reply_markup=reply_markup, inline_message_id=self.inline_message_id, - *args, - **kwargs, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, ) - return self.message.edit_reply_markup(reply_markup=reply_markup, *args, **kwargs) + return self.message.edit_reply_markup( + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def edit_message_media( + self, + media: 'InputMedia' = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: """Shortcut for either:: update.callback_query.message.edit_media(*args, **kwargs) @@ -217,6 +314,9 @@ class CallbackQuery(TelegramObject): bot.edit_message_media(inline_message_id=update.callback_query.inline_message_id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_media`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -224,11 +324,33 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.edit_message_media( - inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, ) - return self.message.edit_media(*args, **kwargs) + return self.message.edit_media( + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def edit_message_live_location( + self, + latitude: float = None, + longitude: float = None, + location: Location = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + ) -> Union[Message, bool]: """Shortcut for either:: update.callback_query.message.edit_live_location(*args, **kwargs) @@ -240,6 +362,9 @@ class CallbackQuery(TelegramObject): *args, **kwargs ) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_live_location`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -247,11 +372,37 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.edit_message_live_location( - inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + chat_id=None, + message_id=None, ) - return self.message.edit_live_location(*args, **kwargs) + return self.message.edit_live_location( + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + ) - def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def stop_message_live_location( + self, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: """Shortcut for either:: update.callback_query.message.stop_live_location(*args, **kwargs) @@ -263,6 +414,9 @@ class CallbackQuery(TelegramObject): *args, **kwargs ) + For the documentation of the arguments, please see + :meth:`telegram.Bot.stop_message_live_location`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -270,11 +424,28 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.stop_message_live_location( - inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, ) - return self.message.stop_live_location(*args, **kwargs) + return self.message.stop_live_location( + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def set_game_score( + self, + user_id: Union[int, str], + score: int, + force: bool = None, + disable_edit_message: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: """Shortcut for either:: update.callback_query.message.set_game_score(*args, **kwargs) @@ -284,6 +455,9 @@ class CallbackQuery(TelegramObject): bot.set_game_score(inline_message_id=update.callback_query.inline_message_id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_game_score`. + Returns: :class:`telegram.Message`: On success, if edited message is sent by the bot, the edited Message is returned, otherwise :obj:`True` is returned. @@ -291,11 +465,31 @@ class CallbackQuery(TelegramObject): """ if self.inline_message_id: return self.bot.set_game_score( - inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, ) - return self.message.set_game_score(*args, **kwargs) + return self.message.set_game_score( + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']: + def get_game_high_scores( + self, + user_id: Union[int, str], + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> List['GameHighScore']: """Shortcut for either:: update.callback_query.message.get_game_high_score(*args, **kwargs) @@ -305,28 +499,55 @@ class CallbackQuery(TelegramObject): bot.get_game_high_scores(inline_message_id=update.callback_query.inline_message_id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_game_high_scores`. + Returns: List[:class:`telegram.GameHighScore`] """ if self.inline_message_id: return self.bot.get_game_high_scores( - inline_message_id=self.inline_message_id, *args, **kwargs + inline_message_id=self.inline_message_id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, ) - return self.message.get_game_high_scores(*args, **kwargs) + return self.message.get_game_high_scores( + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def delete_message(self, *args: Any, **kwargs: Any) -> Union[Message, bool]: + def delete_message( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: update.callback_query.message.delete(*args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.delete_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.message.delete(*args, **kwargs) + return self.message.delete( + timeout=timeout, + api_kwargs=api_kwargs, + ) - def pin_message(self, *args: Any, **kwargs: Any) -> bool: + def pin_message( + self, + disable_notification: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.pin_chat_message(chat_id=message.chat_id, @@ -334,13 +555,24 @@ class CallbackQuery(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.pin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.message.pin(*args, **kwargs) + return self.message.pin( + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def unpin_message(self, *args: Any, **kwargs: Any) -> bool: + def unpin_message( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.unpin_chat_message(chat_id=message.chat_id, @@ -348,13 +580,31 @@ class CallbackQuery(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.message.unpin(*args, **kwargs) + return self.message.unpin( + timeout=timeout, + api_kwargs=api_kwargs, + ) - def copy_message(self, chat_id: int, *args: Any, **kwargs: Any) -> 'MessageId': + def copy_message( + self, + chat_id: Union[int, str], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: update.callback_query.message.copy( @@ -364,8 +614,22 @@ class CallbackQuery(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. """ - return self.message.copy(chat_id, *args, **kwargs) + return self.message.copy( + chat_id=chat_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/telegram/chat.py b/telegram/chat.py index 72686c14c..0a35d8f06 100644 --- a/telegram/chat.py +++ b/telegram/chat.py @@ -18,17 +18,42 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram Chat.""" - -from typing import TYPE_CHECKING, Any, List, Optional, ClassVar +from datetime import datetime +from typing import TYPE_CHECKING, Any, List, Optional, ClassVar, Union, Tuple from telegram import ChatPhoto, TelegramObject, constants -from telegram.utils.types import JSONDict +from telegram.utils.types import JSONDict, FileInput from .chatpermissions import ChatPermissions from .chatlocation import ChatLocation +from .utils.helpers import DefaultValue, DEFAULT_NONE if TYPE_CHECKING: - from telegram import Bot, ChatMember, Message, MessageId + from telegram import ( + Bot, + ChatMember, + Message, + MessageId, + ReplyMarkup, + Contact, + InlineKeyboardMarkup, + Location, + Venue, + MessageEntity, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + PhotoSize, + Audio, + Document, + Animation, + LabeledPrice, + Sticker, + Video, + VideoNote, + Voice, + ) class Chat(TelegramObject): @@ -188,22 +213,33 @@ class Chat(TelegramObject): return cls(bot=bot, **data) - def leave(self, *args: Any, **kwargs: Any) -> bool: + def leave(self, timeout: float = None, api_kwargs: JSONDict = None) -> bool: """Shortcut for:: bot.leave_chat(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.leave_chat`. + Returns: :obj:`bool` If the action was sent successfully. """ - return self.bot.leave_chat(self.id, *args, **kwargs) + return self.bot.leave_chat( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def get_administrators(self, *args: Any, **kwargs: Any) -> List['ChatMember']: + def get_administrators( + self, timeout: float = None, api_kwargs: JSONDict = None + ) -> List['ChatMember']: """Shortcut for:: bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_chat_administrators`. + Returns: List[:class:`telegram.ChatMember`]: A list of administrators in a chat. An Array of :class:`telegram.ChatMember` objects that contains information about all @@ -211,34 +247,66 @@ class Chat(TelegramObject): and no administrators were appointed, only the creator will be returned. """ - return self.bot.get_chat_administrators(self.id, *args, **kwargs) + return self.bot.get_chat_administrators( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def get_members_count(self, *args: Any, **kwargs: Any) -> int: + def get_members_count(self, timeout: float = None, api_kwargs: JSONDict = None) -> int: """Shortcut for:: bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_chat_members_count`. + Returns: :obj:`int` """ - return self.bot.get_chat_members_count(self.id, *args, **kwargs) + return self.bot.get_chat_members_count( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def get_member(self, *args: Any, **kwargs: Any) -> 'ChatMember': + def get_member( + self, + user_id: Union[str, int], + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'ChatMember': """Shortcut for:: bot.get_chat_member(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.get_chat_member`. + Returns: :class:`telegram.ChatMember` """ - return self.bot.get_chat_member(self.id, *args, **kwargs) + return self.bot.get_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def kick_member(self, *args: Any, **kwargs: Any) -> bool: + def kick_member( + self, + user_id: Union[str, int], + timeout: float = None, + until_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: - bot.kick_chat_member(update.effective_chat.id, *args, **kwargs) + bot.kick_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.kick_chat_member`. Returns: :obj:`bool`: If the action was sent successfully. @@ -249,299 +317,983 @@ class Chat(TelegramObject): member that added them. """ - return self.bot.kick_chat_member(self.id, *args, **kwargs) + return self.bot.kick_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + until_date=until_date, + api_kwargs=api_kwargs, + ) - def unban_member(self, *args: Any, **kwargs: Any) -> bool: + def unban_member( + self, + user_id: Union[str, int], + timeout: float = None, + api_kwargs: JSONDict = None, + only_if_banned: bool = None, + ) -> bool: """Shortcut for:: - bot.unban_chat_member(update.effective_chat.id, *args, **kwargs) + bot.unban_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.unban_chat_member`. Returns: :obj:`bool`: If the action was sent successfully. """ - return self.bot.unban_chat_member(self.id, *args, **kwargs) + return self.bot.unban_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + only_if_banned=only_if_banned, + ) - def set_permissions(self, *args: Any, **kwargs: Any) -> bool: + def set_permissions( + self, + permissions: ChatPermissions, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: - bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs) + bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_chat_permissions`. Returns: :obj:`bool`: If the action was sent successfully. """ - return self.bot.set_chat_permissions(self.id, *args, **kwargs) + return self.bot.set_chat_permissions( + chat_id=self.id, + permissions=permissions, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def set_administrator_custom_title(self, *args: Any, **kwargs: Any) -> bool: + def set_administrator_custom_title( + self, + user_id: Union[int, str], + custom_title: str, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: - bot.set_chat_administrator_custom_title(update.effective_chat.id, *args, **kwargs) + bot.set_chat_administrator_custom_title(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_chat_administrator_custom_title`. Returns: :obj:`bool`: If the action was sent successfully. """ - return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs) + return self.bot.set_chat_administrator_custom_title( + chat_id=self.id, + user_id=user_id, + custom_title=custom_title, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def pin_message(self, *args: Any, **kwargs: Any) -> bool: + def pin_message( + self, + message_id: Union[str, int], + disable_notification: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.pin_chat_message(chat_id=update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.pin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.pin_chat_message(self.id, *args, **kwargs) + return self.bot.pin_chat_message( + chat_id=self.id, + message_id=message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def unpin_message(self, *args: Any, **kwargs: Any) -> bool: + def unpin_message( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + message_id: Union[str, int] = None, + ) -> bool: """Shortcut for:: bot.unpin_chat_message(chat_id=update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.unpin_chat_message(self.id, *args, **kwargs) + return self.bot.unpin_chat_message( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + message_id=message_id, + ) - def unpin_all_messages(self, *args: Any, **kwargs: Any) -> bool: + def unpin_all_messages( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.unpin_all_chat_messages(chat_id=update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_all_chat_messages`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.unpin_all_chat_messages(chat_id=self.id, *args, **kwargs) + return self.bot.unpin_all_chat_messages( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def send_message(self, *args: Any, **kwargs: Any) -> 'Message': + def send_message( + self, + text: str, + parse_mode: str = None, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_message(self.id, *args, **kwargs) + return self.bot.send_message( + chat_id=self.id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - def send_media_group(self, *args: Any, **kwargs: Any) -> List['Message']: + def send_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> List['Message']: """Shortcut for:: bot.send_media_group(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. + Returns: List[:class:`telegram.Message`:] On success, instance representing the message posted. """ - return self.bot.send_media_group(self.id, *args, **kwargs) + return self.bot.send_media_group( + chat_id=self.id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_chat_action(self, *args: Any, **kwargs: Any) -> bool: + def send_chat_action( + self, + action: str, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.send_chat_action(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. + Returns: :obj:`True`: On success. """ - return self.bot.send_chat_action(self.id, *args, **kwargs) + return self.bot.send_chat_action( + chat_id=self.id, + action=action, + timeout=timeout, + api_kwargs=api_kwargs, + ) send_action = send_chat_action """Alias for :attr:`send_chat_action`""" - def send_photo(self, *args: Any, **kwargs: Any) -> 'Message': + def send_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_photo(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_photo(self.id, *args, **kwargs) + return self.bot.send_photo( + chat_id=self.id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_contact(self, *args: Any, **kwargs: Any) -> 'Message': + def send_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + contact: 'Contact' = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_contact(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_contact(self.id, *args, **kwargs) + return self.bot.send_contact( + chat_id=self.id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_audio(self, *args: Any, **kwargs: Any) -> 'Message': + def send_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_audio(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_audio(self.id, *args, **kwargs) + return self.bot.send_audio( + chat_id=self.id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_document(self, *args: Any, **kwargs: Any) -> 'Message': + def send_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: bot.send_document(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_document(self.id, *args, **kwargs) + return self.bot.send_document( + chat_id=self.id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) - def send_dice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_dice( + self, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_dice(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_dice(self.id, *args, **kwargs) + return self.bot.send_dice( + chat_id=self.id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_game(self, *args: Any, **kwargs: Any) -> 'Message': + def send_game( + self, + game_short_name: str, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_game(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_game(self.id, *args, **kwargs) + return self.bot.send_game( + chat_id=self.id, + game_short_name=game_short_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_invoice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_invoice( + self, + title: str, + description: str, + payload: str, + provider_token: str, + start_parameter: str, + currency: str, + prices: List['LabeledPrice'], + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'InlineKeyboardMarkup' = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_invoice(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_invoice(self.id, *args, **kwargs) + return self.bot.send_invoice( + chat_id=self.id, + title=title, + description=description, + payload=payload, + provider_token=provider_token, + start_parameter=start_parameter, + currency=currency, + prices=prices, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + is_flexible=is_flexible, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + provider_data=provider_data, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_location(self, *args: Any, **kwargs: Any) -> 'Message': + def send_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + location: 'Location' = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_location(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_location(self.id, *args, **kwargs) + return self.bot.send_location( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_animation(self, *args: Any, **kwargs: Any) -> 'Message': + def send_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_animation(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_animation(self.id, *args, **kwargs) + return self.bot.send_animation( + chat_id=self.id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_sticker(self, *args: Any, **kwargs: Any) -> 'Message': + def send_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_sticker(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_sticker(self.id, *args, **kwargs) + return self.bot.send_sticker( + chat_id=self.id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_venue(self, *args: Any, **kwargs: Any) -> 'Message': + def send_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + venue: 'Venue' = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_venue(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_venue(self.id, *args, **kwargs) + return self.bot.send_venue( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_video(self, *args: Any, **kwargs: Any) -> 'Message': + def send_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + width: int = None, + height: int = None, + parse_mode: str = None, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_video(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_video(self.id, *args, **kwargs) + return self.bot.send_video( + chat_id=self.id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_video_note(self, *args: Any, **kwargs: Any) -> 'Message': + def send_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_video_note(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_video_note(self.id, *args, **kwargs) + return self.bot.send_video_note( + chat_id=self.id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) - def send_voice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: bot.send_voice(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_voice(self.id, *args, **kwargs) + return self.bot.send_voice( + chat_id=self.id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_poll(self, *args: Any, **kwargs: Any) -> 'Message': + def send_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports + type: str = constants.POLL_REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + explanation: str = None, + explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: bot.send_poll(update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_poll(self.id, *args, **kwargs) + return self.bot.send_poll( + chat_id=self.id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, # pylint=pylint, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) - def send_copy(self, *args: Any, **kwargs: Any) -> 'MessageId': + def send_copy( + self, + from_chat_id: Union[str, int], + message_id: Union[str, int], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: bot.copy_message(chat_id=update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.copy_message(chat_id=self.id, *args, **kwargs) + return self.bot.copy_message( + chat_id=self.id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def copy_message(self, *args: Any, **kwargs: Any) -> 'MessageId': + def copy_message( + self, + chat_id: Union[int, str], + message_id: Union[str, int], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: bot.copy_message(from_chat_id=update.effective_chat.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.copy_message(from_chat_id=self.id, *args, **kwargs) + return self.bot.copy_message( + from_chat_id=self.id, + chat_id=chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/telegram/files/animation.py b/telegram/files/animation.py index 45019c019..830cfa3e2 100644 --- a/telegram/files/animation.py +++ b/telegram/files/animation.py @@ -104,15 +104,10 @@ class Animation(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -121,4 +116,4 @@ class Animation(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/audio.py b/telegram/files/audio.py index 7dbdf0a51..29f2aa9b9 100644 --- a/telegram/files/audio.py +++ b/telegram/files/audio.py @@ -108,15 +108,10 @@ class Audio(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -125,4 +120,4 @@ class Audio(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/chatphoto.py b/telegram/files/chatphoto.py index e49a139ae..a2a3dd823 100644 --- a/telegram/files/chatphoto.py +++ b/telegram/files/chatphoto.py @@ -20,6 +20,7 @@ from typing import TYPE_CHECKING, Any from telegram import TelegramObject +from telegram.utils.types import JSONDict if TYPE_CHECKING: from telegram import Bot, File @@ -83,16 +84,11 @@ class ChatPhoto(TelegramObject): self.big_file_unique_id, ) - def get_small_file(self, timeout: int = None, **kwargs: Any) -> 'File': + def get_small_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the small (160x160) chat photo - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -101,18 +97,15 @@ class ChatPhoto(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.small_file_id, timeout=timeout, **kwargs) + return self.bot.get_file( + file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs + ) - def get_big_file(self, timeout: int = None, **kwargs: Any) -> 'File': + def get_big_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the big (640x640) chat photo - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -121,4 +114,4 @@ class ChatPhoto(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.big_file_id, timeout=timeout, **kwargs) + return self.bot.get_file(file_id=self.big_file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/document.py b/telegram/files/document.py index 759fd7fcb..31f74b2b7 100644 --- a/telegram/files/document.py +++ b/telegram/files/document.py @@ -95,15 +95,10 @@ class Document(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -112,4 +107,4 @@ class Document(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/photosize.py b/telegram/files/photosize.py index c2aea363f..d7e681ae3 100644 --- a/telegram/files/photosize.py +++ b/telegram/files/photosize.py @@ -78,15 +78,10 @@ class PhotoSize(TelegramObject): self._id_attrs = (self.file_unique_id,) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -95,4 +90,4 @@ class PhotoSize(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/sticker.py b/telegram/files/sticker.py index 3ffceb14b..3d74ab6e2 100644 --- a/telegram/files/sticker.py +++ b/telegram/files/sticker.py @@ -116,15 +116,10 @@ class Sticker(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: str = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -133,7 +128,7 @@ class Sticker(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) class StickerSet(TelegramObject): diff --git a/telegram/files/video.py b/telegram/files/video.py index 0420bad05..da8bb39c5 100644 --- a/telegram/files/video.py +++ b/telegram/files/video.py @@ -105,15 +105,10 @@ class Video(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -122,4 +117,4 @@ class Video(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/videonote.py b/telegram/files/videonote.py index 983cd2f66..0293e2b7f 100644 --- a/telegram/files/videonote.py +++ b/telegram/files/videonote.py @@ -94,15 +94,10 @@ class VideoNote(TelegramObject): return cls(bot=bot, **data) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -111,4 +106,4 @@ class VideoNote(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/files/voice.py b/telegram/files/voice.py index 66e70144c..d85f51dff 100644 --- a/telegram/files/voice.py +++ b/telegram/files/voice.py @@ -78,15 +78,10 @@ class Voice(TelegramObject): self._id_attrs = (self.file_unique_id,) - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """Convenience wrapper over :attr:`telegram.Bot.get_file` - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -95,4 +90,4 @@ class Voice(TelegramObject): :class:`telegram.TelegramError` """ - return self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/telegram/inline/inlinequery.py b/telegram/inline/inlinequery.py index e591f7a40..e47ce0a05 100644 --- a/telegram/inline/inlinequery.py +++ b/telegram/inline/inlinequery.py @@ -19,13 +19,13 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram InlineQuery.""" -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any, Optional, List, Union, Callable from telegram import Location, TelegramObject, User from telegram.utils.types import JSONDict if TYPE_CHECKING: - from telegram import Bot + from telegram import Bot, InlineQueryResult class InlineQuery(TelegramObject): @@ -93,7 +93,21 @@ class InlineQuery(TelegramObject): return cls(bot=bot, **data) - def answer(self, *args: Any, auto_pagination: bool = False, **kwargs: Any) -> bool: + def answer( + self, + results: Union[ + List['InlineQueryResult'], Callable[[int], Optional[List['InlineQueryResult']]] + ], + cache_time: int = 300, + is_personal: bool = None, + next_offset: str = None, + switch_pm_text: str = None, + switch_pm_parameter: str = None, + timeout: float = None, + current_offset: str = None, + api_kwargs: JSONDict = None, + auto_pagination: bool = False, + ) -> bool: """Shortcut for:: bot.answer_inline_query(update.inline_query.id, @@ -101,33 +115,30 @@ class InlineQuery(TelegramObject): current_offset=self.offset if auto_pagination else None, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_inline_query`. + Args: - results (List[:class:`telegram.InlineQueryResult`] | Callable): A list of results for - the inline query. In case :attr:`auto_pagination` is set to :obj:`True`, - ``results`` may also be a callable may also be a callable accepts the current page - index starting from 0. It must return either a list of - :class:`telegram.InlineResult` instances or :obj:`None` if there are no more - results. - cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the - result of the inline query may be cached on the server. Defaults to 300. - is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on the - server side only for the user that sent the query. By default, results may be - returned to any user who sends the same query. - next_offset (:obj:`str`, optional): Pass the offset that a client should send in the - next query with the same text to receive more results. Pass an empty string if - there are no more results or if you don't support pagination. Offset length can't - exceed 64 bytes. - switch_pm_text (:obj:`str`, optional): If passed, clients will display a button with - specified text that switches the user to a private chat with the bot and sends the - bot a start message with the parameter switch_pm_parameter. - switch_pm_parameter (:obj:`str`, optional): Deep-linking parameter for the /start - message sent to the bot when user presses the switch button. 1-64 characters, - only A-Z, a-z, 0-9, _ and - are allowed. auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be passed as :attr:`current_offset` to :meth:telegram.Bot.answer_inline_query`. Defaults to :obj:`False`. + Raises: + TypeError: If both :attr:`current_offset` and `auto_pagination` are supplied. """ + if current_offset and auto_pagination: + # We raise TypeError instead of ValueError for backwards compatibility with versions + # which didn't check this here but let Python do the checking + raise TypeError('current_offset and auto_pagination are mutually exclusive!') return self.bot.answer_inline_query( - self.id, *args, current_offset=self.offset if auto_pagination else None, **kwargs + inline_query_id=self.id, + current_offset=self.offset if auto_pagination else current_offset, + results=results, + cache_time=cache_time, + is_personal=is_personal, + next_offset=next_offset, + switch_pm_text=switch_pm_text, + switch_pm_parameter=switch_pm_parameter, + timeout=timeout, + api_kwargs=api_kwargs, ) diff --git a/telegram/message.py b/telegram/message.py index 8e295d9d7..9195ecb34 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -21,7 +21,7 @@ import datetime import sys from html import escape -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, ClassVar +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, ClassVar, Tuple from telegram import ( Animation, @@ -48,12 +48,28 @@ from telegram import ( VideoNote, Voice, ProximityAlertTriggered, + ReplyMarkup, ) -from telegram.utils.helpers import escape_markdown, from_timestamp, to_timestamp -from telegram.utils.types import JSONDict +from telegram.utils.helpers import ( + escape_markdown, + from_timestamp, + to_timestamp, + DEFAULT_NONE, + DefaultValue, +) +from telegram.utils.types import JSONDict, FileInput if TYPE_CHECKING: - from telegram import Bot, GameHighScore, InputMedia, MessageId + from telegram import ( + Bot, + GameHighScore, + InputMedia, + MessageId, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + ) _UNDEFINED = object() @@ -321,8 +337,8 @@ class Message(TelegramObject): reply_to_message: 'Message' = None, edit_date: datetime.datetime = None, text: str = None, - entities: List[MessageEntity] = None, - caption_entities: List[MessageEntity] = None, + entities: List['MessageEntity'] = None, + caption_entities: List['MessageEntity'] = None, audio: Audio = None, document: Document = None, game: Game = None, @@ -440,7 +456,7 @@ class Message(TelegramObject): return None @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> 'Message': + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Message']: data = cls.parse_data(data) if not data: @@ -564,17 +580,16 @@ class Message(TelegramObject): return data - def _quote(self, kwargs: JSONDict) -> None: + def _quote( + self, quote: Optional[bool], reply_to_message_id: Optional[Union[int, str]] + ) -> Optional[Union[int, str]]: """Modify kwargs for replying with or without quoting.""" - if 'reply_to_message_id' in kwargs: - if 'quote' in kwargs: - del kwargs['quote'] + if reply_to_message_id is not None: + return reply_to_message_id - elif 'quote' in kwargs: - if kwargs['quote']: - kwargs['reply_to_message_id'] = self.message_id - - del kwargs['quote'] + if quote is not None: + if quote: + return self.message_id else: if self.bot.defaults: @@ -582,14 +597,31 @@ class Message(TelegramObject): else: default_quote = None if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote: - kwargs['reply_to_message_id'] = self.message_id + return self.message_id - def reply_text(self, *args: Any, **kwargs: Any) -> 'Message': + return None + + def reply_text( + self, + text: str, + parse_mode: str = None, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -599,10 +631,34 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_message(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - def reply_markdown(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_markdown( + self, + text: str, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN, *args, @@ -610,11 +666,13 @@ class Message(TelegramObject): Sends a message with Markdown version 1 formatting. + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + Note: :attr:`telegram.ParseMode.MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility. You should use :meth:`reply_markdown_v2` instead. - Keyword Args: + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -623,14 +681,34 @@ class Message(TelegramObject): Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.MARKDOWN, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - kwargs['parse_mode'] = ParseMode.MARKDOWN - - self._quote(kwargs) - - return self.bot.send_message(self.chat_id, *args, **kwargs) - - def reply_markdown_v2(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_markdown_v2( + self, + text: str, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.message.chat_id, parse_mode=ParseMode.MARKDOWN_V2, *args, @@ -638,7 +716,9 @@ class Message(TelegramObject): Sends a message with markdown version 2 formatting. - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -647,21 +727,43 @@ class Message(TelegramObject): Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.MARKDOWN_V2, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - kwargs['parse_mode'] = ParseMode.MARKDOWN_V2 - - self._quote(kwargs) - - return self.bot.send_message(self.chat_id, *args, **kwargs) - - def reply_html(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_html( + self, + text: str, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.message.chat_id, parse_mode=ParseMode.HTML, *args, **kwargs) Sends a message with HTML formatting. - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -670,19 +772,40 @@ class Message(TelegramObject): Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.HTML, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - kwargs['parse_mode'] = ParseMode.HTML - - self._quote(kwargs) - - return self.bot.send_message(self.chat_id, *args, **kwargs) - - def reply_media_group(self, *args: Any, **kwargs: Any) -> List[Optional['Message']]: + def reply_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> List['Message']: """Shortcut for:: bot.send_media_group(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the media group is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -694,15 +817,39 @@ class Message(TelegramObject): Raises: :class:`telegram.TelegramError` """ - self._quote(kwargs) - return self.bot.send_media_group(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_media_group( + chat_id=self.chat_id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def reply_photo(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_photo(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the photo is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -712,15 +859,48 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_photo(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_photo( + chat_id=self.chat_id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def reply_audio(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_audio(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the audio is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -730,15 +910,50 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_audio(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_audio( + chat_id=self.chat_id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def reply_document(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_document(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the document is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -748,15 +963,50 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_document(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_document( + chat_id=self.chat_id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) - def reply_animation(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_animation(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the animation is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -766,15 +1016,44 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_animation(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_animation( + chat_id=self.chat_id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def reply_sticker(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_sticker(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the sticker is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -784,15 +1063,45 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_sticker(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_sticker( + chat_id=self.chat_id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def reply_video(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + width: int = None, + height: int = None, + parse_mode: str = None, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_video(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the video is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -802,15 +1111,49 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_video(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_video( + chat_id=self.chat_id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def reply_video_note(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_video_note(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the video note is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -820,15 +1163,45 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_video_note(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_video_note( + chat_id=self.chat_id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) - def reply_voice(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_voice(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the voice note is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -838,15 +1211,47 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_voice(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_voice( + chat_id=self.chat_id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def reply_location(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + location: Location = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_location(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the location is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -856,15 +1261,50 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_location(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_location( + chat_id=self.chat_id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) - def reply_venue(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + venue: Venue = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_venue(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the venue is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -874,15 +1314,48 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_venue(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_venue( + chat_id=self.chat_id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) - def reply_contact(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + contact: Contact = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_contact(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the contact is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in @@ -892,15 +1365,51 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_contact(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_contact( + chat_id=self.chat_id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def reply_poll(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + type: str = Poll.REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + explanation: str = None, + explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime.datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_poll(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the poll is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -910,15 +1419,47 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_poll(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_poll( + chat_id=self.chat_id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) - def reply_dice(self, *args: Any, **kwargs: Any) -> 'Message': + def reply_dice( + self, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: ReplyMarkup = None, + timeout: float = None, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + quote: bool = None, + ) -> 'Message': """Shortcut for:: bot.send_dice(update.message.chat_id, *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the dice is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` @@ -928,10 +1469,25 @@ class Message(TelegramObject): :class:`telegram.Message`: On success, instance representing the message posted. """ - self._quote(kwargs) - return self.bot.send_dice(self.chat_id, *args, **kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_dice( + chat_id=self.chat_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def forward(self, chat_id: int, *args: Any, **kwargs: Any) -> 'Message': + def forward( + self, + chat_id: Union[int, str], + disable_notification: bool = False, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'Message': """Shortcut for:: bot.forward_message(chat_id=chat_id, @@ -940,15 +1496,34 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message forwarded. """ return self.bot.forward_message( - chat_id=chat_id, from_chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=chat_id, + from_chat_id=self.chat_id, + message_id=self.message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, ) - def copy(self, chat_id: int, *args: Any, **kwargs: Any) -> 'MessageId': + def copy( + self, + chat_id: Union[int, str], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: bot.copy_message(chat_id=chat_id, @@ -957,16 +1532,41 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. """ return self.bot.copy_message( - chat_id=chat_id, from_chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=chat_id, + from_chat_id=self.chat_id, + message_id=self.message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, ) def reply_copy( - self, from_chat_id: int, message_id: int, *args: Any, **kwargs: Any + self, + from_chat_id: Union[str, int], + message_id: Union[str, int], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: ReplyMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + quote: bool = None, ) -> 'MessageId': """Shortcut for:: @@ -976,7 +1576,9 @@ class Message(TelegramObject): *args, **kwargs) - Keyword Args: + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Args: quote (:obj:`bool`, optional): If set to :obj:`True`, the copy is sent as an actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will be ignored. Default: :obj:`True` in group chats and @@ -988,12 +1590,32 @@ class Message(TelegramObject): :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. """ - self._quote(kwargs) + reply_to_message_id = self._quote(quote, reply_to_message_id) return self.bot.copy_message( - chat_id=self.chat_id, from_chat_id=from_chat_id, message_id=message_id, *args, **kwargs + chat_id=self.chat_id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, ) - def edit_text(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def edit_text( + self, + text: str, + parse_mode: str = None, + disable_web_page_preview: bool = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.edit_message_text(chat_id=message.chat_id, @@ -1001,6 +1623,8 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.edit_message_text`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1012,10 +1636,27 @@ class Message(TelegramObject): """ return self.bot.edit_message_text( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + inline_message_id=None, ) - def edit_caption(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def edit_caption( + self, + caption: str = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + parse_mode: str = None, + api_kwargs: JSONDict = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.edit_message_caption(chat_id=message.chat_id, @@ -1023,6 +1664,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_caption`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1034,10 +1678,24 @@ class Message(TelegramObject): """ return self.bot.edit_message_caption( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + caption=caption, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + inline_message_id=None, ) - def edit_media(self, media: 'InputMedia', *args: Any, **kwargs: Any) -> Union['Message', bool]: + def edit_media( + self, + media: 'InputMedia' = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.edit_message_media(chat_id=message.chat_id, @@ -1045,6 +1703,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_media`. + Note: You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1056,10 +1717,21 @@ class Message(TelegramObject): """ return self.bot.edit_message_media( - chat_id=self.chat_id, message_id=self.message_id, media=media, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, ) - def edit_reply_markup(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def edit_reply_markup( + self, + reply_markup: Optional['InlineKeyboardMarkup'] = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.edit_message_reply_markup(chat_id=message.chat_id, @@ -1067,6 +1739,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_reply_markup`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1077,10 +1752,26 @@ class Message(TelegramObject): edited Message is returned, otherwise ``True`` is returned. """ return self.bot.edit_message_reply_markup( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, ) - def edit_live_location(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def edit_live_location( + self, + latitude: float = None, + longitude: float = None, + location: Location = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.edit_message_live_location(chat_id=message.chat_id, @@ -1088,6 +1779,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_live_location`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1098,10 +1792,26 @@ class Message(TelegramObject): edited Message is returned, otherwise :obj:`True` is returned. """ return self.bot.edit_message_live_location( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + inline_message_id=None, ) - def stop_live_location(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def stop_live_location( + self, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.stop_message_live_location(chat_id=message.chat_id, @@ -1109,6 +1819,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.stop_message_live_location`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1119,10 +1832,23 @@ class Message(TelegramObject): edited Message is returned, otherwise :obj:`True` is returned. """ return self.bot.stop_message_live_location( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, ) - def set_game_score(self, *args: Any, **kwargs: Any) -> Union['Message', bool]: + def set_game_score( + self, + user_id: Union[int, str], + score: int, + force: bool = None, + disable_edit_message: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: """Shortcut for:: bot.set_game_score(chat_id=message.chat_id, @@ -1130,6 +1856,8 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.set_game_score`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1140,10 +1868,23 @@ class Message(TelegramObject): edited Message is returned, otherwise :obj:`True` is returned. """ return self.bot.set_game_score( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, ) - def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']: + def get_game_high_scores( + self, + user_id: Union[int, str], + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> List['GameHighScore']: """Shortcut for:: bot.get_game_high_scores(chat_id=message.chat_id, @@ -1151,6 +1892,9 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_game_high_scores`. + Note: You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family of methods) or channel posts, if the bot is an admin in that channel. However, this @@ -1160,10 +1904,19 @@ class Message(TelegramObject): List[:class:`telegram.GameHighScore`] """ return self.bot.get_game_high_scores( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, ) - def delete(self, *args: Any, **kwargs: Any) -> bool: + def delete( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.delete_message(chat_id=message.chat_id, @@ -1171,15 +1924,25 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ return self.bot.delete_message( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + timeout=timeout, + api_kwargs=api_kwargs, ) - def stop_poll(self, *args: Any, **kwargs: Any) -> Poll: + def stop_poll( + self, + reply_markup: InlineKeyboardMarkup = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Poll: """Shortcut for:: bot.stop_poll(chat_id=message.chat_id, @@ -1187,16 +1950,27 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.stop_poll`. + Returns: :class:`telegram.Poll`: On success, the stopped Poll with the final results is returned. """ return self.bot.stop_poll( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, ) - def pin(self, *args: Any, **kwargs: Any) -> bool: + def pin( + self, + disable_notification: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.pin_chat_message(chat_id=message.chat_id, @@ -1204,15 +1978,25 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ return self.bot.pin_chat_message( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, ) - def unpin(self, *args: Any, **kwargs: Any) -> bool: + def unpin( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.unpin_chat_message(chat_id=message.chat_id, @@ -1220,12 +2004,17 @@ class Message(TelegramObject): *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ return self.bot.unpin_chat_message( - chat_id=self.chat_id, message_id=self.message_id, *args, **kwargs + chat_id=self.chat_id, + message_id=self.message_id, + timeout=timeout, + api_kwargs=api_kwargs, ) def parse_entity(self, entity: MessageEntity) -> str: diff --git a/telegram/passport/passportfile.py b/telegram/passport/passportfile.py index 3d39c3fdd..c60a325a6 100644 --- a/telegram/passport/passportfile.py +++ b/telegram/passport/passportfile.py @@ -103,18 +103,13 @@ class PassportFile(TelegramObject): for i, passport_file in enumerate(data) ] - def get_file(self, timeout: int = None, api_kwargs: JSONDict = None) -> 'File': + def get_file(self, timeout: float = None, api_kwargs: JSONDict = None) -> 'File': """ Wrapper over :attr:`telegram.Bot.get_file`. Will automatically assign the correct credentials to the returned :class:`telegram.File` if originating from :obj:`telegram.PassportData.decrypted_data`. - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. Returns: :class:`telegram.File` @@ -123,6 +118,6 @@ class PassportFile(TelegramObject): :class:`telegram.TelegramError` """ - file = self.bot.get_file(self.file_id, timeout=timeout, api_kwargs=api_kwargs) + file = self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) file.set_credentials(self._credentials) return file diff --git a/telegram/payment/precheckoutquery.py b/telegram/payment/precheckoutquery.py index 7b07e0e81..748c145b3 100644 --- a/telegram/payment/precheckoutquery.py +++ b/telegram/payment/precheckoutquery.py @@ -102,21 +102,25 @@ class PreCheckoutQuery(TelegramObject): return cls(bot=bot, **data) - def answer(self, *args: Any, **kwargs: Any) -> bool: + def answer( # pylint: disable=C0103 + self, + ok: bool, + error_message: str = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.answer_pre_checkout_query(update.pre_checkout_query.id, *args, **kwargs) - Args: - ok (:obj:`bool`): Specify :obj:`True` if everything is alright - (goods are available, etc.) and the bot is ready to proceed with the order. - Use :obj:`False` if there are any problems. - error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message in - human readable form that explains the reason for failure to proceed with the - checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts - while you were busy filling out your payment details. Please choose a different - color or garment!"). Telegram will display this message to the user. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_pre_checkout_query`. """ - return self.bot.answer_pre_checkout_query(self.id, *args, **kwargs) + return self.bot.answer_pre_checkout_query( + pre_checkout_query_id=self.id, + ok=ok, + error_message=error_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/telegram/payment/shippingquery.py b/telegram/payment/shippingquery.py index 98f45c551..041be2fdb 100644 --- a/telegram/payment/shippingquery.py +++ b/telegram/payment/shippingquery.py @@ -18,9 +18,9 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram ShippingQuery.""" -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any, Optional, List -from telegram import ShippingAddress, TelegramObject, User +from telegram import ShippingAddress, TelegramObject, User, ShippingOption from telegram.utils.types import JSONDict if TYPE_CHECKING: @@ -83,21 +83,27 @@ class ShippingQuery(TelegramObject): return cls(bot=bot, **data) - def answer(self, *args: Any, **kwargs: Any) -> bool: + def answer( # pylint: disable=C0103 + self, + ok: bool, + shipping_options: List[ShippingOption] = None, + error_message: str = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.answer_shipping_query(update.shipping_query.id, *args, **kwargs) - Args: - ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is - possible and :obj:`False` if there are any problems - (for example, if delivery to the specified address is not possible). - shipping_options (List[:class:`telegram.ShippingOption`], optional): Required if ok is - :obj:`True`. A JSON-serialized array of available shipping options. - error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message in - human readable form that explains why it is impossible to complete the order (e.g. - "Sorry, delivery to your desired address is unavailable'). Telegram will display - this message to the user. + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_shipping_query`. """ - return self.bot.answer_shipping_query(self.id, *args, **kwargs) + return self.bot.answer_shipping_query( + shipping_query_id=self.id, + ok=ok, + shipping_options=shipping_options, + error_message=error_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/telegram/user.py b/telegram/user.py index 3194058bc..4de1a7b7f 100644 --- a/telegram/user.py +++ b/telegram/user.py @@ -18,15 +18,40 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram User.""" +from datetime import datetime +from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import TelegramObject -from telegram.utils.helpers import mention_html as util_mention_html +from telegram import TelegramObject, constants +from telegram.utils.helpers import mention_html as util_mention_html, DefaultValue, DEFAULT_NONE from telegram.utils.helpers import mention_markdown as util_mention_markdown +from telegram.utils.types import JSONDict, FileInput if TYPE_CHECKING: - from telegram import Bot, Message, UserProfilePhotos, MessageId + from telegram import ( + Bot, + Message, + UserProfilePhotos, + MessageId, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + MessageEntity, + ReplyMarkup, + PhotoSize, + Audio, + Contact, + Document, + InlineKeyboardMarkup, + LabeledPrice, + Location, + Animation, + Sticker, + Video, + Venue, + VideoNote, + Voice, + ) class User(TelegramObject): @@ -38,9 +63,9 @@ class User(TelegramObject): Attributes: id (:obj:`int`): Unique identifier for this user or bot. is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`): Optional. User's or bot's last name. - username (:obj:`str`): Optional. User's or bot's username. + first_name (:obj:`str`): User's or bots first name. + last_name (:obj:`str`): Optional. User's or bots last name. + username (:obj:`str`): Optional. User's or bots username. language_code (:obj:`str`): Optional. IETF language tag of the user's language. can_join_groups (:obj:`str`): Optional. :obj:`True`, if the bot can be invited to groups. Returned only in :attr:`telegram.Bot.get_me` requests. @@ -53,9 +78,9 @@ class User(TelegramObject): Args: id (:obj:`int`): Unique identifier for this user or bot. is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`, optional): User's or bot's last name. - username (:obj:`str`, optional): User's or bot's username. + first_name (:obj:`str`): User's or bots first name. + last_name (:obj:`str`, optional): User's or bots last name. + username (:obj:`str`, optional): User's or bots username. language_code (:obj:`str`, optional): IETF language tag of the user's language. can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups. Returned only in :attr:`telegram.Bot.get_me` requests. @@ -122,15 +147,30 @@ class User(TelegramObject): return f"https://t.me/{self.username}" return None - def get_profile_photos(self, *args: Any, **kwargs: Any) -> 'UserProfilePhotos': + def get_profile_photos( + self, + offset: int = None, + limit: int = 100, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> Optional['UserProfilePhotos']: """ Shortcut for:: - bot.get_user_profile_photos(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_user_profile_photos`. """ - return self.bot.get_user_profile_photos(self.id, *args, **kwargs) + return self.bot.get_user_profile_photos( + user_id=self.id, + offset=offset, + limit=limit, + timeout=timeout, + api_kwargs=api_kwargs, + ) def mention_markdown(self, name: str = None) -> str: """ @@ -175,264 +215,898 @@ class User(TelegramObject): return util_mention_html(self.id, name) return util_mention_html(self.id, self.full_name) - def pin_message(self, *args: Any, **kwargs: Any) -> bool: + def pin_message( + self, + message_id: Union[str, int], + disable_notification: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.pin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.pin_chat_message(self.id, *args, **kwargs) + return self.bot.pin_chat_message( + chat_id=self.id, + message_id=message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def unpin_message(self, *args: Any, **kwargs: Any) -> bool: + def unpin_message( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + message_id: Union[str, int] = None, + ) -> bool: """Shortcut for:: bot.unpin_chat_message(chat_id=update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.unpin_chat_message(self.id, *args, **kwargs) + return self.bot.unpin_chat_message( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + message_id=message_id, + ) - def unpin_all_messages(self, *args: Any, **kwargs: Any) -> bool: + def unpin_all_messages( + self, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: bot.unpin_all_chat_messages(chat_id=update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_all_chat_messages`. + Returns: :obj:`bool`: On success, :obj:`True` is returned. """ - return self.bot.unpin_all_chat_messages(self.id, *args, **kwargs) + return self.bot.unpin_all_chat_messages( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def send_message(self, *args: Any, **kwargs: Any) -> 'Message': + def send_message( + self, + text: str, + parse_mode: str = None, + disable_web_page_preview: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: bot.send_message(update.effective_user.id, *args, **kwargs) - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_message(self.id, *args, **kwargs) - - def send_photo(self, *args: Any, **kwargs: Any) -> 'Message': - """Shortcut for:: - - bot.send_photo(update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_photo(self.id, *args, **kwargs) + return self.bot.send_message( + chat_id=self.id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) - def send_media_group(self, *args: Any, **kwargs: Any) -> List['Message']: + def send_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_media_group(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_photo( + chat_id=self.id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> List['Message']: + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. Returns: List[:class:`telegram.Message`:] On success, instance representing the message posted. """ - return self.bot.send_media_group(self.id, *args, **kwargs) + return self.bot.send_media_group( + chat_id=self.id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_audio(self, *args: Any, **kwargs: Any) -> 'Message': + def send_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_audio(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_audio(self.id, *args, **kwargs) + return self.bot.send_audio( + chat_id=self.id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_chat_action(self, *args: Any, **kwargs: Any) -> bool: + def send_chat_action( + self, + action: str, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: """Shortcut for:: - bot.send_chat_action(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. Returns: :obj:`True`: On success. """ - return self.bot.send_chat_action(self.id, *args, **kwargs) + return self.bot.send_chat_action( + chat_id=self.id, + action=action, + timeout=timeout, + api_kwargs=api_kwargs, + ) send_action = send_chat_action """Alias for :attr:`send_chat_action`""" - def send_contact(self, *args: Any, **kwargs: Any) -> 'Message': + def send_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + contact: 'Contact' = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_contact(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_contact(self.id, *args, **kwargs) + return self.bot.send_contact( + chat_id=self.id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_dice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_dice( + self, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_dice(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_dice(self.id, *args, **kwargs) + return self.bot.send_dice( + chat_id=self.id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_document(self, *args: Any, **kwargs: Any) -> 'Message': + def send_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: - bot.send_document(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_document(self.id, *args, **kwargs) + return self.bot.send_document( + chat_id=self.id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) - def send_game(self, *args: Any, **kwargs: Any) -> 'Message': + def send_game( + self, + game_short_name: str, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_game(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_game(self.id, *args, **kwargs) + return self.bot.send_game( + chat_id=self.id, + game_short_name=game_short_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_invoice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_invoice( + self, + title: str, + description: str, + payload: str, + provider_token: str, + start_parameter: str, + currency: str, + prices: List['LabeledPrice'], + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'InlineKeyboardMarkup' = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_invoice(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_invoice(self.id, *args, **kwargs) + return self.bot.send_invoice( + chat_id=self.id, + title=title, + description=description, + payload=payload, + provider_token=provider_token, + start_parameter=start_parameter, + currency=currency, + prices=prices, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + is_flexible=is_flexible, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + provider_data=provider_data, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_location(self, *args: Any, **kwargs: Any) -> 'Message': + def send_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + location: 'Location' = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_location(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_location(self.id, *args, **kwargs) + return self.bot.send_location( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_animation(self, *args: Any, **kwargs: Any) -> 'Message': + def send_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_animation(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_animation(self.id, *args, **kwargs) + return self.bot.send_animation( + chat_id=self.id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_sticker(self, *args: Any, **kwargs: Any) -> 'Message': + def send_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_sticker(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_sticker(self.id, *args, **kwargs) + return self.bot.send_sticker( + chat_id=self.id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_video(self, *args: Any, **kwargs: Any) -> 'Message': + def send_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + width: int = None, + height: int = None, + parse_mode: str = None, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_video(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_video(self.id, *args, **kwargs) + return self.bot.send_video( + chat_id=self.id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_venue(self, *args: Any, **kwargs: Any) -> 'Message': + def send_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + venue: 'Venue' = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: bool = None, + ) -> 'Message': """Shortcut for:: - bot.send_venue(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_venue(self.id, *args, **kwargs) + return self.bot.send_venue( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) - def send_video_note(self, *args: Any, **kwargs: Any) -> 'Message': + def send_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_video_note(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_video_note(self.id, *args, **kwargs) + return self.bot.send_video_note( + chat_id=self.id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) - def send_voice(self, *args: Any, **kwargs: Any) -> 'Message': + def send_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = 20, + parse_mode: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': """Shortcut for:: - bot.send_voice(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_voice(self.id, *args, **kwargs) + return self.bot.send_voice( + chat_id=self.id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) - def send_poll(self, *args: Any, **kwargs: Any) -> 'Message': + def send_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports + type: str = constants.POLL_REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: bool = None, + reply_to_message_id: Union[int, str] = None, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + explanation: str = None, + explanation_parse_mode: Union[str, DefaultValue, None] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: bool = None, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': """Shortcut for:: - bot.send_poll(update.effective_user.id, *args, **kwargs) + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.send_poll(self.id, *args, **kwargs) + return self.bot.send_poll( + chat_id=self.id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, # pylint=pylint, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) - def send_copy(self, *args: Any, **kwargs: Any) -> 'MessageId': + def send_copy( + self, + from_chat_id: Union[str, int], + message_id: Union[str, int], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: bot.copy_message(chat_id=update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.copy_message(chat_id=self.id, *args, **kwargs) + return self.bot.copy_message( + chat_id=self.id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) - def copy_message(self, *args: Any, **kwargs: Any) -> 'MessageId': + def copy_message( + self, + chat_id: Union[int, str], + message_id: Union[str, int], + caption: str = None, + parse_mode: str = None, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: bool = False, + reply_to_message_id: Union[int, str] = None, + allow_sending_without_reply: bool = False, + reply_markup: 'ReplyMarkup' = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> 'MessageId': """Shortcut for:: bot.copy_message(from_chat_id=update.effective_user.id, *args, **kwargs) + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + Returns: :class:`telegram.Message`: On success, instance representing the message posted. """ - return self.bot.copy_message(from_chat_id=self.id, *args, **kwargs) + return self.bot.copy_message( + from_chat_id=self.id, + chat_id=chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/telegram/utils/helpers.py b/telegram/utils/helpers.py index e271b33e2..3da37d916 100644 --- a/telegram/utils/helpers.py +++ b/telegram/utils/helpers.py @@ -28,7 +28,18 @@ from html import escape from numbers import Number from pathlib import Path -from typing import TYPE_CHECKING, Any, DefaultDict, Dict, Optional, Tuple, Union, Type, cast, IO +from typing import ( + TYPE_CHECKING, + Any, + DefaultDict, + Dict, + Optional, + Tuple, + Union, + Type, + cast, + IO, +) import pytz # pylint: disable=E0401 diff --git a/tests/conftest.py b/tests/conftest.py index aa1989866..d17a94e6e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,12 +17,14 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import datetime +import inspect import os import re from collections import defaultdict from queue import Queue from threading import Thread, Event from time import sleep +from typing import Callable, List, Dict, Any import pytest import pytz @@ -339,3 +341,96 @@ def expect_bad_request(func, message, reason): pytest.xfail(f'{reason}. {e}') else: raise e + + +def check_shortcut_signature( + shortcut: Callable, + bot_method: Callable, + shortcut_kwargs: List[str], + additional_kwargs: List[str], +) -> bool: + """ + Checks that the signature of a shortcut matches the signature of the underlying bot method. + + Args: + shortcut: The shortcut, e.g. :meth:`telegram.Message.reply_text` + bot_method: The bot method, e.g. :meth:`telegram.Bot.send_message` + shortcut_kwargs: The kwargs passed by the shortcut directly, e.g. ``chat_id`` + additional_kwargs: Additional kwargs of the shortcut that the bot method doesn't have, e.g. + ``quote``. + + Returns: + :obj:`bool`: Whether or not the signature matches. + """ + shortcut_arg_spec = inspect.getfullargspec(shortcut) + effective_shortcut_args = set(shortcut_arg_spec.args).difference(additional_kwargs) + effective_shortcut_args.discard('self') + + bot_arg_spec = inspect.getfullargspec(bot_method) + expected_args = set(bot_arg_spec.args).difference(shortcut_kwargs) + expected_args.discard('self') + + args_check = expected_args == effective_shortcut_args + + # TODO: Also check annotation of return type. Would currently be a hassle b/c typing doesn't + # resolve `ForwardRef('Type')` to `Type`. For now we rely on MyPy, which probably allows the + # shortcuts to return more specific types than the bot method, but it's only annotations after + # all + annotation_check = True + for kwarg in effective_shortcut_args: + if bot_arg_spec.annotations[kwarg] != shortcut_arg_spec.annotations[kwarg]: + if isinstance(bot_arg_spec.annotations[kwarg], type): + if bot_arg_spec.annotations[kwarg].__name__ != str( + shortcut_arg_spec.annotations[kwarg] + ): + print( + f'Expected {bot_arg_spec.annotations[kwarg]}, but ' + f'got {shortcut_arg_spec.annotations[kwarg]}' + ) + annotation_check = False + break + else: + print( + f'Expected {bot_arg_spec.annotations[kwarg]}, but ' + f'got {shortcut_arg_spec.annotations[kwarg]}' + ) + annotation_check = False + break + + bot_method_signature = inspect.signature(bot_method) + shortcut_signature = inspect.signature(shortcut) + default_check = all( + shortcut_signature.parameters[arg].default == bot_method_signature.parameters[arg].default + for arg in expected_args + ) + + return args_check and annotation_check and default_check + + +def check_shortcut_call( + kwargs: Dict[str, Any], + bot_method: Callable, +) -> bool: + """ + Checks that a shortcut passes all the existing arguments to the underlying bot method. Use as:: + + send_message = message.bot.send_message + + def make_assertion(*_, **kwargs): + return check_shortcut_call(send_message, kwargs) + + monkeypatch.setattr(message.bot, 'send_message', make_assertion) + assert message.reply_text('foobar') + + + Args: + kwargs: The kwargs passed to the bot method by the shortcut + bot_method: The bot method, e.g. :meth:`telegram.Bot.send_message` + + Returns: + :obj:`bool` + """ + bot_arg_spec = inspect.getfullargspec(bot_method) + expected_args = set(bot_arg_spec.args).difference(['self']) + + return expected_args == set(kwargs.keys()) diff --git a/tests/test_animation.py b/tests/test_animation.py index ae3cc841f..eb38a902a 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -23,9 +23,10 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import PhotoSize, Animation, Voice, TelegramError, MessageEntity +from telegram import PhotoSize, Animation, Voice, TelegramError, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -308,10 +309,14 @@ class TestAnimation: bot.send_animation(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, animation): - def test(*args, **kwargs): - return args[1] == animation.file_id + get_file = animation.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == animation.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Animation.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert animation.get_file() def test_equality(self): diff --git a/tests/test_audio.py b/tests/test_audio.py index 31be16a4e..49b3509ae 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -22,8 +22,9 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import Audio, TelegramError, Voice, MessageEntity +from telegram import Audio, TelegramError, Voice, MessageEntity, Bot from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -281,10 +282,14 @@ class TestAudio: bot.send_audio(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, audio): - def test(*args, **kwargs): - return args[1] == audio.file_id + get_file = audio.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == audio.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Audio.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert audio.get_file() def test_equality(self, audio): diff --git a/tests/test_callbackquery.py b/tests/test_callbackquery.py index 686ce2b99..773a2f4ec 100644 --- a/tests/test_callbackquery.py +++ b/tests/test_callbackquery.py @@ -19,7 +19,8 @@ import pytest -from telegram import CallbackQuery, User, Message, Chat, Audio +from telegram import CallbackQuery, User, Message, Chat, Audio, Bot +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='class', params=['message', 'inline']) @@ -49,6 +50,18 @@ class TestCallbackQuery: inline_message_id = 'inline_message_id' game_short_name = 'the_game' + @staticmethod + def check_passed_ids(callback_query: CallbackQuery, kwargs): + if callback_query.inline_message_id: + id_ = kwargs['inline_message_id'] == callback_query.inline_message_id + chat_id = kwargs['chat_id'] is None + message_id = kwargs['message_id'] is None + else: + id_ = kwargs['inline_message_id'] is None + chat_id = kwargs['chat_id'] == callback_query.message.chat_id + message_id = kwargs['message_id'] == callback_query.message.message_id + return id_ and chat_id and message_id + def test_de_json(self, bot): json_dict = { 'id': self.id_, @@ -84,174 +97,240 @@ class TestCallbackQuery: assert callback_query_dict['game_short_name'] == callback_query.game_short_name def test_answer(self, monkeypatch, callback_query): - def test(*args, **kwargs): - return args[0] == callback_query.id + answer_callback_query = callback_query.bot.answer_callback_query - monkeypatch.setattr(callback_query.bot, 'answer_callback_query', test) + def make_assertion(*_, **kwargs): + return kwargs['callback_query_id'] == callback_query.id and check_shortcut_call( + kwargs, answer_callback_query + ) + + assert check_shortcut_signature( + CallbackQuery.answer, Bot.answer_callback_query, ['callback_query_id'], [] + ) + + monkeypatch.setattr(callback_query.bot, 'answer_callback_query', make_assertion) # TODO: PEP8 assert callback_query.answer() def test_edit_message_text(self, monkeypatch, callback_query): - def test(*args, **kwargs): - text = args[0] == 'test' - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and text - except KeyError: - chat_id = kwargs['chat_id'] == callback_query.message.chat_id - message_id = kwargs['message_id'] == callback_query.message.message_id - return chat_id and message_id and text + edit_message_text = callback_query.bot.edit_message_text - monkeypatch.setattr(callback_query.bot, 'edit_message_text', test) + def make_assertion(*_, **kwargs): + text = kwargs['text'] == 'test' + ids = self.check_passed_ids(callback_query, kwargs) + return ids and text and check_shortcut_call(kwargs, edit_message_text) + + assert check_shortcut_signature( + CallbackQuery.edit_message_text, + Bot.edit_message_text, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'edit_message_text', make_assertion) assert callback_query.edit_message_text(text='test') assert callback_query.edit_message_text('test') def test_edit_message_caption(self, monkeypatch, callback_query): - def test(*args, **kwargs): - caption = kwargs['caption'] == 'new caption' - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and caption - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and caption + edit_message_caption = callback_query.bot.edit_message_caption - monkeypatch.setattr(callback_query.bot, 'edit_message_caption', test) + def make_assertion(*_, **kwargs): + caption = kwargs['caption'] == 'new caption' + ids = self.check_passed_ids(callback_query, kwargs) + return ids and caption and check_shortcut_call(kwargs, edit_message_caption) + + assert check_shortcut_signature( + CallbackQuery.edit_message_caption, + Bot.edit_message_caption, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'edit_message_caption', make_assertion) assert callback_query.edit_message_caption(caption='new caption') assert callback_query.edit_message_caption('new caption') def test_edit_message_reply_markup(self, monkeypatch, callback_query): - def test(*args, **kwargs): - reply_markup = kwargs['reply_markup'] == [['1', '2']] - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and reply_markup - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and reply_markup + edit_message_reply_markup = callback_query.bot.edit_message_reply_markup - monkeypatch.setattr(callback_query.bot, 'edit_message_reply_markup', test) + def make_assertion(*_, **kwargs): + reply_markup = kwargs['reply_markup'] == [['1', '2']] + ids = self.check_passed_ids(callback_query, kwargs) + return ids and reply_markup and check_shortcut_call(kwargs, edit_message_reply_markup) + + assert check_shortcut_signature( + CallbackQuery.edit_message_reply_markup, + Bot.edit_message_reply_markup, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'edit_message_reply_markup', make_assertion) assert callback_query.edit_message_reply_markup(reply_markup=[['1', '2']]) assert callback_query.edit_message_reply_markup([['1', '2']]) def test_edit_message_media(self, monkeypatch, callback_query): - def test(*args, **kwargs): - message_media = kwargs.get('media') == [['1', '2']] or args[0] == [['1', '2']] - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and message_media - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and message_media + edit_message_media = callback_query.bot.edit_message_media - monkeypatch.setattr(callback_query.bot, 'edit_message_media', test) + def make_assertion(*_, **kwargs): + message_media = kwargs.get('media') == [['1', '2']] + ids = self.check_passed_ids(callback_query, kwargs) + return ids and message_media and check_shortcut_call(kwargs, edit_message_media) + + assert check_shortcut_signature( + CallbackQuery.edit_message_media, + Bot.edit_message_media, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'edit_message_media', make_assertion) assert callback_query.edit_message_media(media=[['1', '2']]) assert callback_query.edit_message_media([['1', '2']]) def test_edit_message_live_location(self, monkeypatch, callback_query): - def test(*args, **kwargs): - latitude = kwargs.get('latitude') == 1 or args[0] == 1 - longitude = kwargs.get('longitude') == 2 or args[1] == 2 - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and latitude and longitude - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and latitude and longitude + edit_message_live_location = callback_query.bot.edit_message_live_location - monkeypatch.setattr(callback_query.bot, 'edit_message_live_location', test) + def make_assertion(*_, **kwargs): + latitude = kwargs.get('latitude') == 1 + longitude = kwargs.get('longitude') == 2 + ids = self.check_passed_ids(callback_query, kwargs) + return ( + ids + and latitude + and longitude + and check_shortcut_call(kwargs, edit_message_live_location) + ) + + assert check_shortcut_signature( + CallbackQuery.edit_message_live_location, + Bot.edit_message_live_location, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'edit_message_live_location', make_assertion) assert callback_query.edit_message_live_location(latitude=1, longitude=2) assert callback_query.edit_message_live_location(1, 2) def test_stop_message_live_location(self, monkeypatch, callback_query): - def test(*args, **kwargs): - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message + stop_message_live_location = callback_query.bot.stop_message_live_location - monkeypatch.setattr(callback_query.bot, 'stop_message_live_location', test) + def make_assertion(*_, **kwargs): + ids = self.check_passed_ids(callback_query, kwargs) + return ids and check_shortcut_call(kwargs, stop_message_live_location) + + assert check_shortcut_signature( + CallbackQuery.stop_message_live_location, + Bot.stop_message_live_location, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'stop_message_live_location', make_assertion) assert callback_query.stop_message_live_location() def test_set_game_score(self, monkeypatch, callback_query): - def test(*args, **kwargs): - user_id = kwargs.get('user_id') == 1 or args[0] == 1 - score = kwargs.get('score') == 2 or args[1] == 2 - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and user_id and score - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and user_id and score + set_game_score = callback_query.bot.set_game_score - monkeypatch.setattr(callback_query.bot, 'set_game_score', test) + def make_assertion(*_, **kwargs): + user_id = kwargs.get('user_id') == 1 + score = kwargs.get('score') == 2 + ids = self.check_passed_ids(callback_query, kwargs) + return ids and user_id and score and check_shortcut_call(kwargs, set_game_score) + + assert check_shortcut_signature( + CallbackQuery.set_game_score, + Bot.set_game_score, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'set_game_score', make_assertion) assert callback_query.set_game_score(user_id=1, score=2) assert callback_query.set_game_score(1, 2) def test_get_game_high_scores(self, monkeypatch, callback_query): - def test(*args, **kwargs): - user_id = kwargs.get('user_id') == 1 or args[0] == 1 - try: - id_ = kwargs['inline_message_id'] == callback_query.inline_message_id - return id_ and user_id - except KeyError: - id_ = kwargs['chat_id'] == callback_query.message.chat_id - message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and user_id + get_game_high_scores = callback_query.bot.get_game_high_scores - monkeypatch.setattr(callback_query.bot, 'get_game_high_scores', test) + def make_assertion(*_, **kwargs): + user_id = kwargs.get('user_id') == 1 + ids = self.check_passed_ids(callback_query, kwargs) + return ids and user_id and check_shortcut_call(kwargs, get_game_high_scores) + + assert check_shortcut_signature( + CallbackQuery.get_game_high_scores, + Bot.get_game_high_scores, + ['inline_message_id', 'message_id', 'chat_id'], + [], + ) + + monkeypatch.setattr(callback_query.bot, 'get_game_high_scores', make_assertion) assert callback_query.get_game_high_scores(user_id=1) assert callback_query.get_game_high_scores(1) def test_delete_message(self, monkeypatch, callback_query): + delete_message = callback_query.bot.delete_message if callback_query.inline_message_id: pytest.skip("Can't delete inline messages") def make_assertion(*args, **kwargs): id_ = kwargs['chat_id'] == callback_query.message.chat_id message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message + return id_ and message and check_shortcut_call(kwargs, delete_message) + + assert check_shortcut_signature( + CallbackQuery.delete_message, + Bot.delete_message, + ['message_id', 'chat_id'], + [], + ) monkeypatch.setattr(callback_query.bot, 'delete_message', make_assertion) assert callback_query.delete_message() def test_pin_message(self, monkeypatch, callback_query): + pin_message = callback_query.bot.pin_chat_message if callback_query.inline_message_id: pytest.skip("Can't pin inline messages") def make_assertion(*args, **kwargs): - _id = callback_query.message.chat_id - try: - return kwargs['chat_id'] == _id - except KeyError: - return args[0] == _id + return kwargs['chat_id'] == callback_query.message.chat_id and check_shortcut_call( + kwargs, pin_message + ) + + assert check_shortcut_signature( + CallbackQuery.pin_message, + Bot.pin_chat_message, + ['message_id', 'chat_id'], + [], + ) monkeypatch.setattr(callback_query.bot, 'pin_chat_message', make_assertion) assert callback_query.pin_message() def test_unpin_message(self, monkeypatch, callback_query): + unpin_message = callback_query.bot.unpin_chat_message if callback_query.inline_message_id: pytest.skip("Can't unpin inline messages") def make_assertion(*args, **kwargs): - _id = callback_query.message.chat_id - try: - return kwargs['chat_id'] == _id - except KeyError: - return args[0] == _id + return kwargs['chat_id'] == callback_query.message.chat_id and check_shortcut_call( + kwargs, unpin_message + ) + + assert check_shortcut_signature( + CallbackQuery.unpin_message, + Bot.unpin_chat_message, + ['message_id', 'chat_id'], + [], + ) monkeypatch.setattr(callback_query.bot, 'unpin_chat_message', make_assertion) assert callback_query.unpin_message() def test_copy_message(self, monkeypatch, callback_query): + copy_message = callback_query.bot.copy_message if callback_query.inline_message_id: pytest.skip("Can't copy inline messages") @@ -259,7 +338,14 @@ class TestCallbackQuery: id_ = kwargs['from_chat_id'] == callback_query.message.chat_id chat_id = kwargs['chat_id'] == 1 message = kwargs['message_id'] == callback_query.message.message_id - return id_ and message and chat_id + return id_ and message and chat_id and check_shortcut_call(kwargs, copy_message) + + assert check_shortcut_signature( + CallbackQuery.copy_message, + Bot.copy_message, + ['message_id', 'from_chat_id'], + [], + ) monkeypatch.setattr(callback_query.bot, 'copy_message', make_assertion) assert callback_query.copy_message(1) diff --git a/tests/test_chat.py b/tests/test_chat.py index 303d493e0..cd045eac7 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -19,8 +19,9 @@ import pytest -from telegram import Chat, ChatAction, ChatPermissions, ChatLocation, Location +from telegram import Chat, ChatAction, ChatPermissions, ChatLocation, Location, Bot from telegram import User +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='class') @@ -112,251 +113,488 @@ class TestChat: assert chat.link is None def test_send_action(self, monkeypatch, chat): - def test(*args, **kwargs): - id_ = args[0] == chat.id - action = kwargs['action'] == ChatAction.TYPING - return id_ and action + send_chat_action = chat.bot.send_chat_action - monkeypatch.setattr(chat.bot, 'send_chat_action', test) + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == chat.id + action = kwargs['action'] == ChatAction.TYPING + return id_ and action and check_shortcut_call(kwargs, send_chat_action) + + assert check_shortcut_signature( + Chat.send_chat_action, Bot.send_chat_action, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'send_chat_action', make_assertion) assert chat.send_action(action=ChatAction.TYPING) assert chat.send_chat_action(action=ChatAction.TYPING) def test_leave(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id + leave_chat = chat.bot.leave_chat - monkeypatch.setattr(chat.bot, 'leave_chat', test) + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == chat.id and check_shortcut_call(kwargs, leave_chat) + + assert check_shortcut_signature(Chat.leave, Bot.leave_chat, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'leave_chat', make_assertion) assert chat.leave() def test_get_administrators(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id + get_chat_administrators = chat.bot.get_chat_administrators - monkeypatch.setattr(chat.bot, 'get_chat_administrators', test) + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == chat.id and check_shortcut_call( + kwargs, get_chat_administrators + ) + + assert check_shortcut_signature( + Chat.get_administrators, Bot.get_chat_administrators, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'get_chat_administrators', make_assertion) assert chat.get_administrators() def test_get_members_count(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id + get_chat_members_count = chat.bot.get_chat_members_count - monkeypatch.setattr(chat.bot, 'get_chat_members_count', test) + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == chat.id and check_shortcut_call( + kwargs, get_chat_members_count + ) + + assert check_shortcut_signature( + Chat.get_members_count, Bot.get_chat_members_count, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'get_chat_members_count', make_assertion) assert chat.get_members_count() def test_get_member(self, monkeypatch, chat): - def test(*args, **kwargs): - chat_id = args[0] == chat.id - user_id = args[1] == 42 - return chat_id and user_id + get_chat_member = chat.bot.get_chat_member - monkeypatch.setattr(chat.bot, 'get_chat_member', test) - assert chat.get_member(42) + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 + return chat_id and user_id and check_shortcut_call(kwargs, get_chat_member) + + assert check_shortcut_signature(Chat.get_member, Bot.get_chat_member, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'get_chat_member', make_assertion) + assert chat.get_member(user_id=42) def test_kick_member(self, monkeypatch, chat): - def test(*args, **kwargs): - chat_id = args[0] == chat.id - user_id = args[1] == 42 - until = kwargs['until_date'] == 43 - return chat_id and user_id and until + kick_chat_member = chat.bot.kick_chat_member - monkeypatch.setattr(chat.bot, 'kick_chat_member', test) - assert chat.kick_member(42, until_date=43) + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 + until = kwargs['until_date'] == 43 + return chat_id and user_id and until and check_shortcut_call(kwargs, kick_chat_member) + + assert check_shortcut_signature(Chat.kick_member, Bot.kick_chat_member, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'kick_chat_member', make_assertion) + assert chat.kick_member(user_id=42, until_date=43) @pytest.mark.parametrize('only_if_banned', [True, False, None]) def test_unban_member(self, monkeypatch, chat, only_if_banned): - def make_assertion(*args, **kwargs): - chat_id = args[0] == chat.id - user_id = args[1] == 42 + unban_chat_member = chat.bot.unban_chat_member + + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 o_i_b = kwargs.get('only_if_banned', None) == only_if_banned - return chat_id and user_id and o_i_b + return chat_id and user_id and o_i_b and check_shortcut_call(kwargs, unban_chat_member) + + assert check_shortcut_signature(Chat.unban_member, Bot.unban_chat_member, ['chat_id'], []) monkeypatch.setattr(chat.bot, 'unban_chat_member', make_assertion) - assert chat.unban_member(42, only_if_banned=only_if_banned) + assert chat.unban_member(user_id=42, only_if_banned=only_if_banned) def test_set_permissions(self, monkeypatch, chat): - def test(*args, **kwargs): - chat_id = args[0] == chat.id - permissions = args[1] == self.permissions - return chat_id and permissions + set_chat_permissions = chat.bot.set_chat_permissions - monkeypatch.setattr(chat.bot, 'set_chat_permissions', test) - assert chat.set_permissions(self.permissions) + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + permissions = kwargs['permissions'] == self.permissions + return chat_id and permissions and check_shortcut_call(kwargs, set_chat_permissions) + + assert check_shortcut_signature( + Chat.set_permissions, Bot.set_chat_permissions, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'set_chat_permissions', make_assertion) + assert chat.set_permissions(permissions=self.permissions) def test_set_administrator_custom_title(self, monkeypatch, chat): - def test(*args, **kwargs): - chat_id = args[1] == chat.id - user_id = args[2] == 42 - custom_title = args[3] == 'custom_title' + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 + custom_title = kwargs['custom_title'] == 'custom_title' return chat_id and user_id and custom_title - monkeypatch.setattr('telegram.Bot.set_chat_administrator_custom_title', test) - assert chat.set_administrator_custom_title(42, 'custom_title') + monkeypatch.setattr('telegram.Bot.set_chat_administrator_custom_title', make_assertion) + assert chat.set_administrator_custom_title(user_id=42, custom_title='custom_title') def test_pin_message(self, monkeypatch, chat): - def make_assertion(*args, **kwargs): - try: - return kwargs['chat_id'] == chat.id - except KeyError: - return args[0] == chat.id + pin_chat_message = chat.bot.pin_chat_message + + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['message_id'] == 42 + and check_shortcut_call(kwargs, pin_chat_message) + ) + + assert check_shortcut_signature(Chat.pin_message, Bot.pin_chat_message, ['chat_id'], []) monkeypatch.setattr(chat.bot, 'pin_chat_message', make_assertion) - assert chat.pin_message() + assert chat.pin_message(message_id=42) def test_unpin_message(self, monkeypatch, chat): - def make_assertion(*args, **kwargs): - try: - return kwargs['chat_id'] == chat.id - except KeyError: - return args[0] == chat.id + unpin_chat_message = chat.bot.unpin_chat_message + + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == chat.id and check_shortcut_call(kwargs, unpin_chat_message) + + assert check_shortcut_signature( + Chat.unpin_message, Bot.unpin_chat_message, ['chat_id'], [] + ) monkeypatch.setattr(chat.bot, 'unpin_chat_message', make_assertion) assert chat.unpin_message() def test_unpin_all_messages(self, monkeypatch, chat): - def make_assertion(*args, **kwargs): - try: - return kwargs['chat_id'] == chat.id - except KeyError: - return args[0] == chat.id + unpin_all_chat_messages = chat.bot.unpin_all_chat_messages + + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == chat.id and check_shortcut_call( + kwargs, unpin_all_chat_messages + ) + + assert check_shortcut_signature( + Chat.unpin_all_messages, Bot.unpin_all_chat_messages, ['chat_id'], [] + ) monkeypatch.setattr(chat.bot, 'unpin_all_chat_messages', make_assertion) assert chat.unpin_all_messages() def test_instance_method_send_message(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test' + send_message = chat.bot.send_message - monkeypatch.setattr(chat.bot, 'send_message', test) - assert chat.send_message('test') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['text'] == 'test' + and check_shortcut_call(kwargs, send_message) + ) + + assert check_shortcut_signature(Chat.send_message, Bot.send_message, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_message', make_assertion) + assert chat.send_message(text='test') def test_instance_method_send_media_group(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_media_group' + send_media_group = chat.bot.send_media_group - monkeypatch.setattr(chat.bot, 'send_media_group', test) - assert chat.send_media_group('test_media_group') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['media'] == 'test_media_group' + and check_shortcut_call(kwargs, send_media_group) + ) + + assert check_shortcut_signature( + Chat.send_media_group, Bot.send_media_group, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'send_media_group', make_assertion) + assert chat.send_media_group(media='test_media_group') def test_instance_method_send_photo(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_photo' + send_photo = chat.bot.send_photo - monkeypatch.setattr(chat.bot, 'send_photo', test) - assert chat.send_photo('test_photo') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['photo'] == 'test_photo' + and check_shortcut_call(kwargs, send_photo) + ) + + assert check_shortcut_signature(Chat.send_photo, Bot.send_photo, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_photo', make_assertion) + assert chat.send_photo(photo='test_photo') def test_instance_method_send_contact(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_contact' + send_contact = chat.bot.send_contact - monkeypatch.setattr(chat.bot, 'send_contact', test) - assert chat.send_contact('test_contact') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['phone_number'] == 'test_contact' + and check_shortcut_call(kwargs, send_contact) + ) + + assert check_shortcut_signature(Chat.send_contact, Bot.send_contact, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_contact', make_assertion) + assert chat.send_contact(phone_number='test_contact') def test_instance_method_send_audio(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_audio' + send_audio = chat.bot.send_audio - monkeypatch.setattr(chat.bot, 'send_audio', test) - assert chat.send_audio('test_audio') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['audio'] == 'test_audio' + and check_shortcut_call(kwargs, send_audio) + ) + + assert check_shortcut_signature(Chat.send_audio, Bot.send_audio, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_audio', make_assertion) + assert chat.send_audio(audio='test_audio') def test_instance_method_send_document(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_document' + send_document = chat.bot.send_document - monkeypatch.setattr(chat.bot, 'send_document', test) - assert chat.send_document('test_document') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['document'] == 'test_document' + and check_shortcut_call(kwargs, send_document) + ) + + assert check_shortcut_signature(Chat.send_document, Bot.send_document, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_document', make_assertion) + assert chat.send_document(document='test_document') def test_instance_method_send_dice(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_dice' + send_dice = chat.bot.send_dice - monkeypatch.setattr(chat.bot, 'send_dice', test) - assert chat.send_dice('test_dice') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['emoji'] == 'test_dice' + and check_shortcut_call(kwargs, send_dice) + ) + + assert check_shortcut_signature(Chat.send_dice, Bot.send_dice, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_dice', make_assertion) + assert chat.send_dice(emoji='test_dice') def test_instance_method_send_game(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_game' + send_game = chat.bot.send_game - monkeypatch.setattr(chat.bot, 'send_game', test) - assert chat.send_game('test_game') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['game_short_name'] == 'test_game' + and check_shortcut_call(kwargs, send_game) + ) + + assert check_shortcut_signature(Chat.send_game, Bot.send_game, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_game', make_assertion) + assert chat.send_game(game_short_name='test_game') def test_instance_method_send_invoice(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_invoice' + send_invoice = chat.bot.send_invoice - monkeypatch.setattr(chat.bot, 'send_invoice', test) - assert chat.send_invoice('test_invoice') + def make_assertion(*_, **kwargs): + title = kwargs['title'] == 'title' + description = kwargs['description'] == 'description' + payload = kwargs['payload'] == 'payload' + provider_token = kwargs['provider_token'] == 'provider_token' + start_parameter = kwargs['start_parameter'] == 'start_parameter' + currency = kwargs['currency'] == 'currency' + prices = kwargs['prices'] == 'prices' + args = ( + title + and description + and payload + and provider_token + and start_parameter + and currency + and prices + ) + return ( + kwargs['chat_id'] == chat.id and args and check_shortcut_call(kwargs, send_invoice) + ) + + assert check_shortcut_signature(Chat.send_invoice, Bot.send_invoice, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_invoice', make_assertion) + assert chat.send_invoice( + 'title', + 'description', + 'payload', + 'provider_token', + 'start_parameter', + 'currency', + 'prices', + ) def test_instance_method_send_location(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_location' + send_location = chat.bot.send_location - monkeypatch.setattr(chat.bot, 'send_location', test) - assert chat.send_location('test_location') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['latitude'] == 'test_location' + and check_shortcut_call(kwargs, send_location) + ) + + assert check_shortcut_signature(Chat.send_location, Bot.send_location, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_location', make_assertion) + assert chat.send_location(latitude='test_location') def test_instance_method_send_sticker(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_sticker' + send_sticker = chat.bot.send_sticker - monkeypatch.setattr(chat.bot, 'send_sticker', test) - assert chat.send_sticker('test_sticker') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['sticker'] == 'test_sticker' + and check_shortcut_call(kwargs, send_sticker) + ) + + assert check_shortcut_signature(Chat.send_sticker, Bot.send_sticker, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_sticker', make_assertion) + assert chat.send_sticker(sticker='test_sticker') def test_instance_method_send_venue(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_venue' + send_venue = chat.bot.send_venue - monkeypatch.setattr(chat.bot, 'send_venue', test) - assert chat.send_venue('test_venue') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['title'] == 'test_venue' + and check_shortcut_call(kwargs, send_venue) + ) + + assert check_shortcut_signature(Chat.send_venue, Bot.send_venue, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_venue', make_assertion) + assert chat.send_venue(title='test_venue') def test_instance_method_send_video(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_video' + send_video = chat.bot.send_video - monkeypatch.setattr(chat.bot, 'send_video', test) - assert chat.send_video('test_video') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['video'] == 'test_video' + and check_shortcut_call(kwargs, send_video) + ) + + assert check_shortcut_signature(Chat.send_video, Bot.send_video, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_video', make_assertion) + assert chat.send_video(video='test_video') def test_instance_method_send_video_note(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_video_note' + send_video_note = chat.bot.send_video_note - monkeypatch.setattr(chat.bot, 'send_video_note', test) - assert chat.send_video_note('test_video_note') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['video_note'] == 'test_video_note' + and check_shortcut_call(kwargs, send_video_note) + ) + + assert check_shortcut_signature(Chat.send_video_note, Bot.send_video_note, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_video_note', make_assertion) + assert chat.send_video_note(video_note='test_video_note') def test_instance_method_send_voice(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_voice' + send_voice = chat.bot.send_voice - monkeypatch.setattr(chat.bot, 'send_voice', test) - assert chat.send_voice('test_voice') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['voice'] == 'test_voice' + and check_shortcut_call(kwargs, send_voice) + ) + + assert check_shortcut_signature(Chat.send_voice, Bot.send_voice, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_voice', make_assertion) + assert chat.send_voice(voice='test_voice') def test_instance_method_send_animation(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_animation' + send_animation = chat.bot.send_animation - monkeypatch.setattr(chat.bot, 'send_animation', test) - assert chat.send_animation('test_animation') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['animation'] == 'test_animation' + and check_shortcut_call(kwargs, send_animation) + ) + + assert check_shortcut_signature(Chat.send_animation, Bot.send_animation, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_animation', make_assertion) + assert chat.send_animation(animation='test_animation') def test_instance_method_send_poll(self, monkeypatch, chat): - def test(*args, **kwargs): - return args[0] == chat.id and args[1] == 'test_poll' + send_poll = chat.bot.send_poll - monkeypatch.setattr(chat.bot, 'send_poll', test) - assert chat.send_poll('test_poll') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == chat.id + and kwargs['question'] == 'test_poll' + and check_shortcut_call(kwargs, send_poll) + ) + + assert check_shortcut_signature(Chat.send_poll, Bot.send_poll, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'send_poll', make_assertion) + assert chat.send_poll(question='test_poll', options=[1, 2]) def test_instance_method_send_copy(self, monkeypatch, chat): - def test(*args, **kwargs): - assert args[0] == 'test_copy' - assert kwargs['chat_id'] == chat.id - return args + copy_message = chat.bot.copy_message - monkeypatch.setattr(chat.bot, 'copy_message', test) - assert chat.send_copy('test_copy') + def make_assertion(*_, **kwargs): + from_chat_id = kwargs['from_chat_id'] == 'test_copy' + message_id = kwargs['message_id'] == 42 + chat_id = kwargs['chat_id'] == chat.id + return ( + from_chat_id + and message_id + and chat_id + and check_shortcut_call(kwargs, copy_message) + ) + + assert check_shortcut_signature(Chat.send_copy, Bot.copy_message, ['chat_id'], []) + + monkeypatch.setattr(chat.bot, 'copy_message', make_assertion) + assert chat.send_copy(from_chat_id='test_copy', message_id=42) def test_instance_method_copy_message(self, monkeypatch, chat): - def test(*args, **kwargs): - assert args[0] == 'test_copy' - assert kwargs['from_chat_id'] == chat.id - return args + copy_message = chat.bot.copy_message - monkeypatch.setattr(chat.bot, 'copy_message', test) - assert chat.copy_message('test_copy') + def make_assertion(*_, **kwargs): + from_chat_id = kwargs['from_chat_id'] == chat.id + message_id = kwargs['message_id'] == 42 + chat_id = kwargs['chat_id'] == 'test_copy' + return ( + from_chat_id + and message_id + and chat_id + and check_shortcut_call(kwargs, copy_message) + ) + + assert check_shortcut_signature(Chat.copy_message, Bot.copy_message, ['from_chat_id'], []) + + monkeypatch.setattr(chat.bot, 'copy_message', make_assertion) + assert chat.copy_message(chat_id='test_copy', message_id=42) def test_equality(self): a = Chat(self.id_, self.title, self.type_) diff --git a/tests/test_chatphoto.py b/tests/test_chatphoto.py index 76dd227fb..e842f864a 100644 --- a/tests/test_chatphoto.py +++ b/tests/test_chatphoto.py @@ -21,8 +21,8 @@ import os import pytest from flaky import flaky -from telegram import ChatPhoto, Voice, TelegramError -from tests.conftest import expect_bad_request +from telegram import ChatPhoto, Voice, TelegramError, Bot +from tests.conftest import expect_bad_request, check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -125,17 +125,29 @@ class TestChatPhoto: bot.set_chat_photo(chat_id=super_group_id) def test_get_small_file_instance_method(self, monkeypatch, chat_photo): - def test(*args, **kwargs): - return args[1] == chat_photo.small_file_id + get_small_file = chat_photo.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == chat_photo.small_file_id and check_shortcut_call( + kwargs, get_small_file + ) + + assert check_shortcut_signature(ChatPhoto.get_small_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert chat_photo.get_small_file() def test_get_big_file_instance_method(self, monkeypatch, chat_photo): - def test(*args, **kwargs): - return args[1] == chat_photo.big_file_id + get_big_file = chat_photo.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == chat_photo.big_file_id and check_shortcut_call( + kwargs, get_big_file + ) + + assert check_shortcut_signature(ChatPhoto.get_big_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert chat_photo.get_big_file() def test_equality(self): diff --git a/tests/test_document.py b/tests/test_document.py index 77f95fb4d..c7226fcbf 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -22,9 +22,10 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import Document, PhotoSize, TelegramError, Voice, MessageEntity +from telegram import Document, PhotoSize, TelegramError, Voice, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='function') @@ -297,10 +298,14 @@ class TestDocument: bot.send_document(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, document): - def test(*args, **kwargs): - return args[1] == document.file_id + get_file = document.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == document.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Document.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert document.get_file() def test_equality(self, document): diff --git a/tests/test_inlinequery.py b/tests/test_inlinequery.py index 1cdd6cc85..57258f4f1 100644 --- a/tests/test_inlinequery.py +++ b/tests/test_inlinequery.py @@ -19,7 +19,8 @@ import pytest -from telegram import User, Location, InlineQuery, Update +from telegram import User, Location, InlineQuery, Update, Bot +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='class') @@ -68,20 +69,32 @@ class TestInlineQuery: assert inline_query_dict['offset'] == inline_query.offset def test_answer(self, monkeypatch, inline_query): - def test(*args, **kwargs): - return args[0] == inline_query.id + answer_inline_query = inline_query.bot.answer_inline_query - monkeypatch.setattr(inline_query.bot, 'answer_inline_query', test) - assert inline_query.answer() + def make_assertion(*_, **kwargs): + return kwargs['inline_query_id'] == inline_query.id and check_shortcut_call( + kwargs, answer_inline_query + ) + + assert check_shortcut_signature( + InlineQuery.answer, Bot.answer_inline_query, ['inline_query_id'], ['auto_pagination'] + ) + + monkeypatch.setattr(inline_query.bot, 'answer_inline_query', make_assertion) + assert inline_query.answer(results=[]) + + def test_answer_error(self, inline_query): + with pytest.raises(TypeError, match='mutually exclusive'): + inline_query.answer(results=[], auto_pagination=True, current_offset='foobar') def test_answer_auto_pagination(self, monkeypatch, inline_query): - def make_assertion(*args, **kwargs): - inline_query_id_matches = args[0] == inline_query.id + def make_assertion(*_, **kwargs): + inline_query_id_matches = kwargs['inline_query_id'] == inline_query.id offset_matches = kwargs.get('current_offset') == inline_query.offset return offset_matches and inline_query_id_matches monkeypatch.setattr(inline_query.bot, 'answer_inline_query', make_assertion) - assert inline_query.answer(auto_pagination=True) + assert inline_query.answer(results=[], auto_pagination=True) def test_equality(self): a = InlineQuery(self.id_, User(1, '', False), '', '') diff --git a/tests/test_message.py b/tests/test_message.py index 25c249ba5..a4349d63b 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -46,8 +46,10 @@ from telegram import ( PollOption, ProximityAlertTriggered, Dice, + Bot, ) from telegram.ext import Defaults +from tests.conftest import check_shortcut_signature, check_shortcut_call from tests.test_passport import RAW_PASSPORT_DATA @@ -635,21 +637,28 @@ class TestMessage: assert message_params.effective_attachment == item def test_reply_text(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id - text = args[1] == 'test' + send_message = message.bot.send_message + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id + text = kwargs['text'] == 'test' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and text and reply + return id_ and text and reply and check_shortcut_call(kwargs, send_message) - monkeypatch.setattr(message.bot, 'send_message', test) + assert check_shortcut_signature( + Message.reply_text, Bot.send_message, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_message', make_assertion) assert message.reply_text('test') assert message.reply_text('test', quote=True) assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True) def test_reply_markdown(self, monkeypatch, message): + send_message = message.bot.send_message test_md_string = ( r'Test for <*bold*, _ita_\__lic_, `code`, ' '[links](http://github.com/ab_), ' @@ -657,20 +666,26 @@ class TestMessage: r'http://google.com/ab\_' ) - def test(*args, **kwargs): - cid = args[0] == message.chat_id - markdown_text = args[1] == test_md_string + def make_assertion(*_, **kwargs): + cid = kwargs['chat_id'] == message.chat_id + markdown_text = kwargs['text'] == test_md_string markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, markdown_text, reply, markdown_enabled]) + return all([cid, markdown_text, reply, markdown_enabled]) and check_shortcut_call( + kwargs, send_message + ) + + assert check_shortcut_signature( + Message.reply_markdown, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] + ) text_markdown = self.test_message.text_markdown assert text_markdown == test_md_string - monkeypatch.setattr(message.bot, 'send_message', test) + monkeypatch.setattr(message.bot, 'send_message', make_assertion) assert message.reply_markdown(self.test_message.text_markdown) assert message.reply_markdown(self.test_message.text_markdown, quote=True) assert message.reply_markdown( @@ -678,6 +693,7 @@ class TestMessage: ) def test_reply_markdown_v2(self, monkeypatch, message): + send_message = message.bot.send_message test_md_string = ( r'__Test__ for <*bold*, _ita\_lic_, `\\\`code`, ' '[links](http://github.com/abc\\\\\\)def), ' @@ -686,20 +702,26 @@ class TestMessage: '```python\nPython pre```\\.' ) - def test(*args, **kwargs): - cid = args[0] == message.chat_id - markdown_text = args[1] == test_md_string + def make_assertion(*_, **kwargs): + cid = kwargs['chat_id'] == message.chat_id + markdown_text = kwargs['text'] == test_md_string markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN_V2 if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, markdown_text, reply, markdown_enabled]) + return all([cid, markdown_text, reply, markdown_enabled]) and check_shortcut_call( + kwargs, send_message + ) + + assert check_shortcut_signature( + Message.reply_markdown_v2, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] + ) text_markdown = self.test_message_v2.text_markdown_v2 assert text_markdown == test_md_string - monkeypatch.setattr(message.bot, 'send_message', test) + monkeypatch.setattr(message.bot, 'send_message', make_assertion) assert message.reply_markdown_v2(self.test_message_v2.text_markdown_v2) assert message.reply_markdown_v2(self.test_message_v2.text_markdown_v2, quote=True) assert message.reply_markdown_v2( @@ -709,6 +731,7 @@ class TestMessage: ) def test_reply_html(self, monkeypatch, message): + send_message = message.bot.send_message test_html_string = ( 'Test for <bold, ita_lic, ' r'\`code, ' @@ -719,20 +742,26 @@ class TestMessage: '
Python pre
.' ) - def test(*args, **kwargs): - cid = args[0] == message.chat_id - html_text = args[1] == test_html_string + def make_assertion(*_, **kwargs): + cid = kwargs['chat_id'] == message.chat_id + html_text = kwargs['text'] == test_html_string html_enabled = kwargs['parse_mode'] == ParseMode.HTML if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return all([cid, html_text, reply, html_enabled]) + return all([cid, html_text, reply, html_enabled]) and check_shortcut_call( + kwargs, send_message + ) + + assert check_shortcut_signature( + Message.reply_html, Bot.send_message, ['chat_id', 'parse_mode'], ['quote'] + ) text_html = self.test_message_v2.text_html assert text_html == test_html_string - monkeypatch.setattr(message.bot, 'send_message', test) + monkeypatch.setattr(message.bot, 'send_message', make_assertion) assert message.reply_html(self.test_message_v2.text_html) assert message.reply_html(self.test_message_v2.text_html, quote=True) assert message.reply_html( @@ -740,252 +769,353 @@ class TestMessage: ) def test_reply_media_group(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_media_group = message.bot.send_media_group + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id media = kwargs['media'] == 'reply_media_group' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and media and reply + return id_ and media and reply and check_shortcut_call(kwargs, send_media_group) - monkeypatch.setattr(message.bot, 'send_media_group', test) + assert check_shortcut_signature( + Message.reply_media_group, Bot.send_media_group, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_media_group', make_assertion) assert message.reply_media_group(media='reply_media_group') assert message.reply_media_group(media='reply_media_group', quote=True) def test_reply_photo(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_photo = message.bot.send_photo + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id photo = kwargs['photo'] == 'test_photo' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and photo and reply + return id_ and photo and reply and check_shortcut_call(kwargs, send_photo) - monkeypatch.setattr(message.bot, 'send_photo', test) + assert check_shortcut_signature( + Message.reply_photo, Bot.send_photo, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_photo', make_assertion) assert message.reply_photo(photo='test_photo') assert message.reply_photo(photo='test_photo', quote=True) def test_reply_audio(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_audio = message.bot.send_audio + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id audio = kwargs['audio'] == 'test_audio' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and audio and reply + return id_ and audio and reply and check_shortcut_call(kwargs, send_audio) - monkeypatch.setattr(message.bot, 'send_audio', test) + assert check_shortcut_signature( + Message.reply_audio, Bot.send_audio, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_audio', make_assertion) assert message.reply_audio(audio='test_audio') assert message.reply_audio(audio='test_audio', quote=True) def test_reply_document(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_document = message.bot.send_document + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id document = kwargs['document'] == 'test_document' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and document and reply + return id_ and document and reply and check_shortcut_call(kwargs, send_document) - monkeypatch.setattr(message.bot, 'send_document', test) + assert check_shortcut_signature( + Message.reply_document, Bot.send_document, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_document', make_assertion) assert message.reply_document(document='test_document') assert message.reply_document(document='test_document', quote=True) def test_reply_animation(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_animation = message.bot.send_animation + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id animation = kwargs['animation'] == 'test_animation' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and animation and reply + return id_ and animation and reply and check_shortcut_call(kwargs, send_animation) - monkeypatch.setattr(message.bot, 'send_animation', test) + assert check_shortcut_signature( + Message.reply_animation, Bot.send_animation, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_animation', make_assertion) assert message.reply_animation(animation='test_animation') assert message.reply_animation(animation='test_animation', quote=True) def test_reply_sticker(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_sticker = message.bot.send_sticker + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id sticker = kwargs['sticker'] == 'test_sticker' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and sticker and reply + return id_ and sticker and reply and check_shortcut_call(kwargs, send_sticker) - monkeypatch.setattr(message.bot, 'send_sticker', test) + assert check_shortcut_signature( + Message.reply_sticker, Bot.send_sticker, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_sticker', make_assertion) assert message.reply_sticker(sticker='test_sticker') assert message.reply_sticker(sticker='test_sticker', quote=True) def test_reply_video(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_video = message.bot.send_video + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id video = kwargs['video'] == 'test_video' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and video and reply + return id_ and video and reply and check_shortcut_call(kwargs, send_video) - monkeypatch.setattr(message.bot, 'send_video', test) + assert check_shortcut_signature( + Message.reply_video, Bot.send_video, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_video', make_assertion) assert message.reply_video(video='test_video') assert message.reply_video(video='test_video', quote=True) def test_reply_video_note(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_video_note = message.bot.send_video_note + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id video_note = kwargs['video_note'] == 'test_video_note' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and video_note and reply + return id_ and video_note and reply and check_shortcut_call(kwargs, send_video_note) - monkeypatch.setattr(message.bot, 'send_video_note', test) + assert check_shortcut_signature( + Message.reply_video_note, Bot.send_video_note, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_video_note', make_assertion) assert message.reply_video_note(video_note='test_video_note') assert message.reply_video_note(video_note='test_video_note', quote=True) def test_reply_voice(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_voice = message.bot.send_voice + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id voice = kwargs['voice'] == 'test_voice' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and voice and reply + return id_ and voice and reply and check_shortcut_call(kwargs, send_voice) - monkeypatch.setattr(message.bot, 'send_voice', test) + assert check_shortcut_signature( + Message.reply_voice, Bot.send_voice, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_voice', make_assertion) assert message.reply_voice(voice='test_voice') assert message.reply_voice(voice='test_voice', quote=True) def test_reply_location(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_location = message.bot.send_location + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id location = kwargs['location'] == 'test_location' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and location and reply + return id_ and location and reply and check_shortcut_call(kwargs, send_location) - monkeypatch.setattr(message.bot, 'send_location', test) + assert check_shortcut_signature( + Message.reply_location, Bot.send_location, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_location', make_assertion) assert message.reply_location(location='test_location') assert message.reply_location(location='test_location', quote=True) def test_reply_venue(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_venue = message.bot.send_venue + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id venue = kwargs['venue'] == 'test_venue' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and venue and reply + return id_ and venue and reply and check_shortcut_call(kwargs, send_venue) - monkeypatch.setattr(message.bot, 'send_venue', test) + assert check_shortcut_signature( + Message.reply_venue, Bot.send_venue, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_venue', make_assertion) assert message.reply_venue(venue='test_venue') assert message.reply_venue(venue='test_venue', quote=True) def test_reply_contact(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_contact = message.bot.send_contact + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id contact = kwargs['contact'] == 'test_contact' if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and contact and reply + return id_ and contact and reply and check_shortcut_call(kwargs, send_contact) - monkeypatch.setattr(message.bot, 'send_contact', test) + assert check_shortcut_signature( + Message.reply_contact, Bot.send_contact, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'send_contact', make_assertion) assert message.reply_contact(contact='test_contact') assert message.reply_contact(contact='test_contact', quote=True) def test_reply_poll(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id - contact = kwargs['question'] == 'test_poll' + send_poll = message.bot.send_poll + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id + question = kwargs['question'] == 'test_poll' + options = kwargs['options'] == ['1', '2', '3'] if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and contact and reply + return ( + id_ and question and options and reply and check_shortcut_call(kwargs, send_poll) + ) - monkeypatch.setattr(message.bot, 'send_poll', test) - assert message.reply_poll(question='test_poll') - assert message.reply_poll(question='test_poll', quote=True) + assert check_shortcut_signature(Message.reply_poll, Bot.send_poll, ['chat_id'], ['quote']) + + monkeypatch.setattr(message.bot, 'send_poll', make_assertion) + assert message.reply_poll(question='test_poll', options=['1', '2', '3']) + assert message.reply_poll(question='test_poll', quote=True, options=['1', '2', '3']) def test_reply_dice(self, monkeypatch, message): - def test(*args, **kwargs): - id_ = args[0] == message.chat_id + send_dice = message.bot.send_dice + + def make_assertion(*_, **kwargs): + id_ = kwargs['chat_id'] == message.chat_id contact = kwargs['disable_notification'] is True if kwargs.get('reply_to_message_id') is not None: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return id_ and contact and reply + return id_ and contact and reply and check_shortcut_call(kwargs, send_dice) - monkeypatch.setattr(message.bot, 'send_dice', test) + assert check_shortcut_signature(Message.reply_dice, Bot.send_dice, ['chat_id'], ['quote']) + + monkeypatch.setattr(message.bot, 'send_dice', make_assertion) assert message.reply_dice(disable_notification=True) assert message.reply_dice(disable_notification=True, quote=True) - def test_forward(self, monkeypatch, message): - def test(*args, **kwargs): + @pytest.mark.parametrize('disable_notification', [False, True]) + def test_forward(self, monkeypatch, message, disable_notification): + forward_message = message.bot.forward_message + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == 123456 from_chat = kwargs['from_chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - if kwargs.get('disable_notification') is not None: - notification = kwargs['disable_notification'] is True - else: - notification = True - return chat_id and from_chat and message_id and notification + notification = kwargs['disable_notification'] == disable_notification + return ( + chat_id + and from_chat + and message_id + and notification + and check_shortcut_call(kwargs, forward_message) + ) - monkeypatch.setattr(message.bot, 'forward_message', test) - assert message.forward(123456) - assert message.forward(123456, disable_notification=True) + assert check_shortcut_signature( + Message.forward, Bot.forward_message, ['from_chat_id', 'message_id'], [] + ) + + monkeypatch.setattr(message.bot, 'forward_message', make_assertion) + assert message.forward(123456, disable_notification=disable_notification) assert not message.forward(635241) - def test_copy(self, monkeypatch, message): + @pytest.mark.parametrize('disable_notification', [True, False]) + def test_copy(self, monkeypatch, message, disable_notification): keyboard = [[1, 2]] + copy_message = message.bot.copy_message - def test(*args, **kwargs): + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == 123456 from_chat = kwargs['from_chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - if kwargs.get('disable_notification') is not None: - notification = kwargs['disable_notification'] is True - else: - notification = True + notification = kwargs['disable_notification'] == disable_notification if kwargs.get('reply_markup') is not None: reply_markup = kwargs['reply_markup'] is keyboard else: reply_markup = True - return chat_id and from_chat and message_id and notification and reply_markup + return ( + chat_id + and from_chat + and message_id + and notification + and reply_markup + and check_shortcut_call(kwargs, copy_message) + ) - monkeypatch.setattr(message.bot, 'copy_message', test) - assert message.copy(123456) - assert message.copy(123456, disable_notification=True) - assert message.copy(123456, reply_markup=keyboard) + assert check_shortcut_signature( + Message.copy, Bot.copy_message, ['from_chat_id', 'message_id'], [] + ) + + monkeypatch.setattr(message.bot, 'copy_message', make_assertion) + assert message.copy(123456, disable_notification=disable_notification) + assert message.copy( + 123456, reply_markup=keyboard, disable_notification=disable_notification + ) assert not message.copy(635241) - @pytest.mark.pfff - def test_reply_copy(self, monkeypatch, message): + @pytest.mark.parametrize('disable_notification', [True, False]) + def test_reply_copy(self, monkeypatch, message, disable_notification): keyboard = [[1, 2]] + copy_message = message.bot.copy_message - def test(*args, **kwargs): + def make_assertion(*_, **kwargs): chat_id = kwargs['from_chat_id'] == 123456 from_chat = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == 456789 - if kwargs.get('disable_notification') is not None: - notification = kwargs['disable_notification'] is True - else: - notification = True + notification = kwargs['disable_notification'] == disable_notification if kwargs.get('reply_markup') is not None: reply_markup = kwargs['reply_markup'] is keyboard else: @@ -994,155 +1124,300 @@ class TestMessage: reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True - return chat_id and from_chat and message_id and notification and reply_markup and reply + return ( + chat_id + and from_chat + and message_id + and notification + and reply_markup + and reply + and check_shortcut_call(kwargs, copy_message) + ) - monkeypatch.setattr(message.bot, 'copy_message', test) - assert message.reply_copy(123456, 456789) - assert message.reply_copy(123456, 456789, disable_notification=True) - assert message.reply_copy(123456, 456789, reply_markup=keyboard) - assert message.reply_copy(123456, 456789, quote=True) + assert check_shortcut_signature( + Message.reply_copy, Bot.copy_message, ['chat_id'], ['quote'] + ) + + monkeypatch.setattr(message.bot, 'copy_message', make_assertion) + assert message.reply_copy(123456, 456789, disable_notification=disable_notification) assert message.reply_copy( - 123456, 456789, quote=True, reply_to_message_id=message.message_id + 123456, 456789, reply_markup=keyboard, disable_notification=disable_notification + ) + assert message.reply_copy( + 123456, 456789, quote=True, disable_notification=disable_notification + ) + assert message.reply_copy( + 123456, + 456789, + quote=True, + reply_to_message_id=message.message_id, + disable_notification=disable_notification, ) def test_edit_text(self, monkeypatch, message): - def test(*args, **kwargs): + edit_message_text = message.bot.edit_message_text + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id text = kwargs['text'] == 'test' - return chat_id and message_id and text + return ( + chat_id and message_id and text and check_shortcut_call(kwargs, edit_message_text) + ) - monkeypatch.setattr(message.bot, 'edit_message_text', test) + assert check_shortcut_signature( + Message.edit_text, + Bot.edit_message_text, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'edit_message_text', make_assertion) assert message.edit_text(text='test') def test_edit_caption(self, monkeypatch, message): - def test(*args, **kwargs): + edit_message_caption = message.bot.edit_message_caption + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id caption = kwargs['caption'] == 'new caption' - return chat_id and message_id and caption + return ( + chat_id + and message_id + and caption + and check_shortcut_call(kwargs, edit_message_caption) + ) - monkeypatch.setattr(message.bot, 'edit_message_caption', test) + assert check_shortcut_signature( + Message.edit_caption, + Bot.edit_message_caption, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'edit_message_caption', make_assertion) assert message.edit_caption(caption='new caption') def test_edit_media(self, monkeypatch, message): - def test(*args, **kwargs): + edit_message_media = message.bot.edit_message_media + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id media = kwargs['media'] == 'my_media' - return chat_id and message_id and media + return ( + chat_id + and message_id + and media + and check_shortcut_call(kwargs, edit_message_media) + ) - monkeypatch.setattr(message.bot, 'edit_message_media', test) + assert check_shortcut_signature( + Message.edit_media, + Bot.edit_message_media, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'edit_message_media', make_assertion) assert message.edit_media('my_media') def test_edit_reply_markup(self, monkeypatch, message): - def test(*args, **kwargs): + edit_message_reply_markup = message.bot.edit_message_reply_markup + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id reply_markup = kwargs['reply_markup'] == [['1', '2']] - return chat_id and message_id and reply_markup + return ( + chat_id + and message_id + and reply_markup + and check_shortcut_call(kwargs, edit_message_reply_markup) + ) - monkeypatch.setattr(message.bot, 'edit_message_reply_markup', test) + assert check_shortcut_signature( + Message.edit_reply_markup, + Bot.edit_message_reply_markup, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'edit_message_reply_markup', make_assertion) assert message.edit_reply_markup(reply_markup=[['1', '2']]) def test_edit_live_location(self, monkeypatch, message): - def test(*args, **kwargs): + edit_message_live_location = message.bot.edit_message_live_location + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id latitude = kwargs['latitude'] == 1 longitude = kwargs['longitude'] == 2 - return chat_id and message_id and longitude and latitude + return ( + chat_id + and message_id + and longitude + and latitude + and check_shortcut_call(kwargs, edit_message_live_location) + ) - monkeypatch.setattr(message.bot, 'edit_message_live_location', test) + assert check_shortcut_signature( + Message.edit_live_location, + Bot.edit_message_live_location, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'edit_message_live_location', make_assertion) assert message.edit_live_location(latitude=1, longitude=2) def test_stop_live_location(self, monkeypatch, message): - def test(*args, **kwargs): + stop_message_live_location = message.bot.stop_message_live_location + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id + return ( + chat_id and message_id and check_shortcut_call(kwargs, stop_message_live_location) + ) - monkeypatch.setattr(message.bot, 'stop_message_live_location', test) + assert check_shortcut_signature( + Message.stop_live_location, + Bot.stop_message_live_location, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'stop_message_live_location', make_assertion) assert message.stop_live_location() def test_set_game_score(self, monkeypatch, message): - def test(*args, **kwargs): + set_game_score = message.bot.set_game_score + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 score = kwargs['score'] == 2 - return chat_id and message_id and user_id and score + return ( + chat_id + and message_id + and user_id + and score + and check_shortcut_call(kwargs, set_game_score) + ) - monkeypatch.setattr(message.bot, 'set_game_score', test) + assert check_shortcut_signature( + Message.set_game_score, + Bot.set_game_score, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'set_game_score', make_assertion) assert message.set_game_score(user_id=1, score=2) def test_get_game_high_scores(self, monkeypatch, message): - def test(*args, **kwargs): + get_game_high_scores = message.bot.get_game_high_scores + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id user_id = kwargs['user_id'] == 1 - return chat_id and message_id and user_id + return ( + chat_id + and message_id + and user_id + and check_shortcut_call(kwargs, get_game_high_scores) + ) - monkeypatch.setattr(message.bot, 'get_game_high_scores', test) - assert message.get_game_high_scores(user_id=1, score=2) + assert check_shortcut_signature( + Message.get_game_high_scores, + Bot.get_game_high_scores, + ['chat_id', 'message_id', 'inline_message_id'], + [], + ) + + monkeypatch.setattr(message.bot, 'get_game_high_scores', make_assertion) + assert message.get_game_high_scores(user_id=1) def test_delete(self, monkeypatch, message): - def test(*args, **kwargs): + delete_message = message.bot.delete_message + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id + return chat_id and message_id and check_shortcut_call(kwargs, delete_message) - monkeypatch.setattr(message.bot, 'delete_message', test) + assert check_shortcut_signature( + Message.delete, Bot.delete_message, ['chat_id', 'message_id'], [] + ) + + monkeypatch.setattr(message.bot, 'delete_message', make_assertion) assert message.delete() def test_stop_poll(self, monkeypatch, message): - def test(*args, **kwargs): + stop_poll = message.bot.stop_poll + + def make_assertion(*_, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id + return chat_id and message_id and check_shortcut_call(kwargs, stop_poll) - monkeypatch.setattr(message.bot, 'stop_poll', test) + assert check_shortcut_signature( + Message.stop_poll, Bot.stop_poll, ['chat_id', 'message_id'], [] + ) + + monkeypatch.setattr(message.bot, 'stop_poll', make_assertion) assert message.stop_poll() def test_pin(self, monkeypatch, message): + pin_chat_message = message.bot.pin_chat_message + def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id + return chat_id and message_id and check_shortcut_call(kwargs, pin_chat_message) + + assert check_shortcut_signature( + Message.pin, Bot.pin_chat_message, ['chat_id', 'message_id'], [] + ) monkeypatch.setattr(message.bot, 'pin_chat_message', make_assertion) assert message.pin() def test_unpin(self, monkeypatch, message): + unpin_chat_message = message.bot.unpin_chat_message + def make_assertion(*args, **kwargs): chat_id = kwargs['chat_id'] == message.chat_id message_id = kwargs['message_id'] == message.message_id - return chat_id and message_id + return chat_id and message_id and check_shortcut_call(kwargs, unpin_chat_message) + + assert check_shortcut_signature( + Message.unpin, Bot.unpin_chat_message, ['chat_id', 'message_id'], [] + ) monkeypatch.setattr(message.bot, 'unpin_chat_message', make_assertion) assert message.unpin() def test_default_quote(self, message): message.bot.defaults = Defaults() - kwargs = {} message.bot.defaults._quote = False - message._quote(kwargs) - assert 'reply_to_message_id' not in kwargs + assert message._quote(None, None) is None message.bot.defaults._quote = True - message._quote(kwargs) - assert 'reply_to_message_id' in kwargs + assert message._quote(None, None) == message.message_id - kwargs = {} message.bot.defaults._quote = None message.chat.type = Chat.PRIVATE - message._quote(kwargs) - assert 'reply_to_message_id' not in kwargs + assert message._quote(None, None) is None message.chat.type = Chat.GROUP - message._quote(kwargs) - assert 'reply_to_message_id' in kwargs + assert message._quote(None, None) def test_equality(self): id_ = 1 diff --git a/tests/test_passport.py b/tests/test_passport.py index 01cc66461..0481e83d1 100644 --- a/tests/test_passport.py +++ b/tests/test_passport.py @@ -442,8 +442,8 @@ class TestPassport: selfie = passport_data.decrypted_data[1].selfie # NOTE: file_unique_id is not used in the get_file method, so it is passed directly - def get_file(*args, **kwargs): - return File(args[0], selfie.file_unique_id) + def get_file(*_, **kwargs): + return File(kwargs['file_id'], selfie.file_unique_id) monkeypatch.setattr(passport_data.bot, 'get_file', get_file) file = selfie.get_file() diff --git a/tests/test_passportfile.py b/tests/test_passportfile.py index b199bd719..b7ba51e4b 100644 --- a/tests/test_passportfile.py +++ b/tests/test_passportfile.py @@ -19,16 +19,18 @@ import pytest -from telegram import PassportFile, PassportElementError +from telegram import PassportFile, PassportElementError, Bot, File +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='class') -def passport_file(): +def passport_file(bot): return PassportFile( file_id=TestPassportFile.file_id, file_unique_id=TestPassportFile.file_unique_id, file_size=TestPassportFile.file_size, file_date=TestPassportFile.file_date, + bot=bot, ) @@ -53,6 +55,21 @@ class TestPassportFile: assert passport_file_dict['file_size'] == passport_file.file_size assert passport_file_dict['file_date'] == passport_file.file_date + def test_get_file_instance_method(self, monkeypatch, passport_file): + get_file = passport_file.bot.get_file + + def make_assertion(*_, **kwargs): + result = kwargs['file_id'] == passport_file.file_id and check_shortcut_call( + kwargs, get_file + ) + # we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File + return File(file_id=result, file_unique_id=result) + + assert check_shortcut_signature(PassportFile.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr(passport_file.bot, 'get_file', make_assertion) + assert passport_file.get_file().file_id == 'True' + def test_equality(self): a = PassportFile(self.file_id, self.file_unique_id, self.file_size, self.file_date) b = PassportFile('', self.file_unique_id, self.file_size, self.file_date) diff --git a/tests/test_photo.py b/tests/test_photo.py index e423f76f2..6aa5863d0 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -23,10 +23,10 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import Sticker, TelegramError, PhotoSize, InputFile, MessageEntity +from telegram import Sticker, TelegramError, PhotoSize, InputFile, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown -from tests.conftest import expect_bad_request +from tests.conftest import expect_bad_request, check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -466,10 +466,14 @@ class TestPhoto: bot.send_photo(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, photo): - def test(*args, **kwargs): - return args[1] == photo.file_id + get_file = photo.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == photo.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(PhotoSize.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert photo.get_file() def test_equality(self, photo): diff --git a/tests/test_precheckoutquery.py b/tests/test_precheckoutquery.py index 64ca26780..96b4ccbfa 100644 --- a/tests/test_precheckoutquery.py +++ b/tests/test_precheckoutquery.py @@ -19,7 +19,8 @@ import pytest -from telegram import Update, User, PreCheckoutQuery, OrderInfo +from telegram import Update, User, PreCheckoutQuery, OrderInfo, Bot +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='class') @@ -79,11 +80,19 @@ class TestPreCheckoutQuery: assert pre_checkout_query_dict['order_info'] == pre_checkout_query.order_info.to_dict() def test_answer(self, monkeypatch, pre_checkout_query): - def test(*args, **kwargs): - return args[0] == pre_checkout_query.id + answer_pre_checkout_query = pre_checkout_query.bot.answer_pre_checkout_query - monkeypatch.setattr(pre_checkout_query.bot, 'answer_pre_checkout_query', test) - assert pre_checkout_query.answer() + def make_assertion(*_, **kwargs): + return kwargs[ + 'pre_checkout_query_id' + ] == pre_checkout_query.id and check_shortcut_call(kwargs, answer_pre_checkout_query) + + assert check_shortcut_signature( + PreCheckoutQuery.answer, Bot.answer_pre_checkout_query, ['pre_checkout_query_id'], [] + ) + + monkeypatch.setattr(pre_checkout_query.bot, 'answer_pre_checkout_query', make_assertion) + assert pre_checkout_query.answer(ok=True) def test_equality(self): a = PreCheckoutQuery( diff --git a/tests/test_shippingquery.py b/tests/test_shippingquery.py index c0c9cfc7f..4c81ad147 100644 --- a/tests/test_shippingquery.py +++ b/tests/test_shippingquery.py @@ -19,7 +19,8 @@ import pytest -from telegram import Update, User, ShippingAddress, ShippingQuery +from telegram import Update, User, ShippingAddress, ShippingQuery, Bot +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='class') @@ -64,11 +65,19 @@ class TestShippingQuery: assert shipping_query_dict['shipping_address'] == shipping_query.shipping_address.to_dict() def test_answer(self, monkeypatch, shipping_query): - def test(*args, **kwargs): - return args[0] == shipping_query.id + answer_shipping_query = shipping_query.bot.answer_shipping_query - monkeypatch.setattr(shipping_query.bot, 'answer_shipping_query', test) - assert shipping_query.answer() + def make_assertion(*_, **kwargs): + return kwargs['shipping_query_id'] == shipping_query.id and check_shortcut_call( + kwargs, answer_shipping_query + ) + + assert check_shortcut_signature( + ShippingQuery.answer, Bot.answer_shipping_query, ['shipping_query_id'], [] + ) + + monkeypatch.setattr(shipping_query.bot, 'answer_shipping_query', make_assertion) + assert shipping_query.answer(ok=True) def test_equality(self): a = ShippingQuery(self.id_, self.from_user, self.invoice_payload, self.shipping_address) diff --git a/tests/test_sticker.py b/tests/test_sticker.py index 6d50449d5..d88cb0551 100644 --- a/tests/test_sticker.py +++ b/tests/test_sticker.py @@ -24,8 +24,9 @@ from time import sleep import pytest from flaky import flaky -from telegram import Sticker, PhotoSize, TelegramError, StickerSet, Audio, MaskPosition +from telegram import Sticker, PhotoSize, TelegramError, StickerSet, Audio, MaskPosition, Bot from telegram.error import BadRequest +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -505,10 +506,14 @@ class TestStickerSet: assert test_flag def test_get_file_instance_method(self, monkeypatch, sticker): - def test(*args, **kwargs): - return args[1] == sticker.file_id + get_file = sticker.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == sticker.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Sticker.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert sticker.get_file() def test_equality(self): diff --git a/tests/test_user.py b/tests/test_user.py index 069ab10df..fc129a74c 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -18,8 +18,9 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. import pytest -from telegram import Update, User +from telegram import Update, User, Bot from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_signature, check_shortcut_call @pytest.fixture(scope='function') @@ -127,177 +128,381 @@ class TestUser: user.username = None assert user.link is None - def test_get_profile_photos(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id + def test_instance_method_get_profile_photos(self, monkeypatch, user): + get_profile_photos = user.bot.get_user_profile_photos - monkeypatch.setattr(user.bot, 'get_user_profile_photos', test) + def make_assertion(*_, **kwargs): + return kwargs['user_id'] == user.id and check_shortcut_call(kwargs, get_profile_photos) + + assert check_shortcut_signature( + User.get_profile_photos, Bot.get_user_profile_photos, ['user_id'], [] + ) + + monkeypatch.setattr(user.bot, 'get_user_profile_photos', make_assertion) assert user.get_profile_photos() - def test_pin_message(self, monkeypatch, user): - def make_assertion(*args, **kwargs): - return args[0] == user.id + def test_instance_method_pin_message(self, monkeypatch, user): + pin_message = user.bot.pin_chat_message + + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, pin_message) + + assert check_shortcut_signature(User.pin_message, Bot.pin_chat_message, ['chat_id'], []) monkeypatch.setattr(user.bot, 'pin_chat_message', make_assertion) - assert user.pin_message() + assert user.pin_message(1) - def test_unpin_message(self, monkeypatch, user): - def make_assertion(*args, **kwargs): - return args[0] == user.id + def test_instance_method_unpin_message(self, monkeypatch, user): + unpin_message = user.bot.unpin_chat_message + + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, unpin_message) + + assert check_shortcut_signature( + User.unpin_message, Bot.unpin_chat_message, ['chat_id'], [] + ) monkeypatch.setattr(user.bot, 'unpin_chat_message', make_assertion) assert user.unpin_message() - def test_unpin_all_messages(self, monkeypatch, user): - def make_assertion(*args, **kwargs): - return args[0] == user.id + def test_instance_method_unpin_all_messages(self, monkeypatch, user): + unpin_all_messages = user.bot.unpin_all_chat_messages + + def make_assertion(*_, **kwargs): + return kwargs['chat_id'] == user.id and check_shortcut_call(kwargs, unpin_all_messages) + + assert check_shortcut_signature( + User.unpin_all_messages, Bot.unpin_all_chat_messages, ['chat_id'], [] + ) monkeypatch.setattr(user.bot, 'unpin_all_chat_messages', make_assertion) assert user.unpin_all_messages() def test_instance_method_send_message(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test' + send_message = user.bot.send_message - monkeypatch.setattr(user.bot, 'send_message', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['text'] == 'test' + and check_shortcut_call(kwargs, send_message) + ) + + assert check_shortcut_signature(User.send_message, Bot.send_message, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_message', make_assertion) assert user.send_message('test') def test_instance_method_send_photo(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_photo' + send_photo = user.bot.send_photo - monkeypatch.setattr(user.bot, 'send_photo', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['photo'] == 'test_photo' + and check_shortcut_call(kwargs, send_photo) + ) + + assert check_shortcut_signature(User.send_photo, Bot.send_photo, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_photo', make_assertion) assert user.send_photo('test_photo') def test_instance_method_send_media_group(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_media_group' + send_media_group = user.bot.send_media_group - monkeypatch.setattr(user.bot, 'send_media_group', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['media'] == 'test_media_group' + and check_shortcut_call(kwargs, send_media_group) + ) + + assert check_shortcut_signature( + User.send_media_group, Bot.send_media_group, ['chat_id'], [] + ) + + monkeypatch.setattr(user.bot, 'send_media_group', make_assertion) assert user.send_media_group('test_media_group') def test_instance_method_send_audio(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_audio' + send_audio = user.bot.send_audio - monkeypatch.setattr(user.bot, 'send_audio', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['audio'] == 'test_audio' + and check_shortcut_call(kwargs, send_audio) + ) + + assert check_shortcut_signature(User.send_audio, Bot.send_audio, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_audio', make_assertion) assert user.send_audio('test_audio') def test_instance_method_send_chat_action(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_chat_action' + send_chat_action = user.bot.send_chat_action - monkeypatch.setattr(user.bot, 'send_chat_action', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['action'] == 'test_chat_action' + and check_shortcut_call(kwargs, send_chat_action) + ) + + assert check_shortcut_signature( + User.send_chat_action, Bot.send_chat_action, ['chat_id'], [] + ) + + monkeypatch.setattr(user.bot, 'send_chat_action', make_assertion) assert user.send_chat_action('test_chat_action') def test_instance_method_send_contact(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_contact' + send_contact = user.bot.send_contact - monkeypatch.setattr(user.bot, 'send_contact', test) - assert user.send_contact('test_contact') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['phone_number'] == 'test_contact' + and check_shortcut_call(kwargs, send_contact) + ) + + assert check_shortcut_signature(User.send_contact, Bot.send_contact, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_contact', make_assertion) + assert user.send_contact(phone_number='test_contact') def test_instance_method_send_dice(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_dice' + send_dice = user.bot.send_dice - monkeypatch.setattr(user.bot, 'send_dice', test) - assert user.send_dice('test_dice') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['emoji'] == 'test_dice' + and check_shortcut_call(kwargs, send_dice) + ) + + assert check_shortcut_signature(User.send_dice, Bot.send_dice, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_dice', make_assertion) + assert user.send_dice(emoji='test_dice') def test_instance_method_send_document(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_document' + send_document = user.bot.send_document - monkeypatch.setattr(user.bot, 'send_document', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['document'] == 'test_document' + and check_shortcut_call(kwargs, send_document) + ) + + assert check_shortcut_signature(User.send_document, Bot.send_document, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_document', make_assertion) assert user.send_document('test_document') def test_instance_method_send_game(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_game' + send_game = user.bot.send_game - monkeypatch.setattr(user.bot, 'send_game', test) - assert user.send_game('test_game') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['game_short_name'] == 'test_game' + and check_shortcut_call(kwargs, send_game) + ) + + assert check_shortcut_signature(User.send_game, Bot.send_game, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_game', make_assertion) + assert user.send_game(game_short_name='test_game') def test_instance_method_send_invoice(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_invoice' + send_invoice = user.bot.send_invoice - monkeypatch.setattr(user.bot, 'send_invoice', test) - assert user.send_invoice('test_invoice') + def make_assertion(*_, **kwargs): + title = kwargs['title'] == 'title' + description = kwargs['description'] == 'description' + payload = kwargs['payload'] == 'payload' + provider_token = kwargs['provider_token'] == 'provider_token' + start_parameter = kwargs['start_parameter'] == 'start_parameter' + currency = kwargs['currency'] == 'currency' + prices = kwargs['prices'] == 'prices' + args = ( + title + and description + and payload + and provider_token + and start_parameter + and currency + and prices + ) + return ( + kwargs['chat_id'] == user.id and args and check_shortcut_call(kwargs, send_invoice) + ) + + assert check_shortcut_signature(User.send_invoice, Bot.send_invoice, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_invoice', make_assertion) + assert user.send_invoice( + 'title', + 'description', + 'payload', + 'provider_token', + 'start_parameter', + 'currency', + 'prices', + ) def test_instance_method_send_location(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_location' + send_location = user.bot.send_location - monkeypatch.setattr(user.bot, 'send_location', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['latitude'] == 'test_location' + and check_shortcut_call(kwargs, send_location) + ) + + assert check_shortcut_signature(User.send_location, Bot.send_location, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_location', make_assertion) assert user.send_location('test_location') def test_instance_method_send_sticker(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_sticker' + send_sticker = user.bot.send_sticker - monkeypatch.setattr(user.bot, 'send_sticker', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['sticker'] == 'test_sticker' + and check_shortcut_call(kwargs, send_sticker) + ) + + assert check_shortcut_signature(User.send_sticker, Bot.send_sticker, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_sticker', make_assertion) assert user.send_sticker('test_sticker') def test_instance_method_send_video(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_video' + send_video = user.bot.send_video - monkeypatch.setattr(user.bot, 'send_video', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['video'] == 'test_video' + and check_shortcut_call(kwargs, send_video) + ) + + assert check_shortcut_signature(User.send_video, Bot.send_video, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_video', make_assertion) assert user.send_video('test_video') def test_instance_method_send_venue(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_venue' + send_venue = user.bot.send_venue - monkeypatch.setattr(user.bot, 'send_venue', test) - assert user.send_venue('test_venue') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['title'] == 'test_venue' + and check_shortcut_call(kwargs, send_venue) + ) + + assert check_shortcut_signature(User.send_venue, Bot.send_venue, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_venue', make_assertion) + assert user.send_venue(title='test_venue') def test_instance_method_send_video_note(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_video_note' + send_video_note = user.bot.send_video_note - monkeypatch.setattr(user.bot, 'send_video_note', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['video_note'] == 'test_video_note' + and check_shortcut_call(kwargs, send_video_note) + ) + + assert check_shortcut_signature(User.send_video_note, Bot.send_video_note, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_video_note', make_assertion) assert user.send_video_note('test_video_note') def test_instance_method_send_voice(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_voice' + send_voice = user.bot.send_voice - monkeypatch.setattr(user.bot, 'send_voice', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['voice'] == 'test_voice' + and check_shortcut_call(kwargs, send_voice) + ) + + assert check_shortcut_signature(User.send_voice, Bot.send_voice, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_voice', make_assertion) assert user.send_voice('test_voice') def test_instance_method_send_animation(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_animation' + send_animation = user.bot.send_animation - monkeypatch.setattr(user.bot, 'send_animation', test) + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['animation'] == 'test_animation' + and check_shortcut_call(kwargs, send_animation) + ) + + assert check_shortcut_signature(User.send_animation, Bot.send_animation, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_animation', make_assertion) assert user.send_animation('test_animation') def test_instance_method_send_poll(self, monkeypatch, user): - def test(*args, **kwargs): - return args[0] == user.id and args[1] == 'test_poll' + send_poll = user.bot.send_poll - monkeypatch.setattr(user.bot, 'send_poll', test) - assert user.send_poll('test_poll') + def make_assertion(*_, **kwargs): + return ( + kwargs['chat_id'] == user.id + and kwargs['question'] == 'test_poll' + and check_shortcut_call(kwargs, send_poll) + ) + + assert check_shortcut_signature(User.send_poll, Bot.send_poll, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'send_poll', make_assertion) + assert user.send_poll(question='test_poll', options=[1, 2]) def test_instance_method_send_copy(self, monkeypatch, user): - def test(*args, **kwargs): - assert args[0] == 'test_copy' - assert kwargs['chat_id'] == user.id - return args + send_copy = user.bot.copy_message - monkeypatch.setattr(user.bot, 'copy_message', test) - assert user.send_copy('test_copy') + def make_assertion(*_, **kwargs): + user_id = kwargs['chat_id'] == user.id + message_id = kwargs['message_id'] == 'message_id' + from_chat_id = kwargs['from_chat_id'] == 'from_chat_id' + return ( + from_chat_id and message_id and user_id and check_shortcut_call(kwargs, send_copy) + ) + + assert check_shortcut_signature(User.send_copy, Bot.copy_message, ['chat_id'], []) + + monkeypatch.setattr(user.bot, 'copy_message', make_assertion) + assert user.send_copy(from_chat_id='from_chat_id', message_id='message_id') def test_instance_method_copy_message(self, monkeypatch, user): - def test(*args, **kwargs): - assert args[0] == 'test_copy' - assert kwargs['from_chat_id'] == user.id - return args + copy_message = user.bot.copy_message - monkeypatch.setattr(user.bot, 'copy_message', test) - assert user.copy_message('test_copy') + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == 'chat_id' + message_id = kwargs['message_id'] == 'message_id' + user_id = kwargs['from_chat_id'] == user.id + return chat_id and message_id and user_id and check_shortcut_call(kwargs, copy_message) + + assert check_shortcut_signature(User.copy_message, Bot.copy_message, ['from_chat_id'], []) + + monkeypatch.setattr(user.bot, 'copy_message', make_assertion) + assert user.copy_message(chat_id='chat_id', message_id='message_id') def test_mention_html(self, user): expected = u'{}' diff --git a/tests/test_video.py b/tests/test_video.py index e89553027..9fabaaea2 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -22,9 +22,10 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import Video, TelegramError, Voice, PhotoSize, MessageEntity +from telegram import Video, TelegramError, Voice, PhotoSize, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -329,10 +330,14 @@ class TestVideo: bot.send_video(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, video): - def test(*args, **kwargs): - return args[1] == video.file_id + get_file = video.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == video.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Video.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert video.get_file() def test_equality(self, video): diff --git a/tests/test_videonote.py b/tests/test_videonote.py index f2b23be12..3e3a5eb54 100644 --- a/tests/test_videonote.py +++ b/tests/test_videonote.py @@ -22,8 +22,9 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import VideoNote, TelegramError, Voice, PhotoSize +from telegram import VideoNote, TelegramError, Voice, PhotoSize, Bot from telegram.error import BadRequest +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -227,10 +228,16 @@ class TestVideoNote: bot.send_video_note(chat_id=chat_id) def test_get_file_instance_method(self, monkeypatch, video_note): - def test(*args, **kwargs): - return args[1] == video_note.file_id + get_file = video_note.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == video_note.file_id and check_shortcut_call( + kwargs, get_file + ) + + assert check_shortcut_signature(VideoNote.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert video_note.get_file() def test_equality(self, video_note): diff --git a/tests/test_voice.py b/tests/test_voice.py index 0523c6d24..a8af4e0f7 100644 --- a/tests/test_voice.py +++ b/tests/test_voice.py @@ -22,9 +22,10 @@ from pathlib import Path import pytest from flaky import flaky -from telegram import Audio, Voice, TelegramError, MessageEntity +from telegram import Audio, Voice, TelegramError, MessageEntity, Bot from telegram.error import BadRequest from telegram.utils.helpers import escape_markdown +from tests.conftest import check_shortcut_call, check_shortcut_signature @pytest.fixture(scope='function') @@ -283,10 +284,14 @@ class TestVoice: bot.sendVoice(chat_id) def test_get_file_instance_method(self, monkeypatch, voice): - def test(*args, **kwargs): - return args[1] == voice.file_id + get_file = voice.bot.get_file - monkeypatch.setattr('telegram.Bot.get_file', test) + def make_assertion(*_, **kwargs): + return kwargs['file_id'] == voice.file_id and check_shortcut_call(kwargs, get_file) + + assert check_shortcut_signature(Voice.get_file, Bot.get_file, ['file_id'], []) + + monkeypatch.setattr('telegram.Bot.get_file', make_assertion) assert voice.get_file() def test_equality(self, voice):