From d891ed7ae8c709fc0a95963cacc1a2289dd1a277 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 00:49:34 +0300 Subject: [PATCH 1/8] Bot API 10.3 update --- telebot/__init__.py | 299 ++++++++++++------ telebot/apihelper.py | 127 ++++---- telebot/async_telebot.py | 294 ++++++++++++------ telebot/asyncio_helper.py | 123 ++++---- telebot/types.py | 549 ++++++++++++++++++++++++++++++++- tests/test_handler_backends.py | 4 +- tests/test_telebot.py | 3 +- tests/test_types.py | 76 +++++ 8 files changed, 1141 insertions(+), 334 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 10e186122..c004971e4 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -50,7 +50,6 @@ types.ReplyKeyboardRemove, types.ForceReply] - """ Module : telebot """ @@ -1780,8 +1779,9 @@ def send_message( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send text messages. @@ -1803,7 +1803,7 @@ def send_message( :param entities: List of special entities that appear in message text, which can be specified instead of parse_mode :type entities: Array of :class:`telebot.types.MessageEntity` - :param disable_web_page_preview: deprecated. + :param disable_web_page_preview: Deprecated. Use link_preview_options instead. :type disable_web_page_preview: :obj:`bool` :param disable_notification: Sends the message silently. Users will receive a notification with no sound. @@ -1812,10 +1812,10 @@ def send_message( :param protect_content: Protects the contents of the sent message from forwarding and saving :type protect_content: :obj:`bool` - :param reply_to_message_id: deprecated. + :param reply_to_message_id: Deprecated. Use reply_parameters instead. :type reply_to_message_id: :obj:`int` - :param allow_sending_without_reply: deprecated. + :param allow_sending_without_reply: Deprecated. Use reply_parameters instead. :type allow_sending_without_reply: :obj:`bool` :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -1848,14 +1848,15 @@ def send_message( required if the message is sent to a direct messages chat :type direct_messages_topic_id: :obj:`int` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :param suggested_post_parameters: A JSON-serialized 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. @@ -1903,6 +1904,9 @@ def send_message( # create a LinkPreviewOptions object link_preview_options = types.LinkPreviewOptions(is_disabled=self.disable_web_page_preview) + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_message( self.token, chat_id, text, @@ -1910,7 +1914,7 @@ def send_message( timeout=timeout, entities=entities, protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, link_preview_options=link_preview_options, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -2561,8 +2565,9 @@ def send_photo( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send photos. On success, the sent Message is returned. @@ -2636,14 +2641,15 @@ def send_photo( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2669,6 +2675,9 @@ def send_photo( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_photo( self.token, chat_id, photo, caption=caption, reply_markup=reply_markup, @@ -2678,7 +2687,7 @@ def send_photo( business_connection_id=business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -2690,7 +2699,8 @@ def send_live_photo( has_spoiler: Optional[bool]=None, disable_notification: Optional[bool]=None, protect_content: Optional[bool]=None, allow_paid_broadcast: Optional[bool]=None, message_effect_id: Optional[str]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, reply_parameters: Optional[types.ReplyParameters]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send live photos. On success, the sent Message is returned. @@ -2754,6 +2764,9 @@ def send_live_photo( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2769,7 +2782,7 @@ def send_live_photo( has_spoiler=has_spoiler, disable_notification=disable_notification, protect_content=protect_content, allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters, reply_parameters=reply_parameters, - reply_markup=reply_markup + reply_markup=reply_markup, ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -2795,8 +2808,9 @@ def send_audio( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, @@ -2885,14 +2899,15 @@ def send_audio( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2922,6 +2937,9 @@ def send_audio( logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') thumbnail = thumb + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_audio( self.token, chat_id, audio, caption=caption, duration=duration, performer=performer, title=title, @@ -2930,7 +2948,7 @@ def send_audio( message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -2952,8 +2970,9 @@ def send_voice( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.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 encoded with OPUS, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future. @@ -3023,14 +3042,15 @@ def send_voice( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -3055,6 +3075,9 @@ def send_voice( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_voice( self.token, chat_id, voice, caption=caption, duration=duration, reply_markup=reply_markup, @@ -3062,7 +3085,7 @@ def send_voice( caption_entities=caption_entities, protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -3089,8 +3112,9 @@ def send_document( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send general files. @@ -3172,14 +3196,15 @@ def send_document( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3217,6 +3242,9 @@ def send_document( # inputfile name ignored, warn logger.warning('Cannot use both InputFile and visible_file_name. InputFile name will be ignored.') + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_data( self.token, chat_id, document, 'document', @@ -3226,7 +3254,7 @@ def send_document( protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -3248,8 +3276,9 @@ def send_sticker( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned. @@ -3314,14 +3343,15 @@ def send_sticker( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3350,6 +3380,9 @@ def send_sticker( logger.warning('The parameter "data" is deprecated. Use "sticker" instead.') sticker = data + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_data( self.token, chat_id, sticker, 'sticker', @@ -3358,7 +3391,7 @@ def send_sticker( reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -3392,8 +3425,9 @@ def send_video( start_timestamp: Optional[int]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -3496,14 +3530,15 @@ def send_video( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3537,6 +3572,9 @@ def send_video( logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') thumbnail = thumb + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_video( self.token, chat_id, video, @@ -3547,7 +3585,7 @@ def send_video( reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, cover=cover, start_timestamp=start_timestamp, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -3576,8 +3614,9 @@ def send_animation( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -3669,14 +3708,15 @@ def send_animation( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3706,6 +3746,9 @@ def send_animation( logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') thumbnail = thumb + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_animation( self.token, chat_id, animation, duration=duration, caption=caption, reply_markup=reply_markup, @@ -3715,7 +3758,7 @@ def send_animation( has_spoiler=has_spoiler, business_connection_id=business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -3738,8 +3781,9 @@ def send_video_note( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On success, the sent Message is returned. @@ -3813,14 +3857,15 @@ def send_video_note( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3849,6 +3894,9 @@ def send_video_note( logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') thumbnail = thumb + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_video_note( self.token, chat_id, data, duration=duration, length=length, reply_markup=reply_markup, @@ -3856,7 +3904,7 @@ def send_video_note( protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + ephemeral_message_parameters=ephemeral_message_parameters) ) def send_paid_media( @@ -4062,8 +4110,9 @@ def send_location( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send point on the map. On success, the sent Message is returned. @@ -4135,14 +4184,15 @@ def send_location( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4167,6 +4217,9 @@ def send_location( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_location( self.token, chat_id, latitude, longitude, live_period=live_period, reply_markup=reply_markup, @@ -4174,7 +4227,7 @@ def send_location( heading=heading, proximity_alert_radius=proximity_alert_radius, protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -4309,8 +4362,9 @@ def send_venue( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send information about a venue. On success, the sent Message is returned. @@ -4389,14 +4443,15 @@ def send_venue( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4421,6 +4476,9 @@ def send_venue( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_venue( self.token, chat_id, latitude, longitude, title, address, foursquare_id=foursquare_id, @@ -4428,7 +4486,7 @@ def send_venue( timeout=timeout, google_place_id=google_place_id, google_place_type=google_place_type, protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -4448,8 +4506,9 @@ def send_contact( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send phone contacts. On success, the sent Message is returned. @@ -4515,14 +4574,15 @@ def send_contact( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4547,13 +4607,16 @@ def send_contact( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters) + return types.Message.de_json( apihelper.send_contact( self.token, chat_id, phone_number, first_name, last_name=last_name, vcard=vcard, disable_notification=disable_notification, reply_markup=reply_markup, timeout=timeout, protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, - direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, receiver_user_id=receiver_user_id, callback_query_id=callback_query_id) + direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, ephemeral_message_parameters=ephemeral_message_parameters) ) @@ -4563,7 +4626,8 @@ def send_message_draft( text: str, message_thread_id: Optional[int]=None, parse_mode: Optional[str]=None, - entities: Optional[List[types.MessageEntity]]=None): + entities: Optional[List[types.MessageEntity]]=None, can_stop: Optional[bool]=None, + keep_on_stop: Optional[bool]=None): """ Use this method to stream a partial message to a user while the message is being generated; available for all bots. Returns True on success. @@ -4592,7 +4656,8 @@ def send_message_draft( :rtype: :obj:`bool` """ return apihelper.send_message_draft( - self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, message_thread_id=message_thread_id) + self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, message_thread_id=message_thread_id, + can_stop=can_stop, keep_on_stop=keep_on_stop) def send_rich_message( self, chat_id: Union[int, str], @@ -4606,7 +4671,8 @@ def send_rich_message( message_effect_id: Optional[str]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, reply_parameters: Optional[types.ReplyParameters]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send rich messages. If the message contains a block with a media element, then the bot must have the right to send the media to the chat. On success, the sent Message is returned. @@ -4650,6 +4716,9 @@ def send_rich_message( :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat :type direct_messages_topic_id: :obj:`int` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4660,14 +4729,16 @@ def send_rich_message( apihelper.send_rich_message( self.token, chat_id, rich_message, disable_notification=disable_notification, protect_content=protect_content, allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters, reply_parameters=reply_parameters, - reply_markup=reply_markup, business_connection_id=business_connection_id, message_thread_id=message_thread_id, direct_messages_topic_id=direct_messages_topic_id) + reply_markup=reply_markup, business_connection_id=business_connection_id, message_thread_id=message_thread_id, direct_messages_topic_id=direct_messages_topic_id, + ephemeral_message_parameters=ephemeral_message_parameters) ) def send_rich_message_draft( self, chat_id: int, draft_id: int, rich_message: types.InputRichMessage, - message_thread_id: Optional[int]=None) -> bool: + message_thread_id: Optional[int]=None, can_stop: Optional[bool]=None, + keep_on_stop: Optional[bool]=None) -> bool: """ Use this method to stream a partial rich message to a user while the message is being generated Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output @@ -4691,7 +4762,8 @@ def send_rich_message_draft( :rtype: :obj:`bool` """ return apihelper.send_rich_message_draft( - self.token, chat_id, draft_id, rich_message, message_thread_id=message_thread_id) + self.token, chat_id, draft_id, rich_message, message_thread_id=message_thread_id, + can_stop=can_stop, keep_on_stop=keep_on_stop) def send_chat_action( @@ -4914,6 +4986,7 @@ def promote_chat_member( can_post_stories: Optional[bool]=None, can_edit_stories: Optional[bool]=None, can_delete_stories: Optional[bool]=None, + can_send_welcome_messages: Optional[bool]=None, can_manage_direct_messages: Optional[bool]=None, can_manage_tags: Optional[bool]=None) -> bool: """ @@ -5009,6 +5082,7 @@ def promote_chat_member( can_manage_video_chats=can_manage_video_chats, can_manage_topics=can_manage_topics, can_post_stories=can_post_stories, can_edit_stories=can_edit_stories, can_delete_stories=can_delete_stories, can_manage_direct_messages=can_manage_direct_messages, + can_send_welcome_messages=can_send_welcome_messages, can_manage_tags=can_manage_tags, ) @@ -6874,8 +6948,9 @@ def delete_ephemeral_message( def edit_ephemeral_message_text( - self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, text: str, + self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, text: Optional[str]=None, parse_mode: Optional[str]=None, entities: Optional[List[types.MessageEntity]]=None, + rich_message: Optional[types.InputRichMessage]=None, link_preview_options: Optional[types.LinkPreviewOptions]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> bool: """ Use this method to edit an ephemeral text message. Note that it is not guaranteed that the @@ -6914,7 +6989,7 @@ def edit_ephemeral_message_text( return apihelper.edit_ephemeral_message_text( self.token, chat_id, receiver_user_id, ephemeral_message_id, text, - parse_mode=parse_mode, entities=entities, + parse_mode=parse_mode, entities=entities, rich_message=rich_message, link_preview_options=link_preview_options, reply_markup=reply_markup) def edit_ephemeral_message_media( @@ -6953,6 +7028,7 @@ def edit_ephemeral_message_caption( self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, + show_caption_above_media: Optional[bool]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> bool: """ Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed @@ -6988,7 +7064,7 @@ def edit_ephemeral_message_caption( return apihelper.edit_ephemeral_message_caption( self.token, chat_id, receiver_user_id, ephemeral_message_id, caption, - parse_mode=parse_mode, caption_entities=caption_entities, + parse_mode=parse_mode, caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, reply_markup=reply_markup) @@ -11506,3 +11582,28 @@ def _notify_command_handlers(self, handlers, new_messages, update_type): handlers=handlers, middlewares=middlewares, update_type=update_type) + + + @staticmethod + def _convert_deprecated_ephemeral_parameters(receiver_user_id, callback_query_id, ephemeral_message_parameters): + """Convert Bot API 10.2 ephemeral message arguments to their 10.3 replacement.""" + if receiver_user_id is not None or callback_query_id is not None: + logger.warning( + "The parameters 'receiver_user_id' and 'callback_query_id' are deprecated. " + "Use 'ephemeral_message_parameters' instead." + ) + if ephemeral_message_parameters is not None: + logger.warning( + "Both 'ephemeral_message_parameters' and deprecated 'receiver_user_id' or " + "'callback_query_id' are set: using 'ephemeral_message_parameters'." + ) + elif receiver_user_id is None: + logger.warning( + "The deprecated 'callback_query_id' cannot be converted without " + "'receiver_user_id'; no ephemeral message parameters will be sent." + ) + else: + ephemeral_message_parameters = types.EphemeralMessageParameters( + receiver_user_id, callback_query_id + ) + return ephemeral_message_parameters diff --git a/telebot/apihelper.py b/telebot/apihelper.py index bb5d1cc0b..25180e562 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -249,7 +249,7 @@ def send_message( message_thread_id=None, reply_parameters=None, link_preview_options=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendMessage' payload = {'chat_id': str(chat_id), 'text': text} if link_preview_options is not None: @@ -280,10 +280,8 @@ def send_message( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, method='post') @@ -292,7 +290,7 @@ def send_rich_message( disable_notification=None, protect_content=None, message_effect_id=None, reply_parameters=None, reply_markup=None, business_connection_id=None, direct_messages_topic_id=None, suggested_post_parameters=None, allow_paid_broadcast=None, - message_thread_id=None): + message_thread_id=None, ephemeral_message_parameters=None): method_url = r'sendRichMessage' payload = {'chat_id': chat_id, 'rich_message': rich_message.to_json()} if disable_notification is not None: @@ -315,13 +313,19 @@ def send_rich_message( payload['allow_paid_broadcast'] = allow_paid_broadcast if message_thread_id is not None: payload['message_thread_id'] = message_thread_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, method='post') -def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None): +def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None, can_stop=None, keep_on_stop=None): method_url = r'sendRichMessageDraft' payload = {'chat_id': str(chat_id), 'draft_id': draft_id, 'rich_message': rich_message.to_json()} if message_thread_id is not None: payload['message_thread_id'] = message_thread_id + if can_stop is not None: + payload['can_stop'] = can_stop + if keep_on_stop is not None: + payload['keep_on_stop'] = keep_on_stop return _make_request(token, method_url, params=payload, method='post') @@ -622,7 +626,7 @@ def send_photo( caption_entities=None, protect_content=None, message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, - direct_messages_topic_id=None, suggested_post_parameters=None,receiver_user_id=None, callback_query_id=None): + direct_messages_topic_id=None, suggested_post_parameters=None,ephemeral_message_parameters=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -664,10 +668,8 @@ def send_photo( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') def send_live_photo( @@ -675,7 +677,7 @@ def send_live_photo( message_thread_id=None, business_connection_id=None, caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None, has_spoiler=None, disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None, message_effect_id=None, allow_paid_broadcast=None, - direct_messages_topic_id=None, suggested_post_parameters=None): + direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendLivePhoto' files = {} payload = {'chat_id': chat_id} @@ -719,6 +721,8 @@ def send_live_photo( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files or None, method='post') def send_paid_media( @@ -802,7 +806,7 @@ def send_location( proximity_alert_radius=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, - suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendLocation' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} if live_period: @@ -835,10 +839,8 @@ def send_location( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload) @@ -896,7 +898,7 @@ def send_venue( reply_markup=None, timeout=None, google_place_id=None, google_place_type=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendVenue' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address} if foursquare_id: @@ -929,10 +931,8 @@ def send_venue( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload) @@ -941,7 +941,7 @@ def send_contact( disable_notification=None, reply_markup=None, timeout=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendContact' payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name} if last_name: @@ -970,17 +970,15 @@ def send_contact( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload) def send_message_draft( token, chat_id, draft_id, text, - message_thread_id=None, parse_mode=None, entities=None): + message_thread_id=None, parse_mode=None, entities=None, can_stop=None, keep_on_stop=None): method_url = r'sendMessageDraft' payload = {'chat_id': chat_id, 'draft_id': draft_id, 'text': text} if message_thread_id is not None: @@ -989,6 +987,10 @@ def send_message_draft( payload['parse_mode'] = parse_mode if entities: payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) + if can_stop is not None: + payload['can_stop'] = can_stop + if keep_on_stop is not None: + payload['keep_on_stop'] = keep_on_stop return _make_request(token, method_url, params=payload) @@ -1010,7 +1012,7 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_markup=N message_thread_id=None, has_spoiler=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, cover=None, start_timestamp=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -1052,10 +1054,8 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_markup=N payload['message_thread_id'] = message_thread_id if has_spoiler is not None: payload['has_spoiler'] = has_spoiler - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() if reply_parameters is not None: payload['reply_parameters'] = reply_parameters.to_json() if business_connection_id: @@ -1090,7 +1090,7 @@ def send_animation( protect_content=None, width=None, height=None, message_thread_id=None, reply_parameters=None, has_spoiler=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -1142,10 +1142,8 @@ def send_animation( payload['allow_paid_broadcast'] = allow_paid_broadcast if direct_messages_topic_id is not None: payload['direct_messages_topic_id'] = direct_messages_topic_id - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1155,7 +1153,7 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup= parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendVoice' payload = {'chat_id': chat_id} files = None @@ -1193,10 +1191,8 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup= payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1204,7 +1200,7 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_mark disable_notification=None, timeout=None, thumbnail=None, protect_content=None, message_thread_id=None, reply_parameters=None,business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendVideoNote' payload = {'chat_id': chat_id} files = None @@ -1248,10 +1244,8 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_mark payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1259,7 +1253,7 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None, protect_content=None, message_thread_id=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendAudio' payload = {'chat_id': chat_id} files = None @@ -1309,10 +1303,8 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1321,7 +1313,7 @@ def send_data(token, chat_id, data, data_type, reply_markup=None, parse_mode=Non disable_content_type_detection=None, visible_file_name=None, protect_content = None, message_thread_id=None, emoji=None, reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = get_method_by_type(data_type) payload = {'chat_id': chat_id} files = None @@ -1372,10 +1364,8 @@ def send_data(token, chat_id, data, data_type, reply_markup=None, parse_mode=Non payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1431,7 +1421,7 @@ def promote_chat_member( can_restrict_members=None, can_pin_messages=None, can_promote_members=None, is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None, can_post_stories=None, can_edit_stories=None, - can_delete_stories=None, can_manage_direct_messages=None, can_manage_tags=None): + can_delete_stories=None, can_send_welcome_messages=None, can_manage_direct_messages=None, can_manage_tags=None): method_url = 'promoteChatMember' payload = {'chat_id': chat_id, 'user_id': user_id} if can_change_info is not None: @@ -1464,6 +1454,8 @@ def promote_chat_member( payload['can_edit_stories'] = can_edit_stories if can_delete_stories is not None: payload['can_delete_stories'] = can_delete_stories + if can_send_welcome_messages is not None: + payload['can_send_welcome_messages'] = can_send_welcome_messages if can_manage_direct_messages is not None: payload['can_manage_direct_messages'] = can_manage_direct_messages if can_manage_tags is not None: @@ -2885,19 +2877,22 @@ def stop_poll(token, chat_id, message_id, reply_markup=None, business_connection payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload) -def edit_ephemeral_message_text(token, chat_id, receiver_user_id, ephemeral_message_id, text, parse_mode=None, - entities=None, link_preview_options=None, reply_markup=None): +def edit_ephemeral_message_text(token, chat_id, receiver_user_id, ephemeral_message_id, text=None, parse_mode=None, + entities=None, rich_message=None, link_preview_options=None, reply_markup=None): method_url = r'editEphemeralMessageText' payload = { 'chat_id': chat_id, 'receiver_user_id': receiver_user_id, - 'ephemeral_message_id': ephemeral_message_id, - 'text': text + 'ephemeral_message_id': ephemeral_message_id } + if text is not None: + payload['text'] = text if parse_mode: payload['parse_mode'] = parse_mode if entities: payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) + if rich_message is not None: + payload['rich_message'] = rich_message.to_json() if link_preview_options: payload['link_preview_options'] = link_preview_options.to_json() if reply_markup: @@ -2918,7 +2913,7 @@ def edit_ephemeral_message_media(token, chat_id, receiver_user_id, ephemeral_mes return _make_request(token, method_url, params=payload, files=files) def edit_ephemeral_message_caption(token, chat_id, receiver_user_id, ephemeral_message_id, caption=None, - parse_mode=None, caption_entities=None, reply_markup=None): + parse_mode=None, caption_entities=None, show_caption_above_media=None, reply_markup=None): method_url = r'editEphemeralMessageCaption' payload = { 'chat_id': chat_id, @@ -2931,6 +2926,8 @@ def edit_ephemeral_message_caption(token, chat_id, receiver_user_id, ephemeral_m payload['parse_mode'] = parse_mode if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) + if show_caption_above_media is not None: + payload['show_caption_above_media'] = show_caption_above_media if reply_markup: payload['reply_markup'] = _convert_markup(reply_markup) return _make_request(token, method_url, params=payload) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index f01005952..64bb69701 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -3470,8 +3470,9 @@ async def send_message( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send text messages. @@ -3543,14 +3544,15 @@ async def send_message( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3601,6 +3603,10 @@ async def send_message( # create a LinkPreviewOptions object link_preview_options = types.LinkPreviewOptions(is_disabled=self.disable_web_page_preview) + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_message( self.token, chat_id, text, @@ -3608,7 +3614,7 @@ async def send_message( entities, protect_content, message_thread_id, reply_parameters, link_preview_options, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4247,8 +4253,9 @@ async def send_photo( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send photos. On success, the sent Message is returned. @@ -4322,14 +4329,15 @@ async def send_photo( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4358,6 +4366,10 @@ async def send_photo( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_photo( self.token, chat_id, photo, caption, reply_markup, @@ -4365,7 +4377,7 @@ async def send_photo( protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4378,7 +4390,8 @@ async def send_live_photo( disable_notification: Optional[bool]=None, protect_content: Optional[bool]=None, allow_paid_broadcast: Optional[bool]=None, message_effect_id: Optional[str]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, reply_parameters: Optional[types.ReplyParameters]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send live photos. On success, the sent Message is returned. @@ -4442,6 +4455,9 @@ async def send_live_photo( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4459,7 +4475,7 @@ async def send_live_photo( has_spoiler=has_spoiler, disable_notification=disable_notification, protect_content=protect_content, allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters, reply_parameters=reply_parameters, - reply_markup=reply_markup + reply_markup=reply_markup, ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4484,8 +4500,9 @@ async def send_audio( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, @@ -4574,14 +4591,15 @@ async def send_audio( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4614,13 +4632,17 @@ async def send_audio( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_audio( self.token, chat_id, audio, caption, duration, performer, title, reply_markup, parse_mode, disable_notification, timeout, thumbnail, caption_entities, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4642,8 +4664,9 @@ async def send_voice( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.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 encoded with OPUS, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future. @@ -4713,14 +4736,15 @@ async def send_voice( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4749,13 +4773,17 @@ async def send_voice( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_voice( self.token, chat_id, voice, caption, duration, reply_markup, parse_mode, disable_notification, timeout, caption_entities, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4782,8 +4810,9 @@ async def send_document( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send general files. @@ -4865,14 +4894,15 @@ async def send_document( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -4914,6 +4944,10 @@ async def send_document( # inputfile name ignored, warn logger.warning('Cannot use both InputFile and visible_file_name. InputFile name will be ignored.') + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_data( self.token, chat_id, document, 'document', @@ -4923,7 +4957,7 @@ async def send_document( disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content, message_thread_id = message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -4944,8 +4978,9 @@ async def send_sticker( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned. @@ -5010,14 +5045,15 @@ async def send_sticker( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -5050,6 +5086,10 @@ async def send_sticker( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_data( self.token, chat_id, sticker, 'sticker', @@ -5057,7 +5097,7 @@ async def send_sticker( disable_notification=disable_notification, timeout=timeout, protect_content=protect_content, message_thread_id=message_thread_id, emoji=emoji, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, - suggested_post_parameters=suggested_post_parameters, direct_messages_topic_id=direct_messages_topic_id,receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + suggested_post_parameters=suggested_post_parameters, direct_messages_topic_id=direct_messages_topic_id,ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -5090,8 +5130,9 @@ async def send_video( start_timestamp: Optional[int]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -5191,14 +5232,15 @@ async def send_video( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -5236,6 +5278,10 @@ async def send_video( logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') thumbnail = thumb + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_video( self.token, chat_id, video, duration, caption, reply_markup, @@ -5243,7 +5289,7 @@ async def send_video( caption_entities, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, cover=cover, start_timestamp=start_timestamp, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id)) + ephemeral_message_parameters=ephemeral_message_parameters)) async def send_animation( self, chat_id: Union[int, str], animation: Union[Any, str], @@ -5270,8 +5316,9 @@ async def send_animation( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -5363,14 +5410,15 @@ async def send_animation( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -5403,6 +5451,10 @@ async def send_animation( thumbnail = thumb logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_animation( self.token, chat_id, animation, duration, caption, @@ -5410,7 +5462,7 @@ async def send_animation( caption_entities, width, height, protect_content, message_thread_id, has_spoiler, reply_parameters, business_connection_id, message_effect_id=message_effect_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -5433,8 +5485,9 @@ async def send_video_note( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On success, the sent Message is returned. @@ -5508,14 +5561,15 @@ async def send_video_note( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -5547,12 +5601,16 @@ async def send_video_note( thumbnail = thumb logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_video_note( self.token, chat_id, data, duration, length, reply_markup, disable_notification, timeout, thumbnail, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, - suggested_post_parameters=suggested_post_parameters,receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + suggested_post_parameters=suggested_post_parameters,ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -5757,8 +5815,9 @@ async def send_location( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send point on the map. On success, the sent Message is returned. @@ -5830,14 +5889,15 @@ async def send_location( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -5865,13 +5925,17 @@ async def send_location( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_location( self.token, chat_id, latitude, longitude, live_period, reply_markup, disable_notification, timeout, horizontal_accuracy, heading, proximity_alert_radius, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, - direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters,receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters,ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -6002,8 +6066,9 @@ async def send_venue( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send information about a venue. On success, the sent Message is returned. @@ -6083,14 +6148,15 @@ async def send_venue( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -6118,13 +6184,17 @@ async def send_venue( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_venue( self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_markup, timeout, google_place_id, google_place_type, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -6145,8 +6215,9 @@ async def send_contact( allow_paid_broadcast: Optional[bool]=None, direct_messages_topic_id: Optional[int]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, - receiver_user_id: Optional[int]=None, - callback_query_id: Optional[str]=None) -> types.Message: + receiver_user_id: Optional[int]=None, # deprecated, for backward compatibility + callback_query_id: Optional[str]=None, # deprecated, for backward compatibility + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send phone contacts. On success, the sent Message is returned. @@ -6213,14 +6284,15 @@ async def send_contact( is automatically declined. :type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters` - :param receiver_user_id: For outgoing ephemeral messages, unique identifier of the user who will receive the message; - for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially - if they are offline. See ephemeral message sending for more details. + :param receiver_user_id: Deprecated. Use ephemeral_message_parameters instead. :type receiver_user_id: :obj:`int` - :param callback_query_id: For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -6248,6 +6320,10 @@ async def send_contact( if reply_parameters and (reply_parameters.allow_sending_without_reply is None): reply_parameters.allow_sending_without_reply = self.allow_sending_without_reply + ephemeral_message_parameters = self._convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters + ) + return types.Message.de_json( await asyncio_helper.send_contact( self.token, chat_id, phone_number, first_name, last_name, vcard, @@ -6255,7 +6331,7 @@ async def send_contact( protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, direct_messages_topic_id=direct_messages_topic_id, suggested_post_parameters=suggested_post_parameters, - receiver_user_id=receiver_user_id, callback_query_id=callback_query_id + ephemeral_message_parameters=ephemeral_message_parameters ) ) @@ -6271,7 +6347,8 @@ async def send_rich_message( message_effect_id: Optional[str]=None, suggested_post_parameters: Optional[types.SuggestedPostParameters]=None, reply_parameters: Optional[types.ReplyParameters]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + ephemeral_message_parameters: Optional[types.EphemeralMessageParameters]=None) -> types.Message: """ Use this method to send rich messages. If the message contains a block with a media element then the bot must have the right to send the media to the chat. On success, the sent Message is returned. @@ -6322,6 +6399,9 @@ async def send_rich_message( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` + :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -6331,8 +6411,9 @@ async def send_rich_message( return types.Message.de_json( await asyncio_helper.send_rich_message( self.token, chat_id, rich_message, business_connection_id=business_connection_id, message_thread_id=message_thread_id, direct_messages_topic_id=direct_messages_topic_id, - disable_notification=disable_notification, protect_content=protect_content, allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters - , reply_parameters=reply_parameters, reply_markup=reply_markup) + disable_notification=disable_notification, protect_content=protect_content, allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters, + reply_parameters=reply_parameters, reply_markup=reply_markup, + ephemeral_message_parameters=ephemeral_message_parameters) ) async def send_rich_message_draft( @@ -6613,6 +6694,7 @@ async def promote_chat_member( can_post_stories: Optional[bool]=None, can_edit_stories: Optional[bool]=None, can_delete_stories: Optional[bool]=None, + can_send_welcome_messages: Optional[bool]=None, can_manage_direct_messages: Optional[bool]=None, can_manage_tags: Optional[bool]=None) -> bool: """ @@ -6706,6 +6788,7 @@ async def promote_chat_member( can_restrict_members, can_pin_messages, can_promote_members, is_anonymous, can_manage_chat, can_manage_video_chats, can_manage_topics, can_post_stories, can_edit_stories, can_delete_stories, + can_send_welcome_messages=can_send_welcome_messages, can_manage_direct_messages=can_manage_direct_messages, can_manage_tags=can_manage_tags ) @@ -8492,8 +8575,9 @@ async def stop_poll( return types.Poll.de_json(await asyncio_helper.stop_poll(self.token, chat_id, message_id, reply_markup, business_connection_id)) async def edit_ephemeral_message_text( - self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, text: str, + self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, text: Optional[str]=None, parse_mode: Optional[str]=None, entities: Optional[List[types.MessageEntity]]=None, + rich_message: Optional[types.InputRichMessage]=None, link_preview_options: Optional[types.LinkPreviewOptions]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> bool: """ Use this method to edit an ephemeral text message. Note that it is not guaranteed that the @@ -8532,7 +8616,7 @@ async def edit_ephemeral_message_text( return await asyncio_helper.edit_ephemeral_message_text( self.token, chat_id, receiver_user_id, ephemeral_message_id, text, - parse_mode=parse_mode, entities=entities, + parse_mode=parse_mode, entities=entities, rich_message=rich_message, link_preview_options=link_preview_options, reply_markup=reply_markup) async def edit_ephemeral_message_media( @@ -8571,6 +8655,7 @@ async def edit_ephemeral_message_caption( self, chat_id: Union[int, str], receiver_user_id: int, ephemeral_message_id: int, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, + show_caption_above_media: Optional[bool]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> bool: """ Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed @@ -8606,7 +8691,7 @@ async def edit_ephemeral_message_caption( return await asyncio_helper.edit_ephemeral_message_caption( self.token, chat_id, receiver_user_id, ephemeral_message_id, caption, - parse_mode=parse_mode, caption_entities=caption_entities, + parse_mode=parse_mode, caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, reply_markup=reply_markup) @@ -10675,3 +10760,28 @@ async def add_data(self, user_id: int, chat_id: Optional[int]=None, for key, value in kwargs.items(): await self.current_states.set_data(chat_id, user_id, key, value, bot_id=bot_id, business_connection_id=business_connection_id, message_thread_id=message_thread_id) + + @staticmethod + def _convert_deprecated_ephemeral_parameters( + receiver_user_id, callback_query_id, ephemeral_message_parameters): + """Convert Bot API 10.2 ephemeral message arguments to their 10.3 replacement.""" + if receiver_user_id is not None or callback_query_id is not None: + logger.warning( + "The parameters 'receiver_user_id' and 'callback_query_id' are deprecated. " + "Use 'ephemeral_message_parameters' instead." + ) + if ephemeral_message_parameters is not None: + logger.warning( + "Both 'ephemeral_message_parameters' and deprecated 'receiver_user_id' or " + "'callback_query_id' are set: using 'ephemeral_message_parameters'." + ) + elif receiver_user_id is None: + logger.warning( + "The deprecated 'callback_query_id' cannot be converted without " + "'receiver_user_id'; no ephemeral message parameters will be sent." + ) + else: + ephemeral_message_parameters = types.EphemeralMessageParameters( + receiver_user_id, callback_query_id + ) + return ephemeral_message_parameters diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 789d5e929..3c80be92d 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -294,7 +294,7 @@ async def send_message( parse_mode=None, disable_notification=None, timeout=None, entities=None, protect_content=None, message_thread_id=None, reply_parameters=None, link_preview_options=None, business_connection_id=None, message_effect_id=None, - allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_name = 'sendMessage' params = {'chat_id': str(chat_id), 'text': text} if link_preview_options is not None: @@ -325,17 +325,15 @@ async def send_message( params['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: params['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - params['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - params['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + params['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_name, params=params, method='post') async def send_rich_message( token, chat_id, rich_message, disable_notification=None, protect_content=None, message_effect_id=None, reply_parameters=None, reply_markup=None, business_connection_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, - suggested_post_parameters=None, message_thread_id=None): + suggested_post_parameters=None, message_thread_id=None, ephemeral_message_parameters=None): method_url = r'sendRichMessage' payload = {'chat_id': str(chat_id), 'rich_message': rich_message.to_json()} if disable_notification is not None: @@ -358,14 +356,20 @@ async def send_rich_message( payload['suggested_post_parameters'] = suggested_post_parameters.to_json() if message_thread_id is not None: payload['message_thread_id'] = message_thread_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, method='post') -async def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None): +async def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None, can_stop=None, keep_on_stop=None): method_url = r'sendRichMessageDraft' payload = {'chat_id': chat_id, 'draft_id': draft_id, 'rich_message': rich_message.to_json()} if message_thread_id is not None: payload['message_thread_id'] = message_thread_id + if can_stop is not None: + payload['can_stop'] = can_stop + if keep_on_stop is not None: + payload['keep_on_stop'] = keep_on_stop return await _process_request(token, method_url, params=payload, method='post') @@ -634,7 +638,7 @@ async def send_photo( caption_entities=None, protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, - direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -676,10 +680,8 @@ async def send_photo( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_live_photo( @@ -689,7 +691,7 @@ async def send_live_photo( caption_entities=None, protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, - direct_messages_topic_id=None, suggested_post_parameters=None): + direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendLivePhoto' payload = {'chat_id': chat_id} files = {} @@ -735,6 +737,8 @@ async def send_live_photo( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_paid_media( @@ -819,7 +823,7 @@ async def send_location( timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendLocation' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} if live_period: @@ -852,10 +856,8 @@ async def send_location( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload) @@ -914,7 +916,7 @@ async def send_venue( google_place_id=None, google_place_type=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, - receiver_user_id=None, callback_query_id=None): + ephemeral_message_parameters=None): method_url = r'sendVenue' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address} if foursquare_id: @@ -947,10 +949,8 @@ async def send_venue( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload) @@ -958,7 +958,7 @@ async def send_contact( token, chat_id, phone_number, first_name, last_name=None, vcard=None, disable_notification=None, reply_markup=None, timeout=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, - allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendContact' payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name} if last_name: @@ -987,10 +987,8 @@ async def send_contact( payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload) async def send_message_draft( @@ -1023,7 +1021,7 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_m thumbnail=None, width=None, height=None, caption_entities=None, protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, allow_paid_broadcast=None, cover=None, start_timestamp=None, - direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -1089,10 +1087,8 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_m payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') @@ -1101,7 +1097,7 @@ async def send_animation( parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None, width=None, height=None, protect_content=None, message_thread_id=None, has_spoiler=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, show_caption_above_media=None, - allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -1141,10 +1137,8 @@ async def send_animation( payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() if has_spoiler is not None: payload['has_spoiler'] = has_spoiler if business_connection_id: @@ -1165,7 +1159,7 @@ async def send_animation( async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, protect_content=None, message_thread_id=None,reply_parameters=None,business_connection_id=None, message_effect_id=None, - allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendVoice' payload = {'chat_id': chat_id} files = None @@ -1203,17 +1197,15 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_ payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_video_note(token, chat_id, data, duration=None, length=None, reply_markup=None, disable_notification=None, timeout=None, thumbnail=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, allow_paid_broadcast=None, - direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendVideoNote' payload = {'chat_id': chat_id} files = None @@ -1257,17 +1249,15 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, rep payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None, protect_content=None, message_thread_id=None,reply_parameters=None, business_connection_id=None, - message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + message_effect_id=None, allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = r'sendAudio' payload = {'chat_id': chat_id} files = None @@ -1307,10 +1297,8 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() if business_connection_id: payload['business_connection_id'] = business_connection_id if message_effect_id: @@ -1328,7 +1316,7 @@ async def send_data(token, chat_id, data, data_type, reply_markup=None, parse_m disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None, message_thread_id=None, emoji=None,reply_parameters=None, business_connection_id=None, message_effect_id=None, - allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, receiver_user_id=None, callback_query_id=None): + allow_paid_broadcast=None, direct_messages_topic_id=None, suggested_post_parameters=None, ephemeral_message_parameters=None): method_url = await get_method_by_type(data_type) payload = {'chat_id': chat_id} files = None @@ -1379,10 +1367,8 @@ async def send_data(token, chat_id, data, data_type, reply_markup=None, parse_m payload['direct_messages_topic_id'] = direct_messages_topic_id if suggested_post_parameters is not None: payload['suggested_post_parameters'] = suggested_post_parameters.to_json() - if receiver_user_id is not None: - payload['receiver_user_id'] = receiver_user_id - if callback_query_id is not None: - payload['callback_query_id'] = callback_query_id + if ephemeral_message_parameters is not None: + payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload, files=files, method='post') @@ -1435,7 +1421,8 @@ async def promote_chat_member( can_edit_messages=None, can_delete_messages=None, can_invite_users=None, can_restrict_members=None, can_pin_messages=None, can_promote_members=None, is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None, - can_post_stories=None, can_edit_stories=None, can_delete_stories=None, + can_post_stories=None, can_edit_stories=None, can_delete_stories=None, + can_send_welcome_messages=None, can_manage_direct_messages=None, can_manage_tags=None): method_url = 'promoteChatMember' payload = {'chat_id': chat_id, 'user_id': user_id} @@ -1469,6 +1456,8 @@ async def promote_chat_member( payload['can_edit_stories'] = can_edit_stories if can_delete_stories is not None: payload['can_delete_stories'] = can_delete_stories + if can_send_welcome_messages is not None: + payload['can_send_welcome_messages'] = can_send_welcome_messages if can_manage_direct_messages is not None: payload['can_manage_direct_messages'] = can_manage_direct_messages if can_manage_tags is not None: @@ -2998,20 +2987,23 @@ async def stop_poll(token, chat_id, message_id, reply_markup=None, business_conn payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload) -async def edit_ephemeral_message_text(token, chat_id, receiver_user_id, ephemeral_message_id, text, +async def edit_ephemeral_message_text(token, chat_id, receiver_user_id, ephemeral_message_id, text=None, parse_mode=None, entities=None, link_preview_options=None, - reply_markup=None): + rich_message=None, reply_markup=None): method_url = r'editEphemeralMessageText' payload = { 'chat_id': chat_id, 'receiver_user_id': receiver_user_id, - 'ephemeral_message_id': ephemeral_message_id, - 'text': text + 'ephemeral_message_id': ephemeral_message_id } + if text is not None: + payload['text'] = text if parse_mode: payload['parse_mode'] = parse_mode if entities: payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) + if rich_message is not None: + payload['rich_message'] = rich_message.to_json() if link_preview_options: payload['link_preview_options'] = json.dumps(link_preview_options.to_dict()) if reply_markup: @@ -3043,7 +3035,8 @@ async def delete_ephemeral_message(token, chat_id, receiver_user_id, ephemeral_m return await _process_request(token, method_url, params=payload) async def edit_ephemeral_message_caption(token, chat_id, receiver_user_id, ephemeral_message_id, caption, - parse_mode=None, caption_entities=None, reply_markup=None): + parse_mode=None, caption_entities=None, show_caption_above_media=None, + reply_markup=None): method_url = r'editEphemeralMessageCaption' payload = { 'chat_id': chat_id, @@ -3056,6 +3049,8 @@ async def edit_ephemeral_message_caption(token, chat_id, receiver_user_id, ephem payload['parse_mode'] = parse_mode if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) + if show_caption_above_media is not None: + payload['show_caption_above_media'] = show_caption_above_media if reply_markup: payload['reply_markup'] = await _convert_markup(reply_markup) return await _process_request(token, method_url, params=payload) diff --git a/telebot/types.py b/telebot/types.py index adc2b424a..158ed53db 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -203,6 +203,9 @@ class Update(JsonDeserializable): :param subscription: Optional. User payment subscription has changed :type subscription: :class:`telebot.types.BotSubscriptionUpdated` + :param stopped_message_generation: Optional. A user asked the bot to stop message generation + :type stopped_message_generation: :class:`telebot.types.MessageGenerationStopped` + :return: Instance of the class :rtype: :class:`telebot.types.Update` @@ -238,18 +241,21 @@ def de_json(cls, json_string): managed_bot = ManagedBotUpdated.de_json(obj.get('managed_bot')) guest_message = Message.de_json(obj.get('guest_message')) subscription = BotSubscriptionUpdated.de_json(obj.get('subscription')) + stopped_message_generation = MessageGenerationStopped.de_json(obj.get('stopped_message_generation')) return cls(update_id, message, edited_message, channel_post, edited_channel_post, inline_query, chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer, my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, removed_chat_boost, chat_boost, business_connection, business_message, edited_business_message, - deleted_business_messages, purchased_paid_media, managed_bot, guest_message, subscription) + deleted_business_messages, purchased_paid_media, managed_bot, guest_message, subscription, + stopped_message_generation) def __init__(self, update_id, message, edited_message, channel_post, edited_channel_post, inline_query, chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer, my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, removed_chat_boost, chat_boost, business_connection, business_message, edited_business_message, - deleted_business_messages, purchased_paid_media, managed_bot, guest_message, subscription): + deleted_business_messages, purchased_paid_media, managed_bot, guest_message, subscription, + stopped_message_generation): self.update_id: int = update_id self.message: Optional[Message] = message self.edited_message: Optional[Message] = edited_message @@ -277,6 +283,7 @@ def __init__(self, update_id, message, edited_message, channel_post, edited_chan self.managed_bot: Optional[ManagedBotUpdated] = managed_bot self.guest_message: Optional[Message] = guest_message self.subscription: Optional[BotSubscriptionUpdated] = subscription + self.stopped_message_generation: Optional[MessageGenerationStopped] = stopped_message_generation class ChatMemberUpdated(JsonDeserializable): """ @@ -1332,6 +1339,9 @@ class Message(JsonDeserializable): :param community_chat_removed: Optional. Service message: chat removed from a Community :type community_chat_removed: :class:`telebot.types.CommunityChatRemoved` + :param community_chat_joined: Optional. Service message: chat was joined by a user from a Community + :type community_chat_joined: :class:`telebot.types.CommunityChatJoined` + :param direct_message_price_changed: Optional. Service message: the price for paid messages in the corresponding direct messages chat of a channel has changed :type direct_message_price_changed: :class:`telebot.types.DirectMessagePriceChanged` @@ -1738,6 +1748,9 @@ def de_json(cls, json_string): if 'community_chat_removed' in obj: opts['community_chat_removed'] = CommunityChatRemoved.de_json(obj['community_chat_removed']) content_type = 'community_chat_removed' + if 'community_chat_joined' in obj: + opts['community_chat_joined'] = CommunityChatJoined.de_json(obj['community_chat_joined']) + content_type = 'community_chat_joined' return cls(message_id, from_user, date, chat, content_type, opts, json_string) @classmethod @@ -1887,10 +1900,11 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso self.rich_message: Optional[RichMessage] = None self.receiver_user: Optional[User] = None self.ephemeral_message_id: Optional[str] = None + self.community_chat_added: Optional[CommunityChatAdded] = None + self.community_chat_removed: Optional[CommunityChatRemoved] = None + self.community_chat_joined: Optional[CommunityChatJoined] = None self.game: Optional[Game] = None self.passport_data: Optional[PassportData] = None - self.community_chat_added: Optional[Chat] = None - self.community_chat_removed: Optional[Chat] = None for key in options: setattr(self, key, options[key]) @@ -2788,6 +2802,9 @@ class ReplyKeyboardMarkup(JsonSerializable): :param is_persistent: Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to False, in which case the custom keyboard can be hidden and opened with a keyboard icon. :type is_persistent: :obj:`bool` + :param force_reply: Optional. Shows the reply interface to the user + :type force_reply: :obj:`bool` + :param row_width: Non-API. The width of the row in the keyboard when adding keys using "add" method. Defaults to 3. Maximum value is 12. :type row_width: :obj:`int` @@ -2797,7 +2814,8 @@ class ReplyKeyboardMarkup(JsonSerializable): def __init__(self, resize_keyboard: Optional[bool]=None, one_time_keyboard: Optional[bool]=None, selective: Optional[bool]=None, row_width: int=3, input_field_placeholder: Optional[str]=None, - is_persistent: Optional[bool]=None, keyboard: Optional[List[List[KeyboardButton]]]=None): + is_persistent: Optional[bool]=None, force_reply: Optional[bool]=None, + keyboard: Optional[List[List[KeyboardButton]]]=None): if row_width > self.max_row_keys: # Todo: Will be replaced with Exception in future releases if not DISABLE_KEYLEN_ERROR: @@ -2811,6 +2829,7 @@ def __init__(self, resize_keyboard: Optional[bool]=None, one_time_keyboard: Opti self.input_field_placeholder: Optional[str] = input_field_placeholder self.keyboard: List[List[KeyboardButton]] = keyboard or [] self.is_persistent: Optional[bool] = is_persistent + self.force_reply: Optional[bool] = force_reply def add(self, *args, row_width=None) -> 'ReplyKeyboardMarkup': @@ -2879,6 +2898,8 @@ def to_json(self): json_dict['input_field_placeholder'] = self.input_field_placeholder if self.is_persistent is not None: json_dict['is_persistent'] = self.is_persistent + if self.force_reply is not None: + json_dict['force_reply'] = self.force_reply return json.dumps(json_dict) @@ -3180,6 +3201,9 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) :param inline_keyboard: Array of button rows, each represented by an Array of InlineKeyboardButton objects :type inline_keyboard: :obj:`list` of :obj:`list` of :class:`telebot.types.InlineKeyboardButton` + :param force_reply: Optional. Shows the reply interface to the user + :type force_reply: :obj:`bool` + :param keyboard: Deprecated. Use inline_keyboard instead. :type keyboard: :obj:`list` of :obj:`list` of :class:`telebot.types.InlineKeyboardButton` @@ -3200,7 +3224,7 @@ def de_json(cls, json_string): def __init__( self, inline_keyboard: List[List[InlineKeyboardButton]] = None, row_width: int = 3, - keyboard: List[List[InlineKeyboardButton]] = None, **kwargs): + keyboard: List[List[InlineKeyboardButton]] = None, force_reply: Optional[bool] = None, **kwargs): if row_width > self.max_row_keys: # Todo: Will be replaced with Exception in future releases logger.error('Telegram does not support inline keyboard row width over %d.' % self.max_row_keys) @@ -3208,6 +3232,7 @@ def __init__( self.row_width: int = row_width self.inline_keyboard: List[List[InlineKeyboardButton]] = inline_keyboard or [] + self.force_reply: Optional[bool] = force_reply if keyboard is not None: logger.warning('The "keyboard" parameter is deprecated. Use "inline_keyboard" instead.') if not self.inline_keyboard: @@ -3272,6 +3297,8 @@ def to_json(self): def to_dict(self): json_dict = dict() json_dict['inline_keyboard'] = [[button.to_dict() for button in row] for row in self.inline_keyboard] + if self.force_reply is not None: + json_dict['force_reply'] = self.force_reply return json_dict @property @@ -3325,6 +3352,9 @@ class InlineKeyboardButton(Dictionaryable, JsonSerializable, JsonDeserializable) :param copy_text: Optional. Description of the button that copies the specified text to the clipboard. :type copy_text: :class:`telebot.types.CopyTextButton` + :param disabled: Optional. Description of a disabled button + :type disabled: :class:`telebot.types.DisabledButton` + :return: Instance of the class :rtype: :class:`telebot.types.InlineKeyboardButton` """ @@ -3340,6 +3370,8 @@ def de_json(cls, json_string): obj['switch_inline_query_chosen_chat'] = SwitchInlineQueryChosenChat.de_json(obj.get('switch_inline_query_chosen_chat')) if 'copy_text' in obj: obj['copy_text'] = CopyTextButton.de_json(obj.get('copy_text')) + if 'disabled' in obj: + obj['disabled'] = DisabledButton.de_json(obj.get('disabled')) return cls(**obj) @@ -3349,7 +3381,8 @@ def __init__(self, text: str, url: Optional[str] = None, callback_data: Optional switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = None, callback_game: Optional[CallbackGame] = None, pay: Optional[bool] = None, login_url: Optional[LoginUrl] = None, copy_text: Optional[CopyTextButton] = None, - icon_custom_emoji_id: Optional[str] = None, style: Optional[str] = None, **kwargs): + icon_custom_emoji_id: Optional[str] = None, style: Optional[str] = None, + disabled: Optional[DisabledButton] = None, **kwargs): self.text: str = text self.url: Optional[str] = url self.callback_data: Optional[str] = callback_data @@ -3363,6 +3396,7 @@ def __init__(self, text: str, url: Optional[str] = None, callback_data: Optional self.copy_text: Optional[CopyTextButton] = copy_text self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id self.style: Optional[str] = style + self.disabled: Optional[DisabledButton] = disabled def to_json(self): return json.dumps(self.to_dict()) @@ -3389,6 +3423,8 @@ def to_dict(self): json_dict['switch_inline_query_chosen_chat'] = self.switch_inline_query_chosen_chat.to_dict() if self.copy_text: json_dict['copy_text'] = self.copy_text.to_dict() + if self.disabled: + json_dict['disabled'] = self.disabled.to_dict() if self.icon_custom_emoji_id: json_dict['icon_custom_emoji_id'] = self.icon_custom_emoji_id if self.style: @@ -3662,6 +3698,9 @@ class ChatMemberAdministrator(ChatMember): :param can_delete_stories: True, if the administrator can delete stories posted by other users :type can_delete_stories: :obj:`bool` + :param can_send_welcome_messages: Optional. True, if the administrator can manage or send chat welcome messages + :type can_send_welcome_messages: :obj:`bool` + :param can_post_messages: Optional. True, if the administrator can post messages in the channel, approve suggested posts, or access channel statistics; for channels only :type can_post_messages: :obj:`bool` @@ -3694,7 +3733,8 @@ def __init__( can_edit_stories: bool, can_delete_stories: bool, can_post_messages: Optional[bool] = None, can_edit_messages: Optional[bool] = None, can_pin_messages: Optional[bool] = None, can_manage_topics: Optional[bool] = None, - custom_title: Optional[str] = None, can_manage_direct_messages: Optional[bool] = None, + custom_title: Optional[str] = None, can_send_welcome_messages: Optional[bool] = None, + can_manage_direct_messages: Optional[bool] = None, can_manage_tags: Optional[bool] = None, **kwargs): super().__init__(user, status, **kwargs) self.can_be_edited: bool = can_be_edited @@ -3714,6 +3754,7 @@ def __init__( self.can_pin_messages: Optional[bool] = can_pin_messages self.can_manage_topics: Optional[bool] = can_manage_topics self.custom_title: Optional[str] = custom_title + self.can_send_welcome_messages: Optional[bool] = can_send_welcome_messages self.can_manage_direct_messages: Optional[bool] = can_manage_direct_messages self.can_manage_tags: Optional[bool] = can_manage_tags @@ -8327,6 +8368,9 @@ class ChatAdministratorRights(JsonDeserializable, JsonSerializable, Dictionaryab :param can_delete_stories: True, if the administrator can delete stories posted by other users :type can_delete_stories: :obj:`bool` + :param can_send_welcome_messages: Optional. True, if the administrator can manage or send chat welcome messages + :type can_send_welcome_messages: :obj:`bool` + :param can_manage_direct_messages: Optional. True, if the administrator can manage direct messages of the channel and decline suggested posts; for channels only :type can_manage_direct_messages: :obj:`bool` @@ -8349,7 +8393,7 @@ def __init__(self, is_anonymous: bool, can_manage_chat: bool, can_post_messages: Optional[bool]=None, can_edit_messages: Optional[bool]=None, can_pin_messages: Optional[bool]=None, can_manage_topics: Optional[bool]=None, can_post_stories: bool = False, can_edit_stories: bool = False, - can_delete_stories: bool = False, can_manage_direct_messages: Optional[bool] = None, + can_delete_stories: bool = False, can_send_welcome_messages: Optional[bool] = None, can_manage_direct_messages: Optional[bool] = None, can_manage_tags: Optional[bool]=None, **kwargs) -> None: self.is_anonymous: bool = is_anonymous self.can_manage_chat: bool = can_manage_chat @@ -8366,6 +8410,7 @@ def __init__(self, is_anonymous: bool, can_manage_chat: bool, self.can_post_stories: bool = can_post_stories self.can_edit_stories: bool = can_edit_stories self.can_delete_stories: bool = can_delete_stories + self.can_send_welcome_messages: Optional[bool] = can_send_welcome_messages self.can_manage_direct_messages: Optional[bool] = can_manage_direct_messages self.can_manage_tags: Optional[bool] = can_manage_tags @@ -8394,6 +8439,8 @@ def to_dict(self): json_dict['can_edit_stories'] = self.can_edit_stories if self.can_delete_stories is not None: json_dict['can_delete_stories'] = self.can_delete_stories + if self.can_send_welcome_messages is not None: + json_dict['can_send_welcome_messages'] = self.can_send_welcome_messages if self.can_manage_direct_messages is not None: json_dict['can_manage_direct_messages'] = self.can_manage_direct_messages if self.can_manage_tags is not None: @@ -13187,6 +13234,15 @@ class UniqueGiftInfo(JsonDeserializable): :param last_resale_amount: Optional. For gifts bought from other users, the price paid for the gift in either Telegram Stars or nanograms :type last_resale_amount: :obj:`int` + :param text: Optional. Text accompanying the gift + :type text: :obj:`str` + + :param entities: Optional. Special entities that appear in text + :type entities: :obj:`list` of :class:`telebot.types.MessageEntity` + + :param is_private: Optional. True, if the gift must not be shown publicly + :type is_private: :obj:`bool` + :param owned_gift_id: Optional. Unique identifier of the received gift for the bot; only present for gifts received on behalf of business accounts :type owned_gift_id: :obj:`str` @@ -13202,7 +13258,8 @@ class UniqueGiftInfo(JsonDeserializable): def __init__(self, gift: UniqueGift, origin: str, owned_gift_id: Optional[str] = None, transfer_star_count: Optional[int] = None, next_transfer_date: Optional[int] = None, last_resale_currency: Optional[str] = None, - last_resale_amount: Optional[int] = None, **kwargs): + last_resale_amount: Optional[int] = None, text: Optional[str] = None, + entities: Optional[List[MessageEntity]] = None, is_private: Optional[bool] = None, **kwargs): self.gift: UniqueGift = gift self.origin: str = origin self.last_resale_currency: Optional[str] = last_resale_currency @@ -13210,6 +13267,9 @@ def __init__(self, gift: UniqueGift, origin: str, owned_gift_id: Optional[str] = self.owned_gift_id: Optional[str] = owned_gift_id self.transfer_star_count: Optional[int] = transfer_star_count self.next_transfer_date: Optional[int] = next_transfer_date + self.text: Optional[str] = text + self.entities: Optional[List[MessageEntity]] = entities + self.is_private: Optional[bool] = is_private @property def last_resale_star_count(self) -> Optional[int]: @@ -13225,6 +13285,8 @@ def de_json(cls, json_string): if json_string is None: return None obj = cls.check_json(json_string) obj['gift'] = UniqueGift.de_json(obj['gift']) + if 'entities' in obj: + obj['entities'] = [MessageEntity.de_json(entity) for entity in obj['entities']] return cls(**obj) @@ -14692,6 +14754,8 @@ def de_json(cls, json_string): return RichTextReference.de_json(obj) elif type == 'reference_link': return RichTextReferenceLink.de_json(obj) + elif type == 'button': + return RichTextButton.de_json(obj) return None def to_dict(self): @@ -15753,6 +15817,9 @@ class RichBlock(JsonDeserializable, ABC): - :class:`RichBlockVideo` - :class:`RichBlockVoiceNote` - :class:`RichBlockThinking` + - :class:`RichBlockButtons` + - :class:`RichBlockExpandableBlockQuotation` + - :class:`RichBlockDocument` Telegram documentation: https://core.telegram.org/bots/api#richblock @@ -15809,6 +15876,12 @@ def de_json(cls, json_string): return RichBlockVoiceNote.de_json(obj) elif type == 'thinking': return RichBlockThinking.de_json(obj) + elif type == 'buttons': + return RichBlockButtons.de_json(obj) + elif type == 'expandable_blockquote': + return RichBlockExpandableBlockQuotation.de_json(obj) + elif type == 'document': + return RichBlockDocument.de_json(obj) return None @@ -16175,17 +16248,21 @@ class RichBlockTable(RichBlock): :param is_striped: Optional. True, if the table is striped :type is_striped: :obj:`bool` + :param is_compact: Optional. True, if the table must use compact spacing + :type is_compact: :obj:`bool` + :param caption: Optional. Caption of the table :type caption: :class:`RichText` :return: Instance of the class :rtype: :class:`RichBlockTable` """ - def __init__(self, cells: List[List[RichBlockTableCell]], is_bordered: Optional[bool] = None, is_striped: Optional[bool] = None, caption: Optional[RichText] = None, **kwargs): + def __init__(self, cells: List[List[RichBlockTableCell]], is_bordered: Optional[bool] = None, is_striped: Optional[bool] = None, is_compact: Optional[bool] = None, caption: Optional[RichText] = None, **kwargs): super().__init__(type='table', **kwargs) self.cells: List[List[RichBlockTableCell]] = cells self.is_bordered: Optional[bool] = is_bordered self.is_striped: Optional[bool] = is_striped + self.is_compact: Optional[bool] = is_compact self.caption: Optional[RichText] = caption @classmethod @@ -16733,6 +16810,9 @@ class InputRichBlock(Dictionaryable, JsonSerializable): - InputRichBlockVideo - InputRichBlockVoiceNote - InputRichBlockThinking + - InputRichBlockButtons + - InputRichBlockExpandableBlockQuotation + - InputRichBlockDocument Telegram documentation: https://core.telegram.org/bots/api#inputrichblock @@ -17096,6 +17176,9 @@ class InputRichBlockTable(InputRichBlock): :param is_striped: Optional. Pass True if the table is striped :type is_striped: :obj:`bool` + :param is_compact: Optional. Pass True if the table must use compact spacing + :type is_compact: :obj:`bool` + :param caption: Optional. Caption of the table :type caption: :class:`RichText` @@ -17107,6 +17190,7 @@ def __init__( cells: List[List[RichBlockTableCell]], is_bordered: Optional[bool] = None, is_striped: Optional[bool] = None, + is_compact: Optional[bool] = None, caption: Optional[RichText] = None, **kwargs ): @@ -17114,6 +17198,7 @@ def __init__( self.cells: List[List[RichBlockTableCell]] = cells self.is_bordered: Optional[bool] = is_bordered self.is_striped: Optional[bool] = is_striped + self.is_compact: Optional[bool] = is_compact self.caption: Optional[RichText] = caption def to_dict(self) -> dict: @@ -17123,6 +17208,8 @@ def to_dict(self) -> dict: data['is_bordered'] = self.is_bordered if self.is_striped is not None: data['is_striped'] = self.is_striped + if self.is_compact is not None: + data['is_compact'] = self.is_compact if self.caption is not None: data['caption'] = RichText.richtext_to_dict(self.caption) return data @@ -17404,6 +17491,423 @@ def to_dict(self) -> dict: return data +class DisabledButton(Dictionaryable, JsonSerializable, JsonDeserializable): + """ + Represents a disabled inline or rich-message button. + + Telegram documentation: https://core.telegram.org/bots/api#disabledbutton + + :return: Instance of the class + :rtype: :class:`telebot.types.DisabledButton` + """ + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + return cls() + + def to_dict(self): + return {} + + def to_json(self): + return json.dumps(self.to_dict()) + + +class EphemeralMessageParameters(Dictionaryable, JsonSerializable): + """ + Describes the parameters of an ephemeral message. + + Telegram documentation: https://core.telegram.org/bots/api#ephemeralmessageparameters + + :param receiver_user_id: Identifier of the user who will receive the message + :type receiver_user_id: :obj:`int` + + :param callback_query_id: Optional. Identifier of the callback query which triggered the message + :type callback_query_id: :obj:`str` + + :param replace_callback_query_message: Optional. True, if the ephemeral message must replace the original message + :type replace_callback_query_message: :obj:`bool` + + :return: Instance of the class + :rtype: :class:`telebot.types.EphemeralMessageParameters` + """ + def __init__(self, receiver_user_id: int, callback_query_id: Optional[str] = None, + replace_callback_query_message: Optional[bool] = None): + self.receiver_user_id: int = receiver_user_id + self.callback_query_id: Optional[str] = callback_query_id + self.replace_callback_query_message: Optional[bool] = replace_callback_query_message + + def to_dict(self): + data = {'receiver_user_id': self.receiver_user_id} + if self.callback_query_id is not None: + data['callback_query_id'] = self.callback_query_id + if self.replace_callback_query_message is not None: + data['replace_callback_query_message'] = self.replace_callback_query_message + return data + + def to_json(self): + return json.dumps(self.to_dict()) + + +class MessageGenerationStopped(JsonDeserializable): + """ + Describes an update about a user stopping message generation. + + Telegram documentation: https://core.telegram.org/bots/api#messagegenerationstopped + + :param chat: Chat in which the message is generated + :type chat: :class:`telebot.types.Chat` + + :param draft_id: Unique identifier of the stopped message draft + :type draft_id: :obj:`int` + + :param message_thread_id: Optional. Identifier of the message thread in which the message is generated + :type message_thread_id: :obj:`int` + + :return: Instance of the class + :rtype: :class:`telebot.types.MessageGenerationStopped` + """ + def __init__(self, chat: Chat, draft_id: int, message_thread_id: Optional[int] = None): + self.chat: Chat = chat + self.draft_id: int = draft_id + self.message_thread_id: Optional[int] = message_thread_id + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['chat'] = Chat.de_json(obj['chat']) + return cls(**obj) + + +class RichMessageButton(Dictionaryable, JsonSerializable, JsonDeserializable): + """ + Represents a button in a rich formatted message. + + Exactly one field other than text and style must be specified to define the button action. + + Telegram documentation: https://core.telegram.org/bots/api#richmessagebutton + + :param text: Text of the button + :type text: :class:`telebot.types.RichText` + + :param style: Optional. Style of the button + :type style: :obj:`str` + + :param url: Optional. HTTP or tg:// URL to open when the button is pressed + :type url: :obj:`str` + + :param callback_data: Optional. Data to send in a callback query when the button is pressed + :type callback_data: :obj:`str` + + :param web_app: Optional. Description of the Web App to launch when the button is pressed + :type web_app: :class:`telebot.types.WebAppInfo` + + :param login_url: Optional. HTTPS URL used to automatically authorize the user + :type login_url: :class:`telebot.types.LoginUrl` + + :param switch_inline_query: Optional. Inline query to insert after the user chooses a chat + :type switch_inline_query: :obj:`str` + + :param switch_inline_query_current_chat: Optional. Inline query to insert in the current chat + :type switch_inline_query_current_chat: :obj:`str` + + :param switch_inline_query_chosen_chat: Optional. Criteria for choosing a chat for an inline query + :type switch_inline_query_chosen_chat: :class:`telebot.types.SwitchInlineQueryChosenChat` + + :param copy_text: Optional. Description of text to copy to the clipboard + :type copy_text: :class:`telebot.types.CopyTextButton` + + :param disabled: Optional. Marks the button as disabled + :type disabled: :class:`telebot.types.DisabledButton` + + :return: Instance of the class + :rtype: :class:`telebot.types.RichMessageButton` + """ + def __init__(self, text: RichText, style: Optional[str] = None, url: Optional[str] = None, + callback_data: Optional[str] = None, web_app: Optional[WebAppInfo] = None, + login_url: Optional[LoginUrl] = None, switch_inline_query: Optional[str] = None, + switch_inline_query_current_chat: Optional[str] = None, + switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = None, + copy_text: Optional[CopyTextButton] = None, disabled: Optional[DisabledButton] = None, + **kwargs): + self.text: RichText = text + self.style: Optional[str] = style + self.url: Optional[str] = url + self.callback_data: Optional[str] = callback_data + self.web_app: Optional[WebAppInfo] = web_app + self.login_url: Optional[LoginUrl] = login_url + self.switch_inline_query: Optional[str] = switch_inline_query + self.switch_inline_query_current_chat: Optional[str] = switch_inline_query_current_chat + self.switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = switch_inline_query_chosen_chat + self.copy_text: Optional[CopyTextButton] = copy_text + self.disabled: Optional[DisabledButton] = disabled + + def to_dict(self): + data = {'text': RichText.richtext_to_dict(self.text)} + if self.style is not None: + data['style'] = self.style + if self.url is not None: + data['url'] = self.url + if self.callback_data is not None: + data['callback_data'] = self.callback_data + if self.web_app is not None: + data['web_app'] = self.web_app.to_dict() + if self.login_url is not None: + data['login_url'] = self.login_url.to_dict() + if self.switch_inline_query is not None: + data['switch_inline_query'] = self.switch_inline_query + if self.switch_inline_query_current_chat is not None: + data['switch_inline_query_current_chat'] = self.switch_inline_query_current_chat + if self.switch_inline_query_chosen_chat is not None: + data['switch_inline_query_chosen_chat'] = self.switch_inline_query_chosen_chat.to_dict() + if self.copy_text is not None: + data['copy_text'] = self.copy_text.to_dict() + if self.disabled is not None: + data['disabled'] = self.disabled.to_dict() + return data + + def to_json(self): + return json.dumps(self.to_dict()) + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['text'] = RichText.de_json(obj['text']) + if 'web_app' in obj: + obj['web_app'] = WebAppInfo.de_json(obj['web_app']) + if 'login_url' in obj: + obj['login_url'] = LoginUrl.de_json(obj['login_url']) + if 'switch_inline_query_chosen_chat' in obj: + obj['switch_inline_query_chosen_chat'] = SwitchInlineQueryChosenChat.de_json(obj['switch_inline_query_chosen_chat']) + if 'copy_text' in obj: + obj['copy_text'] = CopyTextButton.de_json(obj['copy_text']) + if 'disabled' in obj: + obj['disabled'] = DisabledButton.de_json(obj['disabled']) + return cls(**obj) + + +class RichTextButton(RichText): + """ + Represents a button in rich text. + + Telegram documentation: https://core.telegram.org/bots/api#richtextbutton + + :param type: Type of the rich text, always “button” + :type type: :obj:`str` + + :param button: The button + :type button: :class:`telebot.types.RichMessageButton` + + :return: Instance of the class + :rtype: :class:`telebot.types.RichTextButton` + """ + def __init__(self, button: RichMessageButton, **kwargs): + super().__init__(type='button', **kwargs) + self.button: RichMessageButton = button + + def to_dict(self): + data = super().to_dict() + data['button'] = self.button.to_dict() + return data + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['button'] = RichMessageButton.de_json(obj['button']) + return cls(**obj) + + +class RichBlockButtons(RichBlock): + """ + Represents a block containing buttons shown in one row. + + Telegram documentation: https://core.telegram.org/bots/api#richblockbuttons + + :param type: Type of the block, always “buttons” + :type type: :obj:`str` + + :param buttons: Buttons in the block + :type buttons: :obj:`list` of :class:`telebot.types.RichMessageButton` + + :param align: Optional. Horizontal alignment of the buttons + :type align: :obj:`str` + + :return: Instance of the class + :rtype: :class:`telebot.types.RichBlockButtons` + """ + def __init__(self, buttons: List[RichMessageButton], align: Optional[str] = None, **kwargs): + super().__init__(type='buttons', **kwargs) + self.buttons: List[RichMessageButton] = buttons + self.align: Optional[str] = align + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['buttons'] = [RichMessageButton.de_json(button) for button in obj['buttons']] + return cls(**obj) + + +class InputRichBlockButtons(InputRichBlock): + """ + Represents a button row in a rich formatted message to be sent. + + Telegram documentation: https://core.telegram.org/bots/api#inputrichblockbuttons + + :param type: Type of the block, always “buttons” + :type type: :obj:`str` + + :param buttons: Buttons in the block + :type buttons: :obj:`list` of :class:`telebot.types.RichMessageButton` + + :param align: Optional. Horizontal alignment of the buttons + :type align: :obj:`str` + + :return: Instance of the class + :rtype: :class:`telebot.types.InputRichBlockButtons` + """ + def __init__(self, buttons: List[RichMessageButton], align: Optional[str] = None, **kwargs): + super().__init__(type='buttons', **kwargs) + self.buttons: List[RichMessageButton] = buttons + self.align: Optional[str] = align + + def to_dict(self): + data = super().to_dict() + data['buttons'] = [button.to_dict() for button in self.buttons] + if self.align is not None: + data['align'] = self.align + return data + + +class RichBlockExpandableBlockQuotation(RichBlock): + """ + Represents an expandable block quotation. + + Telegram documentation: https://core.telegram.org/bots/api#richblockexpandableblockquotation + + :param type: Type of the block, always “expandable_blockquote” + :type type: :obj:`str` + + :param text: Content of the block + :type text: :class:`telebot.types.RichText` + + :param credit: Optional. Credit of the block + :type credit: :class:`telebot.types.RichText` + + :return: Instance of the class + :rtype: :class:`telebot.types.RichBlockExpandableBlockQuotation` + """ + def __init__(self, text: RichText, credit: Optional[RichText] = None, **kwargs): + super().__init__(type='expandable_blockquote', **kwargs) + self.text: RichText = text + self.credit: Optional[RichText] = credit + + @classmethod + def de_json(cls, json_string): + if json_string is None: + return None + obj = cls.check_json(json_string) + obj['text'] = RichText.de_json(obj['text']) + obj['credit'] = RichText.de_json(obj['credit']) if obj.get('credit') else None + return cls(**obj) + + +class InputRichBlockExpandableBlockQuotation(InputRichBlock): + """ + Represents an expandable block quotation in a rich formatted message to be sent. + + Telegram documentation: https://core.telegram.org/bots/api#inputrichblockexpandableblockquotation + + :param type: Type of the block, always “expandable_blockquote” + :type type: :obj:`str` + + :param text: Content of the block + :type text: :class:`telebot.types.RichText` + + :param credit: Optional. Credit of the block + :type credit: :class:`telebot.types.RichText` + + :return: Instance of the class + :rtype: :class:`telebot.types.InputRichBlockExpandableBlockQuotation` + """ + def __init__(self, text: RichText, credit: Optional[RichText] = None, **kwargs): + super().__init__(type='expandable_blockquote', **kwargs) + self.text: RichText = text + self.credit: Optional[RichText] = credit + + def to_dict(self): + data = super().to_dict() + data['text'] = RichText.richtext_to_dict(self.text) + if self.credit is not None: + data['credit'] = RichText.richtext_to_dict(self.credit) + return data + + +class RichBlockDocument(RichBlock): + """ + Represents a block with a general file. + + Telegram documentation: https://core.telegram.org/bots/api#richblockdocument + + :param type: Type of the block, always “document” + :type type: :obj:`str` + + :param document: The document + :type document: :class:`telebot.types.Document` + + :param caption: Optional. Caption of the block + :type caption: :class:`telebot.types.RichBlockCaption` + + :return: Instance of the class + :rtype: :class:`telebot.types.RichBlockDocument` + """ + def __init__(self, document: Document, caption: Optional[RichBlockCaption] = None, **kwargs): + super().__init__(type='document', **kwargs) + self.document: Document = document + self.caption: Optional[RichBlockCaption] = caption + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['document'] = Document.de_json(obj['document']) + obj['caption'] = RichBlockCaption.de_json(obj['caption']) if obj.get('caption') else None + return cls(**obj) + + +class InputRichBlockDocument(InputRichBlock): + """ + Represents a block with a general file in a rich formatted message to be sent. + + Telegram documentation: https://core.telegram.org/bots/api#inputrichblockdocument + + :param type: Type of the block, always “document” + :type type: :obj:`str` + + :param document: The document. Its caption is ignored. + :type document: :class:`telebot.types.InputMediaDocument` + + :param caption: Optional. Caption of the block + :type caption: :class:`telebot.types.RichBlockCaption` + + :return: Instance of the class + :rtype: :class:`telebot.types.InputRichBlockDocument` + """ + def __init__(self, document: InputMediaDocument, caption: Optional[RichBlockCaption] = None, **kwargs): + super().__init__(type='document', **kwargs) + self.document: InputMediaDocument = document + self.caption: Optional[RichBlockCaption] = caption + + def to_dict(self): + data = super().to_dict() + data['document'] = self.document.to_dict() + if self.caption is not None: + data['caption'] = self.caption.to_dict() + return data + + # noinspection shadowing-builtins class Community(JsonDeserializable): """ @@ -17473,6 +17977,29 @@ def de_json(cls, json_string): return cls(**obj) +class CommunityChatJoined(JsonDeserializable): + """ + Describes a service message about a chat being joined by a user from a community. + + Telegram documentation: https://core.telegram.org/bots/api#communitychatjoined + + :param community: Community from which the chat was joined + :type community: :class:`telebot.types.Community` + + :return: Instance of the class + :rtype: :class:`telebot.types.CommunityChatJoined` + """ + def __init__(self, community: Community, **kwargs): + self.community: Community = community + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['community'] = Community.de_json(obj.get('community')) + return cls(**obj) + + class BotSubscriptionUpdated(JsonDeserializable): """ This object contains information about changes to a user payment subscription toward the current bot. diff --git a/tests/test_handler_backends.py b/tests/test_handler_backends.py index 47bc5aa89..5b569720b 100644 --- a/tests/test_handler_backends.py +++ b/tests/test_handler_backends.py @@ -72,7 +72,7 @@ def update_type(message): return types.Update(1001234038283, message, edited_message, channel_post, edited_channel_post, inline_query, chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer, my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, chat_boost, chat_boost_removed, None, - None, None, None, None, None, None, None) + None, None, None, None, None, None, None, None) @pytest.fixture() @@ -97,7 +97,7 @@ def reply_to_message_update_type(reply_to_message): return types.Update(1001234038284, reply_to_message, edited_message, channel_post, edited_channel_post, inline_query, chosen_inline_result, callback_query, shipping_query, pre_checkout_query, poll, poll_answer, my_chat_member, chat_member, chat_join_request, message_reaction, message_reaction_count, chat_boost, chat_boost_removed, None, None, None, None, None, None, None, - None) + None, None) def next_handler(message): diff --git a/tests/test_telebot.py b/tests/test_telebot.py index 9294f7749..14d80e89b 100644 --- a/tests/test_telebot.py +++ b/tests/test_telebot.py @@ -557,7 +557,8 @@ def create_message_update(text): deleted_business_messages=None, managed_bot=None, guest_message=None, - subscription=None) + subscription=None, + stopped_message_generation=None) def test_is_string_unicode(self): s1 = u'string' diff --git a/tests/test_types.py b/tests/test_types.py index 208fa3c7a..23a75fc23 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -5,6 +5,82 @@ from telebot import types +def test_api_103_ephemeral_message_parameters(): + parameters = types.EphemeralMessageParameters(1, callback_query_id='query') + + assert parameters.to_dict() == {'receiver_user_id': 1, 'callback_query_id': 'query'} + + +def test_api_103_rich_message_button(): + button = types.RichMessageButton('Open', callback_data='open') + + assert button.to_dict() == {'text': 'Open', 'callback_data': 'open'} + + +def test_api_103_disabled_inline_button(): + button = types.InlineKeyboardButton('Unavailable', disabled=types.DisabledButton()) + + assert button.to_dict()['disabled'] == {} + + +def test_api_103_rich_text_button_round_trip(): + button = types.RichMessageButton(types.RichTextBold('Open'), callback_data='open') + rich_text = types.RichTextButton(button) + + assert types.RichText.de_json(rich_text.to_dict()).to_dict() == rich_text.to_dict() + + +def test_api_103_rich_blocks(): + button = types.RichMessageButton('Open', callback_data='open') + document = types.InputRichBlockDocument(types.InputMediaDocument('document-id')) + buttons = types.RichBlock.de_json({ + 'type': 'buttons', + 'buttons': [button.to_dict()], + }) + quotation = types.RichBlock.de_json({ + 'type': 'expandable_blockquote', + 'text': 'Quote', + }) + + assert isinstance(buttons, types.RichBlockButtons) + assert buttons.buttons[0].callback_data == 'open' + assert isinstance(quotation, types.RichBlockExpandableBlockQuotation) + assert quotation.text == 'Quote' + assert document.to_dict() == { + 'type': 'document', + 'document': {'type': 'document', 'media': 'document-id'}, + } + + +def test_api_103_new_optional_fields(): + table = types.InputRichBlockTable([], is_compact=True) + reply_keyboard = types.ReplyKeyboardMarkup(force_reply=True) + inline_keyboard = types.InlineKeyboardMarkup(force_reply=True) + + assert table.to_dict()['is_compact'] is True + assert '"force_reply":true' in reply_keyboard.to_json() + assert inline_keyboard.to_dict()['force_reply'] is True + + +def test_api_103_new_service_objects(): + update = types.Update.de_json({ + 'update_id': 1, + 'stopped_message_generation': { + 'chat': {'id': 1, 'type': 'private'}, + 'draft_id': 2, + }, + }) + message = types.Message.de_json({ + 'message_id': 1, + 'date': 1, + 'chat': {'id': 1, 'type': 'private'}, + 'community_chat_joined': {'community': {'id': 1, 'name': 'Community'}}, + }) + + assert isinstance(update.stopped_message_generation, types.MessageGenerationStopped) + assert isinstance(message.community_chat_joined, types.CommunityChatJoined) + + def test_json_user(): json_str = r'{"id": 123456789, "is_bot": false, "first_name": "John", "last_name": "Doe", "username": "@johndoe", "language_code": "en", "can_join_groups": true, "can_read_all_group_messages": false, "supports_inline_queries": true, "is_premium": true, "added_to_attachment_menu": false, "can_connect_to_business": true, "has_main_web_app": false, "has_topics_enabled": true, "allows_users_to_create_topics": true, "can_manage_bots": true, "supports_guest_queries": true, "supports_join_request_queries": true}' result = types.User.de_json(json_str) From 395f02a6f68201e65c12d431be883574ad075a2b Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 01:02:17 +0300 Subject: [PATCH 2/8] New Update.stopped_message_generation handling. Fix Update.removed_chat_boost_handlers not called in Asnyc. --- telebot/__init__.py | 67 ++++++++++++++++++++++++++++++++++++++ telebot/async_telebot.py | 69 ++++++++++++++++++++++++++++++++++++++++ telebot/util.py | 5 +-- 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index c004971e4..953e88a2f 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -251,6 +251,7 @@ def __init__( self.managed_bot_handlers = [] self.guest_message_handlers = [] self.subscription_handlers = [] + self.stopped_message_generation_handlers = [] self.custom_filters = {} self.state_handlers = [] @@ -731,6 +732,7 @@ def process_new_updates(self, updates: List[types.Update]): new_managed_bots = None new_guest_messages = None new_subscriptions = None + new_stopped_message_generations = None for update in updates: if apihelper.ENABLE_MIDDLEWARE and not self.use_class_middlewares: @@ -824,6 +826,9 @@ def process_new_updates(self, updates: List[types.Update]): if update.subscription: if new_subscriptions is None: new_subscriptions = [] new_subscriptions.append(update.subscription) + if update.stopped_message_generation: + if new_stopped_message_generations is None: new_stopped_message_generations = [] + new_stopped_message_generations.append(update.stopped_message_generation) if new_messages: self.process_new_messages(new_messages) @@ -853,6 +858,8 @@ def process_new_updates(self, updates: List[types.Update]): self.process_new_chat_member(new_chat_members) if new_subscriptions: self.process_new_subscription(new_subscriptions) + if new_stopped_message_generations: + self.process_new_stopped_message_generation(new_stopped_message_generations) if new_chat_join_request: self.process_new_chat_join_request(new_chat_join_request) if new_message_reactions: @@ -1037,6 +1044,16 @@ def process_new_subscription(self, new_subscriptions): """ self._notify_command_handlers(self.subscription_handlers, new_subscriptions, 'subscription') + def process_new_stopped_message_generation(self, new_stopped_message_generations): + """ + :meta private: + """ + self._notify_command_handlers( + self.stopped_message_generation_handlers, + new_stopped_message_generations, + 'stopped_message_generation', + ) + def process_middlewares(self, update): """ :meta private: @@ -11376,6 +11393,56 @@ def register_subscription_handler(self, callback: Callable, func: Optional[Calla handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) self.add_subscription_handler(handler_dict) + def stopped_message_generation_handler(self, func=None, **kwargs): + """ + Handles updates about a user stopping message generation. + + :param func: Function executed as a filter + :type func: :obj:`function` + + :param kwargs: Optional keyword arguments(custom filters) + :return: None + """ + def decorator(handler): + handler_dict = self._build_handler_dict(handler, func=func, **kwargs) + self.add_stopped_message_generation_handler(handler_dict) + return handler + + return decorator + + def add_stopped_message_generation_handler(self, handler_dict): + """ + Adds a stopped_message_generation handler. + Note that you should use register_stopped_message_generation_handler to add a handler to the bot. + + :meta private: + + :param handler_dict: + :return: + """ + self.stopped_message_generation_handlers.append(handler_dict) + + def register_stopped_message_generation_handler( + self, callback: Callable, func: Optional[Callable]=None, + pass_bot: Optional[bool]=False, **kwargs): + """ + Registers a stopped_message_generation handler. + + :param callback: function to be called + :type callback: :obj:`function` + + :param func: Function executed as a filter + :type func: :obj:`function` + + :param pass_bot: True if you need to pass TeleBot instance to handler(useful for separating handlers into different files) + :type pass_bot: :obj:`bool` + + :param kwargs: Optional keyword arguments(custom filters) + :return: None + """ + handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) + self.add_stopped_message_generation_handler(handler_dict) + def add_custom_filter(self, custom_filter: Union[SimpleCustomFilter, AdvancedCustomFilter]): """ diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 64bb69701..9557a25d8 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -188,6 +188,7 @@ def __init__(self, token: str, parse_mode: Optional[str]=None, offset: Optional[ self.managed_bot_handlers = [] self.guest_message_handlers = [] self.subscription_handlers = [] + self.stopped_message_generation_handlers = [] self.custom_filters = {} self.state_handlers = [] @@ -654,6 +655,7 @@ async def process_new_updates(self, updates: List[types.Update]): new_managed_bots = None new_guest_messages = None new_subscriptions = None + new_stopped_message_generations = None for update in updates: @@ -736,6 +738,9 @@ async def process_new_updates(self, updates: List[types.Update]): if update.subscription: if new_subscriptions is None: new_subscriptions = [] new_subscriptions.append(update.subscription) + if update.stopped_message_generation: + if new_stopped_message_generations is None: new_stopped_message_generations = [] + new_stopped_message_generations.append(update.stopped_message_generation) if new_messages: @@ -772,6 +777,8 @@ async def process_new_updates(self, updates: List[types.Update]): await self.process_new_message_reaction_count(new_message_reaction_count_handlers) if chat_boost_handlers: await self.process_new_chat_boost(chat_boost_handlers) + if removed_chat_boost_handlers: + await self.process_new_removed_chat_boost(removed_chat_boost_handlers) if new_business_connections: await self.process_new_business_connection(new_business_connections) if new_business_messages: @@ -788,6 +795,8 @@ async def process_new_updates(self, updates: List[types.Update]): await self.process_new_guest_message(new_guest_messages) if new_subscriptions: await self.process_new_subscriptions(new_subscriptions) + if new_stopped_message_generations: + await self.process_new_stopped_message_generation(new_stopped_message_generations) async def process_new_messages(self, new_messages): """ @@ -946,6 +955,16 @@ async def process_new_subscriptions(self, new_subscriptions): """ await self._process_updates(self.subscription_handlers, new_subscriptions, 'subscription') + async def process_new_stopped_message_generation(self, new_stopped_message_generations): + """ + :meta private: + """ + await self._process_updates( + self.stopped_message_generation_handlers, + new_stopped_message_generations, + 'stopped_message_generation', + ) + async def _get_middlewares(self, update_type): """ :meta private: @@ -2835,6 +2854,56 @@ def register_subscription_handler(self, callback: Callable, func: Optional[Calla handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) self.add_subscription_handler(handler_dict) + def stopped_message_generation_handler(self, func=None, **kwargs): + """ + Handles updates about a user stopping message generation. + + :param func: Function executed as a filter + :type func: :obj:`function` + + :param kwargs: Optional keyword arguments(custom filters) + :return: None + """ + def decorator(handler): + handler_dict = self._build_handler_dict(handler, func=func, **kwargs) + self.add_stopped_message_generation_handler(handler_dict) + return handler + + return decorator + + def add_stopped_message_generation_handler(self, handler_dict): + """ + Adds a stopped_message_generation handler. + Note that you should use register_stopped_message_generation_handler to add a handler to the bot. + + :meta private: + + :param handler_dict: + :return: + """ + self.stopped_message_generation_handlers.append(handler_dict) + + def register_stopped_message_generation_handler( + self, callback: Callable, func: Optional[Callable]=None, + pass_bot: Optional[bool]=False, **kwargs): + """ + Registers a stopped_message_generation handler. + + :param callback: function to be called + :type callback: :obj:`function` + + :param func: Function executed as a filter + :type func: :obj:`function` + + :param pass_bot: True if you need to pass AsyncTeleBot instance to handler(useful for separating handlers into different files) + :type pass_bot: :obj:`bool` + + :param kwargs: Optional keyword arguments(custom filters) + :return: None + """ + handler_dict = self._build_handler_dict(callback, func=func, pass_bot=pass_bot, **kwargs) + self.add_stopped_message_generation_handler(handler_dict) + @staticmethod def _build_handler_dict(handler, pass_bot=False, **filters): diff --git a/telebot/util.py b/telebot/util.py index 99c0777f7..bbb9b98af 100644 --- a/telebot/util.py +++ b/telebot/util.py @@ -44,7 +44,8 @@ 'checklist_tasks_done', 'checklist_tasks_added', 'direct_message_price_changed', 'suggested_post_refunded', 'suggested_post_info', 'suggested_post_approved', 'suggested_post_approval_failed', 'suggested_post_declined', 'suggested_post_paid', 'gift_upgrade_sent', 'chat_owner_left', 'chat_owner_changed', 'managed_bot_created', - 'poll_option_added', 'poll_option_deleted', 'community_chat_added', 'community_chat_removed' + 'poll_option_added', 'poll_option_deleted', 'community_chat_added', 'community_chat_removed', + 'community_chat_joined' ] #: All update types, should be used for allowed_updates parameter in polling. @@ -53,7 +54,7 @@ "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer", "my_chat_member", "chat_member", "chat_join_request", "message_reaction", "message_reaction_count", "removed_chat_boost", "chat_boost", "business_connection", "business_message", "edited_business_message", "deleted_business_messages", - "purchased_paid_media", "managed_bot", "guest_message", "subscription" + "purchased_paid_media", "managed_bot", "guest_message", "subscription", "stopped_message_generation" ] From 048bc4f3f06252975c4b0651722e33a142c95d1b Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 01:08:56 +0300 Subject: [PATCH 3/8] Fix for typed_middleware_handlers Bump version --- docs/source/conf.py | 2 +- pyproject.toml | 2 +- telebot/__init__.py | 5 +++++ telebot/version.py | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8e6376d40..6bfda157c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ copyright = f'2022-{datetime.now().year}, {author}' # The full version, including alpha/beta/rc tags -release = '4.36.1' +release = '4.37.0' # -- General configuration --------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index da1648f4c..101d8a69e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "pyTelegramBotAPI" -version = "4.36.1" +version = "4.37.0" description = "Python Telegram bot API." authors = [{name = "eternnoir", email = "eternnoir@gmail.com"}] license = {text = "GPL2"} diff --git a/telebot/__init__.py b/telebot/__init__.py index 953e88a2f..2a64397bf 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -282,6 +282,11 @@ def __init__( 'business_message': [], 'edited_business_message': [], 'deleted_business_messages': [], + 'purchased_paid_media': [], + 'managed_bot': [], + 'guest_message': [], + 'subscription': [], + 'stopped_message_generation': [], } self.default_middleware_handlers = [] if apihelper.ENABLE_MIDDLEWARE and use_class_middlewares: diff --git a/telebot/version.py b/telebot/version.py index f81e965a5..06eda0e7e 100644 --- a/telebot/version.py +++ b/telebot/version.py @@ -1,3 +1,3 @@ # Versions should comply with PEP440. # This line is parsed in setup.py: -__version__ = '4.36.1' +__version__ = '4.37.0' From 0a37c400d594264dafd7570b2981704fafcdb54c Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 01:17:14 +0300 Subject: [PATCH 4/8] Readme update. Test fix. --- README.md | 2 +- tests/test_types.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e9fd5e98..94ca926c3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

A simple, but extensible Python implementation for the Telegram Bot API.

Both synchronous and asynchronous.

-##

Supported Bot API version: Supported Bot API version +##

Supported Bot API version: Supported Bot API version

Official documentation

Official ru documentation

diff --git a/tests/test_types.py b/tests/test_types.py index 23a75fc23..73578e17b 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import json import sys sys.path.append('../') @@ -58,7 +59,7 @@ def test_api_103_new_optional_fields(): inline_keyboard = types.InlineKeyboardMarkup(force_reply=True) assert table.to_dict()['is_compact'] is True - assert '"force_reply":true' in reply_keyboard.to_json() + assert json.loads(reply_keyboard.to_json())['force_reply'] is True assert inline_keyboard.to_dict()['force_reply'] is True From a49bd1477f62e96df29109e28dd4a1ef6a6b1f36 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 23:09:55 +0300 Subject: [PATCH 5/8] Added some missed fields. --- telebot/__init__.py | 23 +++++++++++++++++++++-- telebot/async_telebot.py | 31 ++++++++++++++++++++++++++----- telebot/asyncio_helper.py | 10 +++++++++- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 2a64397bf..c058b85c8 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -2715,7 +2715,8 @@ def send_photo( def send_live_photo( self, chat_id: Union[int, str], live_photo: Union[Any, str], photo: Union[Any, str], - message_thread_id: Optional[int]=None, business_connection_id: Optional[str]=None, + message_thread_id: Optional[int]=None, direct_messages_topic_id: Optional[int]=None, + business_connection_id: Optional[str]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, show_caption_above_media: Optional[bool]=None, has_spoiler: Optional[bool]=None, disable_notification: Optional[bool]=None, protect_content: Optional[bool]=None, @@ -2731,6 +2732,9 @@ def send_live_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` + :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat + :type direct_messages_topic_id: :obj:`int` + :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent :type business_connection_id: :obj:`str` @@ -2799,6 +2803,7 @@ def send_live_photo( return types.Message.de_json( apihelper.send_live_photo( self.token, chat_id, live_photo, photo, message_thread_id=message_thread_id, + direct_messages_topic_id=direct_messages_topic_id, business_connection_id=business_connection_id, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, has_spoiler=has_spoiler, disable_notification=disable_notification, protect_content=protect_content, @@ -4674,13 +4679,20 @@ def send_message_draft( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :class:`telebot.types.MessageEntity + :param can_stop: Optional. Pass True if the user can stop message generation + :type can_stop: :obj:`bool` + + :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :type keep_on_stop: :obj:`bool` + :return: Returns True on success. :rtype: :obj:`bool` """ return apihelper.send_message_draft( self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, message_thread_id=message_thread_id, can_stop=can_stop, keep_on_stop=keep_on_stop) - + + def send_rich_message( self, chat_id: Union[int, str], rich_message: types.InputRichMessage, @@ -4755,6 +4767,7 @@ def send_rich_message( ephemeral_message_parameters=ephemeral_message_parameters) ) + def send_rich_message_draft( self, chat_id: int, draft_id: int, @@ -4780,6 +4793,12 @@ def send_rich_message_draft( :param message_thread_id: Unique identifier for the target message thread :type message_thread_id: :obj:`int` + :param can_stop: Optional. Pass True if the user can stop message generation + :type can_stop: :obj:`bool` + + :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :type keep_on_stop: :obj:`bool` + :return: Returns True on success. :rtype: :obj:`bool` """ diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 9557a25d8..85e09a0f6 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -4452,7 +4452,8 @@ async def send_photo( async def send_live_photo( self, chat_id: Union[int, str], live_photo: Union[Any, str], photo: Union[Any, str], - message_thread_id: Optional[int] = None, business_connection_id: Optional[str]=None, + message_thread_id: Optional[int] = None, direct_messages_topic_id: Optional[int]=None, + business_connection_id: Optional[str]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, show_caption_above_media: Optional[bool]=None, has_spoiler: Optional[bool]=None, @@ -4469,6 +4470,9 @@ async def send_live_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` + :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat + :type direct_messages_topic_id: :obj:`int` + :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent :type business_connection_id: :obj:`str` @@ -4539,6 +4543,7 @@ async def send_live_photo( return types.Message.de_json( await asyncio_helper.send_live_photo( self.token, chat_id, live_photo, photo, message_thread_id=message_thread_id, + direct_messages_topic_id=direct_messages_topic_id, business_connection_id=business_connection_id, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, has_spoiler=has_spoiler, disable_notification=disable_notification, protect_content=protect_content, @@ -6489,7 +6494,8 @@ async def send_rich_message_draft( self, chat_id: int, draft_id: int, rich_message: types.InputRichMessage, - message_thread_id: Optional[int]=None) -> bool: + message_thread_id: Optional[int]=None, can_stop: Optional[bool]=None, + keep_on_stop: Optional[bool]=None) -> bool: """ Use this method to stream a partial rich message to a user while the message is being generated Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output is finalized, @@ -6509,11 +6515,18 @@ async def send_rich_message_draft( :param message_thread_id: Unique identifier for the target message thread :type message_thread_id: :obj:`int` + :param can_stop: Optional. Pass True if the user can stop message generation + :type can_stop: :obj:`bool` + + :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :type keep_on_stop: :obj:`bool` + :return: Returns True on success. :rtype: :obj:`bool` """ return await asyncio_helper.send_rich_message_draft( - self.token, chat_id, draft_id, rich_message, message_thread_id=message_thread_id) + self.token, chat_id, draft_id, rich_message, message_thread_id=message_thread_id, + can_stop=can_stop, keep_on_stop=keep_on_stop) async def send_message_draft( self, chat_id: int, @@ -6521,7 +6534,8 @@ async def send_message_draft( text: str, message_thread_id: Optional[int]=None, parse_mode: Optional[str]=None, - entities: Optional[List[types.MessageEntity]]=None): + entities: Optional[List[types.MessageEntity]]=None, can_stop: Optional[bool]=None, + keep_on_stop: Optional[bool]=None): """ Use this method to stream a partial message to a user while the message is being generated; available for all bots. Returns True on success. @@ -6546,11 +6560,18 @@ async def send_message_draft( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :class:`telebot.types.MessageEntity + :param can_stop: Optional. Pass True if the user can stop message generation + :type can_stop: :obj:`bool` + + :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :type keep_on_stop: :obj:`bool` + :return: Returns True on success. :rtype: :obj:`bool` """ return await asyncio_helper.send_message_draft( - self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, message_thread_id=message_thread_id) + self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, + message_thread_id=message_thread_id, can_stop=can_stop, keep_on_stop=keep_on_stop) async def send_chat_action( self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None, message_thread_id: Optional[int]=None, diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 3c80be92d..c54b8ec13 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -329,6 +329,7 @@ async def send_message( params['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_name, params=params, method='post') + async def send_rich_message( token, chat_id, rich_message, disable_notification=None, protect_content=None, message_effect_id=None, @@ -361,6 +362,7 @@ async def send_rich_message( return await _process_request(token, method_url, params=payload, method='post') + async def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None, can_stop=None, keep_on_stop=None): method_url = r'sendRichMessageDraft' payload = {'chat_id': chat_id, 'draft_id': draft_id, 'rich_message': rich_message.to_json()} @@ -991,9 +993,10 @@ async def send_contact( payload['ephemeral_message_parameters'] = ephemeral_message_parameters.to_json() return await _process_request(token, method_url, params=payload) + async def send_message_draft( token, chat_id, draft_id, text, - message_thread_id=None, parse_mode=None, entities=None): + message_thread_id=None, parse_mode=None, entities=None, can_stop=None, keep_on_stop=None): method_url = r'sendMessageDraft' payload = {'chat_id': chat_id, 'draft_id': draft_id, 'text': text} if message_thread_id is not None: @@ -1002,8 +1005,13 @@ async def send_message_draft( payload['parse_mode'] = parse_mode if entities: payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) + if can_stop is not None: + payload['can_stop'] = can_stop + if keep_on_stop is not None: + payload['keep_on_stop'] = keep_on_stop return await _process_request(token, method_url, params=payload) + async def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None, business_connection_id=None): method_url = r'sendChatAction' payload = {'chat_id': chat_id, 'action': action} From d058e1ae21d69406dc1aa606f3deeae7d7aaeb61 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Tue, 8 Sep 2026 23:16:52 +0300 Subject: [PATCH 6/8] Some docstrings missed. --- telebot/__init__.py | 9 +++++++++ telebot/async_telebot.py | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/telebot/__init__.py b/telebot/__init__.py index c058b85c8..713bff803 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -5099,6 +5099,9 @@ def promote_chat_member( :param can_delete_stories: Pass True if the administrator can delete the channel's stories :type can_delete_stories: :obj:`bool` + :param can_send_welcome_messages: Pass True if the administrator can manage or send chat welcome messages + :type can_send_welcome_messages: :obj:`bool` + :param can_manage_direct_messages: Pass True if the administrator can manage direct messages within the channel and decline suggested posts; for channels only :type can_manage_direct_messages: :obj:`bool` @@ -7017,6 +7020,9 @@ def edit_ephemeral_message_text( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :obj:`MessageEntity` + :param rich_message: New rich content of the message; required if text isn't specified + :type rich_message: :obj:`InputRichMessage` + :param link_preview_options: Link preview generation options for the message :type link_preview_options: :obj:`LinkPreviewOptions` @@ -7095,6 +7101,9 @@ def edit_ephemeral_message_caption( :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :obj:`MessageEntity` + :param show_caption_above_media: Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. + :type show_caption_above_media: :obj:`bool` + :param reply_markup: A JSON-serialized object for an inline keyboard :type reply_markup: :obj:`InlineKeyboardMarkup` diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 85e09a0f6..03e1f13a0 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -6856,6 +6856,9 @@ async def promote_chat_member( :param can_delete_stories: Pass True if the administrator can delete the channel's stories :type can_delete_stories: :obj:`bool` + :param can_send_welcome_messages: Pass True if the administrator can manage or send chat welcome messages + :type can_send_welcome_messages: :obj:`bool` + :param can_manage_direct_messages: Pass True if the administrator can manage direct messages within the channel and decline suggested posts; for channels only :type can_manage_direct_messages: :obj:`bool` @@ -8693,6 +8696,9 @@ async def edit_ephemeral_message_text( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :obj:`MessageEntity` + :param rich_message: New rich content of the message; required if text isn't specified + :type rich_message: :obj:`InputRichMessage` + :param link_preview_options: Link preview generation options for the message :type link_preview_options: :obj:`LinkPreviewOptions` @@ -8771,6 +8777,9 @@ async def edit_ephemeral_message_caption( :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :obj:`MessageEntity` + :param show_caption_above_media: Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. + :type show_caption_above_media: :obj:`bool` + :param reply_markup: A JSON-serialized object for an inline keyboard :type reply_markup: :obj:`InlineKeyboardMarkup` From d35afa05b0a06d258bd3aeb252c4b666c2d1d1b0 Mon Sep 17 00:00:00 2001 From: Badiboy Date: Fri, 11 Sep 2026 00:34:33 +0300 Subject: [PATCH 7/8] Docstrings fix: parameters optionality and text --- telebot/__init__.py | 44 +++++++++++++-------------- telebot/async_telebot.py | 44 +++++++++++++-------------- telebot/types.py | 66 ++++++++++++++++++++-------------------- 3 files changed, 77 insertions(+), 77 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 713bff803..45c1da00a 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -1876,7 +1876,7 @@ def send_message( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :param suggested_post_parameters: A JSON-serialized object containing the parameters of the suggested post to send; @@ -2669,7 +2669,7 @@ def send_photo( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -2732,7 +2732,7 @@ def send_live_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` - :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat + :param direct_messages_topic_id: Optional. Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat :type direct_messages_topic_id: :obj:`int` :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent @@ -2790,7 +2790,7 @@ def send_live_photo( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -2932,7 +2932,7 @@ def send_audio( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3075,7 +3075,7 @@ def send_voice( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3229,7 +3229,7 @@ def send_document( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3376,7 +3376,7 @@ def send_sticker( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3563,7 +3563,7 @@ def send_video( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3741,7 +3741,7 @@ def send_animation( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -3890,7 +3890,7 @@ def send_video_note( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4217,7 +4217,7 @@ def send_location( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4476,7 +4476,7 @@ def send_venue( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4607,7 +4607,7 @@ def send_contact( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4679,10 +4679,10 @@ def send_message_draft( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :class:`telebot.types.MessageEntity - :param can_stop: Optional. Pass True if the user can stop message generation + :param can_stop: Optional. Pass True to show the user a button to stop further drafts. The bot will receive an Update “stopped_message_generation” if the user presses the button. :type can_stop: :obj:`bool` - :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :param keep_on_stop: Optional. Pass True to keep the draft in the chat when the button is pressed. The draft will still disappear after a short time or if the bot sends a message. To fully preserve the partial draft, the bot should send it as a new message. :type keep_on_stop: :obj:`bool` :return: Returns True on success. @@ -4750,7 +4750,7 @@ def send_rich_message( :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat :type direct_messages_topic_id: :obj:`int` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4793,10 +4793,10 @@ def send_rich_message_draft( :param message_thread_id: Unique identifier for the target message thread :type message_thread_id: :obj:`int` - :param can_stop: Optional. Pass True if the user can stop message generation + :param can_stop: Optional. Pass True to show the user a button to stop further drafts. The bot will receive an Update “stopped_message_generation” if the user presses the button. :type can_stop: :obj:`bool` - :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :param keep_on_stop: Optional. Pass True to keep the draft in the chat when the button is pressed. The draft will still disappear after a short time or if the bot sends a message. To fully preserve the partial draft, the bot should send it as a new message. :type keep_on_stop: :obj:`bool` :return: Returns True on success. @@ -5099,7 +5099,7 @@ def promote_chat_member( :param can_delete_stories: Pass True if the administrator can delete the channel's stories :type can_delete_stories: :obj:`bool` - :param can_send_welcome_messages: Pass True if the administrator can manage or send chat welcome messages + :param can_send_welcome_messages: Optional. Pass True if the administrator can manage chat welcome messages or directly send them in the case of bots :type can_send_welcome_messages: :obj:`bool` :param can_manage_direct_messages: Pass True if the administrator can manage direct messages @@ -7020,7 +7020,7 @@ def edit_ephemeral_message_text( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :obj:`MessageEntity` - :param rich_message: New rich content of the message; required if text isn't specified + :param rich_message: Optional. New rich content of the message; required if text isn't specified :type rich_message: :obj:`InputRichMessage` :param link_preview_options: Link preview generation options for the message @@ -7101,7 +7101,7 @@ def edit_ephemeral_message_caption( :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :obj:`MessageEntity` - :param show_caption_above_media: Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. + :param show_caption_above_media: Optional. Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. :type show_caption_above_media: :obj:`bool` :param reply_markup: A JSON-serialized object for an inline keyboard diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 03e1f13a0..453ce5e60 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -3619,7 +3619,7 @@ async def send_message( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4404,7 +4404,7 @@ async def send_photo( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4470,7 +4470,7 @@ async def send_live_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` - :param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat + :param direct_messages_topic_id: Optional. Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat :type direct_messages_topic_id: :obj:`int` :param business_connection_id: Unique identifier of the business connection on behalf of which the message will be sent @@ -4528,7 +4528,7 @@ async def send_live_photo( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4671,7 +4671,7 @@ async def send_audio( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4816,7 +4816,7 @@ async def send_voice( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -4974,7 +4974,7 @@ async def send_document( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -5125,7 +5125,7 @@ async def send_sticker( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -5312,7 +5312,7 @@ async def send_video( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -5490,7 +5490,7 @@ async def send_animation( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -5641,7 +5641,7 @@ async def send_video_note( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -5969,7 +5969,7 @@ async def send_location( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -6228,7 +6228,7 @@ async def send_venue( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -6364,7 +6364,7 @@ async def send_contact( :param callback_query_id: Deprecated. Use ephemeral_message_parameters instead. :type callback_query_id: :obj:`str` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send. + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -6473,7 +6473,7 @@ async def send_rich_message( :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` - :param ephemeral_message_parameters: Parameters of the ephemeral message to send + :param ephemeral_message_parameters: Optional. A JSON-serialized object containing the parameters of the ephemeral message to send :type ephemeral_message_parameters: :class:`telebot.types.EphemeralMessageParameters` :return: On success, the sent Message is returned. @@ -6515,10 +6515,10 @@ async def send_rich_message_draft( :param message_thread_id: Unique identifier for the target message thread :type message_thread_id: :obj:`int` - :param can_stop: Optional. Pass True if the user can stop message generation + :param can_stop: Optional. Pass True to show the user a button to stop further drafts. The bot will receive an Update “stopped_message_generation” if the user presses the button. :type can_stop: :obj:`bool` - :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :param keep_on_stop: Optional. Pass True to keep the draft in the chat when the button is pressed. The draft will still disappear after a short time or if the bot sends a message. To fully preserve the partial draft, the bot should send it as a new message. :type keep_on_stop: :obj:`bool` :return: Returns True on success. @@ -6560,10 +6560,10 @@ async def send_message_draft( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :class:`telebot.types.MessageEntity - :param can_stop: Optional. Pass True if the user can stop message generation + :param can_stop: Optional. Pass True to show the user a button to stop further drafts. The bot will receive an Update “stopped_message_generation” if the user presses the button. :type can_stop: :obj:`bool` - :param keep_on_stop: Optional. Pass True if the generated message must be kept after the user stops generation + :param keep_on_stop: Optional. Pass True to keep the draft in the chat when the button is pressed. The draft will still disappear after a short time or if the bot sends a message. To fully preserve the partial draft, the bot should send it as a new message. :type keep_on_stop: :obj:`bool` :return: Returns True on success. @@ -6856,7 +6856,7 @@ async def promote_chat_member( :param can_delete_stories: Pass True if the administrator can delete the channel's stories :type can_delete_stories: :obj:`bool` - :param can_send_welcome_messages: Pass True if the administrator can manage or send chat welcome messages + :param can_send_welcome_messages: Optional. Pass True if the administrator can manage chat welcome messages or directly send them in the case of bots :type can_send_welcome_messages: :obj:`bool` :param can_manage_direct_messages: Pass True if the administrator can manage direct messages @@ -8696,7 +8696,7 @@ async def edit_ephemeral_message_text( :param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode :type entities: :obj:`list` of :obj:`MessageEntity` - :param rich_message: New rich content of the message; required if text isn't specified + :param rich_message: Optional. New rich content of the message; required if text isn't specified :type rich_message: :obj:`InputRichMessage` :param link_preview_options: Link preview generation options for the message @@ -8777,7 +8777,7 @@ async def edit_ephemeral_message_caption( :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :obj:`MessageEntity` - :param show_caption_above_media: Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. + :param show_caption_above_media: Optional. Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. :type show_caption_above_media: :obj:`bool` :param reply_markup: A JSON-serialized object for an inline keyboard diff --git a/telebot/types.py b/telebot/types.py index 158ed53db..13c42864e 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -203,7 +203,7 @@ class Update(JsonDeserializable): :param subscription: Optional. User payment subscription has changed :type subscription: :class:`telebot.types.BotSubscriptionUpdated` - :param stopped_message_generation: Optional. A user asked the bot to stop message generation + :param stopped_message_generation: Optional. A user asked the bot to stop the generation of a message :type stopped_message_generation: :class:`telebot.types.MessageGenerationStopped` :return: Instance of the class @@ -2802,7 +2802,7 @@ class ReplyKeyboardMarkup(JsonSerializable): :param is_persistent: Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to False, in which case the custom keyboard can be hidden and opened with a keyboard icon. :type is_persistent: :obj:`bool` - :param force_reply: Optional. Shows the reply interface to the user + :param force_reply: Optional. Pass True if the reply interface must be shown to the user, as if they had manually selected the bot's message and tapped 'Reply' :type force_reply: :obj:`bool` :param row_width: Non-API. The width of the row in the keyboard when adding keys using "add" method. Defaults to 3. Maximum value is 12. @@ -3201,7 +3201,7 @@ class InlineKeyboardMarkup(Dictionaryable, JsonSerializable, JsonDeserializable) :param inline_keyboard: Array of button rows, each represented by an Array of InlineKeyboardButton objects :type inline_keyboard: :obj:`list` of :obj:`list` of :class:`telebot.types.InlineKeyboardButton` - :param force_reply: Optional. Shows the reply interface to the user + :param force_reply: Optional. Pass True if the reply interface must be shown to the user, as if they had manually selected the bot's message and tapped 'Reply'. The value of the field can't be changed when the inline keyboard is edited. :type force_reply: :obj:`bool` :param keyboard: Deprecated. Use inline_keyboard instead. @@ -3352,7 +3352,7 @@ class InlineKeyboardButton(Dictionaryable, JsonSerializable, JsonDeserializable) :param copy_text: Optional. Description of the button that copies the specified text to the clipboard. :type copy_text: :class:`telebot.types.CopyTextButton` - :param disabled: Optional. Description of a disabled button + :param disabled: Optional. If set, then the button is disabled and does nothing :type disabled: :class:`telebot.types.DisabledButton` :return: Instance of the class @@ -3698,7 +3698,7 @@ class ChatMemberAdministrator(ChatMember): :param can_delete_stories: True, if the administrator can delete stories posted by other users :type can_delete_stories: :obj:`bool` - :param can_send_welcome_messages: Optional. True, if the administrator can manage or send chat welcome messages + :param can_send_welcome_messages: True, if the administrator can manage chat welcome messages or directly send them in the case of bots :type can_send_welcome_messages: :obj:`bool` :param can_post_messages: Optional. True, if the administrator can post messages in the channel, approve suggested posts, or access channel statistics; for channels only @@ -8368,7 +8368,7 @@ class ChatAdministratorRights(JsonDeserializable, JsonSerializable, Dictionaryab :param can_delete_stories: True, if the administrator can delete stories posted by other users :type can_delete_stories: :obj:`bool` - :param can_send_welcome_messages: Optional. True, if the administrator can manage or send chat welcome messages + :param can_send_welcome_messages: True, if the administrator can manage chat welcome messages or directly send them in the case of bots :type can_send_welcome_messages: :obj:`bool` :param can_manage_direct_messages: Optional. True, if the administrator can manage direct messages of the channel and decline suggested posts; for channels only @@ -13234,13 +13234,13 @@ class UniqueGiftInfo(JsonDeserializable): :param last_resale_amount: Optional. For gifts bought from other users, the price paid for the gift in either Telegram Stars or nanograms :type last_resale_amount: :obj:`int` - :param text: Optional. Text accompanying the gift + :param text: Optional. Text of the message that was added to the gift :type text: :obj:`str` - :param entities: Optional. Special entities that appear in text + :param entities: Optional. Special entities that appear in the text :type entities: :obj:`list` of :class:`telebot.types.MessageEntity` - :param is_private: Optional. True, if the gift must not be shown publicly + :param is_private: Optional. True, if the sender and gift text are shown only to the gift receiver; otherwise, everyone will be able to see them :type is_private: :obj:`bool` :param owned_gift_id: Optional. Unique identifier of the received gift for the bot; only present for gifts received on behalf of business accounts @@ -16248,7 +16248,7 @@ class RichBlockTable(RichBlock): :param is_striped: Optional. True, if the table is striped :type is_striped: :obj:`bool` - :param is_compact: Optional. True, if the table must use compact spacing + :param is_compact: Optional. True, if table cells have smaller indents :type is_compact: :obj:`bool` :param caption: Optional. Caption of the table @@ -17176,7 +17176,7 @@ class InputRichBlockTable(InputRichBlock): :param is_striped: Optional. Pass True if the table is striped :type is_striped: :obj:`bool` - :param is_compact: Optional. Pass True if the table must use compact spacing + :param is_compact: Optional. Pass True if table cells must have smaller indents :type is_compact: :obj:`bool` :param caption: Optional. Caption of the table @@ -17518,13 +17518,13 @@ class EphemeralMessageParameters(Dictionaryable, JsonSerializable): Telegram documentation: https://core.telegram.org/bots/api#ephemeralmessageparameters - :param receiver_user_id: Identifier of the user who will receive the message + :param receiver_user_id: Identifier of the user who will receive the message. It is not guaranteed that the user will receive the message, especially if they are offline. See here for more details. :type receiver_user_id: :obj:`int` - :param callback_query_id: Optional. Identifier of the callback query which triggered the message + :param callback_query_id: Optional. Identifier of the callback query which triggered the message, if any :type callback_query_id: :obj:`str` - :param replace_callback_query_message: Optional. True, if the ephemeral message must replace the original message + :param replace_callback_query_message: Optional. Pass True if the ephemeral message must be shown in place of the original message. Must be False for callback queries from ephemeral messages, which must be edited using regular editEphemeralMessage… methods. :type replace_callback_query_message: :obj:`bool` :return: Instance of the class @@ -17557,10 +17557,10 @@ class MessageGenerationStopped(JsonDeserializable): :param chat: Chat in which the message is generated :type chat: :class:`telebot.types.Chat` - :param draft_id: Unique identifier of the stopped message draft + :param draft_id: Unique identifier of the message draft which was stopped :type draft_id: :obj:`int` - :param message_thread_id: Optional. Identifier of the message thread in which the message is generated + :param message_thread_id: Optional. Unique identifier of the message thread in which the message is generated :type message_thread_id: :obj:`int` :return: Instance of the class @@ -17587,37 +17587,37 @@ class RichMessageButton(Dictionaryable, JsonSerializable, JsonDeserializable): Telegram documentation: https://core.telegram.org/bots/api#richmessagebutton - :param text: Text of the button + :param text: Text of the button. May contain only plain text, RichTextCustomEmoji and RichTextDateTime entities. :type text: :class:`telebot.types.RichText` - :param style: Optional. Style of the button + :param style: Optional. Style of the button. Must be one of “danger”, “success”, “primary”, or “link” (the button is shown as a regular link without borders). Apps may use theme-specific colors for the button background and text based on the style. The style “link” is allowed only for callback buttons. :type style: :obj:`str` - :param url: Optional. HTTP or tg:// URL to open when the button is pressed + :param url: Optional. HTTP or tg:// URL to be opened when the button is pressed. Links tg://user?id= can be used to mention a user by their identifier without using a username, if this is allowed by their privacy settings. :type url: :obj:`str` - :param callback_data: Optional. Data to send in a callback query when the button is pressed + :param callback_data: Optional. Data to be sent in a callback query to the bot when the button is pressed, 1-64 bytes :type callback_data: :obj:`str` - :param web_app: Optional. Description of the Web App to launch when the button is pressed + :param web_app: Optional. Description of the Web App that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method answerWebAppQuery. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a business account. :type web_app: :class:`telebot.types.WebAppInfo` - :param login_url: Optional. HTTPS URL used to automatically authorize the user + :param login_url: Optional. An HTTPS URL used to automatically authorize the user. Can be used as a replacement for the Telegram Login Widget. Not supported for ephemeral messages. :type login_url: :class:`telebot.types.LoginUrl` - :param switch_inline_query: Optional. Inline query to insert after the user chooses a chat + :param switch_inline_query: Optional. If set, pressing the button will prompt the user to select one of their chats, open that chat and insert the bot's username and the specified inline query in the input field. May be empty, in which case just the bot's username will be inserted. Not supported for messages sent in channel direct messages chats and on behalf of a business account. :type switch_inline_query: :obj:`str` - :param switch_inline_query_current_chat: Optional. Inline query to insert in the current chat + :param switch_inline_query_current_chat: Optional. If set, pressing the button will insert the bot's username and the specified inline query in the current chat's input field. May be empty, in which case only the bot's username will be inserted. Not supported in channels and for messages sent in channel direct messages chats and on behalf of a business account. :type switch_inline_query_current_chat: :obj:`str` - :param switch_inline_query_chosen_chat: Optional. Criteria for choosing a chat for an inline query + :param switch_inline_query_chosen_chat: Optional. If set, pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field. Not supported for messages sent in channel direct messages chats and on behalf of a business account. :type switch_inline_query_chosen_chat: :class:`telebot.types.SwitchInlineQueryChosenChat` - :param copy_text: Optional. Description of text to copy to the clipboard + :param copy_text: Optional. A button that copies the specified text to the clipboard :type copy_text: :class:`telebot.types.CopyTextButton` - :param disabled: Optional. Marks the button as disabled + :param disabled: Optional. If set, then the button is disabled and does nothing :type disabled: :class:`telebot.types.DisabledButton` :return: Instance of the class @@ -17728,10 +17728,10 @@ class RichBlockButtons(RichBlock): :param type: Type of the block, always “buttons” :type type: :obj:`str` - :param buttons: Buttons in the block + :param buttons: The buttons :type buttons: :obj:`list` of :class:`telebot.types.RichMessageButton` - :param align: Optional. Horizontal alignment of the buttons + :param align: Optional. Horizontal alignment of the buttons. Currently, must be one of “left”, “center”, or “right”. :type align: :obj:`str` :return: Instance of the class @@ -17759,10 +17759,10 @@ class InputRichBlockButtons(InputRichBlock): :param type: Type of the block, always “buttons” :type type: :obj:`str` - :param buttons: Buttons in the block + :param buttons: List of 1-8 buttons to send :type buttons: :obj:`list` of :class:`telebot.types.RichMessageButton` - :param align: Optional. Horizontal alignment of the buttons + :param align: Optional. Horizontal alignment of the buttons. Currently, must be one of “left”, “center”, or “right”. :type align: :obj:`str` :return: Instance of the class @@ -17886,7 +17886,7 @@ class InputRichBlockDocument(InputRichBlock): :param type: Type of the block, always “document” :type type: :obj:`str` - :param document: The document. Its caption is ignored. + :param document: The document. Caption is ignored. :type document: :class:`telebot.types.InputMediaDocument` :param caption: Optional. Caption of the block @@ -17983,7 +17983,7 @@ class CommunityChatJoined(JsonDeserializable): Telegram documentation: https://core.telegram.org/bots/api#communitychatjoined - :param community: Community from which the chat was joined + :param community: The community from which the chat was joined :type community: :class:`telebot.types.Community` :return: Instance of the class From dd3fc3eae79f8963f0aa6159896d0b3aa4485c2b Mon Sep 17 00:00:00 2001 From: Badiboy Date: Fri, 11 Sep 2026 00:38:36 +0300 Subject: [PATCH 8/8] Docstring fix: classes descriptions. --- telebot/types.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index 13c42864e..4ce780b2c 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -17493,7 +17493,7 @@ def to_dict(self) -> dict: class DisabledButton(Dictionaryable, JsonSerializable, JsonDeserializable): """ - Represents a disabled inline or rich-message button. + This object represents a disabled button which does nothing. Currently holds no information. Telegram documentation: https://core.telegram.org/bots/api#disabledbutton @@ -17550,7 +17550,7 @@ def to_json(self): class MessageGenerationStopped(JsonDeserializable): """ - Describes an update about a user stopping message generation. + This object describes an update about a user stopping message generation. Telegram documentation: https://core.telegram.org/bots/api#messagegenerationstopped @@ -17581,9 +17581,7 @@ def de_json(cls, json_string): class RichMessageButton(Dictionaryable, JsonSerializable, JsonDeserializable): """ - Represents a button in a rich formatted message. - - Exactly one field other than text and style must be specified to define the button action. + This object represents a button in a RichMessage. Exactly one of the fields other than text and style must be used to specify the type of the button. Telegram documentation: https://core.telegram.org/bots/api#richmessagebutton @@ -17689,7 +17687,7 @@ def de_json(cls, json_string): class RichTextButton(RichText): """ - Represents a button in rich text. + A button. Telegram documentation: https://core.telegram.org/bots/api#richtextbutton @@ -17721,7 +17719,7 @@ def de_json(cls, json_string): class RichBlockButtons(RichBlock): """ - Represents a block containing buttons shown in one row. + A block containing a list of buttons that are shown in one row, corresponding to the custom HTML tag . Telegram documentation: https://core.telegram.org/bots/api#richblockbuttons @@ -17752,7 +17750,7 @@ def de_json(cls, json_string): class InputRichBlockButtons(InputRichBlock): """ - Represents a button row in a rich formatted message to be sent. + A block containing a list of buttons that are shown in one row, corresponding to the custom HTML tag . Telegram documentation: https://core.telegram.org/bots/api#inputrichblockbuttons @@ -17783,7 +17781,7 @@ def to_dict(self): class RichBlockExpandableBlockQuotation(RichBlock): """ - Represents an expandable block quotation. + A block quotation, corresponding to the HTML tag
with custom attribute "expandable". Telegram documentation: https://core.telegram.org/bots/api#richblockexpandableblockquotation @@ -17816,7 +17814,7 @@ def de_json(cls, json_string): class InputRichBlockExpandableBlockQuotation(InputRichBlock): """ - Represents an expandable block quotation in a rich formatted message to be sent. + A block quotation, corresponding to the HTML tag
with custom attribute "expandable". Telegram documentation: https://core.telegram.org/bots/api#inputrichblockexpandableblockquotation @@ -17847,7 +17845,7 @@ def to_dict(self): class RichBlockDocument(RichBlock): """ - Represents a block with a general file. + A block with a general file, corresponding to the custom HTML tag . Telegram documentation: https://core.telegram.org/bots/api#richblockdocument @@ -17879,7 +17877,7 @@ def de_json(cls, json_string): class InputRichBlockDocument(InputRichBlock): """ - Represents a block with a general file in a rich formatted message to be sent. + A block with a general file, corresponding to the custom HTML tag . Telegram documentation: https://core.telegram.org/bots/api#inputrichblockdocument