diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 233c2ca27a0..ad590831b4e 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -34,7 +34,7 @@ .. |allow_sending_without_reply| replace:: Pass :obj:`True`, if the message should be sent even if the specified replied-to message is not found. -.. |caption_entities| replace:: List of special entities that appear in the caption, which can be specified instead of ``parse_mode``. +.. |caption_entities| replace:: Sequence of special entities that appear in the caption, which can be specified instead of ``parse_mode``. .. |protect_content| replace:: Protects the contents of the sent message from forwarding and saving. @@ -42,8 +42,12 @@ .. |reply_to_msg_id| replace:: If the message is a reply, ID of the original message. -.. |sequenceclassargs| replace:: Accepts any :class:`collections.abc.Sequence` as input instead of just a list. The input is converted to a tuple. +.. |sequenceclassargs| replace:: |sequenceargs| The input is converted to a tuple. .. |tupleclassattrs| replace:: This attribute is now an immutable tuple. .. |alwaystuple| replace:: This attribute is now always a tuple, that may be empty. + +.. |sequenceargs| replace:: Accepts any :class:`collections.abc.Sequence` as input instead of just a list. + +.. |captionentitiesattr| replace:: Tuple of special entities that appear in the caption, which can be specified instead of ``parse_mode``. \ No newline at end of file diff --git a/telegram/_bot.py b/telegram/_bot.py index cad02962e95..355ca22c667 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -383,7 +383,7 @@ def _insert_defaults(self, data: Dict[str, object]) -> None: # skipcq: PYL-R020 with val._unfrozen(): val.parse_mode = DefaultValue.get_value(val.parse_mode) data[key] = val - elif key == "media" and isinstance(val, list): + elif key == "media" and isinstance(val, Sequence): # Copy objects as not to edit them in-place copy_list = [copy.copy(media) for media in val] for media in copy_list: @@ -473,7 +473,7 @@ async def _send_message( message_thread_id: int = None, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, *, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -708,7 +708,7 @@ async def send_message( chat_id: Union[int, str], text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: DVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, @@ -735,9 +735,12 @@ async def send_message( :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): |parse_mode| - entities (List[:class:`telegram.MessageEntity`], optional): List of special entities - that appear in message text, which can be specified instead of + entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special + entities that appear in message text, which can be specified instead of :paramref:`parse_mode`. + + .. versionchanged:: 20.0 + |sequenceargs| disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this message. disable_notification (:obj:`bool`, optional): |disable_notification| @@ -915,7 +918,7 @@ async def send_photo( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -948,7 +951,11 @@ async def send_photo( by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| @@ -1016,7 +1023,7 @@ async def send_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1057,7 +1064,11 @@ async def send_audio( 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| duration (:obj:`int`, optional): Duration of sent audio in seconds. performer (:obj:`str`, optional): Performer. title (:obj:`str`, optional): Track name. @@ -1140,7 +1151,7 @@ async def send_document( thumb: FileInput = None, disable_content_type_detection: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1183,7 +1194,11 @@ async def send_document( disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side content type detection for files uploaded using multipart/form-data. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| @@ -1338,7 +1353,7 @@ async def send_video( supports_streaming: bool = None, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1385,7 +1400,11 @@ async def send_video( by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is suitable for streaming. disable_notification (:obj:`bool`, optional): |disable_notification| @@ -1586,7 +1605,7 @@ async def send_animation( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1639,7 +1658,11 @@ async def send_animation( 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| @@ -1709,7 +1732,7 @@ async def send_voice( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1754,7 +1777,11 @@ async def send_voice( 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |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| @@ -1814,7 +1841,7 @@ async def send_voice( async def send_media_group( self, chat_id: Union[int, str], - media: List[ + media: Sequence[ Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, @@ -1830,7 +1857,7 @@ async def send_media_group( api_kwargs: JSONDict = None, caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, ) -> Tuple[Message, ...]: """Use this method to send a group of photos or videos as an album. @@ -1848,11 +1875,15 @@ async def send_media_group( Args: chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - media (List[:class:`telegram.InputMediaAudio`, :class:`telegram.InputMediaDocument`,\ - :class:`telegram.InputMediaPhoto`, :class:`telegram.InputMediaVideo`]): - An array describing messages to be sent, must include + media (Sequence[:class:`telegram.InputMediaAudio`,\ + :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto`,\ + :class:`telegram.InputMediaVideo`]): An array + describing messages to be sent, must include :tg-const:`telegram.constants.MediaGroupLimit.MIN_MEDIA_LENGTH`– :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items. + + .. versionchanged:: 20.0 + |sequenceargs| disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| @@ -1877,7 +1908,7 @@ async def send_media_group( available modes. .. versionadded:: 20.0 - caption_entities (List[:class:`telegram.MessageEntity`], optional): + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): List of special entities for :paramref:`caption`, which can be specified instead of :paramref:`parse_mode`. Defaults to :obj:`None`. @@ -1911,7 +1942,7 @@ async def send_media_group( item_to_get_caption.caption_entities = parse_sequence_arg(caption_entities) # copy the list (just the references) to avoid mutating the original list - media = media[:] + media = list(media) media[0] = item_to_get_caption data: JSONDict = { @@ -3165,7 +3196,7 @@ async def edit_message_text( parse_mode: ODVInput[str] = DEFAULT_NONE, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: InlineKeyboardMarkup = None, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3194,9 +3225,12 @@ async def edit_message_text( :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - entities (List[:class:`telegram.MessageEntity`], optional): List of special entities - that appear in message text, which can be specified instead of + entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special + entities that appear in message text, which can be specified instead of :paramref:`parse_mode`. + + .. versionchanged:: 20.0 + |sequenceargs| disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this message. reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an @@ -3240,7 +3274,7 @@ async def edit_message_caption( caption: str = None, reply_markup: InlineKeyboardMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3268,7 +3302,11 @@ async def edit_message_caption( 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an inline keyboard. @@ -3430,7 +3468,7 @@ async def get_updates( offset: int = None, limit: int = None, timeout: float = None, - allowed_updates: List[str] = None, + allowed_updates: Sequence[str] = None, *, read_timeout: float = 2, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3467,16 +3505,19 @@ async def get_updates( timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only. - allowed_updates (List[:obj:`str`]), optional): A list the types of + allowed_updates (Sequence[:obj:`str`]), optional): A sequence the types of updates you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See :class:`telegram.Update` for a complete list of available update types. - Specify an empty list to receive all updates except + Specify an empty sequence to receive all updates except :attr:`telegram.Update.chat_member` (default). If not specified, the previous setting will be used. Please note that this parameter doesn't affect updates created before the call to the get_updates, so unwanted updates may be received for a short period of time. + .. versionchanged:: 20.0 + |sequenceargs| + Returns: Tuple[:class:`telegram.Update`] @@ -3522,7 +3563,7 @@ async def set_webhook( url: str, certificate: FileInput = None, max_connections: int = None, - allowed_updates: List[str] = None, + allowed_updates: Sequence[str] = None, ip_address: str = None, drop_pending_updates: bool = None, secret_token: str = None, @@ -3589,15 +3630,18 @@ async def set_webhook( :tg-const:`telegram.constants.WebhookLimit.MAX_CONNECTIONS_LIMIT`. Defaults to ``40``. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput. - allowed_updates (List[:obj:`str`], optional): A list the types of + allowed_updates (Sequence[:obj:`str`], optional): A sequence the types of updates you want your bot to receive. For example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these types. See :class:`telegram.Update` for a complete list of available update types. - Specify an empty list to receive all updates except + Specify an empty sequence to receive all updates except :attr:`telegram.Update.chat_member` (default). If not specified, the previous setting will be used. Please note that this parameter doesn't affect updates created before the call to the set_webhook, so unwanted updates may be received for a short period of time. + + .. versionchanged:: 20.0 + |sequenceargs| drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending updates. secret_token (:obj:`str`, optional): A secret token to be sent in a header @@ -4118,7 +4162,7 @@ async def send_invoice( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], start_parameter: str = None, photo_url: str = None, photo_size: int = None, @@ -4137,7 +4181,7 @@ async def send_invoice( send_email_to_provider: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -4175,9 +4219,12 @@ async def send_invoice( `@BotFather `_. currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies `_. - prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list + prices (Sequence[:class:`telegram.LabeledPrice`)]: Price breakdown, a sequence of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). + + .. versionchanged:: 20.0 + |sequenceargs| max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the *smallest* units of the currency (integer, **not** float/double). For example, for a maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in @@ -4186,13 +4233,16 @@ async def send_invoice( majority of currencies). Defaults to ``0``. .. versionadded:: 13.5 - suggested_tip_amounts (List[:obj:`int`], optional): An array of + suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested amounts of tips in the *smallest* units of the currency (integer, **not** float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed :paramref:`max_tip_amount`. .. versionadded:: 13.5 + + .. versionchanged:: 20.0 + |sequenceargs| start_parameter (:obj:`str`, optional): Unique deep-linking parameter. If left empty, *forwarded copies* of the sent message will have a *Pay* button, allowing multiple users to pay directly from the forwarded message, using the same invoice. @@ -4293,7 +4343,7 @@ async def answer_shipping_query( # pylint: disable=invalid-name self, shipping_query_id: str, ok: bool, - shipping_options: List[ShippingOption] = None, + shipping_options: Sequence[ShippingOption] = None, error_message: str = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -4315,8 +4365,11 @@ async def answer_shipping_query( # pylint: disable=invalid-name ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is possible and :obj:`False` if there are any problems (for example, if delivery to the specified address is not possible). - shipping_options (List[:class:`telegram.ShippingOption`]), optional]: Required if - :paramref:`ok` is :obj:`True`. A list of available shipping options. + shipping_options (Sequence[:class:`telegram.ShippingOption`]), optional): Required if + :paramref:`ok` is :obj:`True`. A sequence of available shipping options. + + .. versionchanged:: 20.0 + |sequenceargs| error_message (:obj:`str`, optional): Required if :paramref:`ok` is :obj:`False`. Error message in human readable form that explains why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is unavailable"). Telegram @@ -5419,7 +5472,7 @@ async def get_sticker_set( @_log async def get_custom_emoji_stickers( self, - custom_emoji_ids: List[str], + custom_emoji_ids: Sequence[str], *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -5435,10 +5488,13 @@ async def get_custom_emoji_stickers( Returns a tuple instead of a list. Args: - custom_emoji_ids (List[:obj:`str`]): List of custom emoji identifiers. + custom_emoji_ids (Sequence[:obj:`str`]): Sequence of custom emoji identifiers. At most :tg-const:`telegram.constants.CustomEmojiStickerLimit.\ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified. + .. versionchanged:: 20.0 + |sequenceargs| + Returns: Tuple[:class:`telegram.Sticker`] @@ -5862,7 +5918,7 @@ async def set_sticker_set_thumb( async def set_passport_data_errors( self, user_id: Union[str, int], - errors: List[PassportElementError], + errors: Sequence[PassportElementError], *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -5882,7 +5938,10 @@ async def set_passport_data_errors( Args: user_id (:obj:`int`): User identifier - errors (List[:class:`PassportElementError`]): A list describing the errors. + errors (Sequence[:class:`PassportElementError`]): A Sequence describing the errors. + + .. versionchanged:: 20.0 + |sequenceargs| Returns: :obj:`bool`: On success, :obj:`True` is returned. @@ -5908,7 +5967,7 @@ async def send_poll( self, chat_id: Union[int, str], question: str, - options: List[str], + options: Sequence[str], is_anonymous: bool = None, type: str = None, # pylint: disable=redefined-builtin allows_multiple_answers: bool = None, @@ -5922,7 +5981,7 @@ async def send_poll( open_period: int = None, close_date: Union[int, datetime] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + explanation_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -5942,11 +6001,14 @@ async def send_poll( chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`- :tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters. - options (List[:obj:`str`]): List of answer options, + options (Sequence[:obj:`str`]): Sequence of answer options, :tg-const:`telegram.Poll.MIN_OPTION_NUMBER`- :tg-const:`telegram.Poll.MAX_OPTION_NUMBER` strings :tg-const:`telegram.Poll.MIN_OPTION_LENGTH`- :tg-const:`telegram.Poll.MAX_OPTION_LENGTH` characters each. + + .. versionchanged:: 20.0 + |sequenceargs| is_anonymous (:obj:`bool`, optional): :obj:`True`, if the poll needs to be anonymous, defaults to :obj:`True`. type (:obj:`str`, optional): Poll type, :tg-const:`telegram.Poll.QUIZ` or @@ -5963,9 +6025,12 @@ async def send_poll( explanation_parse_mode (:obj:`str`, optional): Mode for parsing entities in the explanation. See the constants in :class:`telegram.constants.ParseMode` for the available modes. - explanation_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of + explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of + special entities that appear in message text, which can be specified instead of :paramref:`explanation_parse_mode`. + + .. versionchanged:: 20.0 + |sequenceargs| open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active after creation, :tg-const:`telegram.Poll.MIN_OPEN_PERIOD`- :tg-const:`telegram.Poll.MAX_OPEN_PERIOD`. Can't be used together with @@ -6309,7 +6374,7 @@ async def get_my_commands( @_log async def set_my_commands( self, - commands: List[Union[BotCommand, Tuple[str, str]]], + commands: Sequence[Union[BotCommand, Tuple[str, str]]], scope: BotCommandScope = None, language_code: str = None, *, @@ -6327,10 +6392,13 @@ async def set_my_commands( .. seealso:: :meth:`get_my_commands`, :meth:`delete_my_commands` Args: - commands (List[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A list + commands (Sequence[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A sequence of bot commands to be set as the list of the bot's commands. At most :tg-const:`telegram.constants.BotCommandLimit.MAX_COMMAND_NUMBER` commands can be specified. + + .. versionchanged:: 20.0 + |sequenceargs| scope (:class:`telegram.BotCommandScope`, optional): An object, describing scope of users for which the commands are relevant. Defaults to :class:`telegram.BotCommandScopeDefault`. @@ -6488,7 +6556,7 @@ async def copy_message( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -6521,7 +6589,11 @@ async def copy_message( entities parsing. If not specified, the original caption is kept. parse_mode (:obj:`str`, optional): Mode for parsing entities in the new caption. See the constants in :class:`telegram.constants.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |caption_entities| + + .. versionchanged:: 20.0 + |sequenceargs| disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| @@ -6662,9 +6734,9 @@ async def create_invoice_link( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, provider_data: Union[str, object] = None, photo_url: str = None, photo_size: int = None, @@ -6702,20 +6774,26 @@ async def create_invoice_link( `@BotFather `_. currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies `_. - prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list + prices (Sequence[:class:`telegram.LabeledPrice`)]: Price breakdown, a sequence of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). + + .. versionchanged:: 20.0 + |sequenceargs| max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the *smallest* units of the currency (integer, **not** float/double). For example, for a maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to ``0``. - suggested_tip_amounts (List[:obj:`int`], optional): An array of + suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested amounts of tips in the *smallest* units of the currency (integer, **not** float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed :paramref:`max_tip_amount`. + + .. versionchanged:: 20.0 + |sequenceargs| provider_data (:obj:`str` | :obj:`object`, optional): Data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. When an object is diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index a6963f46146..b72541f62c6 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -18,7 +18,7 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. # pylint: disable=redefined-builtin """This module contains an object that represents a Telegram CallbackQuery""" -from typing import TYPE_CHECKING, ClassVar, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, ClassVar, Optional, Sequence, Tuple, Union from telegram import constants from telegram._files.location import Location @@ -192,7 +192,7 @@ async def edit_message_text( parse_mode: ODVInput[str] = DEFAULT_NONE, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: "InlineKeyboardMarkup" = None, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -252,7 +252,7 @@ async def edit_message_caption( caption: str = None, reply_markup: "InlineKeyboardMarkup" = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -720,7 +720,7 @@ async def copy_message( chat_id: Union[int, str], caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, diff --git a/telegram/_chat.py b/telegram/_chat.py index 7cdd9c79386..4206710244f 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -20,7 +20,7 @@ """This module contains an object that represents a Telegram Chat.""" from datetime import datetime from html import escape -from typing import TYPE_CHECKING, ClassVar, List, Optional, Sequence, Tuple, Union +from typing import TYPE_CHECKING, ClassVar, Optional, Sequence, Tuple, Union from telegram import constants from telegram._chatlocation import ChatLocation @@ -1239,7 +1239,7 @@ async def send_message( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1280,7 +1280,7 @@ async def send_message( async def send_media_group( self, - media: List[ + media: Sequence[ Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, @@ -1296,7 +1296,7 @@ async def send_media_group( api_kwargs: JSONDict = None, caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, ) -> Tuple["Message", ...]: """Shortcut for:: @@ -1369,7 +1369,7 @@ async def send_photo( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1473,7 +1473,7 @@ async def send_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1529,7 +1529,7 @@ async def send_document( thumb: FileInput = None, disable_content_type_detection: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1663,7 +1663,7 @@ async def send_invoice( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], start_parameter: str = None, photo_url: str = None, photo_size: int = None, @@ -1682,7 +1682,7 @@ async def send_invoice( send_email_to_provider: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1815,7 +1815,7 @@ async def send_animation( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1974,7 +1974,7 @@ async def send_video( supports_streaming: bool = None, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2080,7 +2080,7 @@ async def send_voice( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2125,7 +2125,7 @@ async def send_voice( async def send_poll( self, question: str, - options: List[str], + options: Sequence[str], is_anonymous: bool = None, type: str = None, allows_multiple_answers: bool = None, @@ -2139,7 +2139,7 @@ async def send_poll( open_period: int = None, close_date: Union[int, datetime] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + explanation_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2192,7 +2192,7 @@ async def send_copy( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -2242,7 +2242,7 @@ async def copy_message( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, diff --git a/telegram/_files/inputmedia.py b/telegram/_files/inputmedia.py index bf40b1ea21c..1e346456966 100644 --- a/telegram/_files/inputmedia.py +++ b/telegram/_files/inputmedia.py @@ -68,7 +68,7 @@ class InputMedia(TelegramObject): media (:obj:`str` | :class:`telegram.InputFile`): Media to send. caption (:obj:`str`): Optional. Caption of the media to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 @@ -150,7 +150,7 @@ class InputMediaAnimation(InputMedia): media (:obj:`str` | :class:`telegram.InputFile`): Animation to send. caption (:obj:`str`): Optional. Caption of the document to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 @@ -234,7 +234,7 @@ class InputMediaPhoto(InputMedia): media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. caption (:obj:`str`): Optional. Caption of the document to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 @@ -318,7 +318,7 @@ class InputMediaVideo(InputMedia): media (:obj:`str` | :class:`telegram.InputFile`): Video file to send. caption (:obj:`str`): Optional. Caption of the document to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 @@ -421,7 +421,7 @@ class InputMediaAudio(InputMedia): media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send. caption (:obj:`str`): Optional. Caption of the document to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 @@ -514,7 +514,7 @@ class InputMediaDocument(InputMedia): media (:obj:`str` | :class:`telegram.InputFile`): File to send. caption (:obj:`str`): Optional. Caption of the document to be sent. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_games/game.py b/telegram/_games/game.py index 3691d3b1208..849b0c27062 100644 --- a/telegram/_games/game.py +++ b/telegram/_games/game.py @@ -77,7 +77,7 @@ class Game(TelegramObject): using :meth:`telegram.Bot.edit_message_text`. text_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that appear in text, such as usernames, URLs, bot commands, etc. - This list is empty if the message does not contain text entities. + This tuple is empty if the message does not contain text entities. .. versionchanged:: 20.0 |tupleclassattrs| diff --git a/telegram/_inline/inlinekeyboardmarkup.py b/telegram/_inline/inlinekeyboardmarkup.py index f4906097bf4..a80dabe6e6c 100644 --- a/telegram/_inline/inlinekeyboardmarkup.py +++ b/telegram/_inline/inlinekeyboardmarkup.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram InlineKeyboardMarkup.""" -from typing import TYPE_CHECKING, List, Optional, Sequence +from typing import TYPE_CHECKING, Optional, Sequence from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton from telegram._telegramobject import TelegramObject @@ -111,7 +111,7 @@ def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> "InlineK @classmethod def from_row( - cls, button_row: List[InlineKeyboardButton], **kwargs: object + cls, button_row: Sequence[InlineKeyboardButton], **kwargs: object ) -> "InlineKeyboardMarkup": """Shortcut for:: @@ -120,15 +120,18 @@ def from_row( Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons Args: - button_row (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the - markup + button_row (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use + in the markup + + .. versionchanged:: 20.0 + |sequenceargs| """ return cls([button_row], **kwargs) # type: ignore[arg-type] @classmethod def from_column( - cls, button_column: List[InlineKeyboardButton], **kwargs: object + cls, button_column: Sequence[InlineKeyboardButton], **kwargs: object ) -> "InlineKeyboardMarkup": """Shortcut for:: @@ -137,8 +140,11 @@ def from_column( Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons Args: - button_column (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the - markup + button_column (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use + in the markup + + .. versionchanged:: 20.0 + |sequenceargs| """ button_grid = [[button] for button in button_column] diff --git a/telegram/_inline/inlinequeryresultaudio.py b/telegram/_inline/inlinequeryresultaudio.py index 1c1bbe6d24c..3feffbe2f28 100644 --- a/telegram/_inline/inlinequeryresultaudio.py +++ b/telegram/_inline/inlinequeryresultaudio.py @@ -71,7 +71,7 @@ class InlineQueryResultAudio(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedaudio.py b/telegram/_inline/inlinequeryresultcachedaudio.py index 370a9883313..b811dccdcc5 100644 --- a/telegram/_inline/inlinequeryresultcachedaudio.py +++ b/telegram/_inline/inlinequeryresultcachedaudio.py @@ -66,7 +66,7 @@ class InlineQueryResultCachedAudio(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcacheddocument.py b/telegram/_inline/inlinequeryresultcacheddocument.py index 74cda79aca8..55fa23df066 100644 --- a/telegram/_inline/inlinequeryresultcacheddocument.py +++ b/telegram/_inline/inlinequeryresultcacheddocument.py @@ -70,7 +70,7 @@ class InlineQueryResultCachedDocument(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedgif.py b/telegram/_inline/inlinequeryresultcachedgif.py index 2f5038d3a3e..e0da75c5ba9 100644 --- a/telegram/_inline/inlinequeryresultcachedgif.py +++ b/telegram/_inline/inlinequeryresultcachedgif.py @@ -69,7 +69,7 @@ class InlineQueryResultCachedGif(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedmpeg4gif.py b/telegram/_inline/inlinequeryresultcachedmpeg4gif.py index 1857113832f..5505dcdbce7 100644 --- a/telegram/_inline/inlinequeryresultcachedmpeg4gif.py +++ b/telegram/_inline/inlinequeryresultcachedmpeg4gif.py @@ -69,7 +69,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedphoto.py b/telegram/_inline/inlinequeryresultcachedphoto.py index 30855e7129c..a0017ed0df4 100644 --- a/telegram/_inline/inlinequeryresultcachedphoto.py +++ b/telegram/_inline/inlinequeryresultcachedphoto.py @@ -71,7 +71,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedvideo.py b/telegram/_inline/inlinequeryresultcachedvideo.py index d82ca22a896..f0bea8dce00 100644 --- a/telegram/_inline/inlinequeryresultcachedvideo.py +++ b/telegram/_inline/inlinequeryresultcachedvideo.py @@ -67,7 +67,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultcachedvoice.py b/telegram/_inline/inlinequeryresultcachedvoice.py index 19c5f4051bf..99611b4bd54 100644 --- a/telegram/_inline/inlinequeryresultcachedvoice.py +++ b/telegram/_inline/inlinequeryresultcachedvoice.py @@ -47,7 +47,8 @@ class InlineQueryResultCachedVoice(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |captionentitiesattr| .. versionchanged:: 20.0 |sequenceclassargs| diff --git a/telegram/_inline/inlinequeryresultdocument.py b/telegram/_inline/inlinequeryresultdocument.py index e262b38c4dd..f05d27afb7d 100644 --- a/telegram/_inline/inlinequeryresultdocument.py +++ b/telegram/_inline/inlinequeryresultdocument.py @@ -74,7 +74,7 @@ class InlineQueryResultDocument(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultgif.py b/telegram/_inline/inlinequeryresultgif.py index 9bbc236478c..5c4bdb099a6 100644 --- a/telegram/_inline/inlinequeryresultgif.py +++ b/telegram/_inline/inlinequeryresultgif.py @@ -81,7 +81,7 @@ class InlineQueryResultGif(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultmpeg4gif.py b/telegram/_inline/inlinequeryresultmpeg4gif.py index 5656da94a24..b37077f2bc4 100644 --- a/telegram/_inline/inlinequeryresultmpeg4gif.py +++ b/telegram/_inline/inlinequeryresultmpeg4gif.py @@ -54,7 +54,8 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`, optional): |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): + |captionentitiesattr| .. versionchanged:: 20.0 |sequenceclassargs| diff --git a/telegram/_inline/inlinequeryresultphoto.py b/telegram/_inline/inlinequeryresultphoto.py index 4517e7acfe1..35b5898b553 100644 --- a/telegram/_inline/inlinequeryresultphoto.py +++ b/telegram/_inline/inlinequeryresultphoto.py @@ -78,7 +78,7 @@ class InlineQueryResultPhoto(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultvideo.py b/telegram/_inline/inlinequeryresultvideo.py index 5fd617f7550..cbd4aa85687 100644 --- a/telegram/_inline/inlinequeryresultvideo.py +++ b/telegram/_inline/inlinequeryresultvideo.py @@ -83,7 +83,8 @@ class InlineQueryResultVideo(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Sequence[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Sequence[:class:`telegram.MessageEntity`]): Optional. + |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inlinequeryresultvoice.py b/telegram/_inline/inlinequeryresultvoice.py index 6a4d52109cc..2ec3cff50cd 100644 --- a/telegram/_inline/inlinequeryresultvoice.py +++ b/telegram/_inline/inlinequeryresultvoice.py @@ -70,7 +70,7 @@ class InlineQueryResultVoice(InlineQueryResult): 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 6d23b26a8d4..8664ca49ffb 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -55,7 +55,7 @@ class InputTextMessageContent(InputMessageContent): 1-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities parsing. parse_mode (:obj:`str`): Optional. |parse_mode| - entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities| + entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr| .. versionchanged:: 20.0 diff --git a/telegram/_message.py b/telegram/_message.py index 3f84539f4bf..e1be325622f 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -808,7 +808,7 @@ def effective_attachment( Invoice, Location, PassportData, - List[PhotoSize], + Sequence[PhotoSize], Poll, Sticker, SuccessfulPayment, @@ -888,7 +888,7 @@ async def reply_text( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -942,7 +942,7 @@ async def reply_markdown( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1006,7 +1006,7 @@ async def reply_markdown_v2( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1066,7 +1066,7 @@ async def reply_html( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1120,7 +1120,7 @@ async def reply_html( async def reply_media_group( self, - media: List[ + media: Sequence[ Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, @@ -1137,7 +1137,7 @@ async def reply_media_group( api_kwargs: JSONDict = None, caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, ) -> Tuple["Message", ...]: """Shortcut for:: @@ -1185,7 +1185,7 @@ async def reply_photo( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1246,7 +1246,7 @@ async def reply_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1309,7 +1309,7 @@ async def reply_document( thumb: FileInput = None, disable_content_type_detection: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1372,7 +1372,7 @@ async def reply_animation( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1488,7 +1488,7 @@ async def reply_video( supports_streaming: bool = None, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1609,7 +1609,7 @@ async def reply_voice( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1845,7 +1845,7 @@ async def reply_contact( async def reply_poll( self, question: str, - options: List[str], + options: Sequence[str], is_anonymous: bool = None, type: str = None, # pylint: disable=redefined-builtin allows_multiple_answers: bool = None, @@ -1859,7 +1859,7 @@ async def reply_poll( open_period: int = None, close_date: Union[int, datetime.datetime] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + explanation_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2052,7 +2052,7 @@ async def reply_invoice( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], start_parameter: str = None, photo_url: str = None, photo_size: int = None, @@ -2071,7 +2071,7 @@ async def reply_invoice( send_email_to_provider: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2201,7 +2201,7 @@ async def copy( chat_id: Union[int, str], caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -2257,7 +2257,7 @@ async def reply_copy( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -2321,7 +2321,7 @@ async def edit_text( parse_mode: ODVInput[str] = DEFAULT_NONE, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: InlineKeyboardMarkup = None, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2368,7 +2368,7 @@ async def edit_caption( caption: str = None, reply_markup: InlineKeyboardMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_payment/shippingquery.py b/telegram/_payment/shippingquery.py index 1bcee1f83b2..1f97420c15f 100644 --- a/telegram/_payment/shippingquery.py +++ b/telegram/_payment/shippingquery.py @@ -18,7 +18,7 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram ShippingQuery.""" -from typing import TYPE_CHECKING, List, Optional +from typing import TYPE_CHECKING, Optional, Sequence from telegram._payment.shippingaddress import ShippingAddress from telegram._payment.shippingoption import ShippingOption @@ -92,7 +92,7 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ShippingQuer async def answer( # pylint: disable=invalid-name self, ok: bool, - shipping_options: List[ShippingOption] = None, + shipping_options: Sequence[ShippingOption] = None, error_message: str = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_replykeyboardmarkup.py b/telegram/_replykeyboardmarkup.py index 2a481c8e6a8..08e043a4c98 100644 --- a/telegram/_replykeyboardmarkup.py +++ b/telegram/_replykeyboardmarkup.py @@ -18,7 +18,7 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram ReplyKeyboardMarkup.""" -from typing import ClassVar, List, Sequence, Union +from typing import ClassVar, Sequence, Union from telegram import constants from telegram._keyboardbutton import KeyboardButton @@ -178,7 +178,7 @@ def from_button( @classmethod def from_row( cls, - button_row: List[Union[str, KeyboardButton]], + button_row: Sequence[Union[str, KeyboardButton]], resize_keyboard: bool = False, one_time_keyboard: bool = False, selective: bool = False, @@ -192,8 +192,11 @@ def from_row( Return a ReplyKeyboardMarkup from a single row of KeyboardButtons. Args: - button_row (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use in - the markup. + button_row (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to + use in the markup. + + .. versionchanged:: 20.0 + |sequenceargs| resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is @@ -230,7 +233,7 @@ def from_row( @classmethod def from_column( cls, - button_column: List[Union[str, KeyboardButton]], + button_column: Sequence[Union[str, KeyboardButton]], resize_keyboard: bool = False, one_time_keyboard: bool = False, selective: bool = False, @@ -244,8 +247,11 @@ def from_column( Return a ReplyKeyboardMarkup from a single column of KeyboardButtons. Args: - button_column (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use - in the markup. + button_column (Sequence[:class:`telegram.KeyboardButton` | :obj:`str`]): The button + to use in the markup. + + .. versionchanged:: 20.0 + |sequenceargs| resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is diff --git a/telegram/_user.py b/telegram/_user.py index ba0e2364757..10a702d2471 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -19,7 +19,7 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram User.""" from datetime import datetime -from typing import TYPE_CHECKING, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Optional, Sequence, Tuple, Union from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton from telegram._menubutton import MenuButton @@ -376,7 +376,7 @@ async def send_message( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -424,7 +424,7 @@ async def send_photo( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -467,7 +467,7 @@ async def send_photo( async def send_media_group( self, - media: List[ + media: Sequence[ Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, @@ -483,7 +483,7 @@ async def send_media_group( api_kwargs: JSONDict = None, caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, ) -> Tuple["Message", ...]: """Shortcut for:: @@ -527,7 +527,7 @@ async def send_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -708,7 +708,7 @@ async def send_document( thumb: FileInput = None, disable_content_type_detection: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -800,7 +800,7 @@ async def send_invoice( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], start_parameter: str = None, photo_url: str = None, photo_size: int = None, @@ -819,7 +819,7 @@ async def send_invoice( send_email_to_provider: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -952,7 +952,7 @@ async def send_animation( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1053,7 +1053,7 @@ async def send_video( supports_streaming: bool = None, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1217,7 +1217,7 @@ async def send_voice( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1262,7 +1262,7 @@ async def send_voice( async def send_poll( self, question: str, - options: List[str], + options: Sequence[str], is_anonymous: bool = None, type: str = None, allows_multiple_answers: bool = None, @@ -1276,7 +1276,7 @@ async def send_poll( open_period: int = None, close_date: Union[int, datetime] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + explanation_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -1329,7 +1329,7 @@ async def send_copy( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -1379,7 +1379,7 @@ async def copy_message( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index 358e023e45c..e41ae887726 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -385,7 +385,7 @@ def _insert_defaults(self, data: Dict[str, object]) -> None: with val._unfrozen(): val.parse_mode = self.defaults.parse_mode if self.defaults else None data[key] = val - elif key == "media" and isinstance(val, list): + elif key == "media" and isinstance(val, Sequence): # Copy objects as not to edit them in-place copy_list = [copy(media) for media in val] for media in copy_list: @@ -476,7 +476,7 @@ async def _send_message( message_thread_id: int = None, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, *, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -515,7 +515,7 @@ async def get_updates( offset: int = None, limit: int = None, timeout: float = None, - allowed_updates: List[str] = None, + allowed_updates: Sequence[str] = None, *, read_timeout: float = 2, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -646,7 +646,7 @@ async def copy_message( message_id: int, caption: str = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple["MessageEntity", ...], List["MessageEntity"]] = None, + caption_entities: Sequence["MessageEntity"] = None, disable_notification: DVInput[bool] = DEFAULT_NONE, reply_to_message_id: int = None, allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, @@ -828,7 +828,7 @@ async def answer_shipping_query( self, shipping_query_id: str, ok: bool, - shipping_options: List[ShippingOption] = None, + shipping_options: Sequence[ShippingOption] = None, error_message: str = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -977,9 +977,9 @@ async def create_invoice_link( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, provider_data: Union[str, object] = None, photo_url: str = None, photo_size: int = None, @@ -1296,7 +1296,7 @@ async def edit_message_caption( caption: str = None, reply_markup: InlineKeyboardMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1421,7 +1421,7 @@ async def edit_message_text( parse_mode: ODVInput[str] = DEFAULT_NONE, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: InlineKeyboardMarkup = None, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1726,7 +1726,7 @@ async def get_sticker_set( async def get_custom_emoji_stickers( self, - custom_emoji_ids: List[str], + custom_emoji_ids: Sequence[str], *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2044,7 +2044,7 @@ async def send_animation( reply_to_message_id: int = None, reply_markup: ReplyMarkup = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2094,7 +2094,7 @@ async def send_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2240,7 +2240,7 @@ async def send_document( thumb: FileInput = None, disable_content_type_detection: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2316,7 +2316,7 @@ async def send_invoice( payload: str, provider_token: str, currency: str, - prices: List["LabeledPrice"], + prices: Sequence["LabeledPrice"], start_parameter: str = None, photo_url: str = None, photo_size: int = None, @@ -2335,7 +2335,7 @@ async def send_invoice( send_email_to_provider: bool = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, + suggested_tip_amounts: Sequence[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2431,7 +2431,7 @@ async def send_location( async def send_media_group( self, chat_id: Union[int, str], - media: List[ + media: Sequence[ Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, @@ -2448,7 +2448,7 @@ async def send_media_group( rate_limit_args: RLARGS = None, caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, ) -> Tuple[Message, ...]: return await super().send_media_group( chat_id=chat_id, @@ -2473,7 +2473,7 @@ async def send_message( chat_id: Union[int, str], text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + entities: Sequence["MessageEntity"] = None, disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: DVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, @@ -2518,7 +2518,7 @@ async def send_photo( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2554,7 +2554,7 @@ async def send_poll( self, chat_id: Union[int, str], question: str, - options: List[str], + options: Sequence[str], is_anonymous: bool = None, type: str = None, # pylint: disable=redefined-builtin allows_multiple_answers: bool = None, @@ -2568,7 +2568,7 @@ async def send_poll( open_period: int = None, close_date: Union[int, datetime] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + explanation_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2705,7 +2705,7 @@ async def send_video( supports_streaming: bool = None, thumb: FileInput = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -2795,7 +2795,7 @@ async def send_voice( reply_markup: ReplyMarkup = None, parse_mode: ODVInput[str] = DEFAULT_NONE, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None, + caption_entities: Sequence["MessageEntity"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: int = None, *, @@ -3018,7 +3018,7 @@ async def set_game_score( async def set_my_commands( self, - commands: List[Union[BotCommand, Tuple[str, str]]], + commands: Sequence[Union[BotCommand, Tuple[str, str]]], scope: BotCommandScope = None, language_code: str = None, *, @@ -3065,7 +3065,7 @@ async def set_my_default_administrator_rights( async def set_passport_data_errors( self, user_id: Union[str, int], - errors: List[PassportElementError], + errors: Sequence[PassportElementError], *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3135,7 +3135,7 @@ async def set_webhook( url: str, certificate: FileInput = None, max_connections: int = None, - allowed_updates: List[str] = None, + allowed_updates: Sequence[str] = None, ip_address: str = None, drop_pending_updates: bool = None, secret_token: str = None, diff --git a/telegram/request/_requestparameter.py b/telegram/request/_requestparameter.py index e7b931e480e..89eba0f014e 100644 --- a/telegram/request/_requestparameter.py +++ b/telegram/request/_requestparameter.py @@ -20,7 +20,7 @@ import json from dataclasses import dataclass from datetime import datetime -from typing import List, Optional, Tuple +from typing import List, Optional, Sequence, Tuple from telegram._files.inputfile import InputFile from telegram._files.inputmedia import InputMedia @@ -143,7 +143,7 @@ def from_input(cls, key: str, value: object) -> "RequestParameter": """Builds an instance of this class for a given key-value pair that represents the raw input as passed along from a method of :class:`telegram.Bot`. """ - if isinstance(value, list): + if not isinstance(value, (str, bytes)) and isinstance(value, Sequence): param_values = [] input_files = [] for obj in value: diff --git a/tests/test_inputmedia.py b/tests/test_inputmedia.py index d7f0e96789d..3658853399d 100644 --- a/tests/test_inputmedia.py +++ b/tests/test_inputmedia.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import copy +from collections.abc import Sequence import pytest @@ -120,6 +121,17 @@ def input_media_document(class_thumb_file): ) +class CustomSequence(Sequence): + def __init__(self, items): + self.items = items + + def __getitem__(self, index): + return self.items[index] + + def __len__(self): + return len(self.items) + + class TestInputMediaVideo: type_ = "video" media = "NOTAREALFILEID" @@ -683,6 +695,22 @@ async def func(): assert all(isinstance(mes, Message) for mes in messages) assert all(mes.media_group_id == messages[0].media_group_id for mes in messages) + @pytest.mark.flaky(3, 1) + @pytest.mark.parametrize("sequence_type", [list, tuple, CustomSequence]) + @pytest.mark.parametrize("bot_class", ["raw_bot", "ext_bot"]) + async def test_send_media_group_different_sequences( + self, bot, chat_id, media_group, sequence_type, bot_class, raw_bot + ): + """Test that send_media_group accepts different sequence types. This test ensures that + Bot._insert_defaults works for arbitrary sequence types.""" + bot = bot if bot_class == "ext_bot" else raw_bot + + messages = await bot.send_media_group(chat_id, sequence_type(media_group)) + assert isinstance(messages, tuple) + assert len(messages) == 3 + assert all(isinstance(mes, Message) for mes in messages) + assert all(mes.media_group_id == messages[0].media_group_id for mes in messages) + @pytest.mark.flaky(3, 1) @pytest.mark.parametrize( "default_bot,custom", diff --git a/tests/test_requestparameter.py b/tests/test_requestparameter.py index f5add3dbfba..0c7687d3ff8 100644 --- a/tests/test_requestparameter.py +++ b/tests/test_requestparameter.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. import datetime +from typing import Sequence import pytest @@ -156,3 +157,45 @@ def test_from_input_inputmedia_without_attach(self): request_parameter = RequestParameter.from_input("key", input_media) assert request_parameter.value == {"type": "video"} assert request_parameter.input_files == [input_media.media, input_media.thumb] + + def test_from_input_str_and_bytes(self): + input_str = "test_input" + request_parameter = RequestParameter.from_input("input", input_str) + assert request_parameter.value == input_str + assert request_parameter.name == "input" + assert request_parameter.input_files is None + + input_bytes = b"test_input" + request_parameter = RequestParameter.from_input("input", input_bytes) + assert request_parameter.value == input_bytes + assert request_parameter.name == "input" + assert request_parameter.input_files is None + + def test_from_input_different_sequences(self): + input_list = ["item1", "item2"] + request_parameter = RequestParameter.from_input("input", input_list) + assert request_parameter.value == input_list + assert request_parameter.name == "input" + assert request_parameter.input_files is None + + input_tuple = tuple(input_list) + request_parameter = RequestParameter.from_input("input", input_tuple) + assert request_parameter.value == input_list + assert request_parameter.name == "input" + assert request_parameter.input_files is None + + class CustomSequence(Sequence): + def __init__(self, items): + self.items = items + + def __getitem__(self, index): + return self.items[index] + + def __len__(self): + return len(self.items) + + input_custom_sequence = CustomSequence(input_list) + request_parameter = RequestParameter.from_input("input", input_custom_sequence) + assert request_parameter.value == input_list + assert request_parameter.name == "input" + assert request_parameter.input_files is None