From dab75fb9636b0b7c2aba899f6a6023c552bab614 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:33:56 +0100 Subject: [PATCH] Add `Message.reply_paid_media` (#4551) --- telegram/_message.py | 72 +++++++++++++++++++++++++++++++++++++++++++ tests/test_message.py | 66 ++++++++++++++++++++++++++++++++------- 2 files changed, 127 insertions(+), 11 deletions(-) diff --git a/telegram/_message.py b/telegram/_message.py index 6390c8b05..33f1bc150 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -105,6 +105,7 @@ if TYPE_CHECKING: InputMediaDocument, InputMediaPhoto, InputMediaVideo, + InputPaidMedia, InputPollOption, LabeledPrice, MessageId, @@ -3668,6 +3669,77 @@ class Message(MaybeInaccessibleMessage): allow_paid_broadcast=allow_paid_broadcast, ) + async def reply_paid_media( + self, + star_count: int, + media: Sequence["InputPaidMedia"], + caption: Optional[str] = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Optional[Sequence["MessageEntity"]] = None, + show_caption_above_media: Optional[bool] = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + protect_content: ODVInput[bool] = DEFAULT_NONE, + reply_parameters: Optional["ReplyParameters"] = None, + reply_markup: Optional[ReplyMarkup] = None, + payload: Optional[str] = None, + allow_paid_broadcast: Optional[bool] = None, + *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + do_quote: Optional[Union[bool, _ReplyKwargs]] = None, + read_timeout: ODVInput[float] = DEFAULT_NONE, + write_timeout: ODVInput[float] = DEFAULT_NONE, + connect_timeout: ODVInput[float] = DEFAULT_NONE, + pool_timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: Optional[JSONDict] = None, + ) -> "Message": + """Shortcut for:: + + await bot.send_paid_media( + chat_id=message.chat.id, + business_connection_id=message.business_connection_id, + *args, + **kwargs + ) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_paid_media`. + + .. versionadded:: NEXT.VERSION + + Keyword Args: + do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote| + Mutually exclusive with :paramref:`quote`. + + Returns: + :class:`telegram.Message`: On success, the sent message is returned. + + """ + chat_id, effective_reply_parameters = await self._parse_quote_arguments( + do_quote, None, reply_to_message_id, reply_parameters + ) + return await self.get_bot().send_paid_media( + chat_id=chat_id, + caption=caption, + star_count=star_count, + media=media, + payload=payload, + business_connection_id=self.business_connection_id, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_parameters=effective_reply_parameters, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + read_timeout=read_timeout, + write_timeout=write_timeout, + connect_timeout=connect_timeout, + pool_timeout=pool_timeout, + api_kwargs=api_kwargs, + protect_content=protect_content, + show_caption_above_media=show_caption_above_media, + allow_paid_broadcast=allow_paid_broadcast, + ) + async def edit_text( self, text: str, diff --git a/tests/test_message.py b/tests/test_message.py index 602d1e1f8..a9fb9a46c 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -16,6 +16,7 @@ # # 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 contextlib from copy import copy from datetime import datetime @@ -39,6 +40,7 @@ from telegram import ( GiveawayCompleted, GiveawayCreated, GiveawayWinners, + InputPaidMediaPhoto, Invoice, LinkPreviewOptions, Location, @@ -447,11 +449,14 @@ class TestMessageWithoutRequest(MessageTestBase): """Used in testing reply_* below. Makes sure that quote and do_quote are handled correctly """ - with pytest.raises(ValueError, match="`quote` and `do_quote` are mutually exclusive"): - await method(*args, quote=True, do_quote=True) + with contextlib.suppress(TypeError): + # for newer methods that don't have the deprecated argument + with pytest.raises(ValueError, match="`quote` and `do_quote` are mutually exclusive"): + await method(*args, quote=True, do_quote=True) - with pytest.warns(PTBDeprecationWarning, match="`quote` parameter is deprecated"): - await method(*args, quote=True) + # for newer methods that don't have the deprecated argument + with pytest.warns(PTBDeprecationWarning, match="`quote` parameter is deprecated"): + await method(*args, quote=True) with pytest.raises( ValueError, @@ -465,13 +470,16 @@ class TestMessageWithoutRequest(MessageTestBase): monkeypatch.setattr(message.get_bot(), bot_method_name, make_assertion) for param in ("quote", "do_quote"): - chat_id, reply_parameters = await method(*args, **{param: True}) - if chat_id != message.chat.id: - pytest.fail(f"chat_id is {chat_id} but should be {message.chat.id}") - if reply_parameters is None or reply_parameters.message_id != message.message_id: - pytest.fail( - f"reply_parameters is {reply_parameters} but should be {message.message_id}" - ) + with contextlib.suppress(TypeError): + # for newer methods that don't have the deprecated argument + chat_id, reply_parameters = await method(*args, **{param: True}) + if chat_id != message.chat.id: + pytest.fail(f"chat_id is {chat_id} but should be {message.chat.id}") + if reply_parameters is None or reply_parameters.message_id != message.message_id: + pytest.fail( + f"reply_parameters is {reply_parameters} " + "but should be {message.message_id}" + ) input_chat_id = object() input_reply_parameters = ReplyParameters(message_id=1, chat_id=42) @@ -2349,6 +2357,42 @@ class TestMessageWithoutRequest(MessageTestBase): monkeypatch, ) + async def test_reply_paid_media(self, monkeypatch, message): + async def make_assertion(*_, **kwargs): + id_ = kwargs["chat_id"] == message.chat_id + media = kwargs["media"][0].media == "media" + star_count = kwargs["star_count"] == 5 + return id_ and media and star_count + + assert check_shortcut_signature( + Message.reply_paid_media, + Bot.send_paid_media, + ["chat_id", "reply_to_message_id", "business_connection_id"], + ["do_quote", "reply_to_message_id"], + ) + assert await check_shortcut_call( + message.reply_paid_media, + message.get_bot(), + "send_paid_media", + skip_params=["reply_to_message_id"], + shortcut_kwargs=["business_connection_id"], + ) + assert await check_defaults_handling( + message.reply_paid_media, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) + + monkeypatch.setattr(message.get_bot(), "send_paid_media", make_assertion) + assert await message.reply_paid_media( + star_count=5, media=[InputPaidMediaPhoto(media="media")] + ) + await self.check_quote_parsing( + message, + message.reply_paid_media, + "send_paid_media", + ["test", [InputPaidMediaPhoto(media="media")]], + monkeypatch, + ) + async def test_edit_text(self, monkeypatch, message): async def make_assertion(*_, **kwargs): chat_id = kwargs["chat_id"] == message.chat_id