diff --git a/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml b/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml index 771c28c63ba..94cef0849eb 100644 --- a/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml +++ b/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml @@ -2,4 +2,5 @@ features = "Full Support for Bot API 9.2" pull_requests = [ { uid = "4911", author_uid = "aelkheir", closes_threads = ["4910"] }, + { uid = "4912", author_uid = "aelkheir" }, ] diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index acfaf866f46..a792aedee58 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -168,6 +168,8 @@ Available Types telegram.storyareatypesuggestedreaction telegram.storyareatypeuniquegift telegram.storyareatypeweather + telegram.suggestedpostparameters + telegram.suggestedpostprice telegram.switchinlinequerychosenchat telegram.telegramobject telegram.textquote diff --git a/docs/source/telegram.suggestedpostparameters.rst b/docs/source/telegram.suggestedpostparameters.rst new file mode 100644 index 00000000000..5111d8fdd48 --- /dev/null +++ b/docs/source/telegram.suggestedpostparameters.rst @@ -0,0 +1,6 @@ +SuggestedPostParameters +======================= + +.. autoclass:: telegram.SuggestedPostParameters + :members: + :show-inheritance: diff --git a/docs/source/telegram.suggestedpostprice.rst b/docs/source/telegram.suggestedpostprice.rst new file mode 100644 index 00000000000..f5034e8f047 --- /dev/null +++ b/docs/source/telegram.suggestedpostprice.rst @@ -0,0 +1,6 @@ +SuggestedPostPrice +================== + +.. autoclass:: telegram.SuggestedPostPrice + :members: + :show-inheritance: diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index c161278591a..35b387e2e54 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -96,6 +96,8 @@ .. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits `__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance. +.. |suggested_post_parameters| replace:: An object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined. + .. |tz-naive-dtms| replace:: For timezone naive :obj:`datetime.datetime` objects, the default timezone of the bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. .. |org-verify| replace:: `on behalf of the organization `__ diff --git a/src/telegram/__init__.py b/src/telegram/__init__.py index b0277a7e77a..5cf89142c5e 100644 --- a/src/telegram/__init__.py +++ b/src/telegram/__init__.py @@ -264,6 +264,8 @@ "StoryAreaTypeUniqueGift", "StoryAreaTypeWeather", "SuccessfulPayment", + "SuggestedPostParameters", + "SuggestedPostPrice", "SwitchInlineQueryChosenChat", "TelegramObject", "TextQuote", @@ -571,6 +573,7 @@ StoryAreaTypeUniqueGift, StoryAreaTypeWeather, ) +from ._suggestedpost import SuggestedPostParameters, SuggestedPostPrice from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat from ._telegramobject import TelegramObject from ._uniquegift import ( diff --git a/src/telegram/_bot.py b/src/telegram/_bot.py index 33fba87e798..03c3a03992e 100644 --- a/src/telegram/_bot.py +++ b/src/telegram/_bot.py @@ -136,6 +136,7 @@ PassportElementError, ShippingOption, StoryArea, + SuggestedPostParameters, ) BT = TypeVar("BT", bound="Bot") @@ -758,6 +759,7 @@ async def _send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -808,6 +810,7 @@ async def _send_message( "protect_content": protect_content, "reply_markup": reply_markup, "reply_parameters": reply_parameters, + "suggested_post_parameters": suggested_post_parameters, } ) @@ -1003,6 +1006,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1057,6 +1061,10 @@ async def send_message( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1116,6 +1124,7 @@ async def send_message( reply_parameters=reply_parameters, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -1232,6 +1241,7 @@ async def forward_message( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1267,6 +1277,11 @@ async def forward_message( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): An + object containing the parameters of the suggested post to send; for direct messages + chats only. + + .. versionadded:: NEXT.VERSION Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -1287,6 +1302,7 @@ async def forward_message( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -1373,6 +1389,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1445,6 +1462,11 @@ async def send_photo( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1506,6 +1528,7 @@ async def send_photo( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -1527,6 +1550,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1609,6 +1633,10 @@ async def send_audio( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1672,6 +1700,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -1691,6 +1720,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1768,6 +1798,10 @@ async def send_document( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1827,6 +1861,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1842,6 +1877,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1899,6 +1935,10 @@ async def send_sticker( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1950,6 +1990,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1976,6 +2017,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2076,6 +2118,10 @@ async def send_video( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2144,6 +2190,7 @@ async def send_video( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -2161,6 +2208,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2237,6 +2285,10 @@ async def send_video_note( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2296,6 +2348,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -2319,6 +2372,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2406,6 +2460,10 @@ async def send_animation( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2471,6 +2529,7 @@ async def send_animation( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -2489,6 +2548,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2567,6 +2627,10 @@ async def send_voice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2627,6 +2691,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -2824,6 +2889,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2890,6 +2956,10 @@ async def send_location( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2961,6 +3031,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def edit_message_live_location( @@ -3148,6 +3219,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3206,6 +3278,10 @@ async def send_venue( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -3288,6 +3364,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_contact( @@ -3305,6 +3382,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3353,6 +3431,10 @@ async def send_contact( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -3426,6 +3508,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -5231,6 +5314,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -5351,6 +5435,10 @@ async def send_invoice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -5421,6 +5509,7 @@ async def send_invoice( api_kwargs=api_kwargs, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def answer_shipping_query( @@ -7707,6 +7796,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -7759,6 +7849,10 @@ async def send_dice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -7808,6 +7902,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def get_my_default_administrator_rights( @@ -8140,6 +8235,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -8194,6 +8290,10 @@ async def copy_message( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -8254,6 +8354,7 @@ async def copy_message( "show_caption_above_media": show_caption_above_media, "allow_paid_broadcast": allow_paid_broadcast, "video_start_timestamp": video_start_timestamp, + "suggested_post_parameters": suggested_post_parameters, } result = await self._post( @@ -10729,6 +10830,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -10775,6 +10877,10 @@ async def send_paid_media( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -10819,6 +10925,7 @@ async def send_paid_media( api_kwargs=api_kwargs, business_connection_id=business_connection_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def create_chat_subscription_invite_link( diff --git a/src/telegram/_callbackquery.py b/src/telegram/_callbackquery.py index 18b5980e6c6..666bdc03bde 100644 --- a/src/telegram/_callbackquery.py +++ b/src/telegram/_callbackquery.py @@ -42,6 +42,7 @@ MessageEntity, MessageId, ReplyParameters, + SuggestedPostParameters, ) @@ -871,6 +872,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -920,6 +922,7 @@ async def copy_message( reply_parameters=reply_parameters, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) MAX_ANSWER_TEXT_LENGTH: Final[int] = ( diff --git a/src/telegram/_chat.py b/src/telegram/_chat.py index 53e4934523b..64c6d640c05 100644 --- a/src/telegram/_chat.py +++ b/src/telegram/_chat.py @@ -71,6 +71,7 @@ PhotoSize, ReplyParameters, Sticker, + SuggestedPostParameters, UserChatBoosts, Venue, Video, @@ -1018,6 +1019,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1060,6 +1062,7 @@ async def send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def delete_message( @@ -1236,6 +1239,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1280,6 +1284,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_contact( @@ -1296,6 +1301,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1338,6 +1344,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -1358,6 +1365,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1404,6 +1412,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -1422,6 +1431,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1466,6 +1476,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_checklist( @@ -1527,6 +1538,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1564,6 +1576,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -1646,6 +1659,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1712,6 +1726,7 @@ async def send_invoice( reply_parameters=reply_parameters, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -1730,6 +1745,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1774,6 +1790,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -1796,6 +1813,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1844,6 +1862,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1858,6 +1877,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1896,6 +1916,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -1916,6 +1937,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1962,6 +1984,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1987,6 +2010,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2038,6 +2062,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -2054,6 +2079,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2096,6 +2122,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -2113,6 +2140,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2156,6 +2184,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -2249,6 +2278,7 @@ async def send_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2292,6 +2322,7 @@ async def send_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_message( @@ -2309,6 +2340,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2352,6 +2384,7 @@ async def copy_message( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_copies( @@ -2452,6 +2485,7 @@ async def forward_from( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2486,6 +2520,7 @@ async def forward_from( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_to( @@ -2496,6 +2531,7 @@ async def forward_to( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2531,6 +2567,7 @@ async def forward_to( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_messages_from( @@ -3456,6 +3493,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3499,6 +3537,7 @@ async def send_paid_media( business_connection_id=business_connection_id, payload=payload, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_gift( diff --git a/src/telegram/_message.py b/src/telegram/_message.py index 16a4cd65ea3..8c20f1a9e13 100644 --- a/src/telegram/_message.py +++ b/src/telegram/_message.py @@ -118,6 +118,7 @@ MessageId, MessageOrigin, ReactionType, + SuggestedPostParameters, TextQuote, ) @@ -1865,6 +1866,7 @@ async def reply_text( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1927,6 +1929,7 @@ async def reply_text( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_markdown( @@ -1941,6 +1944,7 @@ async def reply_markdown( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2009,6 +2013,7 @@ async def reply_markdown( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_markdown_v2( @@ -2023,6 +2028,7 @@ async def reply_markdown_v2( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2087,6 +2093,7 @@ async def reply_markdown_v2( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_html( @@ -2101,6 +2108,7 @@ async def reply_html( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2165,6 +2173,7 @@ async def reply_html( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_media_group( @@ -2259,6 +2268,7 @@ async def reply_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2323,6 +2333,7 @@ async def reply_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_audio( @@ -2342,6 +2353,7 @@ async def reply_audio( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2408,6 +2420,7 @@ async def reply_audio( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_document( @@ -2425,6 +2438,7 @@ async def reply_document( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2489,6 +2503,7 @@ async def reply_document( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_animation( @@ -2510,6 +2525,7 @@ async def reply_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2578,6 +2594,7 @@ async def reply_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_sticker( @@ -2591,6 +2608,7 @@ async def reply_sticker( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2649,6 +2667,7 @@ async def reply_sticker( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_video( @@ -2673,6 +2692,7 @@ async def reply_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2744,6 +2764,7 @@ async def reply_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_video_note( @@ -2759,6 +2780,7 @@ async def reply_video_note( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2821,6 +2843,7 @@ async def reply_video_note( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_voice( @@ -2837,6 +2860,7 @@ async def reply_voice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2900,6 +2924,7 @@ async def reply_voice( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_location( @@ -2917,6 +2942,7 @@ async def reply_location( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2981,6 +3007,7 @@ async def reply_location( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_venue( @@ -3000,6 +3027,7 @@ async def reply_venue( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3066,6 +3094,7 @@ async def reply_venue( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_contact( @@ -3081,6 +3110,7 @@ async def reply_contact( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3143,6 +3173,7 @@ async def reply_contact( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_poll( @@ -3250,6 +3281,7 @@ async def reply_dice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3307,6 +3339,7 @@ async def reply_dice( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_checklist( @@ -3511,6 +3544,7 @@ async def reply_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3598,6 +3632,7 @@ async def reply_invoice( message_thread_id=message_thread_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def forward( @@ -3607,6 +3642,7 @@ async def forward( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3645,6 +3681,7 @@ async def forward( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -3666,6 +3703,7 @@ async def copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3713,6 +3751,7 @@ async def copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_copy( @@ -3730,6 +3769,7 @@ async def reply_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3791,6 +3831,7 @@ async def reply_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_paid_media( @@ -3807,6 +3848,7 @@ async def reply_paid_media( reply_markup: Optional[ReplyMarkup] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3860,6 +3902,7 @@ async def reply_paid_media( protect_content=protect_content, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def edit_text( diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py new file mode 100644 index 00000000000..fc597e3aad1 --- /dev/null +++ b/src/telegram/_suggestedpost.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2025 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# 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 objects related to Telegram suggested posts.""" + +import datetime as dtm +from typing import TYPE_CHECKING, Literal, Optional + +from telegram._telegramobject import TelegramObject +from telegram._utils.argumentparsing import de_json_optional +from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp +from telegram._utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class SuggestedPostPrice(TelegramObject): + """ + Desribes the price of a suggested post. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`currency` and :attr:`amount` are equal. + + .. versionadded:: NEXT.VERSION + + Args: + currency (:obj:`str`): + Currency in which the post will be paid. Currently, must be one of ``“XTR”`` for + Telegram Stars or ``“TON”`` for toncoins. + amount (:obj:`int`): + The amount of the currency that will be paid for the post in the smallest units of the + currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must + be between :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_STARS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_STARS`, and price in + nanotoncoins must be between + :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_NANOTONCOINS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_NANOTONCOINS`. + + Attributes: + currency (:obj:`str`): + Currency in which the post will be paid. Currently, must be one of ``“XTR”`` for + Telegram Stars or ``“TON”`` for toncoins. + amount (:obj:`int`): + The amount of the currency that will be paid for the post in the smallest units of the + currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must + be between :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_STARS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_STARS`, and price in + nanotoncoins must be between + :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_NANOTONCOINS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_NANOTONCOINS`. + """ + + __slots__ = ("amount", "currency") + + def __init__( + self, + currency: Literal["XTR", "TON"], + amount: int, + *, + api_kwargs: Optional[JSONDict] = None, + ): + super().__init__(api_kwargs=api_kwargs) + self.currency: Literal["XTR", "TON"] = currency + self.amount: int = amount + + self._id_attrs = (self.currency, self.amount) + + self._freeze() + + +class SuggestedPostParameters(TelegramObject): + """ + Contains parameters of a post that is being suggested by the bot. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`price` and :attr:`send_date` are equal. + + .. versionadded:: NEXT.VERSION + + Args: + price (:class:`telegram.SuggestedPostPrice`, optional): + Proposed price for the post. If the field is omitted, then the post is unpaid. + send_date (:class:`datetime.datetime`, optional): + Proposed send date of the post. If specified, then the date + must be between :tg-const:`telegram.constants.SuggestedPost.MIN_SEND_DATE` + second and :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) + in the future. If the field is omitted, then the post can be published at any time + within :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) at + the sole discretion of the user who approves it. + |datetime_localization| + + Attributes: + price (:class:`telegram.SuggestedPostPrice`): + Optional. Proposed price for the post. If the field is omitted, then the post + is unpaid. + send_date (:class:`datetime.datetime`): + Optional. Proposed send date of the post. If specified, then the date + must be between :tg-const:`telegram.constants.SuggestedPost.MIN_SEND_DATE` + second and :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) + in the future. If the field is omitted, then the post can be published at any time + within :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) at + the sole discretion of the user who approves it. + |datetime_localization| + + """ + + __slots__ = ("price", "send_date") + + def __init__( + self, + price: Optional[SuggestedPostPrice] = None, + send_date: Optional[dtm.datetime] = None, + *, + api_kwargs: Optional[JSONDict] = None, + ): + super().__init__(api_kwargs=api_kwargs) + self.price: Optional[SuggestedPostPrice] = price + self.send_date: Optional[dtm.datetime] = send_date + + self._id_attrs = (self.price, self.send_date) + + self._freeze() + + @classmethod + def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostParameters": + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot) + + # Get the local timezone from the bot if it has defaults + loc_tzinfo = extract_tzinfo_from_defaults(bot) + + data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo) + + return super().de_json(data=data, bot=bot) diff --git a/src/telegram/_user.py b/src/telegram/_user.py index ca9cd637193..370f41b7d7c 100644 --- a/src/telegram/_user.py +++ b/src/telegram/_user.py @@ -61,6 +61,7 @@ PhotoSize, ReplyParameters, Sticker, + SuggestedPostParameters, UserChatBoosts, UserProfilePhotos, Venue, @@ -435,6 +436,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, disable_web_page_preview: Optional[bool] = None, @@ -480,6 +482,7 @@ async def send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def delete_message( @@ -562,6 +565,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -609,6 +613,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -689,6 +694,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -738,6 +744,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_chat_action( @@ -794,6 +801,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -839,6 +847,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_dice( @@ -852,6 +861,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -892,6 +902,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -910,6 +921,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -957,6 +969,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -1042,6 +1055,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1111,6 +1125,7 @@ async def send_invoice( message_thread_id=message_thread_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -1129,6 +1144,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1176,6 +1192,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -1198,6 +1215,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1249,6 +1267,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1263,6 +1282,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1304,6 +1324,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1329,6 +1350,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1383,6 +1405,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -1403,6 +1426,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1452,6 +1476,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -1468,6 +1493,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1513,6 +1539,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -1530,6 +1557,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1576,6 +1604,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -1752,6 +1781,7 @@ async def send_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1796,6 +1826,7 @@ async def send_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_message( @@ -1813,6 +1844,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1857,6 +1889,7 @@ async def copy_message( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_copies( @@ -1957,6 +1990,7 @@ async def forward_from( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1991,6 +2025,7 @@ async def forward_from( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_to( @@ -2001,6 +2036,7 @@ async def forward_to( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2036,6 +2072,7 @@ async def forward_to( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_messages_from( diff --git a/src/telegram/constants.py b/src/telegram/constants.py index 435f1d8684c..0fdd801c017 100644 --- a/src/telegram/constants.py +++ b/src/telegram/constants.py @@ -117,6 +117,7 @@ "StoryAreaTypeLimit", "StoryAreaTypeType", "StoryLimit", + "SuggestedPost", "TransactionPartnerType", "TransactionPartnerUser", "UniqueGiftInfoOrigin", @@ -3054,6 +3055,46 @@ class StoryLimit(StringEnum): :meth:`telegram.Bot.post_story`.""" +class SuggestedPost(IntEnum): + """This enum contains limitations for :class:`telegram.SuggestedPostPrice`\ +/:class:`telegram.SuggestedPostParameters`. The enum + members of this enumeration are instances of :class:`int` and can be treated as such. + + .. versionadded:: NEXT.VERSION + """ + + __slots__ = () + + MIN_PRICE_STARS = 5 + """:obj:`int`: Minimum number of Telegram Stars in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MAX_PRICE_STARS = 100_000 + """:obj:`int`: Maximum number of Telegram Stars in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MIN_PRICE_NANOTONCOINS = 10_000_000 + """:obj:`int`: Minimum number of nanotoncoins in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MAX_PRICE_NANOTONCOINS = 10_000_000_000_000 + """:obj:`int`: Maximum number of nanotoncoins in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MIN_SEND_DATE = 300 + """:obj:`int`: Minimum number of seconds in the future for + the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of + :class:`telegram.SuggestedPostParameters`.""" + MAX_SEND_DATE = 2_678_400 + """:obj:`int`: Maximum number of seconds in the future for + the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of + :class:`telegram.SuggestedPostParameters`.""" + + class TransactionPartnerType(StringEnum): """This enum contains the available types of :class:`telegram.TransactionPartner`. The enum members of this enumeration are instances of :class:`str` and can be treated as such. diff --git a/src/telegram/ext/_extbot.py b/src/telegram/ext/_extbot.py index 1f9e14644c9..32c0f245bd9 100644 --- a/src/telegram/ext/_extbot.py +++ b/src/telegram/ext/_extbot.py @@ -129,6 +129,7 @@ PassportElementError, ShippingOption, StoryArea, + SuggestedPostParameters, ) from telegram.ext import BaseRateLimiter, Defaults @@ -617,6 +618,7 @@ async def _send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -650,6 +652,7 @@ async def _send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) if isinstance(result, Message): self._insert_callback_data(result) @@ -829,6 +832,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -862,6 +866,7 @@ async def copy_message( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_messages( @@ -1768,6 +1773,7 @@ async def forward_message( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1784,6 +1790,7 @@ async def forward_message( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -2466,6 +2473,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2505,6 +2513,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -2526,6 +2535,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2563,6 +2573,7 @@ async def send_audio( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_chat_action( @@ -2606,6 +2617,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2639,6 +2651,7 @@ async def send_contact( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_checklist( @@ -2719,6 +2732,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2747,6 +2761,7 @@ async def send_dice( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -2766,6 +2781,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2801,6 +2817,7 @@ async def send_document( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -2876,6 +2893,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2923,6 +2941,7 @@ async def send_invoice( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -2942,6 +2961,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2977,6 +2997,7 @@ async def send_location( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -3042,6 +3063,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, disable_web_page_preview: Optional[bool] = None, reply_to_message_id: Optional[int] = None, @@ -3075,6 +3097,7 @@ async def send_message( link_preview_options=link_preview_options, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_photo( @@ -3094,6 +3117,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3129,6 +3153,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -3212,6 +3237,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3241,6 +3267,7 @@ async def send_sticker( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -3262,6 +3289,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3299,6 +3327,7 @@ async def send_venue( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -3325,6 +3354,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3367,6 +3397,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -3384,6 +3415,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3417,6 +3449,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -3435,6 +3468,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3469,6 +3503,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def set_chat_administrator_custom_title( @@ -4907,6 +4942,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -4939,6 +4975,7 @@ async def send_paid_media( business_connection_id=business_connection_id, payload=payload, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def create_chat_subscription_invite_link( diff --git a/tests/test_bot.py b/tests/test_bot.py index 6ecf041f77a..c54bc0b3697 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -75,6 +75,8 @@ ShippingOption, StarTransaction, StarTransactions, + SuggestedPostParameters, + SuggestedPostPrice, Update, User, WebAppInfo, @@ -2373,6 +2375,22 @@ async def make_assertion(url, request_data: RequestData, *args, **kwargs): monkeypatch.setattr(offline_bot.request, "post", make_assertion) assert await offline_bot.send_message(2, "text", allow_paid_broadcast=42) + async def test_suggested_post_parameters_argument(self, offline_bot, monkeypatch): + """We can't test every single method easily, so we just test one. Our linting will catch + any unused args with the others.""" + suggested_post_parameters = SuggestedPostParameters(price=SuggestedPostPrice("TON", 10)) + + async def make_assertion(url, request_data: RequestData, *args, **kwargs): + return ( + request_data.parameters.get("suggested_post_parameters") + == suggested_post_parameters.to_dict() + ) + + monkeypatch.setattr(offline_bot.request, "post", make_assertion) + assert await offline_bot.send_message( + 2, "text", suggested_post_parameters=suggested_post_parameters + ) + async def test_send_chat_action_all_args(self, bot, chat_id, monkeypatch): async def make_assertion(*args, **_): kwargs = args[1] diff --git a/tests/test_suggestedpost.py b/tests/test_suggestedpost.py new file mode 100644 index 00000000000..73fa9206779 --- /dev/null +++ b/tests/test_suggestedpost.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2025 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# 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 as dtm + +import pytest + +from telegram import Dice +from telegram._suggestedpost import SuggestedPostParameters, SuggestedPostPrice +from telegram._utils.datetime import UTC, to_timestamp +from tests.auxil.slots import mro_slots + + +@pytest.fixture(scope="module") +def suggested_post_parameters(): + return SuggestedPostParameters( + price=SuggestedPostParametersTestBase.price, + send_date=SuggestedPostParametersTestBase.send_date, + ) + + +class SuggestedPostParametersTestBase: + price = SuggestedPostPrice(currency="XTR", amount=100) + send_date = dtm.datetime.now(tz=UTC).replace(microsecond=0) + + +class TestSuggestedPostParametersWithoutRequest(SuggestedPostParametersTestBase): + def test_slot_behaviour(self, suggested_post_parameters): + for attr in suggested_post_parameters.__slots__: + assert getattr(suggested_post_parameters, attr, "err") != "err", ( + f"got extra slot '{attr}'" + ) + assert len(mro_slots(suggested_post_parameters)) == len( + set(mro_slots(suggested_post_parameters)) + ), "duplicate slot" + + def test_de_json(self, offline_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + spp = SuggestedPostParameters.de_json(json_dict, offline_bot) + assert spp.price == self.price + assert spp.send_date == self.send_date + assert spp.api_kwargs == {} + + def test_de_json_localization(self, offline_bot, raw_bot, tz_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + + spp_bot = SuggestedPostParameters.de_json(json_dict, offline_bot) + spp_bot_raw = SuggestedPostParameters.de_json(json_dict, raw_bot) + spp_bot_tz = SuggestedPostParameters.de_json(json_dict, tz_bot) + + # comparing utcoffsets because comparing tzinfo objects is not reliable + send_date_offset = spp_bot_tz.send_date.utcoffset() + send_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset( + spp_bot_tz.send_date.replace(tzinfo=None) + ) + + assert spp_bot.send_date.tzinfo == UTC + assert spp_bot_raw.send_date.tzinfo == UTC + assert send_date_offset_tz == send_date_offset + + def test_to_dict(self, suggested_post_parameters): + spp_dict = suggested_post_parameters.to_dict() + + assert isinstance(spp_dict, dict) + assert spp_dict["price"] == self.price.to_dict() + assert spp_dict["send_date"] == to_timestamp(self.send_date) + + def test_equality(self, suggested_post_parameters): + a = suggested_post_parameters + b = SuggestedPostParameters(price=self.price, send_date=self.send_date) + c = SuggestedPostParameters( + price=self.price, send_date=self.send_date + dtm.timedelta(seconds=1) + ) + e = Dice(4, "emoji") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != e + assert hash(a) != hash(e) + + +@pytest.fixture(scope="module") +def suggested_post_price(): + return SuggestedPostPrice( + currency=SuggestedPostPriceTestBase.currency, + amount=SuggestedPostPriceTestBase.amount, + ) + + +class SuggestedPostPriceTestBase: + currency = "XTR" + amount = 100 + + +class TestSuggestedPostPriceWithoutRequest(SuggestedPostPriceTestBase): + def test_slot_behaviour(self, suggested_post_price): + for attr in suggested_post_price.__slots__: + assert getattr(suggested_post_price, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(suggested_post_price)) == len(set(mro_slots(suggested_post_price))), ( + "duplicate slot" + ) + + def test_de_json(self, offline_bot): + json_dict = { + "currency": self.currency, + "amount": self.amount, + } + spp = SuggestedPostPrice.de_json(json_dict, offline_bot) + assert spp.currency == self.currency + assert spp.amount == self.amount + assert spp.api_kwargs == {} + + def test_to_dict(self, suggested_post_price): + spp_dict = suggested_post_price.to_dict() + + assert isinstance(spp_dict, dict) + assert spp_dict["currency"] == self.currency + assert spp_dict["amount"] == self.amount + + def test_equality(self, suggested_post_price): + a = suggested_post_price + b = SuggestedPostPrice(currency=self.currency, amount=self.amount) + c = SuggestedPostPrice(currency="TON", amount=self.amount) + e = Dice(4, "emoji") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != e + assert hash(a) != hash(e)