From 3fb148886d898aaf437c71f7edeb06f8b6d4f77e Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:41:00 +0100 Subject: [PATCH 01/24] Make `allow_sending_without_reply`, `reply_to_message_id` and `disable_web_page_preview` keyword-only parameters --- docs/substitutions/global.rst | 2 +- telegram/_bot.py | 735 +++++++++--------- telegram/_callbackquery.py | 6 +- telegram/_chat.py | 78 +- telegram/_inline/inputtextmessagecontent.py | 13 +- telegram/_message.py | 98 +-- telegram/_user.py | 78 +- telegram/_utils/argumentparsing.py | 21 + telegram/_utils/warnings_transition.py | 25 - telegram/ext/_extbot.py | 80 +- tests/_inline/test_inputtextmessagecontent.py | 2 +- tests/test_bot.py | 4 +- 12 files changed, 579 insertions(+), 563 deletions(-) diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 3909c0d51d9..228bd459bac 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -68,7 +68,7 @@ .. |rtm_aswr_deprecated| replace:: replacing this argument. PTB will automatically convert this argument to that one, but you should update your code to use the new argument. -.. |keyword_only_arg| replace:: In future versions, this argument will become a keyword-only argument. +.. |keyword_only_arg| replace:: This argument is now a keyword-only argument. .. |text_html| replace:: The return value of this property is a best-effort approach. Unfortunately, it can not be guaranteed that sending a message with the returned string will render in the same way as the original message produces the same :attr:`~telegram.Message.entities`/:attr:`~telegram.Message.caption_entities` as the original message. For example, Telegram recommends that entities of type :attr:`~telegram.MessageEntity.BLOCKQUOTE` and :attr:`~telegram.MessageEntity.PRE` *should* start and end on a new line, but does not enforce this and leaves rendering decisions up to the clients. diff --git a/telegram/_bot.py b/telegram/_bot.py index 280e47d1282..ee51da2a3ec 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -92,7 +92,7 @@ from telegram._update import Update from telegram._user import User from telegram._userprofilephotos import UserProfilePhotos -from telegram._utils.argumentparsing import parse_sequence_arg +from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue from telegram._utils.files import is_local_file, parse_file_input from telegram._utils.logging import get_logger @@ -100,7 +100,6 @@ from telegram._utils.strings import to_camel_case from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import warn_for_link_preview_options from telegram._webhookinfo import WebhookInfo from telegram.constants import InlineQueryLimit, ReactionEmoji from telegram.error import EndPointNotFound, InvalidToken @@ -668,10 +667,8 @@ async def _send_message( self, endpoint: str, data: JSONDict, - reply_to_message_id: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, caption: Optional[str] = None, @@ -680,6 +677,8 @@ async def _send_message( link_preview_options: ODVInput["LinkPreviewOptions"] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -918,19 +917,16 @@ async def send_message( text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, - # Deprecated since Bot API 7.0 (to be made keyword arg): - # --- - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - # --- disable_notification: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -957,49 +953,52 @@ async def send_message( .. versionadded:: 20.8 - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Mutually exclusive with :paramref:`link_preview_options`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`link_preview_options` replacing this - argument. PTB will automatically convert this argument to that one, but - for advanced options, please use :paramref:`link_preview_options` directly. - - .. deprecated:: 20.8 - In future versions, this argument will become a keyword-only argument. - disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| .. versionadded:: 13.10 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.0 + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.0 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in + this message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`link_preview_options` replacing this + argument. PTB will automatically convert this argument to that one, but + for advanced options, please use :paramref:`link_preview_options` directly. + + .. versionchanged:: NEXT.VERSION + This parameter is now a keyword only parameter. Returns: :class:`telegram.Message`: On success, the sent message is returned. @@ -1011,9 +1010,7 @@ async def send_message( """ data: JSONDict = {"chat_id": chat_id, "text": text, "entities": entities} - link_preview_options = warn_for_link_preview_options( - disable_web_page_preview, link_preview_options - ) + link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) return await self._send_message( "sendMessage", @@ -1271,16 +1268,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1326,23 +1323,6 @@ async def send_photo( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1357,6 +1337,24 @@ async def send_photo( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the photo, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1406,16 +1404,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1470,23 +1468,6 @@ async def send_audio( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1501,6 +1482,24 @@ async def send_audio( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the audio, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1550,17 +1549,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1614,23 +1613,6 @@ async def send_document( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1645,6 +1627,24 @@ async def send_document( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the document, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1689,14 +1689,14 @@ async def send_sticker( chat_id: Union[int, str], sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1734,31 +1734,34 @@ async def send_sticker( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -1797,13 +1800,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1811,6 +1812,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1870,24 +1873,6 @@ async def send_video( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -1905,6 +1890,24 @@ async def send_video( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1957,14 +1960,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2012,23 +2015,6 @@ async def send_video_note( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -2043,6 +2029,24 @@ async def send_video_note( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video note, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2092,9 +2096,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2102,6 +2104,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2155,24 +2159,6 @@ async def send_animation( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -2190,6 +2176,24 @@ async def send_animation( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the animation, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2241,15 +2245,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2297,29 +2301,12 @@ async def send_voice( |sequenceargs| duration (:obj:`int`, optional): Duration of the voice message in seconds. disable_notification (:obj:`bool`, optional): |disable_notification| - protect_content (:obj:`bool`, optional): |protect_content| - - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + protect_content (:obj:`bool`, optional): |protect_content| - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + .. versionadded:: 13.10 + message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.0 reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -2330,6 +2317,24 @@ async def send_voice( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the voice, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2377,12 +2382,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2423,29 +2428,30 @@ async def send_media_group( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| caption (:obj:`str`, optional): Caption that will be added to the first element of :paramref:`media`, so that it will be used as caption for the whole media group. @@ -2539,17 +2545,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, location: Optional[Location] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2590,33 +2596,34 @@ async def send_location( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| location (:class:`telegram.Location`, optional): The location to send. Returns: @@ -2820,16 +2827,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, venue: Optional[Venue] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2868,33 +2875,34 @@ async def send_venue( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| venue (:class:`telegram.Venue`, optional): The venue to send. Returns: @@ -2964,14 +2972,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, contact: Optional[Contact] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3000,33 +3008,34 @@ async def send_contact( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| contact (:class:`telegram.Contact`, optional): The contact to send. Returns: @@ -3085,13 +3094,13 @@ async def send_game( chat_id: int, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3111,29 +3120,33 @@ async def send_game( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new + inline keyboard. If empty, one "Play game_title" button will be + shown. If not empty, the first button must launch the game. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - inline keyboard. If empty, one "Play game_title" button will be - shown. If not empty, the first button must launch the game. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -3782,14 +3795,11 @@ async def edit_message_text( message_id: Optional[int] = None, inline_message_id: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - # Deprecated since Bot API 7.0 (to be keyword only): - # --- - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - # --- reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3829,19 +3839,22 @@ async def edit_message_text( .. versionadded:: 20.8 + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an + inline keyboard. + + Keyword Args: disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Mutually exclusive with :paramref:`link_preview_options`. + this message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`link_preview_options` replacing this argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. deprecated:: 20.8 - In future versions, this argument will become keyword only. + .. versionchanged:: NEXT.VERSION + This parameter is now a keyword only parameter. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. Returns: :class:`telegram.Message`: On success, if edited message is not an inline message, the @@ -3861,9 +3874,7 @@ async def edit_message_text( "entities": entities, } - link_preview_options = warn_for_link_preview_options( - disable_web_page_preview, link_preview_options - ) + link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) return await self._send_message( "editMessageText", @@ -4777,18 +4788,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -4884,30 +4895,33 @@ async def send_invoice( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an + inline keyboard. If empty, one 'Pay total price' button will be + shown. If not empty, the first button must be a Pay button. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. If empty, one 'Pay total price' button will be - shown. If not empty, the first button must be a Pay button. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -6794,18 +6808,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -6870,30 +6884,34 @@ async def send_poll( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -6986,14 +7004,14 @@ async def send_dice( self, chat_id: Union[int, str], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -7006,15 +7024,6 @@ async def send_dice( Args: chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| disable_notification (:obj:`bool`, optional): |disable_notification| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -7034,15 +7043,6 @@ async def send_dice( .. versionchanged:: 13.4 Added the :tg-const:`telegram.Dice.BOWLING` emoji. - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - protect_content (:obj:`bool`, optional): |protect_content| .. versionadded:: 13.10 @@ -7053,6 +7053,27 @@ async def send_dice( .. versionadded:: 20.8 + Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + + Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -7409,13 +7430,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -7449,31 +7470,33 @@ async def copy_message( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.MessageId`: On success diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index 66e4ebac54b..7fae55ab3e4 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -209,11 +209,11 @@ async def edit_message_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -808,13 +808,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_chat.py b/telegram/_chat.py index e9e40ee913d..c272bdab8d2 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -1411,17 +1411,17 @@ async def send_message( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1529,12 +1529,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1614,16 +1614,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1669,14 +1669,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional["Contact"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1723,16 +1723,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1780,17 +1780,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1834,14 +1834,14 @@ async def send_document( async def send_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1879,13 +1879,13 @@ async def send_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1938,18 +1938,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2018,17 +2018,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional["Location"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2078,9 +2078,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2088,6 +2086,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2135,14 +2135,14 @@ async def send_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2185,16 +2185,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional["Venue"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2243,13 +2243,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2257,6 +2255,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2307,14 +2307,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2359,15 +2359,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2417,18 +2417,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2481,13 +2481,13 @@ async def send_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2535,13 +2535,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 1a9207864e2..49666104bb6 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -21,13 +21,10 @@ from telegram._inline.inputmessagecontent import InputMessageContent from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg +from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings_transition import ( - warn_about_deprecated_attr_in_property, - warn_for_link_preview_options, -) +from telegram._utils.warnings_transition import warn_about_deprecated_attr_in_property if TYPE_CHECKING: from telegram._linkpreviewoptions import LinkPreviewOptions @@ -97,7 +94,7 @@ def __init__( self, message_text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, entities: Optional[Sequence[MessageEntity]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, @@ -111,8 +108,8 @@ def __init__( # Optionals self.parse_mode: ODVInput[str] = parse_mode self.entities: Tuple[MessageEntity, ...] = parse_sequence_arg(entities) - self.link_preview_options: ODVInput["LinkPreviewOptions"] = ( - warn_for_link_preview_options(disable_web_page_preview, link_preview_options) + self.link_preview_options: ODVInput["LinkPreviewOptions"] = parse_lpo_and_dwpp( + disable_web_page_preview, link_preview_options ) self._id_attrs = (self.message_text,) diff --git a/telegram/_message.py b/telegram/_message.py index 5c896b83483..7452c06a827 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -1764,17 +1764,17 @@ async def reply_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1829,17 +1829,17 @@ async def reply_text( async def reply_markdown( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1904,17 +1904,17 @@ async def reply_markdown( async def reply_markdown_v2( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1975,17 +1975,17 @@ async def reply_markdown_v2( async def reply_html( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2049,12 +2049,12 @@ async def reply_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2114,16 +2114,16 @@ async def reply_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2185,16 +2185,16 @@ async def reply_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2256,17 +2256,17 @@ async def reply_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2330,9 +2330,7 @@ async def reply_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2340,6 +2338,8 @@ async def reply_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2401,14 +2401,14 @@ async def reply_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2463,13 +2463,11 @@ async def reply_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2477,6 +2475,8 @@ async def reply_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2541,14 +2541,14 @@ async def reply_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2607,15 +2607,15 @@ async def reply_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2674,17 +2674,17 @@ async def reply_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional[Location] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2747,16 +2747,16 @@ async def reply_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional[Venue] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2819,14 +2819,14 @@ async def reply_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional[Contact] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2889,18 +2889,18 @@ async def reply_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime.datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2962,14 +2962,14 @@ async def reply_poll( async def reply_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3055,13 +3055,13 @@ async def reply_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3130,18 +3130,18 @@ async def reply_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3278,13 +3278,13 @@ async def copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3336,13 +3336,13 @@ async def reply_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3404,11 +3404,11 @@ async def edit_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_user.py b/telegram/_user.py index 5f6e251f578..27fefb9a053 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -386,17 +386,17 @@ async def send_message( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + disable_web_page_preview: Optional[bool] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -506,16 +506,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -564,12 +564,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -620,16 +620,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -719,14 +719,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional["Contact"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -771,14 +771,14 @@ async def send_contact( async def send_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -820,17 +820,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -878,13 +878,13 @@ async def send_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -940,18 +940,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1023,17 +1023,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional["Location"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1086,9 +1086,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1096,6 +1094,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1146,14 +1146,14 @@ async def send_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1197,13 +1197,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1211,6 +1209,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1266,16 +1266,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional["Venue"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1327,14 +1327,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1382,15 +1382,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1443,18 +1443,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1510,13 +1510,13 @@ async def send_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1565,13 +1565,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_utils/argumentparsing.py b/telegram/_utils/argumentparsing.py index b7232d7faa5..129f38a5cc4 100644 --- a/telegram/_utils/argumentparsing.py +++ b/telegram/_utils/argumentparsing.py @@ -25,6 +25,9 @@ """ from typing import Optional, Sequence, Tuple, TypeVar +from telegram._linkpreviewoptions import LinkPreviewOptions +from telegram._utils.types import ODVInput + T = TypeVar("T") @@ -38,3 +41,21 @@ def parse_sequence_arg(arg: Optional[Sequence[T]]) -> Tuple[T, ...]: :obj:`Tuple`: The sequence converted to a tuple or an empty tuple. """ return tuple(arg) if arg else () + + +def parse_lpo_and_dwpp( + disable_web_page_preview: Optional[bool], link_preview_options: ODVInput[LinkPreviewOptions] +) -> ODVInput[LinkPreviewOptions]: + """Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting + disable_web_page_preview to LinkPreviewOptions. + """ + if disable_web_page_preview and link_preview_options: + raise ValueError( + "Parameters `disable_web_page_preview` and `link_preview_options` are mutually " + "exclusive." + ) + + if disable_web_page_preview is not None: + link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview) + + return link_preview_options diff --git a/telegram/_utils/warnings_transition.py b/telegram/_utils/warnings_transition.py index b4e56d600d1..3caca518953 100644 --- a/telegram/_utils/warnings_transition.py +++ b/telegram/_utils/warnings_transition.py @@ -25,9 +25,6 @@ """ from typing import Any, Callable, Type -from telegram._linkpreviewoptions import LinkPreviewOptions -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.types import ODVInput from telegram._utils.warnings import warn from telegram.warnings import PTBDeprecationWarning @@ -93,28 +90,6 @@ def warn_about_deprecated_arg_return_new_arg( return new_arg -def warn_for_link_preview_options( - disable_web_page_preview: ODVInput[bool], link_preview_options: ODVInput[LinkPreviewOptions] -) -> ODVInput[LinkPreviewOptions]: - """Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting - disable_web_page_preview to LinkPreviewOptions. - """ - warn_about_deprecated_arg_return_new_arg( - deprecated_arg=disable_web_page_preview, - new_arg=link_preview_options, - deprecated_arg_name="disable_web_page_preview", - new_arg_name="link_preview_options", - bot_api_version="7.0", - stacklevel=2, - ) - - # Convert to LinkPreviewOptions: - if not isinstance(disable_web_page_preview, DefaultValue): - link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview) - - return link_preview_options - - def warn_about_deprecated_attr_in_property( deprecated_attr_name: str, new_attr_name: str, diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index a92ea2fab6d..a85ddf53b6e 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -558,10 +558,8 @@ async def _send_message( self, endpoint: str, data: JSONDict, - reply_to_message_id: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, caption: Optional[str] = None, @@ -570,6 +568,8 @@ async def _send_message( link_preview_options: ODVInput["LinkPreviewOptions"] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -767,13 +767,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1603,11 +1603,11 @@ async def edit_message_text( message_id: Optional[int] = None, inline_message_id: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2344,9 +2344,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2354,6 +2352,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2397,16 +2397,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2471,14 +2471,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional[Contact] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2512,14 +2512,14 @@ async def send_dice( self, chat_id: Union[int, str], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2550,17 +2550,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2597,13 +2597,13 @@ async def send_game( chat_id: int, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2648,18 +2648,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2710,17 +2710,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional[Location] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2759,12 +2759,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2800,16 +2800,16 @@ async def send_message( text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + disable_web_page_preview: Optional[bool] = None, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2844,16 +2844,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2895,18 +2895,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2947,14 +2947,14 @@ async def send_sticker( chat_id: Union[int, str], sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2989,16 +2989,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional[Venue] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3039,13 +3039,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -3053,6 +3051,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3095,14 +3095,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3139,15 +3139,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/tests/_inline/test_inputtextmessagecontent.py b/tests/_inline/test_inputtextmessagecontent.py index 052df0bbfa9..3d3a6b2f658 100644 --- a/tests/_inline/test_inputtextmessagecontent.py +++ b/tests/_inline/test_inputtextmessagecontent.py @@ -95,7 +95,7 @@ def test_equality(self): assert hash(a) != hash(d) def test_mutually_exclusive(self): - with pytest.raises(ValueError, match="'link_preview_options' in Bot API 7.0"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): InputTextMessageContent( "text", disable_web_page_preview=True, link_preview_options=LinkPreviewOptions() ) diff --git a/tests/test_bot.py b/tests/test_bot.py index 991d7e534cb..9f1d25d43f2 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -1061,12 +1061,12 @@ async def make_assertion(url, request_data: RequestData, *args, **kwargs): async def test_send_edit_message_mutually_exclusive_link_preview(self, bot, chat_id): """Test that link_preview is mutually exclusive with disable_web_page_preview.""" - with pytest.raises(ValueError, match="'disable_web_page_preview' was renamed to"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): await bot.send_message( chat_id, "text", disable_web_page_preview=True, link_preview_options="something" ) - with pytest.raises(ValueError, match="'disable_web_page_preview' was renamed to"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): await bot.edit_message_text( "text", chat_id, 1, disable_web_page_preview=True, link_preview_options="something" ) From c72d338c607f5b9c4a1799456631ffb608b12d43 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Mon, 12 Feb 2024 23:18:09 +0100 Subject: [PATCH 02/24] Remove `UserShared` and `KeyboardButtonRequestUser` --- telegram/__init__.py | 10 +--- telegram/_keyboardbutton.py | 57 +++++---------------- telegram/_keyboardbuttonrequest.py | 46 ----------------- telegram/_message.py | 69 +++++++------------------ telegram/_shared.py | 55 -------------------- telegram/ext/filters.py | 8 ++- tests/ext/test_filters.py | 4 +- tests/test_keyboardbutton.py | 46 ++++------------- tests/test_keyboardbuttonrequest.py | 31 +----------- tests/test_message.py | 26 +++------- tests/test_shared.py | 78 +---------------------------- 11 files changed, 58 insertions(+), 372 deletions(-) diff --git a/telegram/__init__.py b/telegram/__init__.py index 44505e52732..192edfd1b57 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -130,7 +130,6 @@ "KeyboardButton", "KeyboardButtonPollType", "KeyboardButtonRequestChat", - "KeyboardButtonRequestUser", "KeyboardButtonRequestUsers", "LabeledPrice", "LinkPreviewOptions", @@ -198,7 +197,6 @@ "User", "UserChatBoosts", "UserProfilePhotos", - "UserShared", "UsersShared", "Venue", "Video", @@ -338,11 +336,7 @@ from ._inline.inputvenuemessagecontent import InputVenueMessageContent from ._keyboardbutton import KeyboardButton from ._keyboardbuttonpolltype import KeyboardButtonPollType -from ._keyboardbuttonrequest import ( - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) +from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers from ._linkpreviewoptions import LinkPreviewOptions from ._loginurl import LoginUrl from ._menubutton import MenuButton, MenuButtonCommands, MenuButtonDefault, MenuButtonWebApp @@ -397,7 +391,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup from ._replykeyboardremove import ReplyKeyboardRemove from ._sentwebappmessage import SentWebAppMessage -from ._shared import ChatShared, UserShared, UsersShared +from ._shared import ChatShared, UsersShared from ._story import Story from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat from ._telegramobject import TelegramObject diff --git a/telegram/_keyboardbutton.py b/telegram/_keyboardbutton.py index 0c526b74ae8..bee303dd264 100644 --- a/telegram/_keyboardbutton.py +++ b/telegram/_keyboardbutton.py @@ -18,20 +18,12 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram KeyboardButton.""" -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional from telegram._keyboardbuttonpolltype import KeyboardButtonPollType -from telegram._keyboardbuttonrequest import ( - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) +from telegram._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings_transition import ( - warn_about_deprecated_arg_return_new_arg, - warn_about_deprecated_attr_in_property, -) from telegram._webappinfo import WebAppInfo if TYPE_CHECKING: @@ -60,6 +52,8 @@ class KeyboardButton(TelegramObject): versions released after 3 February, 2023. Older clients will display unsupported message. + .. versionchanged:: NEXT.VERSION + Removed deprecated argument and attribute ``request_user``. .. versionchanged:: 20.0 :attr:`web_app` is considered as well when comparing objects of this type in terms of equality. @@ -83,13 +77,6 @@ class KeyboardButton(TelegramObject): Available in private chats only. .. versionadded:: 20.0 - request_user (:class:`KeyboardButtonRequestUser` | :class:`KeyboardButtonRequestUsers`, \ - optional): Alias for - :attr:`request_users`. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates this argument in favor of ref`request_users`. request_users (:class:`KeyboardButtonRequestUsers`, optional): If specified, pressing the button will open a list of suitable users. Tapping on any user will send its @@ -150,9 +137,6 @@ def __init__( request_location: Optional[bool] = None, request_poll: Optional[KeyboardButtonPollType] = None, web_app: Optional[WebAppInfo] = None, - request_user: Optional[ - Union[KeyboardButtonRequestUsers, KeyboardButtonRequestUser] - ] = None, request_chat: Optional[KeyboardButtonRequestChat] = None, request_users: Optional[KeyboardButtonRequestUsers] = None, *, @@ -167,15 +151,7 @@ def __init__( self.request_location: Optional[bool] = request_location self.request_poll: Optional[KeyboardButtonPollType] = request_poll self.web_app: Optional[WebAppInfo] = web_app - self.request_users: Optional[KeyboardButtonRequestUsers] = ( - warn_about_deprecated_arg_return_new_arg( - deprecated_arg=request_user, - new_arg=request_users, - deprecated_arg_name="request_user", - new_arg_name="request_users", - bot_api_version="7.0", - ) - ) + self.request_users: Optional[KeyboardButtonRequestUsers] = request_users self.request_chat: Optional[KeyboardButtonRequestChat] = request_chat self._id_attrs = ( @@ -190,21 +166,6 @@ def __init__( self._freeze() - @property - def request_user(self) -> Optional[KeyboardButtonRequestUsers]: - """Optional[:class:`KeyboardButtonRequestUsers`]: Alias for :attr:`request_users`. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates this attribute in favor of :attr:`request_users`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="request_user", - new_attr_name="request_users", - bot_api_version="7.0", - ) - return self.request_users - @classmethod def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["KeyboardButton"]: """See :meth:`telegram.TelegramObject.de_json`.""" @@ -218,4 +179,10 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["KeyboardButt data["request_chat"] = KeyboardButtonRequestChat.de_json(data.get("request_chat"), bot) data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot) - return super().de_json(data=data, bot=bot) + api_kwargs = {} + # This is a deprecated field that TG still returns for backwards compatibility + # Let's filter it out to speed up the de-json process + if request_user := data.get("request_user"): + api_kwargs = {"request_user": request_user} + + return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) diff --git a/telegram/_keyboardbuttonrequest.py b/telegram/_keyboardbuttonrequest.py index e06d5c0f780..8d2d2398d56 100644 --- a/telegram/_keyboardbuttonrequest.py +++ b/telegram/_keyboardbuttonrequest.py @@ -22,9 +22,6 @@ from telegram._chatadministratorrights import ChatAdministratorRights from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import build_deprecation_warning_message -from telegram.warnings import PTBDeprecationWarning if TYPE_CHECKING: from telegram import Bot @@ -106,49 +103,6 @@ def __init__( self._freeze() -class KeyboardButtonRequestUser(KeyboardButtonRequestUsers): - """Alias for :class:`KeyboardButtonRequestUsers`, kept for backward compatibility. - - .. versionadded:: 20.1 - - .. deprecated:: 20.8 - Use :class:`KeyboardButtonRequestUsers` instead. - - """ - - __slots__ = () - - def __init__( - self, - request_id: int, - user_is_bot: Optional[bool] = None, - user_is_premium: Optional[bool] = None, - max_quantity: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, # skipcq: PYL-W0622 - ): - super().__init__( - request_id=request_id, - user_is_bot=user_is_bot, - user_is_premium=user_is_premium, - max_quantity=max_quantity, - api_kwargs=api_kwargs, - ) - - warn( - build_deprecation_warning_message( - deprecated_name="KeyboardButtonRequestUser", - new_name="KeyboardButtonRequestUsers", - object_type="class", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - - self._freeze() - - class KeyboardButtonRequestChat(TelegramObject): """This object defines the criteria used to request a suitable chat. The identifier of the selected user will be shared with the bot when the corresponding button is pressed. diff --git a/telegram/_message.py b/telegram/_message.py index 7452c06a827..5204cf9e9b2 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -55,7 +55,7 @@ from telegram._poll import Poll from telegram._proximityalerttriggered import ProximityAlertTriggered from telegram._reply import ReplyParameters -from telegram._shared import ChatShared, UserShared, UsersShared +from telegram._shared import ChatShared, UsersShared from telegram._story import Story from telegram._telegramobject import TelegramObject from telegram._user import User @@ -71,10 +71,7 @@ ReplyMarkup, ) from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import ( - build_deprecation_warning_message, - warn_about_deprecated_attr_in_property, -) +from telegram._utils.warnings_transition import warn_about_deprecated_attr_in_property from telegram._videochat import ( VideoChatEnded, VideoChatParticipantsInvited, @@ -218,7 +215,9 @@ def is_accessible(self) -> bool: return self.date != ZERO_DATE @classmethod - def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MaybeInaccessibleMessage"]: + def _de_json( + cls, data: Optional[JSONDict], bot: "Bot", api_kwargs: Optional[JSONDict] = None + ) -> Optional["MaybeInaccessibleMessage"]: """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) @@ -240,7 +239,7 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MaybeInacces data["date"] = from_timestamp(data["date"], tzinfo=loc_tzinfo) data["chat"] = Chat.de_json(data.get("chat"), bot) - return super().de_json(data=data, bot=bot) + return super()._de_json(data=data, bot=bot) class InaccessibleMessage(MaybeInaccessibleMessage): @@ -287,6 +286,9 @@ class Message(MaybeInaccessibleMessage): Note: In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. + .. versionchanged:: NEXT.VERSION + Removed deprecated argument and attribute ``user_shared``. + .. versionchanged:: 20.8 * This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`. * The :paramref:`pinned_message` now can be either class:`telegram.Message` or @@ -563,12 +565,6 @@ class Message(MaybeInaccessibleMessage): by a spoiler animation. .. versionadded:: 20.0 - user_shared (:class:`telegram.UserShared`, optional): Service message: a user was shared - with the bot. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`user_shared` in favor of :paramref:`users_shared`. users_shared (:class:`telegram.UsersShared`, optional): Service message: users were shared with the bot @@ -894,7 +890,6 @@ class Message(MaybeInaccessibleMessage): "_forward_from_message_id", "_forward_sender_name", "_forward_signature", - "_user_shared", "animation", "audio", "author_signature", @@ -1039,7 +1034,6 @@ def __init__( general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None, write_access_allowed: Optional[WriteAccessAllowed] = None, has_media_spoiler: Optional[bool] = None, - user_shared: Optional[UserShared] = None, chat_shared: Optional[ChatShared] = None, story: Optional[Story] = None, giveaway: Optional["Giveaway"] = None, @@ -1056,18 +1050,6 @@ def __init__( ): super().__init__(chat=chat, message_id=message_id, date=date, api_kwargs=api_kwargs) - if user_shared: - warn( - build_deprecation_warning_message( - deprecated_name="user_shared", - new_name="users_shared", - object_type="parameter", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - if any( ( forward_from, @@ -1181,7 +1163,6 @@ def __init__( ) self.write_access_allowed: Optional[WriteAccessAllowed] = write_access_allowed self.has_media_spoiler: Optional[bool] = has_media_spoiler - self._user_shared: Optional[UserShared] = user_shared self.users_shared: Optional[UsersShared] = users_shared self.chat_shared: Optional[ChatShared] = chat_shared self.story: Optional[Story] = story @@ -1209,27 +1190,6 @@ def __bool__(self) -> bool: """ return True - @property - def user_shared(self) -> Optional[UserShared]: - """:class:`telegram.UserShared`: Optional. Service message. A user was shared with the - bot. - - Hint: - In case a single user was shared, :attr:`user_shared` will be present in addition to - :attr:`users_shared`. If multiple users where shared, only :attr:`users_shared` will - be present. However, this behavior is not documented and may be changed by Telegram. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`user_shared` in favor of :attr:`users_shared`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="user_shared", - new_attr_name="users_shared", - bot_api_version="7.0", - ) - return self._user_shared - @property def forward_from(self) -> Optional[User]: """:class:`telegram.User`: Optional. For forwarded messages, sender of the original @@ -1434,7 +1394,6 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["write_access_allowed"] = WriteAccessAllowed.de_json( data.get("write_access_allowed"), bot ) - data["user_shared"] = UserShared.de_json(data.get("user_shared"), bot) data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot) data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot) @@ -1464,7 +1423,15 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["quote"] = TextQuote.de_json(data.get("quote"), bot) data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] + api_kwargs = {} + # This is a deprecated field that TG still returns for backwards compatibility + # Let's filter it out to speed up the de-json process + if user_shared := data.get("user_shared"): + api_kwargs = {"user_shared": user_shared} + + return super()._de_json( # type: ignore[return-value] + data=data, bot=bot, api_kwargs=api_kwargs + ) @property def effective_attachment( diff --git a/telegram/_shared.py b/telegram/_shared.py index f062ea4a7be..c6724f283a9 100644 --- a/telegram/_shared.py +++ b/telegram/_shared.py @@ -21,12 +21,6 @@ from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import ( - build_deprecation_warning_message, - warn_about_deprecated_attr_in_property, -) -from telegram.warnings import PTBDeprecationWarning class UsersShared(TelegramObject): @@ -78,55 +72,6 @@ def __init__( self._freeze() -class UserShared(UsersShared): - """Alias for :class:`UsersShared`, kept for backward compatibility. - - .. versionadded:: 20.1 - - .. deprecated:: 20.8 - Use :class:`UsersShared` instead. - - """ - - __slots__ = () - - def __init__( - self, - request_id: int, - user_id: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(request_id, (user_id,), api_kwargs=api_kwargs) - - warn( - build_deprecation_warning_message( - deprecated_name="UserShared", - new_name="UsersShared", - object_type="class", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - - self._freeze() - - @property - def user_id(self) -> int: - """Alias for the first entry of :attr:`UsersShared.user_ids`. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates this attribute in favor of :attr:`UsersShared.user_ids`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="user_id", - new_attr_name="user_ids", - bot_api_version="7.0", - ) - return self.user_ids[0] - - class ChatShared(TelegramObject): """ This object contains information about the chat whose identifier was shared with the bot diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index e4bba593b9e..9ca51d537e1 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -2146,15 +2146,19 @@ class _UserShared(MessageFilter): __slots__ = () def filter(self, message: Message) -> bool: - return bool(message.user_shared) + return bool(message.api_kwargs.get("user_shared")) USER_SHARED = _UserShared(name="filters.StatusUpdate.USER_SHARED") """Messages that contain :attr:`telegram.Message.user_shared`. Warning: - This will only catch the legacy :attr:`telegram.Message.user_shared` attribute, not the + This will only catch the legacy ``user_shared`` field, not the new :attr:`telegram.Message.users_shared` attribute! + .. versionchanged:: NEXT.VERSION + Now relies on :attr:`TelegramObject.api_kwargs` as the native attribute + ``Message.user_shared`` was removed. + .. versionadded:: 20.1 .. deprecated:: 20.8 Use :attr:`USERS_SHARED` instead. diff --git a/tests/ext/test_filters.py b/tests/ext/test_filters.py index bc848a17a19..468e5943b1f 100644 --- a/tests/ext/test_filters.py +++ b/tests/ext/test_filters.py @@ -1065,10 +1065,10 @@ def test_filters_status_update(self, update): assert filters.StatusUpdate.WRITE_ACCESS_ALLOWED.check_update(update) update.message.write_access_allowed = None - update.message._user_shared = "user_shared" + update.message.api_kwargs = {"user_shared": "user_shared"} assert filters.StatusUpdate.ALL.check_update(update) assert filters.StatusUpdate.USER_SHARED.check_update(update) - update.message._user_shared = None + update.message.api_kwargs = {} update.message.users_shared = "users_shared" assert filters.StatusUpdate.ALL.check_update(update) diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index 4709ee18cf3..c1ca88984ef 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -23,11 +23,9 @@ KeyboardButton, KeyboardButtonPollType, KeyboardButtonRequestChat, - KeyboardButtonRequestUser, KeyboardButtonRequestUsers, WebAppInfo, ) -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -91,46 +89,22 @@ def test_de_json(self, bot): "web_app": self.web_app.to_dict(), "request_chat": self.request_chat.to_dict(), "request_users": self.request_users.to_dict(), + "request_user": {"request_id": 2}, } - inline_keyboard_button = KeyboardButton.de_json(json_dict, None) - assert inline_keyboard_button.api_kwargs == {} - assert inline_keyboard_button.text == self.text - assert inline_keyboard_button.request_location == self.request_location - assert inline_keyboard_button.request_contact == self.request_contact - assert inline_keyboard_button.request_poll == self.request_poll - assert inline_keyboard_button.web_app == self.web_app - assert inline_keyboard_button.request_chat == self.request_chat - assert inline_keyboard_button.request_user == self.request_users - assert inline_keyboard_button.request_users == self.request_users + keyboard_button = KeyboardButton.de_json(json_dict, None) + assert keyboard_button.api_kwargs == {"request_user": {"request_id": 2}} + assert keyboard_button.text == self.text + assert keyboard_button.request_location == self.request_location + assert keyboard_button.request_contact == self.request_contact + assert keyboard_button.request_poll == self.request_poll + assert keyboard_button.web_app == self.web_app + assert keyboard_button.request_chat == self.request_chat + assert keyboard_button.request_users == self.request_users none = KeyboardButton.de_json({}, None) assert none is None - def test_request_user_deprecation_mutually_exclusive(self): - with pytest.raises(ValueError, match="'request_user' was renamed to 'request_users'"): - KeyboardButton( - "test", - request_users=KeyboardButtonRequestUsers(1), - request_user=KeyboardButtonRequestUsers(2), - ) - - def test_request_user_argument_deprecation_warning(self): - with pytest.warns( - PTBDeprecationWarning, match="'request_user' to 'request_users'" - ) as record: - KeyboardButton("test", request_user=KeyboardButtonRequestUser(2)) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_request_user_property_deprecation_warning(self, keyboard_button): - with pytest.warns( - PTBDeprecationWarning, match="'request_user' to 'request_users'" - ) as record: - assert keyboard_button.request_user is keyboard_button.request_users - - assert record[0].filename == __file__, "wrong stacklevel" - def test_equality(self): a = KeyboardButton("test", request_contact=True) b = KeyboardButton("test", request_contact=True) diff --git a/tests/test_keyboardbuttonrequest.py b/tests/test_keyboardbuttonrequest.py index 2a70df2406e..609c2652627 100644 --- a/tests/test_keyboardbuttonrequest.py +++ b/tests/test_keyboardbuttonrequest.py @@ -16,17 +16,10 @@ # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. -import inspect import pytest -from telegram import ( - ChatAdministratorRights, - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) -from telegram.warnings import PTBDeprecationWarning +from telegram import ChatAdministratorRights, KeyboardButtonRequestChat, KeyboardButtonRequestUsers from tests.auxil.slots import mro_slots @@ -92,28 +85,6 @@ def test_equality(self): assert hash(a) != hash(c) -class TestKeyboardButtonRequestUserWithoutRequest: - def test_slot_behaviour(self): - inst = KeyboardButtonRequestUser(1) - for attr in inst.__slots__: - assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'" - assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" - - def test_signature(self): - assert inspect.signature(KeyboardButtonRequestUser) == inspect.signature( - KeyboardButtonRequestUsers - ) - - def test_deprecation_warning(self): - with pytest.warns( - PTBDeprecationWarning, - match="'KeyboardButtonRequestUser' was renamed to 'KeyboardButtonRequestUsers'", - ) as record: - KeyboardButtonRequestUser(request_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - @pytest.fixture(scope="class") def request_chat(): return KeyboardButtonRequestChat( diff --git a/tests/test_message.py b/tests/test_message.py index ae9e79b69c5..4af15c42791 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -224,9 +224,6 @@ def message(bot): }, {"web_app_data": WebAppData("some_data", "some_button_text")}, {"message_thread_id": 123}, - # Using a `UserShared` object here doesn't work, because `to_dict` produces `user_ids` - # instead of `user_id` - but that's what we want to test here. - {"user_shared": {"request_id": 1, "user_id": 2}}, {"users_shared": UsersShared(1, [2, 3])}, {"chat_shared": ChatShared(3, 4)}, { @@ -324,7 +321,6 @@ def message(bot): "entities", "web_app_data", "message_thread_id", - "user_shared", "users_shared", "chat_shared", "giveaway", @@ -551,6 +547,12 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): assert message_bot.forward_date.tzinfo == UTC assert forward_date_offset == forward_date_tz_bot_offset + def test_de_json_api_kwargs_backward_compatibility(self, bot, message_params): + message_dict = message_params.to_dict() + message_dict["user_shared"] = {"request_id": 1, "user_id": 2} + message = Message.de_json(message_dict, bot) + assert message.api_kwargs == {"user_shared": {"request_id": 1, "user_id": 2}} + def test_equality(self): id_ = 1 a = Message(id_, self.date, self.chat, from_user=self.from_user) @@ -572,22 +574,6 @@ def test_equality(self): assert a != e assert hash(a) != hash(e) - def test_user_shared_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'user_shared' was renamed to 'users_shared'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, user_shared=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_user_shared_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'user_shared' to 'users_shared'" - ) as record: - message.user_shared - - assert record[0].filename == __file__, "wrong stacklevel" - def test_forward_from_init_deprecation(self, message): with pytest.warns( PTBDeprecationWarning, match="'forward_from' was transferred to 'forward_origin'" diff --git a/tests/test_shared.py b/tests/test_shared.py index 1ea98ac5d20..da1f21881fc 100644 --- a/tests/test_shared.py +++ b/tests/test_shared.py @@ -16,20 +16,13 @@ # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. -import inspect import pytest -from telegram import ChatShared, UserShared, UsersShared -from telegram.warnings import PTBDeprecationWarning +from telegram import ChatShared, UsersShared from tests.auxil.slots import mro_slots -@pytest.fixture(scope="class") -def user_shared(): - return UserShared(TestUsersSharedBase.request_id, TestUsersSharedBase.user_id) - - @pytest.fixture(scope="class") def users_shared(): return UsersShared(TestUsersSharedBase.request_id, TestUsersSharedBase.user_ids) @@ -82,75 +75,6 @@ def test_equality(self): assert hash(a) != hash(d) -class TestUserSharedWithoutRequest(TestUsersSharedBase): - def test_slot_behaviour(self, user_shared): - for attr in user_shared.__slots__: - assert getattr(user_shared, attr, "err") != "err", f"got extra slot '{attr}'" - assert len(mro_slots(user_shared)) == len(set(mro_slots(user_shared))), "duplicate slot" - - def test_to_dict(self, user_shared): - user_shared_dict = user_shared.to_dict() - - assert isinstance(user_shared_dict, dict) - assert user_shared_dict["request_id"] == self.request_id - assert user_shared_dict["user_ids"] == [self.user_id] - - def test_de_json(self, bot): - json_dict = { - "request_id": self.request_id, - "user_id": self.user_id, - } - user_shared = UserShared.de_json(json_dict, bot) - assert user_shared.api_kwargs == {} - - assert user_shared.request_id == self.request_id - assert user_shared.user_id == self.user_id - assert user_shared.user_ids == (self.user_id,) - - def test_signature(self): - user_signature = inspect.signature(UserShared) - users_signature = inspect.signature(UsersShared) - - assert user_signature.return_annotation == users_signature.return_annotation - - for name, parameter in user_signature.parameters.items(): - if name not in users_signature.parameters: - assert name == "user_id" - else: - assert parameter.annotation == users_signature.parameters[name].annotation - - assert set(users_signature.parameters) - set(user_signature.parameters) == {"user_ids"} - - def test_deprecation_warnings(self): - with pytest.warns( - PTBDeprecationWarning, match="'UserShared' was renamed to 'UsersShared'" - ) as record: - user_shared = UserShared(request_id=1, user_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - with pytest.warns(PTBDeprecationWarning, match="'user_id' to 'user_ids'") as record: - user_shared.user_id - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_equality(self): - a = UserShared(self.request_id, self.user_id) - b = UserShared(self.request_id, self.user_id) - c = UserShared(1, self.user_id) - d = UserShared(self.request_id, 1) - - assert a == b - assert hash(a) == hash(b) - assert a is not b - - assert a != c - assert hash(a) != hash(c) - - assert a != d - assert hash(a) != hash(d) - - @pytest.fixture(scope="class") def chat_shared(): return ChatShared( From f0047012c6a61da756a90477a65a6f316520bff3 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 15 Feb 2024 23:15:46 +0100 Subject: [PATCH 03/24] Feat: API 7.1 --- README.rst | 4 +- README_RAW.rst | 4 +- docs/source/telegram.at-tree.rst | 1 + docs/source/telegram.chatboostadded.rst | 6 +++ telegram/__init__.py | 2 + telegram/_bot.py | 14 +++--- telegram/_chat.py | 26 +++++++++++ telegram/_chatadministratorrights.py | 22 +++++---- telegram/_chatboostadded.py | 56 +++++++++++++++++++++++ telegram/_chatmember.py | 22 +++++---- telegram/_message.py | 38 +++++++++++++++- telegram/_story.py | 51 ++++++++++++++++++--- telegram/constants.py | 17 ++++++- tests/test_chat.py | 10 +++++ tests/test_chatboostadded.py | 59 +++++++++++++++++++++++++ tests/test_message.py | 9 +++- tests/test_story.py | 45 +++++++++++++++---- 17 files changed, 334 insertions(+), 52 deletions(-) create mode 100644 docs/source/telegram.chatboostadded.rst create mode 100644 telegram/_chatboostadded.py create mode 100644 tests/test_chatboostadded.py diff --git a/README.rst b/README.rst index b40ac1331ee..23ac978b316 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.0-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.0** are supported. +All types and methods of the Telegram Bot API **7.1** are supported. Installing ========== diff --git a/README_RAW.rst b/README_RAW.rst index 5c3f7f60dfa..d0ece2a8117 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot-raw/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.0-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.0** are supported. +All types and methods of the Telegram Bot API **7.1** are supported. Installing ========== diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index c5159a71e0c..bcf3d6a9cf2 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -22,6 +22,7 @@ Available Types telegram.chat telegram.chatadministratorrights telegram.chatboost + telegram.chatboostadded telegram.chatboostremoved telegram.chatboostsource telegram.chatboostsourcegiftcode diff --git a/docs/source/telegram.chatboostadded.rst b/docs/source/telegram.chatboostadded.rst new file mode 100644 index 00000000000..b4551e75b84 --- /dev/null +++ b/docs/source/telegram.chatboostadded.rst @@ -0,0 +1,6 @@ +ChatBoostAdded +============== + +.. autoclass:: telegram.ChatBoostAdded + :members: + :show-inheritance: \ No newline at end of file diff --git a/telegram/__init__.py b/telegram/__init__.py index 192edfd1b57..9410740d20c 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -40,6 +40,7 @@ "Chat", "ChatAdministratorRights", "ChatBoost", + "ChatBoostAdded", "ChatBoostRemoved", "ChatBoostSource", "ChatBoostSourceGiftCode", @@ -250,6 +251,7 @@ ChatBoostUpdated, UserChatBoosts, ) +from ._chatboostadded import ChatBoostAdded from ._chatinvitelink import ChatInviteLink from ._chatjoinrequest import ChatJoinRequest from ._chatlocation import ChatLocation diff --git a/telegram/_bot.py b/telegram/_bot.py index 8cecdedffea..1cf6cd9ec6d 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -5250,10 +5250,10 @@ async def promote_chat_member( user_id (:obj:`int`): Unique identifier of the target user. is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence in the chat is hidden. - can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - access the chat event log, chat statistics, boost list in channels, see channel - members, report spam messages, see anonymous administrators in supergroups and - ignore slow mode. Implied by any other administrator privilege. + can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + access the chat event log, get boost list, see hidden supergroup and channel + members, report spam messages and ignore slow mode. Implied by any other + administrator privilege. .. versionadded:: 13.4 @@ -5285,15 +5285,15 @@ async def promote_chat_member( .. versionadded:: 20.0 can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - post stories in the channel; channels only. + post stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit stories posted by other users; channels only. + edit stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - delete stories posted by other users; channels only. + delete stories posted by other users. .. versionadded:: 20.6 diff --git a/telegram/_chat.py b/telegram/_chat.py index c272bdab8d2..9b7234667e4 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -219,6 +219,16 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of + boosts that a non-administrator user needs to add in order to ignore slow mode and chat + permissions. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION + custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the + group's custom emoji sticker set. Custom emoji from this set can be used by all users + and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION Attributes: id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits @@ -352,6 +362,16 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of + boosts that a non-administrator user needs to add in order to ignore slow mode and chat + permissions. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION + custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the + group's custom emoji sticker set. Custom emoji from this set can be used by all users + and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups .. _accent colors: https://core.telegram.org/bots/api#accent-colors @@ -364,6 +384,7 @@ class Chat(TelegramObject): "background_custom_emoji_id", "bio", "can_set_sticker_set", + "custom_emoji_sticker_set_name", "description", "emoji_status_custom_emoji_id", "emoji_status_expiration_date", @@ -392,6 +413,7 @@ class Chat(TelegramObject): "sticker_set_name", "title", "type", + "unrestrict_boost_count", "username", ) @@ -446,6 +468,8 @@ def __init__( profile_accent_color_id: Optional[int] = None, profile_background_custom_emoji_id: Optional[str] = None, has_visible_history: Optional[bool] = None, + unrestrict_boost_count: Optional[int] = None, + custom_emoji_sticker_set_name: Optional[str] = None, *, api_kwargs: Optional[JSONDict] = None, ): @@ -493,6 +517,8 @@ def __init__( self.background_custom_emoji_id: Optional[str] = background_custom_emoji_id self.profile_accent_color_id: Optional[int] = profile_accent_color_id self.profile_background_custom_emoji_id: Optional[str] = profile_background_custom_emoji_id + self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count + self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name self._id_attrs = (self.id,) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index f0c84eeb5e9..066e7ca963c 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -47,9 +47,8 @@ class ChatAdministratorRights(TelegramObject): Args: is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video @@ -71,15 +70,15 @@ class ChatAdministratorRights(TelegramObject): can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post - stories in the channel; channels only. + stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed @@ -90,9 +89,8 @@ class ChatAdministratorRights(TelegramObject): Attributes: is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video @@ -114,15 +112,15 @@ class ChatAdministratorRights(TelegramObject): can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - stories in the channel; channels only. + stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed diff --git a/telegram/_chatboostadded.py b/telegram/_chatboostadded.py new file mode 100644 index 00000000000..d1ec211dba8 --- /dev/null +++ b/telegram/_chatboostadded.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2023 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the ChatBoostAdded object.""" +from typing import Optional + +from telegram._telegramobject import TelegramObject +from telegram._utils.types import JSONDict + + +class ChatBoostAdded(TelegramObject): + """ + This object represents a service message about a user boosting a chat. + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`boost_count` are equal. + + .. versionadded:: NEXT.VERSION + + Args: + boost_count (:obj:`int`): Number of boosts added by the user. + + Attributes: + boost_count (:obj:`int`): Number of boosts added by the user. + + """ + + __slots__ = ("boost_count",) + + def __init__( + self, + boost_count: int, + *, + api_kwargs: Optional[JSONDict] = None, + ) -> None: + super().__init__(api_kwargs=api_kwargs) + self.boost_count: int = boost_count + self._id_attrs = (self.boost_count,) + + self._freeze() diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index d385b8bf7b6..3953a9dde7e 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -197,9 +197,8 @@ class ChatMemberAdministrator(ChatMember): is allowed to edit administrator privileges of that user. is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator - can access the chat event log, chat statistics, message statistics in - channels, see channel members, see anonymous administrators in supergroups + can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event + log, get boost list, see hidden supergroup and channel members, report spam messages and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. @@ -226,15 +225,15 @@ class ChatMemberAdministrator(ChatMember): can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post - stories in the channel; channels only. + stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed @@ -252,9 +251,8 @@ class ChatMemberAdministrator(ChatMember): is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the @@ -280,15 +278,15 @@ class ChatMemberAdministrator(ChatMember): can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - stories in the channel; channels only. + stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + stories posted by other users. .. versionadded:: 20.6 can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed diff --git a/telegram/_message.py b/telegram/_message.py index 5204cf9e9b2..f9b6dfb5b60 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, TypedDict, Union from telegram._chat import Chat +from telegram._chatboostadded import ChatBoostAdded from telegram._dice import Dice from telegram._files.animation import Animation from telegram._files.audio import Audio @@ -601,6 +602,18 @@ class Message(MaybeInaccessibleMessage): message for forwarded messages .. versionadded:: 20.8 + reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original + message. + + .. versionadded:: NEXT.VERSION + boost_added (:class:`telegram.ChatBoostAdded`, optional): The message is a service message + about a user boosting the chat. + + .. versionadded:: NEXT.VERSION + sender_boost_count (:class:`telegram.ChatBoostAdded`, optional): If the sender of the + message boosted the chat, the number of boosts added by the user. + + .. versionadded:: NEXT.VERSION Attributes: message_id (:obj:`int`): Unique message identifier inside this chat. @@ -867,10 +880,22 @@ class Message(MaybeInaccessibleMessage): message, the quoted part of the message. .. versionadded:: 20.8 - forward_origin (:class:`telegram.MessageOrigin`, optional): Information about the original + forward_origin (:class:`telegram.MessageOrigin`): Optional. Information about the original message for forwarded messages .. versionadded:: 20.8 + reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original + message. + + .. versionadded:: NEXT.VERSION + boost_added (:class:`telegram.ChatBoostAdded`): Optional. The message is a service message + about a user boosting the chat. + + .. versionadded:: NEXT.VERSION + sender_boost_count (:class:`telegram.ChatBoostAdded`): Optional. If the sender of the + message boosted the chat, the number of boosts added by the user. + + .. versionadded:: NEXT.VERSION .. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a @@ -893,6 +918,7 @@ class Message(MaybeInaccessibleMessage): "animation", "audio", "author_signature", + "boost_added", "caption", "caption_entities", "channel_chat_created", @@ -943,6 +969,8 @@ class Message(MaybeInaccessibleMessage): "quote", "reply_markup", "reply_to_message", + "reply_to_story", + "sender_boost_count", "sender_chat", "sticker", "story", @@ -1045,6 +1073,9 @@ def __init__( external_reply: Optional["ExternalReplyInfo"] = None, quote: Optional["TextQuote"] = None, forward_origin: Optional["MessageOrigin"] = None, + reply_to_story: Optional[Story] = None, + boost_added: Optional[ChatBoostAdded] = None, + sender_boost_count: Optional[int] = None, *, api_kwargs: Optional[JSONDict] = None, ): @@ -1174,6 +1205,9 @@ def __init__( self.external_reply: Optional[ExternalReplyInfo] = external_reply self.quote: Optional[TextQuote] = quote self.forward_origin: Optional[MessageOrigin] = forward_origin + self.reply_to_story: Optional[Story] = reply_to_story + self.boost_added: Optional[ChatBoostAdded] = boost_added + self.sender_boost_count: Optional[int] = sender_boost_count self._effective_attachment = DEFAULT_NONE @@ -1422,6 +1456,8 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["external_reply"] = ExternalReplyInfo.de_json(data.get("external_reply"), bot) data["quote"] = TextQuote.de_json(data.get("quote"), bot) data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot) + data["reply_to_story"] = Story.de_json(data.get("reply_to_story"), bot) + data["boost_added"] = ChatBoostAdded.de_json(data.get("boost_added"), bot) api_kwargs = {} # This is a deprecated field that TG still returns for backwards compatibility diff --git a/telegram/_story.py b/telegram/_story.py index 7a1db0a3697..22955d211c2 100644 --- a/telegram/_story.py +++ b/telegram/_story.py @@ -18,24 +18,65 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object related to a Telegram Story.""" -from typing import Optional +from typing import TYPE_CHECKING, Optional +from telegram._chat import Chat from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict +if TYPE_CHECKING: + from telegram import Bot + class Story(TelegramObject): """ - This object represents a message about a forwarded story in the chat. Currently holds no - information. + This object represents a story. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`chat` and :attr:`id` are equal. .. versionadded:: 20.5 + .. versionchanged:: NEXT.VERSION + Added attributes ``chat`` and ``id`` and equality based on them. + + Args: + chat (:class:`telegram.Chat`): Chat that posted the story. + id (:obj:`int`): Unique identifier for the story in the chat. + + Attributes: + chat (:class:`telegram.Chat`): Chat that posted the story. + id (:obj:`int`): Unique identifier for the story in the chat. + """ - __slots__ = () + __slots__ = ( + "chat", + "id", + ) - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: + def __init__( + self, + chat: Chat, + id: int, # pylint: disable=redefined-builtin + *, + api_kwargs: Optional[JSONDict] = None, + ) -> None: super().__init__(api_kwargs=api_kwargs) + self.chat: Chat = chat + self.id: int = id + + self._id_attrs = (self.chat, self.id) self._freeze() + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Story"]: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data["chat"] = Chat.de_json(data.get("chat", {}), bot) + return super().de_json(data=data, bot=bot) diff --git a/telegram/constants.py b/telegram/constants.py index 59ba4b73e3c..fdcafadbed3 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -142,7 +142,7 @@ class _AccentColor(NamedTuple): #: :data:`telegram.__bot_api_version_info__`. #: #: .. versionadded:: 20.0 -BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=0) +BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=1) #: :obj:`str`: Telegram Bot API #: version supported by this version of `python-telegram-bot`. Also available as #: :data:`telegram.__bot_api_version__`. @@ -1843,6 +1843,21 @@ class MessageType(StringEnum): .. versionadded:: 20.8 """ + REPLY_TO_STORY = "reply_to_story" + """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. + + .. versionadded:: NEXT.VERSION + """ + BOOST_ADDED = "boost_added" + """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. + + .. versionadded:: NEXT.VERSION + """ + SENDER_BOOST_COUNT = "sender_boost_count" + """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. + + .. versionadded:: NEXT.VERSION + """ class PollingLimit(IntEnum): diff --git a/tests/test_chat.py b/tests/test_chat.py index c6c19828dee..b3a37f75ad1 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -72,6 +72,8 @@ def chat(bot): background_custom_emoji_id=TestChatBase.background_custom_emoji_id, profile_accent_color_id=TestChatBase.profile_accent_color_id, profile_background_custom_emoji_id=TestChatBase.profile_background_custom_emoji_id, + unrestrict_boost_count=TestChatBase.unrestrict_boost_count, + custom_emoji_sticker_set_name=TestChatBase.custom_emoji_sticker_set_name, ) chat.set_bot(bot) chat._unfreeze() @@ -115,6 +117,8 @@ class TestChatBase: background_custom_emoji_id = "background_custom_emoji_id" profile_accent_color_id = 2 profile_background_custom_emoji_id = "profile_background_custom_emoji_id" + unrestrict_boost_count = 100 + custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name" class TestChatWithoutRequest(TestChatBase): @@ -156,6 +160,8 @@ def test_de_json(self, bot): "background_custom_emoji_id": self.background_custom_emoji_id, "profile_accent_color_id": self.profile_accent_color_id, "profile_background_custom_emoji_id": self.profile_background_custom_emoji_id, + "unrestrict_boost_count": self.unrestrict_boost_count, + "custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name, } chat = Chat.de_json(json_dict, bot) @@ -194,6 +200,8 @@ def test_de_json(self, bot): assert chat.background_custom_emoji_id == self.background_custom_emoji_id assert chat.profile_accent_color_id == self.profile_accent_color_id assert chat.profile_background_custom_emoji_id == self.profile_background_custom_emoji_id + assert chat.unrestrict_boost_count == self.unrestrict_boost_count + assert chat.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name def test_de_json_localization(self, bot, raw_bot, tz_bot): json_dict = { @@ -257,6 +265,8 @@ def test_to_dict(self, chat): chat_dict["profile_background_custom_emoji_id"] == chat.profile_background_custom_emoji_id ) + assert chat_dict["custom_emoji_sticker_set_name"] == chat.custom_emoji_sticker_set_name + assert chat_dict["unrestrict_boost_count"] == chat.unrestrict_boost_count def test_always_tuples_attributes(self): chat = Chat( diff --git a/tests/test_chatboostadded.py b/tests/test_chatboostadded.py new file mode 100644 index 00000000000..619ef2d0f7b --- /dev/null +++ b/tests/test_chatboostadded.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2023 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. + +from telegram import ChatBoostAdded, VideoChatStarted +from tests.auxil.slots import mro_slots + + +class TestChatBoostAddedWithoutRequest: + boost_count = 100 + + def test_slot_behaviour(self): + action = ChatBoostAdded(8) + for attr in action.__slots__: + assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" + + def test_de_json(self): + json_dict = {"boost_count": self.boost_count} + chat_boost_added = ChatBoostAdded.de_json(json_dict, None) + assert chat_boost_added.api_kwargs == {} + + assert chat_boost_added.boost_count == self.boost_count + + def test_to_dict(self): + chat_boost_added = ChatBoostAdded(self.boost_count) + chat_boost_added_dict = chat_boost_added.to_dict() + + assert isinstance(chat_boost_added_dict, dict) + assert chat_boost_added_dict["boost_count"] == self.boost_count + + def test_equality(self): + a = ChatBoostAdded(100) + b = ChatBoostAdded(100) + c = ChatBoostAdded(50) + d = VideoChatStarted() + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != d + assert hash(a) != hash(d) diff --git a/tests/test_message.py b/tests/test_message.py index 4af15c42791..89f83081b23 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -26,6 +26,7 @@ Audio, Bot, Chat, + ChatBoostAdded, ChatShared, Contact, Dice, @@ -135,7 +136,7 @@ def message(bot): }, {"photo": [PhotoSize("photo_id", "unique_id", 50, 50)], "caption": "photo_file"}, {"sticker": Sticker("sticker_id", "unique_id", 50, 50, True, False, Sticker.REGULAR)}, - {"story": Story()}, + {"story": Story(Chat(1, Chat.PRIVATE), 0)}, {"video": Video("video_id", "unique_id", 12, 12, 12), "caption": "video_file"}, {"voice": Voice("voice_id", "unique_id", 5)}, {"video_note": VideoNote("video_note_id", "unique_id", 20, 12)}, @@ -266,6 +267,9 @@ def message(bot): }, {"quote": TextQuote("a text quote", 1)}, {"forward_origin": MessageOriginChat(datetime.utcnow(), Chat(1, Chat.PRIVATE))}, + {"reply_to_story": Story(Chat(1, Chat.PRIVATE), 0)}, + {"boost_added": ChatBoostAdded(100)}, + {"sender_boost_count": 1}, ], ids=[ "forwarded_user", @@ -331,6 +335,9 @@ def message(bot): "external_reply", "quote", "forward_origin", + "reply_to_story", + "boost_added", + "sender_boost_count", ], ) def message_params(bot, request): diff --git a/tests/test_story.py b/tests/test_story.py index 2aa9358ad65..eb1014fcaed 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -18,28 +18,55 @@ import pytest -from telegram import Story +from telegram import Chat, Story from tests.auxil.slots import mro_slots @pytest.fixture(scope="module") def story(): - return Story() + return Story(TestStoryBase.chat, TestStoryBase.id) + + +class TestStoryBase: + chat = Chat(1, "") + id = 0 class TestStoryWithoutRequest: - def test_slot_behaviour(self): - story = Story() + def test_slot_behaviour(self, story): for attr in story.__slots__: assert getattr(story, attr, "err") != "err", f"got extra slot '{attr}'" assert len(mro_slots(story)) == len(set(mro_slots(story))), "duplicate slot" - def test_de_json(self): - story = Story.de_json({}, None) + def test_de_json(self, bot): + json_dict = {"chat": TestStoryBase.chat.to_dict(), "id": TestStoryBase.id} + story = Story.de_json(json_dict, bot) assert story.api_kwargs == {} + assert story.chat == TestStoryBase.chat + assert story.id == TestStoryBase.id assert isinstance(story, Story) + assert Story.de_json(None, bot) is None - def test_to_dict(self): - story = Story() + def test_to_dict(self, story): story_dict = story.to_dict() - assert story_dict == {} + assert story_dict["chat"] == TestStoryBase.chat.to_dict() + assert story_dict["id"] == TestStoryBase.id + + def test_equality(self): + a = Story(Chat(1, ""), 0) + b = Story(Chat(1, ""), 0) + c = Story(Chat(1, ""), 1) + d = Story(Chat(2, ""), 0) + e = Chat(1, "") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != d + assert hash(a) != hash(d) + + assert a != e + assert hash(a) != hash(e) From ca3b638b2c493bc88a0ae038ceedf29f63f72ff0 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Fri, 16 Feb 2024 18:38:02 +0100 Subject: [PATCH 04/24] Remove rest & adapt tests --- telegram/_inline/inputtextmessagecontent.py | 44 +-- telegram/_message.py | 262 ++---------------- tests/_inline/test_inputtextmessagecontent.py | 10 +- tests/auxil/bot_method_checks.py | 6 +- tests/test_bot.py | 14 +- tests/test_maybeinaccessiblemessage.py | 26 +- tests/test_message.py | 136 +-------- tests/test_official/exceptions.py | 27 +- 8 files changed, 63 insertions(+), 462 deletions(-) diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 49666104bb6..1f44a2395fa 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -22,9 +22,8 @@ from telegram._inline.inputmessagecontent import InputMessageContent from telegram._messageentity import MessageEntity from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue +from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings_transition import warn_about_deprecated_attr_in_property if TYPE_CHECKING: from telegram._linkpreviewoptions import LinkPreviewOptions @@ -51,22 +50,24 @@ class InputTextMessageContent(InputMessageContent): .. versionchanged:: 20.0 |sequenceclassargs| + link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation + options for the message. Mutually exclusive with + :paramref:`disable_web_page_preview`. + + .. versionadded:: 20.8 + + Keyword Args: disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the - sent message. Mutually exclusive with :paramref:`link_preview_options`. + sent message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`link_preview_options` replacing this argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. deprecated:: 20.8 - In future versions, this argument will become keyword only. - - link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation - options for the message. Mutually exclusive with - :paramref:`disable_web_page_preview`. - - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + This parameter is now a keyword only parameter. Attributes: message_text (:obj:`str`): Text of the message to be sent, @@ -94,10 +95,10 @@ def __init__( self, message_text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: Optional[bool] = None, entities: Optional[Sequence[MessageEntity]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) @@ -113,22 +114,3 @@ def __init__( ) self._id_attrs = (self.message_text,) - - @property - def disable_web_page_preview(self) -> Optional[bool]: - """Optional[:obj:`bool`]: Disables link previews for links in the sent message. - - .. deprecated:: 20.8 - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="disable_web_page_preview", - new_attr_name="link_preview_options", - bot_api_version="7.0", - stacklevel=2, - ) - if ( - isinstance(self.link_preview_options, DefaultValue) - or self.link_preview_options is None - ): - return None - return bool(self.link_preview_options.is_disabled) diff --git a/telegram/_message.py b/telegram/_message.py index 5204cf9e9b2..8d27452ffba 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -71,7 +71,6 @@ ReplyMarkup, ) from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import warn_about_deprecated_attr_in_property from telegram._videochat import ( VideoChatEnded, VideoChatParticipantsInvited, @@ -121,6 +120,9 @@ class MaybeInaccessibleMessage(TelegramObject): Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`message_id` and :attr:`chat` are equal + .. versionchanged:: NEXT.VERSION + ``__bool__`` is no longer overriden and defaults to Pythons standard implementation. + .. versionadded:: 20.8 Args: @@ -159,51 +161,6 @@ def __init__( self._freeze() - def __bool__(self) -> bool: - """Overrides :meth:`object.__bool__` to return the value of :attr:`is_accessible`. - This is intended to ease migration to Bot API 7.0, as this allows checks like - - .. code-block:: python - - if message.pinned_message: - ... - - to work as before, when ``message.pinned_message`` was :obj:`None`. Note that this does not - help with check like - - .. code-block:: python - - if message.pinned_message is None: - ... - - for cases where ``message.pinned_message`` is now no longer :obj:`None`. - - Tip: - Since objects that can only be of type :class:`~telegram.Message` or :obj:`None` are - not affected by this change, :meth:`Message.__bool__` is not overridden and will - continue to work as before. - - .. versionadded:: 20.8 - .. deprecated:: 20.8 - This behavior is introduced only temporarily to ease migration to Bot API 7.0. It will - be removed along with other functionality deprecated by Bot API 7.0. - """ - # Once we remove this method, also remove `Message.__bool__`. - warn( - category=PTBDeprecationWarning, - message=( - "You probably see this warning " - "because you wrote `if callback_query.message` or `if message.pinned_message` in " - "your code. This is not the supported way of checking the existence of a message " - "as of API 7.0. Please use `if message.is_accessible` or `if isinstance(message, " - "Message)` instead. `if message is None` may be suitable for specific use cases " - f"as well.\n`{self.__class__.__name__}.__bool__` will be reverted to Pythons " - f"default implementation in future versions." - ), - stacklevel=2, - ) - return self.is_accessible - @property def is_accessible(self) -> bool: """Convenience attribute. :obj:`True`, if the date is not 0 in Unix time. @@ -287,7 +244,9 @@ class Message(MaybeInaccessibleMessage): In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. .. versionchanged:: NEXT.VERSION - Removed deprecated argument and attribute ``user_shared``. + Removed deprecated arguments and attributes ``user_shared``, ``forward_from``, + ``forward_from_chat``, ``forward_from_message_id``, ``forward_signature``, + ``forward_sender_name`` and ``forward_date``. .. versionchanged:: 20.8 * This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`. @@ -325,39 +284,6 @@ class Message(MaybeInaccessibleMessage): .. versionchanged:: 20.3 |datetime_localization| chat (:class:`telegram.Chat`): Conversation the message belongs to. - forward_from (:class:`telegram.User`, optional): For forwarded messages, sender of - the original message. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from` in favor of - :paramref:`forward_origin`. - forward_from_chat (:class:`telegram.Chat`, optional): For messages forwarded from channels - or from anonymous administrators, information about the original sender chat. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from_chat` in favor of - :paramref:`forward_origin`. - forward_from_message_id (:obj:`int`, optional): For forwarded channel posts, identifier of - the original message in the channel. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from_message_id` in favor of - :paramref:`forward_origin`. - forward_sender_name (:obj:`str`, optional): Sender's name for messages forwarded from - users who disallow adding a link to their account in forwarded messages. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_sender_name` in favor of - :paramref:`forward_origin`. - forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the - original message was sent in Unix time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_date` in favor of - :paramref:`forward_origin`. is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel post that was automatically forwarded to the connected discussion group. @@ -483,12 +409,6 @@ class Message(MaybeInaccessibleMessage): message about a successful payment, information about the payment. connected_website (:obj:`str`, optional): The domain name of the website on which the user has logged in. - forward_signature (:obj:`str`, optional): For messages forwarded from channels, signature - of the post author if present. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_signature` in favor of - :paramref:`forward_origin`. author_signature (:obj:`str`, optional): Signature of the post author for messages in channels, or the custom title of an anonymous group administrator. passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data. @@ -884,12 +804,6 @@ class Message(MaybeInaccessibleMessage): # fmt: on __slots__ = ( "_effective_attachment", - "_forward_date", - "_forward_from", - "_forward_from_chat", - "_forward_from_message_id", - "_forward_sender_name", - "_forward_signature", "animation", "audio", "author_signature", @@ -969,10 +883,6 @@ def __init__( date: datetime.datetime, chat: Chat, from_user: Optional[User] = None, - forward_from: Optional[User] = None, - forward_from_chat: Optional[Chat] = None, - forward_from_message_id: Optional[int] = None, - forward_date: Optional[datetime.datetime] = None, reply_to_message: Optional["Message"] = None, edit_date: Optional[datetime.datetime] = None, text: Optional[str] = None, @@ -1003,14 +913,12 @@ def __init__( pinned_message: Optional[MaybeInaccessibleMessage] = None, invoice: Optional[Invoice] = None, successful_payment: Optional[SuccessfulPayment] = None, - forward_signature: Optional[str] = None, author_signature: Optional[str] = None, media_group_id: Optional[str] = None, connected_website: Optional[str] = None, animation: Optional[Animation] = None, passport_data: Optional[PassportData] = None, poll: Optional[Poll] = None, - forward_sender_name: Optional[str] = None, reply_markup: Optional[InlineKeyboardMarkup] = None, dice: Optional[Dice] = None, via_bot: Optional[User] = None, @@ -1050,37 +958,6 @@ def __init__( ): super().__init__(chat=chat, message_id=message_id, date=date, api_kwargs=api_kwargs) - if any( - ( - forward_from, - forward_from_chat, - forward_from_message_id, - forward_signature, - forward_sender_name, - forward_date, - ) - ): - if forward_from: - _warn_param = "forward_from" - elif forward_from_chat: - _warn_param = "forward_from_chat" - elif forward_from_message_id: - _warn_param = "forward_from_message_id" - elif forward_signature: - _warn_param = "forward_signature" - elif forward_sender_name: - _warn_param = "forward_sender_name" - else: - _warn_param = "forward_date" - - warn( - f"The information about parameter '{_warn_param}' was transferred to " - "'forward_origin' in Bot API 7.0. We recommend using 'forward_origin' instead of " - f"'{_warn_param}'", - PTBDeprecationWarning, - stacklevel=2, - ) - with self._unfrozen(): # Required self.message_id: int = message_id @@ -1089,9 +966,6 @@ def __init__( self.sender_chat: Optional[Chat] = sender_chat self.date: datetime.datetime = date self.chat: Chat = chat - self._forward_from: Optional[User] = forward_from - self._forward_from_chat: Optional[Chat] = forward_from_chat - self._forward_date: Optional[datetime.datetime] = forward_date self.is_automatic_forward: Optional[bool] = is_automatic_forward self.reply_to_message: Optional[Message] = reply_to_message self.edit_date: Optional[datetime.datetime] = edit_date @@ -1125,12 +999,9 @@ def __init__( message_auto_delete_timer_changed ) self.pinned_message: Optional[MaybeInaccessibleMessage] = pinned_message - self._forward_from_message_id: Optional[int] = forward_from_message_id self.invoice: Optional[Invoice] = invoice self.successful_payment: Optional[SuccessfulPayment] = successful_payment self.connected_website: Optional[str] = connected_website - self._forward_signature: Optional[str] = forward_signature - self._forward_sender_name: Optional[str] = forward_sender_name self.author_signature: Optional[str] = author_signature self.media_group_id: Optional[str] = media_group_id self.animation: Optional[Animation] = animation @@ -1179,111 +1050,6 @@ def __init__( self._id_attrs = (self.message_id, self.chat) - def __bool__(self) -> bool: - """Overrides :meth:`telegram.MaybeInaccessibleMessage.__bool__` to use Pythons - default implementation of :meth:`object.__bool__` instead. - - Tip: - The current behavior is the same as before the introduction of - :class:`telegram.MaybeInaccessibleMessage`. This documentation is relevant only until - :meth:`telegram.MaybeInaccessibleMessage.__bool__` is removed. - """ - return True - - @property - def forward_from(self) -> Optional[User]: - """:class:`telegram.User`: Optional. For forwarded messages, sender of the original - message. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from - - @property - def forward_from_chat(self) -> Optional[Chat]: - """:class:`telegram.Chat`: Optional. For messages forwarded from channels or from anonymous - administrators, information about the original sender chat. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from_chat` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from_chat", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from_chat - - @property - def forward_from_message_id(self) -> Optional[int]: - """:obj:`int`: Optional. For forwarded channel posts, identifier of the original message - in the channel. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from_message_id` in favor of - :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from_message_id", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from_message_id - - @property - def forward_signature(self) -> Optional[str]: - """:obj:`str`: Optional. For messages forwarded from channels, signature - of the post author if present. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_signature` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_signature", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_signature - - @property - def forward_sender_name(self) -> Optional[str]: - """:class:`telegram.User`: Optional. Sender's name for messages forwarded from users who - disallow adding a link to their account in forwarded messages. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_sender_name` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_sender_name", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_sender_name - - @property - def forward_date(self) -> Optional[datetime.datetime]: - """:obj:`datetime.datetime`: Optional. For forwarded messages, date the original message - was sent in Unix time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_date` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_date", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_date - @property def chat_id(self) -> int: """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`.""" @@ -1333,9 +1099,6 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot) data["entities"] = MessageEntity.de_list(data.get("entities"), bot) data["caption_entities"] = MessageEntity.de_list(data.get("caption_entities"), bot) - data["forward_from"] = User.de_json(data.get("forward_from"), bot) - data["forward_from_chat"] = Chat.de_json(data.get("forward_from_chat"), bot) - data["forward_date"] = from_timestamp(data.get("forward_date"), tzinfo=loc_tzinfo) data["reply_to_message"] = Message.de_json(data.get("reply_to_message"), bot) data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo) data["audio"] = Audio.de_json(data.get("audio"), bot) @@ -1426,8 +1189,17 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: api_kwargs = {} # This is a deprecated field that TG still returns for backwards compatibility # Let's filter it out to speed up the de-json process - if user_shared := data.get("user_shared"): - api_kwargs = {"user_shared": user_shared} + for key in ( + "user_shared", + "forward_from", + "forward_from_chat", + "forward_from_message_id", + "forward_signature", + "forward_sender_name", + "forward_date", + ): + if entry := data.get(key): + api_kwargs = {key: entry} return super()._de_json( # type: ignore[return-value] data=data, bot=bot, api_kwargs=api_kwargs diff --git a/tests/_inline/test_inputtextmessagecontent.py b/tests/_inline/test_inputtextmessagecontent.py index 3d3a6b2f658..2c34c4f0a2e 100644 --- a/tests/_inline/test_inputtextmessagecontent.py +++ b/tests/_inline/test_inputtextmessagecontent.py @@ -20,7 +20,6 @@ from telegram import InputTextMessageContent, LinkPreviewOptions, MessageEntity from telegram.constants import ParseMode -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -52,7 +51,6 @@ def test_slot_behaviour(self, input_text_message_content): def test_expected_values(self, input_text_message_content): assert input_text_message_content.parse_mode == self.parse_mode assert input_text_message_content.message_text == self.message_text - assert input_text_message_content.disable_web_page_preview == self.disable_web_page_preview assert input_text_message_content.entities == tuple(self.entities) assert input_text_message_content.link_preview_options == self.link_preview_options @@ -100,8 +98,6 @@ def test_mutually_exclusive(self): "text", disable_web_page_preview=True, link_preview_options=LinkPreviewOptions() ) - def test_disable_web_page_preview_deprecated(self): - with pytest.warns( - PTBDeprecationWarning, match="'disable_web_page_preview' to 'link_preview_options'" - ): - InputTextMessageContent("text", disable_web_page_preview=True).disable_web_page_preview + def test_disable_web_page_preview_deprecation(self): + itmc = InputTextMessageContent("text", disable_web_page_preview=True) + assert itmc.link_preview_options.is_disabled is True diff --git a/tests/auxil/bot_method_checks.py b/tests/auxil/bot_method_checks.py index 396516f216d..79fd8014ca0 100644 --- a/tests/auxil/bot_method_checks.py +++ b/tests/auxil/bot_method_checks.py @@ -549,11 +549,9 @@ async def check_defaults_handling( } # We tested this for a long time, but Bot API 7.0 deprecated it in favor of # reply_parameters. In the transition phase, both exist in a mutually exclusive - # way. Testing both cases would require a lot of additional code, so we just - # ignore this parameter here until it is removed. - # Same for disable_web_page_preview + # way. Testing both cases would require a lot of additional code, so we for now are content + # with the explicit tests that we have inplace for allow_sending_without_reply kwargs_need_default.discard("allow_sending_without_reply") - kwargs_need_default.discard("disable_web_page_preview") if method.__name__.endswith("_media_group"): # the parse_mode is applied to the first media item, and we test this elsewhere diff --git a/tests/test_bot.py b/tests/test_bot.py index 9f1d25d43f2..2e3a0237112 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -2120,8 +2120,8 @@ async def test_forward_message(self, bot, chat_id, message): ) assert forward_message.text == message.text - assert forward_message.forward_from.username == message.from_user.username - assert isinstance(forward_message.forward_date, dtm.datetime) + assert forward_message.forward_origin.sender_user == message.from_user + assert isinstance(forward_message.forward_origin.date, dtm.datetime) async def test_forward_protected_message(self, bot, chat_id): tasks = asyncio.gather( @@ -2155,7 +2155,7 @@ async def test_forward_messages(self, bot, chat_id): msg1, msg2 = await tasks forward_messages = await bot.forward_messages( - chat_id, from_chat_id=chat_id, message_ids=(msg1.message_id, msg2.message_id) + chat_id, from_chat_id=chat_id, message_ids=sorted((msg1.message_id, msg2.message_id)) ) assert isinstance(forward_messages, tuple) @@ -2174,12 +2174,12 @@ async def test_forward_messages(self, bot, chat_id): forward_msg2 = temp_msg2.reply_to_message assert forward_msg1.text == msg1.text - assert forward_msg1.forward_from.username == msg1.from_user.username - assert isinstance(forward_msg1.forward_date, dtm.datetime) + assert forward_msg1.forward_origin.sender_user == msg1.from_user + assert isinstance(forward_msg1.forward_origin.date, dtm.datetime) assert forward_msg2.text == msg2.text - assert forward_msg2.forward_from.username == msg2.from_user.username - assert isinstance(forward_msg2.forward_date, dtm.datetime) + assert forward_msg2.forward_origin.sender_user == msg2.from_user + assert isinstance(forward_msg2.forward_origin.date, dtm.datetime) async def test_delete_message(self, bot, chat_id): message = await bot.send_message(chat_id, text="will be deleted") diff --git a/tests/test_maybeinaccessiblemessage.py b/tests/test_maybeinaccessiblemessage.py index 0db8fc75ef3..87c2f6c3a86 100644 --- a/tests/test_maybeinaccessiblemessage.py +++ b/tests/test_maybeinaccessiblemessage.py @@ -20,10 +20,9 @@ import pytest -from telegram import Chat, InaccessibleMessage, MaybeInaccessibleMessage +from telegram import Chat, MaybeInaccessibleMessage from telegram._utils.datetime import UTC, to_timestamp from telegram.constants import ZERO_DATE -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -111,29 +110,6 @@ def test_is_accessible(self): assert MaybeInaccessibleMessage(self.chat, self.message_id, self.date).is_accessible assert not MaybeInaccessibleMessage(self.chat, self.message_id, ZERO_DATE).is_accessible - def test_bool(self): - assert bool(MaybeInaccessibleMessage(self.chat, self.message_id, self.date).is_accessible) - assert not bool( - MaybeInaccessibleMessage(self.chat, self.message_id, ZERO_DATE).is_accessible - ) - - @pytest.mark.parametrize("cls", [MaybeInaccessibleMessage, InaccessibleMessage]) - def test_bool_deprecation_warning(self, cls): - if cls is MaybeInaccessibleMessage: - args = (self.chat, self.message_id, self.date) - else: - args = (self.chat, self.message_id) - - with pytest.warns( - PTBDeprecationWarning, - match=( - f"`{cls.__name__}.__bool__` will be reverted to Pythons default implementation" - ), - ) as record: - bool(cls(*args)) - - assert record[0].filename == __file__, "wrong stacklevel" - def test_equality(self, maybe_inaccessible_message): a = maybe_inaccessible_message b = MaybeInaccessibleMessage( diff --git a/tests/test_message.py b/tests/test_message.py index 4af15c42791..bb6f906d630 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -98,12 +98,6 @@ def message(bot): @pytest.fixture( params=[ - {"forward_from": User(99, "forward_user", False), "forward_date": datetime.utcnow()}, - { - "forward_from_chat": Chat(-23, "channel"), - "forward_from_message_id": 101, - "forward_date": datetime.utcnow(), - }, { "reply_to_message": Message( 50, datetime.utcnow(), Chat(13, "channel"), User(9, "i", False) @@ -165,7 +159,6 @@ def message(bot): ) }, {"connected_website": "http://example.com/"}, - {"forward_signature": "some_forward_sign"}, {"author_signature": "some_author_sign"}, { "photo": [PhotoSize("photo_id", "unique_id", 50, 50)], @@ -268,8 +261,6 @@ def message(bot): {"forward_origin": MessageOriginChat(datetime.utcnow(), Chat(1, Chat.PRIVATE))}, ], ids=[ - "forwarded_user", - "forwarded_channel", "reply", "edited", "text", @@ -302,7 +293,6 @@ def message(bot): "invoice", "successful_payment", "connected_website", - "forward_signature", "author_signature", "photo_from_media_group", "passport_data", @@ -514,7 +504,6 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): "date": int(datetime.now().timestamp()), "chat": None, "edit_date": int(datetime.now().timestamp()), - "forward_date": int(datetime.now().timestamp()), } message_raw = Message.de_json(json_dict, raw_bot) @@ -530,11 +519,6 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): message_tz.edit_date.replace(tzinfo=None) ) - forward_date_offset = message_tz.forward_date.utcoffset() - forward_date_tz_bot_offset = tz_bot.defaults.tzinfo.utcoffset( - message_tz.forward_date.replace(tzinfo=None) - ) - assert message_raw.date.tzinfo == UTC assert message_bot.date.tzinfo == UTC assert date_offset == date_tz_bot_offset @@ -543,15 +527,21 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): assert message_bot.edit_date.tzinfo == UTC assert edit_date_offset == edit_date_tz_bot_offset - assert message_raw.forward_date.tzinfo == UTC - assert message_bot.forward_date.tzinfo == UTC - assert forward_date_offset == forward_date_tz_bot_offset - def test_de_json_api_kwargs_backward_compatibility(self, bot, message_params): message_dict = message_params.to_dict() - message_dict["user_shared"] = {"request_id": 1, "user_id": 2} + keys = ( + "user_shared", + "forward_from", + "forward_from_chat", + "forward_from_message_id", + "forward_signature", + "forward_sender_name", + "forward_date", + ) + for key in keys: + message_dict[key] = key message = Message.de_json(message_dict, bot) - assert message.api_kwargs == {"user_shared": {"request_id": 1, "user_id": 2}} + assert message.api_kwargs == {key: key for key in keys} def test_equality(self): id_ = 1 @@ -574,108 +564,6 @@ def test_equality(self): assert a != e assert hash(a) != hash(e) - def test_forward_from_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from' was transferred to 'forward_origin'" - ) as record: - Message( - message_id=1, date=self.date, chat=self.chat, forward_from=User(1, "user", False) - ) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from' to 'forward_origin'" - ) as record: - message.forward_from - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_chat_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_chat' was transferred to 'forward_origin'" - ) as record: - Message( - message_id=1, date=self.date, chat=self.chat, forward_from_chat=Chat(1, "private") - ) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_chat_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_chat' to 'forward_origin'" - ) as record: - message.forward_from_chat - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_message_id_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, - match="'forward_from_message_id' was transferred to 'forward_origin'", - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_from_message_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_message_id_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_message_id' to 'forward_origin'" - ) as record: - message.forward_from_message_id - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_signature_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_signature' was transferred to 'forward_origin'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_signature="signature") - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_signature_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_signature' to 'forward_origin'" - ) as record: - message.forward_signature - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_sender_name_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, - match="'forward_sender_name' was transferred to 'forward_origin'", - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_sender_name="name") - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_sender_name_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_sender_name' to 'forward_origin'" - ) as record: - message.forward_sender_name - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_date_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_date' was transferred to 'forward_origin'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_date=datetime.utcnow()) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_date_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_date' to 'forward_origin'" - ) as record: - message.forward_date - - assert record[0].filename == __file__, "wrong stacklevel" - def test_bool(self, message, recwarn): # Relevant as long as we override MaybeInaccessibleMessage.__bool__ # Can be removed once that's removed diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index e554b0888ad..7807a02784a 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -94,6 +94,13 @@ class ParamTypeCheckingExceptions: PTB_EXTRA_PARAMS = { "send_contact": {"contact"}, "send_location": {"location"}, + "(send_message|edit_message_text)": { # convenience parameters + "disable_web_page_preview", + }, + r"(send|copy)_\w+": { # convenience parameters + "reply_to_message_id", + "allow_sending_without_reply", + }, "edit_message_live_location": {"location"}, "send_venue": {"venue"}, "answer_inline_query": {"current_offset"}, @@ -159,25 +166,7 @@ def ignored_param_requirements(object_name: str) -> set[str]: # Arguments that are optional arguments for now for backwards compatibility -BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { - # Deprecated by Bot API 7.0, kept for now for bw compat: - "KeyboardButton": {"request_user"}, - "Message": { - "forward_from", - "forward_signature", - "forward_sender_name", - "forward_date", - "forward_from_chat", - "forward_from_message_id", - "user_shared", - }, - "(send_message|edit_message_text)": { - "disable_web_page_preview", - "reply_to_message_id", - "allow_sending_without_reply", - }, - r"copy_message|send_\w+": {"allow_sending_without_reply", "reply_to_message_id"}, -} +BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {} def backwards_compat_kwargs(object_name: str) -> set[str]: From 2816ffa55ee4ceb30a9cf4323eca1e39f1a8e66b Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Fri, 16 Feb 2024 18:57:35 +0100 Subject: [PATCH 05/24] Try Fixing docs --- docs/source/telegram.at-tree.rst | 2 -- docs/source/telegram.keyboardbuttonrequestuser.rst | 6 ------ docs/source/telegram.usershared.rst | 6 ------ 3 files changed, 14 deletions(-) delete mode 100644 docs/source/telegram.keyboardbuttonrequestuser.rst delete mode 100644 docs/source/telegram.usershared.rst diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index c5159a71e0c..ed71b5f6760 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -73,7 +73,6 @@ Available Types telegram.keyboardbutton telegram.keyboardbuttonpolltype telegram.keyboardbuttonrequestchat - telegram.keyboardbuttonrequestuser telegram.keyboardbuttonrequestusers telegram.linkpreviewoptions telegram.location @@ -115,7 +114,6 @@ Available Types telegram.user telegram.userchatboosts telegram.userprofilephotos - telegram.usershared telegram.usersshared telegram.venue telegram.video diff --git a/docs/source/telegram.keyboardbuttonrequestuser.rst b/docs/source/telegram.keyboardbuttonrequestuser.rst deleted file mode 100644 index 24ebfa758a4..00000000000 --- a/docs/source/telegram.keyboardbuttonrequestuser.rst +++ /dev/null @@ -1,6 +0,0 @@ -KeyboardButtonRequestUser -========================= - -.. autoclass:: telegram.KeyboardButtonRequestUser - :members: - :show-inheritance: diff --git a/docs/source/telegram.usershared.rst b/docs/source/telegram.usershared.rst deleted file mode 100644 index 831c1d9492a..00000000000 --- a/docs/source/telegram.usershared.rst +++ /dev/null @@ -1,6 +0,0 @@ -UserShared -========== - -.. autoclass:: telegram.UserShared - :members: - :show-inheritance: From dd12f84f5b5c7399105879691da4df0cc4cc60b5 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:07:51 +0100 Subject: [PATCH 06/24] Try harder --- telegram/_inline/inputtextmessagecontent.py | 5 ++--- telegram/_keyboardbutton.py | 4 ++-- telegram/_keyboardbuttonrequest.py | 2 +- telegram/_shared.py | 2 +- telegram/ext/filters.py | 10 +++++----- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 1f44a2395fa..6b84f82868c 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -59,7 +59,7 @@ class InputTextMessageContent(InputMessageContent): Keyword Args: disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the sent message. Convenience parameter for setting :paramref:`link_preview_options`. - Mutually exclusive with :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`link_preview_options` replacing this @@ -82,8 +82,7 @@ class InputTextMessageContent(InputMessageContent): * |tupleclassattrs| * |alwaystuple| link_preview_options (:obj:`LinkPreviewOptions`): Optional. Link preview generation - options for the message. Mutually exclusive with - :attr:`disable_web_page_preview`. + options for the message. .. versionadded:: 20.8 diff --git a/telegram/_keyboardbutton.py b/telegram/_keyboardbutton.py index bee303dd264..b216aae36a9 100644 --- a/telegram/_keyboardbutton.py +++ b/telegram/_keyboardbutton.py @@ -80,7 +80,7 @@ class KeyboardButton(TelegramObject): request_users (:class:`KeyboardButtonRequestUsers`, optional): If specified, pressing the button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.user_shared` service message. + identifier to the bot in a :attr:`telegram.Message.users_shared` service message. Available in private chats only. .. versionadded:: 20.8 @@ -108,7 +108,7 @@ class KeyboardButton(TelegramObject): .. versionadded:: 20.0 request_users (:class:`KeyboardButtonRequestUsers`): Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.user_shared` service message. + identifier to the bot in a :attr:`telegram.Message.users_shared` service message. Available in private chats only. .. versionadded:: 20.8 diff --git a/telegram/_keyboardbuttonrequest.py b/telegram/_keyboardbuttonrequest.py index 8d2d2398d56..8e9ac16e604 100644 --- a/telegram/_keyboardbuttonrequest.py +++ b/telegram/_keyboardbuttonrequest.py @@ -39,7 +39,7 @@ class KeyboardButtonRequestUsers(TelegramObject): `_ .. versionadded:: 20.8 - This class was previously named :class:`KeyboardButtonRequestUser`. + This class was previously named ``KeyboardButtonRequestUser``. Args: request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received diff --git a/telegram/_shared.py b/telegram/_shared.py index c6724f283a9..d5e13d012c4 100644 --- a/telegram/_shared.py +++ b/telegram/_shared.py @@ -32,7 +32,7 @@ class UsersShared(TelegramObject): considered equal, if their :attr:`request_id` and :attr:`user_ids` are equal. .. versionadded:: 20.8 - Bot API 7.0 replaces :class:`UserShared` with this class. The only difference is that now + Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now the :attr:`user_ids` is a sequence instead of a single integer. Args: diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index 9ca51d537e1..1afa879cd74 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -1364,7 +1364,7 @@ def filter(self, message: Message) -> bool: .. versionchanged:: 20.8 Now based on :attr:`telegram.Message.forward_origin` instead of - :attr:`telegram.Message.forward_date`. + ``telegram.Message.forward_date``. """ @@ -1379,8 +1379,8 @@ class ForwardedFrom(_ChatUserBaseFilter): .. versionadded:: 13.5 .. versionchanged:: 20.8 - Was previously based on :attr:`telegram.Message.forward_from` and - :attr:`telegram.Message.forward_from_chat`. + Was previously based on ``telegram.Message.forward_from`` and + ``telegram.Message.forward_from_chat``. Examples: ``MessageHandler(filters.ForwardedFrom(chat_id=1234), callback_method)`` @@ -2149,14 +2149,14 @@ def filter(self, message: Message) -> bool: return bool(message.api_kwargs.get("user_shared")) USER_SHARED = _UserShared(name="filters.StatusUpdate.USER_SHARED") - """Messages that contain :attr:`telegram.Message.user_shared`. + """Messages that contain ``"user_shared"`` in :attr:`telegram.TelegramObject.api_kwargs`. Warning: This will only catch the legacy ``user_shared`` field, not the new :attr:`telegram.Message.users_shared` attribute! .. versionchanged:: NEXT.VERSION - Now relies on :attr:`TelegramObject.api_kwargs` as the native attribute + Now relies on :attr:`telegram.TelegramObject.api_kwargs` as the native attribute ``Message.user_shared`` was removed. .. versionadded:: 20.1 From 391cebf65cea819959054f4035e35e186f52182b Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Fri, 16 Feb 2024 20:13:52 +0100 Subject: [PATCH 07/24] Code Coverage --- tests/test_keyboardbutton.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index c1ca88984ef..9f8f261bf97 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -80,7 +80,8 @@ def test_to_dict(self, keyboard_button): assert keyboard_button_dict["request_chat"] == keyboard_button.request_chat.to_dict() assert keyboard_button_dict["request_users"] == keyboard_button.request_users.to_dict() - def test_de_json(self, bot): + @pytest.mark.parametrize("request_user", [True, False]) + def test_de_json(self, bot, request_user): json_dict = { "text": self.text, "request_location": self.request_location, @@ -89,11 +90,16 @@ def test_de_json(self, bot): "web_app": self.web_app.to_dict(), "request_chat": self.request_chat.to_dict(), "request_users": self.request_users.to_dict(), - "request_user": {"request_id": 2}, } + if request_user: + json_dict["request_user"] = {"request_id": 2} keyboard_button = KeyboardButton.de_json(json_dict, None) - assert keyboard_button.api_kwargs == {"request_user": {"request_id": 2}} + if request_user: + assert keyboard_button.api_kwargs == {"request_user": {"request_id": 2}} + else: + assert keyboard_button.api_kwargs == {} + assert keyboard_button.text == self.text assert keyboard_button.request_location == self.request_location assert keyboard_button.request_contact == self.request_contact From e3fd1d2ade675b303b26fdfab78d03b1eac65581 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Fri, 16 Feb 2024 23:51:27 +0100 Subject: [PATCH 08/24] Fix: move Chatboostadded to the correct file --- docs/source/telegram.chatboostadded.rst | 2 + telegram/__init__.py | 2 +- telegram/_chatboost.py | 33 ++++++++++++++ telegram/_chatboostadded.py | 56 ----------------------- telegram/_message.py | 2 +- tests/test_chatboost.py | 40 +++++++++++++++++ tests/test_chatboostadded.py | 59 ------------------------- 7 files changed, 77 insertions(+), 117 deletions(-) delete mode 100644 telegram/_chatboostadded.py delete mode 100644 tests/test_chatboostadded.py diff --git a/docs/source/telegram.chatboostadded.rst b/docs/source/telegram.chatboostadded.rst index b4551e75b84..e0a24b9ce11 100644 --- a/docs/source/telegram.chatboostadded.rst +++ b/docs/source/telegram.chatboostadded.rst @@ -1,6 +1,8 @@ ChatBoostAdded ============== +.. versionadded:: NEXT.VERSION + .. autoclass:: telegram.ChatBoostAdded :members: :show-inheritance: \ No newline at end of file diff --git a/telegram/__init__.py b/telegram/__init__.py index 9410740d20c..aeed15094ab 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -243,6 +243,7 @@ from ._chatadministratorrights import ChatAdministratorRights from ._chatboost import ( ChatBoost, + ChatBoostAdded, ChatBoostRemoved, ChatBoostSource, ChatBoostSourceGiftCode, @@ -251,7 +252,6 @@ ChatBoostUpdated, UserChatBoosts, ) -from ._chatboostadded import ChatBoostAdded from ._chatinvitelink import ChatInviteLink from ._chatjoinrequest import ChatJoinRequest from ._chatlocation import ChatLocation diff --git a/telegram/_chatboost.py b/telegram/_chatboost.py index 71d299de0b3..f16cf9db0eb 100644 --- a/telegram/_chatboost.py +++ b/telegram/_chatboost.py @@ -34,6 +34,39 @@ from telegram import Bot +class ChatBoostAdded(TelegramObject): + """ + This object represents a service message about a user boosting a chat. + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`boost_count` are equal. + + .. versionadded:: NEXT.VERSION + + Args: + boost_count (:obj:`int`): Number of boosts added by the user. + + Attributes: + boost_count (:obj:`int`): Number of boosts added by the user. + + """ + + __slots__ = ("boost_count",) + + def __init__( + self, + boost_count: int, + *, + api_kwargs: Optional[JSONDict] = None, + ) -> None: + super().__init__(api_kwargs=api_kwargs) + self.boost_count: int = boost_count + self._id_attrs = (self.boost_count,) + + self._freeze() + + class ChatBoostSource(TelegramObject): """ Base class for Telegram ChatBoostSource objects. It can be one of: diff --git a/telegram/_chatboostadded.py b/telegram/_chatboostadded.py deleted file mode 100644 index d1ec211dba8..00000000000 --- a/telegram/_chatboostadded.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChatBoostAdded object.""" -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class ChatBoostAdded(TelegramObject): - """ - This object represents a service message about a user boosting a chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`boost_count` are equal. - - .. versionadded:: NEXT.VERSION - - Args: - boost_count (:obj:`int`): Number of boosts added by the user. - - Attributes: - boost_count (:obj:`int`): Number of boosts added by the user. - - """ - - __slots__ = ("boost_count",) - - def __init__( - self, - boost_count: int, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.boost_count: int = boost_count - self._id_attrs = (self.boost_count,) - - self._freeze() diff --git a/telegram/_message.py b/telegram/_message.py index f9b6dfb5b60..e743681867e 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -24,7 +24,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, TypedDict, Union from telegram._chat import Chat -from telegram._chatboostadded import ChatBoostAdded +from telegram._chatboost import ChatBoostAdded from telegram._dice import Dice from telegram._files.animation import Animation from telegram._files.audio import Audio diff --git a/tests/test_chatboost.py b/tests/test_chatboost.py index ee0a5c9e3c3..bc33e1fe21e 100644 --- a/tests/test_chatboost.py +++ b/tests/test_chatboost.py @@ -24,6 +24,7 @@ from telegram import ( Chat, ChatBoost, + ChatBoostAdded, ChatBoostRemoved, ChatBoostSource, ChatBoostSourceGiftCode, @@ -542,3 +543,42 @@ class TestUserChatBoostsWithRequest(ChatBoostDefaults): async def test_get_user_chat_boosts(self, bot, channel_id, chat_id): chat_boosts = await bot.get_user_chat_boosts(channel_id, chat_id) assert isinstance(chat_boosts, UserChatBoosts) + + +class TestChatBoostAddedWithoutRequest: + boost_count = 100 + + def test_slot_behaviour(self): + action = ChatBoostAdded(8) + for attr in action.__slots__: + assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" + + def test_de_json(self): + json_dict = {"boost_count": self.boost_count} + chat_boost_added = ChatBoostAdded.de_json(json_dict, None) + assert chat_boost_added.api_kwargs == {} + + assert chat_boost_added.boost_count == self.boost_count + + def test_to_dict(self): + chat_boost_added = ChatBoostAdded(self.boost_count) + chat_boost_added_dict = chat_boost_added.to_dict() + + assert isinstance(chat_boost_added_dict, dict) + assert chat_boost_added_dict["boost_count"] == self.boost_count + + def test_equality(self): + a = ChatBoostAdded(100) + b = ChatBoostAdded(100) + c = ChatBoostAdded(50) + d = Chat(1, "") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != d + assert hash(a) != hash(d) diff --git a/tests/test_chatboostadded.py b/tests/test_chatboostadded.py deleted file mode 100644 index 619ef2d0f7b..00000000000 --- a/tests/test_chatboostadded.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. - -from telegram import ChatBoostAdded, VideoChatStarted -from tests.auxil.slots import mro_slots - - -class TestChatBoostAddedWithoutRequest: - boost_count = 100 - - def test_slot_behaviour(self): - action = ChatBoostAdded(8) - for attr in action.__slots__: - assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'" - assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" - - def test_de_json(self): - json_dict = {"boost_count": self.boost_count} - chat_boost_added = ChatBoostAdded.de_json(json_dict, None) - assert chat_boost_added.api_kwargs == {} - - assert chat_boost_added.boost_count == self.boost_count - - def test_to_dict(self): - chat_boost_added = ChatBoostAdded(self.boost_count) - chat_boost_added_dict = chat_boost_added.to_dict() - - assert isinstance(chat_boost_added_dict, dict) - assert chat_boost_added_dict["boost_count"] == self.boost_count - - def test_equality(self): - a = ChatBoostAdded(100) - b = ChatBoostAdded(100) - c = ChatBoostAdded(50) - d = VideoChatStarted() - - assert a == b - assert hash(a) == hash(b) - - assert a != c - assert hash(a) != hash(c) - - assert a != d - assert hash(a) != hash(d) From f39d62df0caa28a710661810b1c7a51fadbae1a8 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 17 Feb 2024 00:12:27 +0100 Subject: [PATCH 09/24] Feat: Mark admin right stories as non optional --- telegram/_chatadministratorrights.py | 54 +++++++++++++---- tests/test_chatadministratorrights.py | 87 ++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 19 deletions(-) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index 066e7ca963c..b36c7287c09 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -69,18 +69,30 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -111,18 +123,30 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + As of this version, this argument is now required. As of our Backward Compatibility + policy, the signature will be kept as optional, though they are mandatory and an error + will be raised if you don't pass it. can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -161,9 +185,9 @@ def __init__( can_edit_messages: Optional[bool] = None, can_pin_messages: Optional[bool] = None, can_manage_topics: Optional[bool] = None, - can_post_stories: Optional[bool] = None, - can_edit_stories: Optional[bool] = None, - can_delete_stories: Optional[bool] = None, + can_post_stories: bool = None, # type: ignore # noqa: RUF013 + can_edit_stories: bool = None, # type: ignore # noqa: RUF013 + can_delete_stories: bool = None, # type: ignore # noqa: RUF013 *, api_kwargs: Optional[JSONDict] = None, ) -> None: @@ -177,13 +201,19 @@ def __init__( self.can_promote_members: bool = can_promote_members self.can_change_info: bool = can_change_info self.can_invite_users: bool = can_invite_users + # Not actually optionals but because of backwards compatability we pretend they are + if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: + raise TypeError( + "As of NEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories must" + " be set in order to create this object." + ) + self.can_post_stories: bool = can_post_stories + self.can_edit_stories: bool = can_edit_stories + self.can_delete_stories: bool = can_delete_stories # Optionals self.can_post_messages: Optional[bool] = can_post_messages self.can_edit_messages: Optional[bool] = can_edit_messages self.can_pin_messages: Optional[bool] = can_pin_messages - self.can_post_stories: Optional[bool] = can_post_stories - self.can_edit_stories: Optional[bool] = can_edit_stories - self.can_delete_stories: Optional[bool] = can_delete_stories self.can_manage_topics: Optional[bool] = can_manage_topics self._id_attrs = ( diff --git a/tests/test_chatadministratorrights.py b/tests/test_chatadministratorrights.py index 31a69cfeef0..0f2df4f0112 100644 --- a/tests/test_chatadministratorrights.py +++ b/tests/test_chatadministratorrights.py @@ -95,11 +95,42 @@ def test_to_dict(self, chat_admin_rights): assert admin_rights_dict["can_delete_stories"] == car.can_delete_stories def test_equality(self): - a = ChatAdministratorRights(True, *((False,) * 11)) - b = ChatAdministratorRights(True, *((False,) * 11)) - c = ChatAdministratorRights(*(False,) * 12) - d = ChatAdministratorRights(True, True, *((False,) * 10)) - e = ChatAdministratorRights(True, True, *((False,) * 10)) + a = ChatAdministratorRights( + True, + *((False,) * 11), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + b = ChatAdministratorRights( + True, + *((False,) * 11), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + c = ChatAdministratorRights( + *(False,) * 12, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + d = ChatAdministratorRights( + True, + True, + *((False,) * 10), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + e = ChatAdministratorRights( + True, + True, + *((False,) * 10), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) assert a == b assert hash(a) == hash(b) @@ -115,7 +146,20 @@ def test_equality(self): assert hash(d) == hash(e) def test_all_rights(self): - f = ChatAdministratorRights(True, True, True, True, True, True, True, True, True) + f = ChatAdministratorRights( + True, + True, + True, + True, + True, + True, + True, + True, + True, + can_post_stories=True, + can_edit_stories=True, + can_delete_stories=True, + ) t = ChatAdministratorRights.all_rights() # if the dirs are the same, the attributes will all be there assert dir(f) == dir(t) @@ -127,7 +171,20 @@ def test_all_rights(self): assert f != t def test_no_rights(self): - f = ChatAdministratorRights(False, False, False, False, False, False, False, False, False) + f = ChatAdministratorRights( + False, + False, + False, + False, + False, + False, + False, + False, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) t = ChatAdministratorRights.no_rights() # if the dirs are the same, the attributes will all be there assert dir(f) == dir(t) @@ -137,3 +194,19 @@ def test_no_rights(self): assert t[key] is False # and as a finisher, make sure the default is different. assert f != t + + def test_depreciation_typeerror(self): + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights( + *(False,) * 12, + ) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_edit_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_delete_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_edit_stories=True, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_delete_stories=True, can_post_stories=True) From 2a9812e5aa71a4bb5d1705258421e0c424a61102 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 17 Feb 2024 00:34:05 +0100 Subject: [PATCH 10/24] Feat: Mark chat member right stories as non optional --- telegram/_chatmember.py | 19 +++++++++++++------ tests/test_chatmember.py | 26 ++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index 3953a9dde7e..98e4b1ffdd2 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -333,9 +333,9 @@ def __init__( can_pin_messages: Optional[bool] = None, can_manage_topics: Optional[bool] = None, custom_title: Optional[str] = None, - can_post_stories: Optional[bool] = None, - can_edit_stories: Optional[bool] = None, - can_delete_stories: Optional[bool] = None, + can_post_stories: bool = None, # type: ignore # noqa: RUF013 + can_edit_stories: bool = None, # type: ignore # noqa: RUF013 + can_delete_stories: bool = None, # type: ignore # noqa: RUF013 *, api_kwargs: Optional[JSONDict] = None, ): @@ -350,14 +350,21 @@ def __init__( self.can_promote_members: bool = can_promote_members self.can_change_info: bool = can_change_info self.can_invite_users: bool = can_invite_users + # Not actually optionals but because of backwards compatability we pretend they are + if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: + raise TypeError( + "As of NEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories " + "must be set in order to create this object." + ) + self.can_post_stories: bool = can_post_stories + self.can_edit_stories: bool = can_edit_stories + self.can_delete_stories: bool = can_delete_stories + # Optionals self.can_post_messages: Optional[bool] = can_post_messages self.can_edit_messages: Optional[bool] = can_edit_messages 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_post_stories: Optional[bool] = can_post_stories - self.can_edit_stories: Optional[bool] = can_edit_stories - self.can_delete_stories: Optional[bool] = can_delete_stories class ChatMemberMember(ChatMember): diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index 8a09e28b071..f0b2d83db5c 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -150,8 +150,13 @@ def make_json_dict(instance: ChatMember, include_optional_args: bool = False) -> val = val.to_dict() json_dict[param.name] = val - # If we want to test all args (for de_json)- - elif param.default is not inspect.Parameter.empty and include_optional_args: + # If we want to test all args (for de_json) + # or if the param is optional but for backwards compatability + elif ( + param.default is not inspect.Parameter.empty + and include_optional_args + or param.name in ["can_delete_stories", "can_post_stories", "can_edit_stories"] + ): json_dict[param.name] = val return json_dict @@ -205,6 +210,7 @@ def test_de_json_required_args(self, bot, chat_member_type): assert cls.de_json({}, bot) is None json_dict = make_json_dict(chat_member_type) + print(chat_member_type) const_chat_member = ChatMember.de_json(json_dict, bot) assert const_chat_member.api_kwargs == {} @@ -297,3 +303,19 @@ def test_equality(self, chat_member_type): assert c != e assert hash(c) != hash(e) + + def test_depreciation_typeerror(self, chat_member_type): + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator( + *(False,) * 12, + ) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_edit_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_delete_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_edit_stories=True, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_delete_stories=True, can_post_stories=True) From 1aeee911fb266127f5f3ea02b57d19f357f80160 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 17 Feb 2024 00:41:21 +0100 Subject: [PATCH 11/24] Fix: Small review things --- telegram/_message.py | 16 ++++++++-------- telegram/_story.py | 2 +- telegram/constants.py | 30 +++++++++++++++--------------- tests/test_story.py | 12 ++++++------ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/telegram/_message.py b/telegram/_message.py index e743681867e..dd0c7d28e1c 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -603,14 +603,14 @@ class Message(MaybeInaccessibleMessage): .. versionadded:: 20.8 reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original - message. + story. .. versionadded:: NEXT.VERSION - boost_added (:class:`telegram.ChatBoostAdded`, optional): The message is a service message - about a user boosting the chat. + boost_added (:class:`telegram.ChatBoostAdded`, optional): Service message: user boosted + the chat. .. versionadded:: NEXT.VERSION - sender_boost_count (:class:`telegram.ChatBoostAdded`, optional): If the sender of the + sender_boost_count (:obj:`int`, optional): If the sender of the message boosted the chat, the number of boosts added by the user. .. versionadded:: NEXT.VERSION @@ -885,14 +885,14 @@ class Message(MaybeInaccessibleMessage): .. versionadded:: 20.8 reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original - message. + story. .. versionadded:: NEXT.VERSION - boost_added (:class:`telegram.ChatBoostAdded`): Optional. The message is a service message - about a user boosting the chat. + boost_added (:class:`telegram.ChatBoostAdded`): Optional. Service message: user boosted + the chat. .. versionadded:: NEXT.VERSION - sender_boost_count (:class:`telegram.ChatBoostAdded`): Optional. If the sender of the + sender_boost_count (:obj:`int`): Optional. If the sender of the message boosted the chat, the number of boosts added by the user. .. versionadded:: NEXT.VERSION diff --git a/telegram/_story.py b/telegram/_story.py index 22955d211c2..d62e96e5b8e 100644 --- a/telegram/_story.py +++ b/telegram/_story.py @@ -38,7 +38,7 @@ class Story(TelegramObject): .. versionadded:: 20.5 .. versionchanged:: NEXT.VERSION - Added attributes ``chat`` and ``id`` and equality based on them. + Added attributes :attr:`chat` and :attr:`id` and equality based on them. Args: chat (:class:`telegram.Chat`): Chat that posted the story. diff --git a/telegram/constants.py b/telegram/constants.py index fdcafadbed3..0ec8ad1ba4b 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -1705,6 +1705,11 @@ class MessageType(StringEnum): """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" AUDIO = "audio" """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" + BOOST_ADDED = "boost_added" + """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. + + .. versionadded:: NEXT.VERSION + """ CHANNEL_CHAT_CREATED = "channel_chat_created" """:obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`.""" CHAT_SHARED = "chat_shared" @@ -1802,6 +1807,16 @@ class MessageType(StringEnum): """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered" """:obj:`str`: Messages with :attr:`telegram.Message.proximity_alert_triggered`.""" + REPLY_TO_STORY = "reply_to_story" + """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. + + .. versionadded:: NEXT.VERSION + """ + SENDER_BOOST_COUNT = "sender_boost_count" + """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. + + .. versionadded:: NEXT.VERSION + """ STICKER = "sticker" """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" STORY = "story" @@ -1843,21 +1858,6 @@ class MessageType(StringEnum): .. versionadded:: 20.8 """ - REPLY_TO_STORY = "reply_to_story" - """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. - - .. versionadded:: NEXT.VERSION - """ - BOOST_ADDED = "boost_added" - """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. - - .. versionadded:: NEXT.VERSION - """ - SENDER_BOOST_COUNT = "sender_boost_count" - """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. - - .. versionadded:: NEXT.VERSION - """ class PollingLimit(IntEnum): diff --git a/tests/test_story.py b/tests/test_story.py index eb1014fcaed..f36f23b14f6 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -32,25 +32,25 @@ class TestStoryBase: id = 0 -class TestStoryWithoutRequest: +class TestStoryWithoutRequest(TestStoryBase): def test_slot_behaviour(self, story): for attr in story.__slots__: assert getattr(story, attr, "err") != "err", f"got extra slot '{attr}'" assert len(mro_slots(story)) == len(set(mro_slots(story))), "duplicate slot" def test_de_json(self, bot): - json_dict = {"chat": TestStoryBase.chat.to_dict(), "id": TestStoryBase.id} + json_dict = {"chat": self.chat.to_dict(), "id": self.id} story = Story.de_json(json_dict, bot) assert story.api_kwargs == {} - assert story.chat == TestStoryBase.chat - assert story.id == TestStoryBase.id + assert story.chat == self.chat + assert story.id == self.id assert isinstance(story, Story) assert Story.de_json(None, bot) is None def test_to_dict(self, story): story_dict = story.to_dict() - assert story_dict["chat"] == TestStoryBase.chat.to_dict() - assert story_dict["id"] == TestStoryBase.id + assert story_dict["chat"] == self.chat.to_dict() + assert story_dict["id"] == self.id def test_equality(self): a = Story(Chat(1, ""), 0) From 0829abdf95636ef1b7cef66f2663c57b53191fa5 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 17 Feb 2024 00:45:59 +0100 Subject: [PATCH 12/24] Feat: Trying to improve workflow trigger --- .github/workflows/docs.yml | 6 ++++-- .github/workflows/test_official.yml | 10 ++++++---- .github/workflows/type_completeness.yml | 8 ++++---- .github/workflows/unit_tests.yml | 10 ++++++---- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 70f83574d35..d64641f7858 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,12 +2,14 @@ name: Test Documentation Build on: pull_request: branches: - - master - doc-fixes + paths: + - telegram/** push: branches: - - master - doc-fixes + paths: + - telegram/** jobs: test-sphinx-build: diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index 9b972694616..86f0ed5b82b 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -1,11 +1,13 @@ name: Bot API Tests on: pull_request: - branches: - - master + paths: + - telegram/** + - tests/** push: - branches: - - master + paths: + - telegram/** + - tests/** schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5' diff --git a/.github/workflows/type_completeness.yml b/.github/workflows/type_completeness.yml index 14e84d4d3e1..6bb3be29305 100644 --- a/.github/workflows/type_completeness.yml +++ b/.github/workflows/type_completeness.yml @@ -1,11 +1,11 @@ name: Check Type Completeness on: pull_request: - branches: - - master + paths: + - telegram/** push: - branches: - - master + paths: + - telegram/** jobs: test-type-completeness: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 1f45f0ab895..ae575781cc4 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -1,12 +1,14 @@ name: Unit Tests on: pull_request: - branches: - - master + paths: + - telegram/** + - tests/** push: - branches: - - master + paths: + - telegram/** + - tests/** schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions From fe7dff7f3686c2931df225868e4fa4aa27980716 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:24:38 +0100 Subject: [PATCH 13/24] review --- telegram/_bot.py | 4 ++-- telegram/_inline/inputtextmessagecontent.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/telegram/_bot.py b/telegram/_bot.py index 8cecdedffea..0d3a5f6e407 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -998,7 +998,7 @@ async def send_message( for advanced options, please use :paramref:`link_preview_options` directly. .. versionchanged:: NEXT.VERSION - This parameter is now a keyword only parameter. + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent message is returned. @@ -3853,7 +3853,7 @@ async def edit_message_text( for advanced options, please use :paramref:`link_preview_options` directly. .. versionchanged:: NEXT.VERSION - This parameter is now a keyword only parameter. + |keyword_only_arg| Returns: diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 6b84f82868c..7e04de4f2df 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -67,7 +67,7 @@ class InputTextMessageContent(InputMessageContent): for advanced options, please use :paramref:`link_preview_options` directly. .. versionchanged:: NEXT.VERSION - This parameter is now a keyword only parameter. + |keyword_only_arg| Attributes: message_text (:obj:`str`): Text of the message to be sent, From 2341d92133feb0e24a82c4a3b50605a2470210dd Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Sat, 24 Feb 2024 20:04:52 +0100 Subject: [PATCH 14/24] Apply suggestions from code review Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com> --- tests/test_chatmember.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index f0b2d83db5c..dbe4527cf5c 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -304,7 +304,7 @@ def test_equality(self, chat_member_type): assert c != e assert hash(c) != hash(e) - def test_depreciation_typeerror(self, chat_member_type): + def test_deprecation_typeerror(self, chat_member_type): with pytest.raises(TypeError, match="must be set in order"): ChatMemberAdministrator( *(False,) * 12, From ad654a5963b7e33c47542f3fdbcba148d4ca8b0c Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 24 Feb 2024 20:05:09 +0100 Subject: [PATCH 15/24] Fix: Apply suggestions --- .github/workflows/docs.yml | 8 +------ .github/workflows/test_official.yml | 4 ---- .github/workflows/type_completeness.yml | 3 --- .github/workflows/unit_tests.yml | 6 ----- docs/substitutions/global.rst | 2 ++ telegram/_chatadministratorrights.py | 30 ++++++++----------------- telegram/_chatmember.py | 18 ++++++++++++--- tests/test_chatmember.py | 1 - 8 files changed, 27 insertions(+), 45 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d64641f7858..e21d7bb4c32 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,15 +1,9 @@ name: Test Documentation Build on: pull_request: - branches: - - doc-fixes - paths: - - telegram/** - push: - branches: - - doc-fixes paths: - telegram/** + - docs/** jobs: test-sphinx-build: diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index 86f0ed5b82b..bb14554d0d3 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -4,10 +4,6 @@ on: paths: - telegram/** - tests/** - push: - paths: - - telegram/** - - tests/** schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5' diff --git a/.github/workflows/type_completeness.yml b/.github/workflows/type_completeness.yml index 6bb3be29305..8af5897be5e 100644 --- a/.github/workflows/type_completeness.yml +++ b/.github/workflows/type_completeness.yml @@ -3,9 +3,6 @@ on: pull_request: paths: - telegram/** - push: - paths: - - telegram/** jobs: test-type-completeness: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index ae575781cc4..b76bc8c276a 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -4,12 +4,6 @@ on: paths: - telegram/** - tests/** - - push: - paths: - - telegram/** - - tests/** - schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5' diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 228bd459bac..050a6d52b9e 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -77,3 +77,5 @@ .. |reply_quote| replace:: If set to :obj:`True`, the reply is sent as an actual reply to this message. If ``reply_to_message_id`` is passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. .. |do_quote| replace:: If set to :obj:`True`, the replied message is quoted. For a dict, it must be the output of :meth:`~telegram.Message.build_reply_arguments` to specify exact ``reply_parameters``. If ``reply_to_message_id`` or ``reply_parameters`` are passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. + +.. |non_optional_story_argument| replace:: As of this version, this argument is now required. In accordance with our `stability policy `__, the signature will be kept as optional for now, though they are mandatory and an error will be raised if you don't pass it. diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index b36c7287c09..dd6680ad626 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -74,25 +74,19 @@ class ChatAdministratorRights(TelegramObject): .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -128,25 +122,19 @@ class ChatAdministratorRights(TelegramObject): .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION - As of this version, this argument is now required. As of our Backward Compatibility - policy, the signature will be kept as optional, though they are mandatory and an error - will be raised if you don't pass it. + |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -185,9 +173,9 @@ def __init__( can_edit_messages: Optional[bool] = None, can_pin_messages: Optional[bool] = None, can_manage_topics: Optional[bool] = None, - can_post_stories: bool = None, # type: ignore # noqa: RUF013 - can_edit_stories: bool = None, # type: ignore # noqa: RUF013 - can_delete_stories: bool = None, # type: ignore # noqa: RUF013 + can_post_stories: Optional[bool] = None, + can_edit_stories: Optional[bool] = None, + can_delete_stories: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None, ) -> None: diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index 98e4b1ffdd2..ebb587174e5 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -228,14 +228,20 @@ class ChatMemberAdministrator(ChatMember): stories to the chat. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -281,14 +287,20 @@ class ChatMemberAdministrator(ChatMember): stories to the chat. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only @@ -333,9 +345,9 @@ def __init__( can_pin_messages: Optional[bool] = None, can_manage_topics: Optional[bool] = None, custom_title: Optional[str] = None, - can_post_stories: bool = None, # type: ignore # noqa: RUF013 - can_edit_stories: bool = None, # type: ignore # noqa: RUF013 - can_delete_stories: bool = None, # type: ignore # noqa: RUF013 + can_post_stories: Optional[bool] = None, + can_edit_stories: Optional[bool] = None, + can_delete_stories: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None, ): diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index f0b2d83db5c..7006f3e2d2f 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -210,7 +210,6 @@ def test_de_json_required_args(self, bot, chat_member_type): assert cls.de_json({}, bot) is None json_dict = make_json_dict(chat_member_type) - print(chat_member_type) const_chat_member = ChatMember.de_json(json_dict, bot) assert const_chat_member.api_kwargs == {} From b72df9063e84a45ad897c008f9c89a47b7003416 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 24 Feb 2024 20:18:45 +0100 Subject: [PATCH 16/24] Fix: Fixing tests --- tests/test_chatmemberupdated.py | 32 ++++++++++++++++++++++++++--- tests/test_keyboardbuttonrequest.py | 24 ++++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/test_chatmemberupdated.py b/tests/test_chatmemberupdated.py index f0baf88e038..1eebad2eac9 100644 --- a/tests/test_chatmemberupdated.py +++ b/tests/test_chatmemberupdated.py @@ -64,6 +64,9 @@ def new_chat_member(user): True, True, True, + can_post_stories=True, + can_edit_stories=True, + can_delete_stories=True, ) @@ -264,10 +267,19 @@ def test_difference_required(self, user, chat): @pytest.mark.parametrize( "optional_attribute", # This gives the names of all optional arguments of ChatMember + # skipping stories names because they aren't optional even though we pretend they are [ name for name, param in inspect.signature(ChatMemberAdministrator).parameters.items() - if name not in ["self", "api_kwargs"] and param.default != inspect.Parameter.empty + if name + not in [ + "self", + "api_kwargs", + "can_delete_stories", + "can_post_stories", + "can_edit_stories", + ] + and param.default != inspect.Parameter.empty ], ) def test_difference_optionals(self, optional_attribute, user, chat): @@ -276,8 +288,22 @@ def test_difference_optionals(self, optional_attribute, user, chat): old_value = "old_value" new_value = "new_value" trues = tuple(True for _ in range(9)) - old_chat_member = ChatMemberAdministrator(user, *trues, **{optional_attribute: old_value}) - new_chat_member = ChatMemberAdministrator(user, *trues, **{optional_attribute: new_value}) + old_chat_member = ChatMemberAdministrator( + user, + *trues, + **{optional_attribute: old_value}, + can_delete_stories=True, + can_edit_stories=True, + can_post_stories=True, + ) + new_chat_member = ChatMemberAdministrator( + user, + *trues, + **{optional_attribute: new_value}, + can_delete_stories=True, + can_edit_stories=True, + can_post_stories=True, + ) chat_member_updated = ChatMemberUpdated( chat, user, datetime.datetime.utcnow(), old_chat_member, new_chat_member ) diff --git a/tests/test_keyboardbuttonrequest.py b/tests/test_keyboardbuttonrequest.py index 609c2652627..17040ec5903 100644 --- a/tests/test_keyboardbuttonrequest.py +++ b/tests/test_keyboardbuttonrequest.py @@ -106,10 +106,30 @@ class TestKeyboardButtonRequestChatBase: chat_has_username = True chat_is_created = False user_administrator_rights = ChatAdministratorRights( - True, False, True, False, True, False, True, False + True, + False, + True, + False, + True, + False, + True, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, ) bot_administrator_rights = ChatAdministratorRights( - True, False, True, False, True, False, True, False + True, + False, + True, + False, + True, + False, + True, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, ) bot_is_member = True From 7b354b1f372fde16537c7307679da7acc7609122 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 24 Feb 2024 20:34:49 +0100 Subject: [PATCH 17/24] Fix: Adding filters --- telegram/ext/filters.py | 36 ++++++++++++++++++++++++++++++++++++ tests/ext/test_filters.py | 21 +++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index 9ca51d537e1..cf82b3e25cb 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -41,6 +41,7 @@ "ANIMATION", "ATTACHMENT", "AUDIO", + "BOOST_ADDED", "CAPTION", "CHAT", "COMMAND", @@ -60,6 +61,8 @@ "POLL", "PREMIUM_USER", "REPLY", + "REPLY_TO_STORY", + "SENDER_BOOST_COUNT", "STORY", "SUCCESSFUL_PAYMENT", "TEXT", @@ -2789,3 +2792,36 @@ def filter(self, message: Message) -> bool: VOICE = _Voice("filters.VOICE") """Messages that contain :attr:`telegram.Message.voice`.""" + + +class _ReplyToStory(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.reply_to_story) + + +REPLY_TO_STORY = _ReplyToStory(name="filters.REPLY_TO_STORY") +"""Messages that contain :attr:`telegram.Message.reply_to_story`.""" + + +class _BoostAdded(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.boost_added) + + +BOOST_ADDED = _BoostAdded(name="filters.BOOST_ADDED") +"""Messages that contain :attr:`telegram.Message.boost_added`.""" + + +class _SenderBoostCount(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.sender_boost_count) + + +SENDER_BOOST_COUNT = _SenderBoostCount(name="filters.SENDER_BOOST_COUNT") +"""Messages that contain :attr:`telegram.Message.sender_boost_count`.""" diff --git a/tests/ext/test_filters.py b/tests/ext/test_filters.py index 468e5943b1f..dcf5636b8a7 100644 --- a/tests/ext/test_filters.py +++ b/tests/ext/test_filters.py @@ -2700,3 +2700,24 @@ def test_filters_giveaway_winners(self, update): update.message.giveaway_winners = "test" assert filters.GIVEAWAY_WINNERS.check_update(update) assert str(filters.GIVEAWAY_WINNERS) == "filters.GIVEAWAY_WINNERS" + + def test_filters_reply_to_story(self, update): + assert not filters.REPLY_TO_STORY.check_update(update) + + update.message.reply_to_story = "test" + assert filters.REPLY_TO_STORY.check_update(update) + assert str(filters.REPLY_TO_STORY) == "filters.REPLY_TO_STORY" + + def test_filters_boost_added(self, update): + assert not filters.BOOST_ADDED.check_update(update) + + update.message.boost_added = "test" + assert filters.BOOST_ADDED.check_update(update) + assert str(filters.BOOST_ADDED) == "filters.BOOST_ADDED" + + def test_filters_sender_boost_count(self, update): + assert not filters.SENDER_BOOST_COUNT.check_update(update) + + update.message.sender_boost_count = "test" + assert filters.SENDER_BOOST_COUNT.check_update(update) + assert str(filters.SENDER_BOOST_COUNT) == "filters.SENDER_BOOST_COUNT" From 7fe06396c999c3fe8b191ba0170f9bbde17ecf7f Mon Sep 17 00:00:00 2001 From: poolitzer Date: Sat, 24 Feb 2024 20:58:03 +0100 Subject: [PATCH 18/24] Fix: Missed adding optionals here --- telegram/_chatadministratorrights.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index dd6680ad626..c558ae886d8 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -69,19 +69,19 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 @@ -117,19 +117,19 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 From 8791fc60977421104eff3bdb690aef53bccc601c Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Wed, 28 Feb 2024 19:57:22 +0100 Subject: [PATCH 19/24] Update telegram/_chatadministratorrights.py Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com> --- telegram/_chatadministratorrights.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index b81f5eb630f..7802e8ad614 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -192,7 +192,7 @@ def __init__( # Not actually optionals but because of backwards compatability we pretend they are if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: raise TypeError( - "As of NEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories must" + "As of vNEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories must" " be set in order to create this object." ) self.can_post_stories: bool = can_post_stories From 6b020fc72d6aaa006f1ecb0996a5d216eba44f7b Mon Sep 17 00:00:00 2001 From: poolitzer Date: Wed, 28 Feb 2024 19:59:26 +0100 Subject: [PATCH 20/24] Fix: add ignore for official test --- tests/test_official/exceptions.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index 7807a02784a..6f83e9ca74e 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -132,6 +132,9 @@ def ptb_extra_params(object_name: str) -> set[str]: # Mostly due to the value being fixed anyway PTB_IGNORED_PARAMS = { r"InlineQueryResult\w+": {"type"}, + # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, + r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, r"ChatMember\w+": {"status"}, r"PassportElementError\w+": {"source"}, "ForceReply": {"force_reply"}, @@ -166,7 +169,11 @@ def ignored_param_requirements(object_name: str) -> set[str]: # Arguments that are optional arguments for now for backwards compatibility -BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {} +BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { + # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, + r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, +} def backwards_compat_kwargs(object_name: str) -> set[str]: From 946f2af756bf32ad39c0c765e455d3b27d2432c6 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Wed, 28 Feb 2024 20:01:37 +0100 Subject: [PATCH 21/24] Fix: remove optional from docstring --- telegram/_chatadministratorrights.py | 12 ++++++------ telegram/_chatmember.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index b81f5eb630f..39db2c0a37e 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -69,19 +69,19 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 @@ -117,19 +117,19 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index a46416e238b..6d2d35ce3f4 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -224,19 +224,19 @@ class ChatMemberAdministrator(ChatMember): messages; channels only. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 @@ -283,19 +283,19 @@ class ChatMemberAdministrator(ChatMember): messages; channels only. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 .. versionchanged:: NEXT.VERSION |non_optional_story_argument| - can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 From b8489fe0ecb1553c44ce733bf2e5cb613528eea2 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Wed, 28 Feb 2024 20:11:26 +0100 Subject: [PATCH 22/24] Fix: pre commit failling --- telegram/_chatadministratorrights.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index 4a249e298f9..35e1adaac0d 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -192,8 +192,8 @@ def __init__( # Not actually optionals but because of backwards compatability we pretend they are if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: raise TypeError( - "As of vNEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories must" - " be set in order to create this object." + "As of vNEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories" + " must be set in order to create this object." ) self.can_post_stories: bool = can_post_stories self.can_edit_stories: bool = can_edit_stories From 2cc97a72668542bcaafa7dacb022b4b368605f52 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 29 Feb 2024 18:39:25 +0100 Subject: [PATCH 23/24] Fix: Remove double version added --- docs/source/telegram.chatboostadded.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/telegram.chatboostadded.rst b/docs/source/telegram.chatboostadded.rst index e0a24b9ce11..b4551e75b84 100644 --- a/docs/source/telegram.chatboostadded.rst +++ b/docs/source/telegram.chatboostadded.rst @@ -1,8 +1,6 @@ ChatBoostAdded ============== -.. versionadded:: NEXT.VERSION - .. autoclass:: telegram.ChatBoostAdded :members: :show-inheritance: \ No newline at end of file From ad1e21938d5fd0e0bb99b25735bce942614a01c0 Mon Sep 17 00:00:00 2001 From: poolitzer Date: Thu, 29 Feb 2024 19:07:03 +0100 Subject: [PATCH 24/24] Fix: Improve workflow trigger --- .github/workflows/docs.yml | 3 +++ .github/workflows/test_official.yml | 3 +++ .github/workflows/type_completeness.yml | 3 +++ .github/workflows/unit_tests.yml | 3 +++ 4 files changed, 12 insertions(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e21d7bb4c32..ea1173d6986 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -4,6 +4,9 @@ on: paths: - telegram/** - docs/** + push: + branches: + - master jobs: test-sphinx-build: diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index bb14554d0d3..d4853781142 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -4,6 +4,9 @@ on: paths: - telegram/** - tests/** + push: + branches: + - master schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5' diff --git a/.github/workflows/type_completeness.yml b/.github/workflows/type_completeness.yml index 8af5897be5e..ac3b9934e9b 100644 --- a/.github/workflows/type_completeness.yml +++ b/.github/workflows/type_completeness.yml @@ -3,6 +3,9 @@ on: pull_request: paths: - telegram/** + push: + branches: + - master jobs: test-type-completeness: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index b76bc8c276a..682ceead685 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -4,6 +4,9 @@ on: paths: - telegram/** - tests/** + push: + branches: + - master schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5'