Make TelegramObject Immutable (#3249)

This commit is contained in:
Bibo-Joshi 2022-12-15 15:00:36 +01:00 committed by GitHub
parent ff645c6fe2
commit b11a0c7778
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
164 changed files with 2151 additions and 975 deletions

View file

@ -4,4 +4,4 @@ telegram.TelegramObject
.. autoclass:: telegram.TelegramObject
:members:
:show-inheritance:
:special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__
:special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__, __setattr__, __delattr__

View file

@ -40,4 +40,10 @@
.. |disable_notification| replace:: Sends the message silently. Users will receive a notification with no sound.
.. |reply_to_msg_id| replace:: If the message is a reply, ID of the original message.
.. |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.
.. |tupleclassattrs| replace:: This attribute is now an immutable tuple.
.. |alwaystuple| replace:: This attribute is now always a tuple, that may be empty.

View file

@ -21,6 +21,7 @@ disable = duplicate-code,too-many-arguments,too-many-public-methods,too-few-publ
missing-class-docstring,too-many-locals,too-many-lines,too-many-branches,
too-many-statements
enable=useless-suppression ; Warns about unused pylint ignores
exclude-protected=_unfrozen
[tool:pytest]
testpaths = tests

File diff suppressed because it is too large Load diff

View file

@ -55,6 +55,8 @@ class BotCommand(TelegramObject):
self._id_attrs = (self.command, self.description)
self._freeze()
MIN_COMMAND: ClassVar[int] = constants.BotCommandLimit.MIN_COMMAND
""":const:`telegram.constants.BotCommandLimit.MIN_COMMAND`

View file

@ -80,6 +80,8 @@ class BotCommandScope(TelegramObject):
self.type = type
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BotCommandScope"]:
"""Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
@ -128,6 +130,7 @@ class BotCommandScopeDefault(BotCommandScope):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.DEFAULT, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllPrivateChats(BotCommandScope):
@ -143,6 +146,7 @@ class BotCommandScopeAllPrivateChats(BotCommandScope):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_PRIVATE_CHATS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllGroupChats(BotCommandScope):
@ -157,6 +161,7 @@ class BotCommandScopeAllGroupChats(BotCommandScope):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_GROUP_CHATS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeAllChatAdministrators(BotCommandScope):
@ -171,6 +176,7 @@ class BotCommandScopeAllChatAdministrators(BotCommandScope):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.ALL_CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
self._freeze()
class BotCommandScopeChat(BotCommandScope):
@ -193,10 +199,11 @@ class BotCommandScopeChat(BotCommandScope):
def __init__(self, chat_id: Union[str, int], *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT, api_kwargs=api_kwargs)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
class BotCommandScopeChatAdministrators(BotCommandScope):
@ -219,10 +226,11 @@ class BotCommandScopeChatAdministrators(BotCommandScope):
def __init__(self, chat_id: Union[str, int], *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self._id_attrs = (self.type, self.chat_id)
class BotCommandScopeChatMember(BotCommandScope):
@ -248,8 +256,9 @@ class BotCommandScopeChatMember(BotCommandScope):
def __init__(self, chat_id: Union[str, int], user_id: int, *, api_kwargs: JSONDict = None):
super().__init__(type=BotCommandScope.CHAT_MEMBER, api_kwargs=api_kwargs)
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self.user_id = user_id
self._id_attrs = (self.type, self.chat_id, self.user_id)
with self._unfrozen():
self.chat_id = (
chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
)
self.user_id = user_id
self._id_attrs = (self.type, self.chat_id, self.user_id)

View file

@ -134,6 +134,8 @@ class CallbackQuery(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["CallbackQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -590,7 +592,7 @@ class CallbackQuery(TelegramObject):
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List["GameHighScore"]:
) -> Tuple["GameHighScore", ...]:
"""Shortcut for either::
await update.callback_query.message.get_game_high_score(*args, **kwargs)
@ -606,7 +608,7 @@ class CallbackQuery(TelegramObject):
:meth:`telegram.Message.get_game_high_scores`.
Returns:
List[:class:`telegram.GameHighScore`]
Tuple[:class:`telegram.GameHighScore`]
"""
if self.inline_message_id:

View file

@ -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, Tuple, Union
from typing import TYPE_CHECKING, ClassVar, List, Optional, Sequence, Tuple, Union
from telegram import constants
from telegram._chatlocation import ChatLocation
@ -30,6 +30,7 @@ from telegram._forumtopic import ForumTopic
from telegram._menubutton import MenuButton
from telegram._telegramobject import TelegramObject
from telegram._utils import enum
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
from telegram.helpers import escape_markdown
@ -153,7 +154,7 @@ class Chat(TelegramObject):
(has topics_ enabled).
.. versionadded:: 20.0
active_usernames (List[:obj:`str`], optional): If set, the list of all `active chat
active_usernames (Sequence[:obj:`str`], optional): If set, the list of all `active chat
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
#collectible-usernames>`_; for private chats, supergroups and channels. Returned
only in :meth:`telegram.Bot.get_chat`.
@ -234,10 +235,12 @@ class Chat(TelegramObject):
(has topics_ enabled).
.. versionadded:: 20.0
active_usernames (List[:obj:`str`]): Optional. If set, the list of all `active chat
active_usernames (Tuple[:obj:`str`]): Optional. If set, the list of all `active chat
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
#collectible-usernames>`_; for private chats, supergroups and channels. Returned
only in :meth:`telegram.Bot.get_chat`.
This list is empty if the chat has no active usernames or this chat instance was not
obtained via :meth:`~telegram.Bot.get_chat`.
.. versionadded:: 20.0
emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji
@ -318,7 +321,7 @@ class Chat(TelegramObject):
join_by_request: bool = None,
has_restricted_voice_and_video_messages: bool = None,
is_forum: bool = None,
active_usernames: List[str] = None,
active_usernames: Sequence[str] = None,
emoji_status_custom_emoji_id: str = None,
*,
api_kwargs: JSONDict = None,
@ -352,11 +355,13 @@ class Chat(TelegramObject):
self.join_by_request = join_by_request
self.has_restricted_voice_and_video_messages = has_restricted_voice_and_video_messages
self.is_forum = is_forum
self.active_usernames = active_usernames
self.active_usernames = parse_sequence_arg(active_usernames)
self.emoji_status_custom_emoji_id = emoji_status_custom_emoji_id
self._id_attrs = (self.id,)
self._freeze()
@property
def full_name(self) -> Optional[str]:
"""
@ -546,7 +551,7 @@ class Chat(TelegramObject):
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List["ChatMember"]:
) -> Tuple["ChatMember", ...]:
"""Shortcut for::
await bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs)
@ -555,7 +560,7 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat_administrators`.
Returns:
List[:class:`telegram.ChatMember`]: A list of administrators in a chat. An Array of
Tuple[:class:`telegram.ChatMember`]: A tuple of administrators in a chat. An Array of
:class:`telegram.ChatMember` objects that contains information about all
chat administrators except other bots. If the chat is a group or a supergroup
and no administrators were appointed, only the creator will be returned.
@ -1292,7 +1297,7 @@ class Chat(TelegramObject):
caption: Optional[str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
) -> List["Message"]:
) -> Tuple["Message", ...]:
"""Shortcut for::
await bot.send_media_group(update.effective_chat.id, *args, **kwargs)
@ -1300,7 +1305,8 @@ class Chat(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`.
Returns:
List[:class:`telegram.Message`]: On success, instance representing the message posted.
Tuple[:class:`telegram.Message`]: On success, a tuple of :class:`~telegram.Message`
instances that were sent is returned.
"""
return await self.get_bot().send_media_group(

View file

@ -167,6 +167,8 @@ class ChatAdministratorRights(TelegramObject):
self.can_manage_topics,
)
self._freeze()
@classmethod
def all_rights(cls) -> "ChatAdministratorRights":
"""

View file

@ -141,6 +141,8 @@ class ChatInviteLink(TelegramObject):
self.is_revoked,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatInviteLink"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -88,6 +88,8 @@ class ChatJoinRequest(TelegramObject):
self._id_attrs = (self.chat, self.from_user, self.date)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatJoinRequest"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -62,6 +62,8 @@ class ChatLocation(TelegramObject):
self._id_attrs = (self.location,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatLocation"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -98,6 +98,8 @@ class ChatMember(TelegramObject):
self._id_attrs = (self.user, self.status)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMember"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -159,8 +161,9 @@ class ChatMemberOwner(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.OWNER, user=user, api_kwargs=api_kwargs)
self.is_anonymous = is_anonymous
self.custom_title = custom_title
with self._unfrozen():
self.is_anonymous = is_anonymous
self.custom_title = custom_title
class ChatMemberAdministrator(ChatMember):
@ -295,20 +298,21 @@ class ChatMemberAdministrator(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.ADMINISTRATOR, user=user, api_kwargs=api_kwargs)
self.can_be_edited = can_be_edited
self.is_anonymous = is_anonymous
self.can_manage_chat = can_manage_chat
self.can_delete_messages = can_delete_messages
self.can_manage_video_chats = can_manage_video_chats
self.can_restrict_members = can_restrict_members
self.can_promote_members = can_promote_members
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self.custom_title = custom_title
with self._unfrozen():
self.can_be_edited = can_be_edited
self.is_anonymous = is_anonymous
self.can_manage_chat = can_manage_chat
self.can_delete_messages = can_delete_messages
self.can_manage_video_chats = can_manage_video_chats
self.can_restrict_members = can_restrict_members
self.can_promote_members = can_promote_members
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self.custom_title = custom_title
class ChatMemberMember(ChatMember):
@ -337,6 +341,7 @@ class ChatMemberMember(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.MEMBER, user=user, api_kwargs=api_kwargs)
self._freeze()
class ChatMemberRestricted(ChatMember):
@ -439,17 +444,18 @@ class ChatMemberRestricted(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs)
self.is_member = is_member
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_send_messages = can_send_messages
self.can_send_media_messages = can_send_media_messages
self.can_send_polls = can_send_polls
self.can_send_other_messages = can_send_other_messages
self.can_add_web_page_previews = can_add_web_page_previews
self.can_manage_topics = can_manage_topics
self.until_date = until_date
with self._unfrozen():
self.is_member = is_member
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_send_messages = can_send_messages
self.can_send_media_messages = can_send_media_messages
self.can_send_polls = can_send_polls
self.can_send_other_messages = can_send_other_messages
self.can_add_web_page_previews = can_add_web_page_previews
self.can_manage_topics = can_manage_topics
self.until_date = until_date
class ChatMemberLeft(ChatMember):
@ -477,6 +483,7 @@ class ChatMemberLeft(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.LEFT, user=user, api_kwargs=api_kwargs)
self._freeze()
class ChatMemberBanned(ChatMember):
@ -510,4 +517,5 @@ class ChatMemberBanned(ChatMember):
api_kwargs: JSONDict = None,
):
super().__init__(status=ChatMember.BANNED, user=user, api_kwargs=api_kwargs)
self.until_date = until_date
with self._unfrozen():
self.until_date = until_date

View file

@ -108,6 +108,8 @@ class ChatMemberUpdated(TelegramObject):
self.new_chat_member,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatMemberUpdated"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -142,6 +142,8 @@ class ChatPermissions(TelegramObject):
self.can_manage_topics,
)
self._freeze()
@classmethod
def all_permissions(cls) -> "ChatPermissions":
"""

View file

@ -86,6 +86,8 @@ class ChosenInlineResult(TelegramObject):
self._id_attrs = (self.result_id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChosenInlineResult"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -88,6 +88,8 @@ class Dice(TelegramObject):
self._id_attrs = (self.value, self.emoji)
self._freeze()
DICE: ClassVar[str] = constants.DiceEmoji.DICE # skipcq: PTC-W0052
""":const:`telegram.constants.DiceEmoji.DICE`"""
DARTS: ClassVar[str] = constants.DiceEmoji.DARTS

View file

@ -82,10 +82,11 @@ class Animation(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name

View file

@ -86,10 +86,11 @@ class Audio(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Required
self.duration = duration
# Optional
self.performer = performer
self.title = title
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.duration = duration
# Optional
self.performer = performer
self.title = title
self.mime_type = mime_type
self.file_name = file_name

View file

@ -100,6 +100,8 @@ class ChatPhoto(TelegramObject):
self.big_file_unique_id,
)
self._freeze()
async def get_small_file(
self,
*,

View file

@ -66,3 +66,5 @@ class Contact(TelegramObject):
self.vcard = vcard
self._id_attrs = (self.phone_number,)
self._freeze()

View file

@ -73,6 +73,7 @@ class Document(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Optional
self.mime_type = mime_type
self.file_name = file_name

View file

@ -102,6 +102,8 @@ class File(TelegramObject):
self._id_attrs = (self.file_unique_id,)
self._freeze()
def _get_encoded_url(self) -> str:
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
sres = urllib_parse.urlsplit(str(self.file_path))

View file

@ -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/].
"""Base class for Telegram InputMedia Objects."""
from typing import List, Optional, Tuple, Union
from typing import Optional, Sequence, Union
from telegram._files.animation import Animation
from telegram._files.audio import Audio
@ -27,6 +27,7 @@ from telegram._files.photosize import PhotoSize
from telegram._files.video import Video
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.files import parse_file_input
from telegram._utils.types import FileInput, JSONDict, ODVInput
@ -55,7 +56,11 @@ class InputMedia(TelegramObject):
caption (:obj:`str`, optional): Caption of the media to be sent,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
parsing.
caption_entities (List[:class:`telegram.MessageEntity`], optional): |caption_entities|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
parse_mode (:obj:`str`, optional): |parse_mode|
Attributes:
@ -63,8 +68,13 @@ 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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
__slots__ = ("caption", "caption_entities", "media", "parse_mode", "type")
@ -74,7 +84,7 @@ class InputMedia(TelegramObject):
media_type: str,
media: Union[str, InputFile, MediaType],
caption: str = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
*,
api_kwargs: JSONDict = None,
@ -83,9 +93,11 @@ class InputMedia(TelegramObject):
self.type = media_type
self.media = media
self.caption = caption
self.caption_entities = caption_entities
self.caption_entities = parse_sequence_arg(caption_entities)
self.parse_mode = parse_mode
self._freeze()
@staticmethod
def _parse_thumb_input(thumb: Optional[FileInput]) -> Optional[Union[str, InputFile]]:
# We use local_mode=True because we don't have access to the actual setting and want
@ -124,7 +136,11 @@ class InputMediaAnimation(InputMedia):
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
|sequenceclassargs|
width (:obj:`int`, optional): Animation width.
height (:obj:`int`, optional): Animation height.
duration (:obj:`int`, optional): Animation duration in seconds.
@ -134,8 +150,13 @@ 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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
width (:obj:`int`): Optional. Animation width.
height (:obj:`int`): Optional. Animation height.
@ -154,7 +175,7 @@ class InputMediaAnimation(InputMedia):
width: int = None,
height: int = None,
duration: int = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
@ -177,10 +198,11 @@ class InputMediaAnimation(InputMedia):
parse_mode,
api_kwargs=api_kwargs,
)
self.thumb = self._parse_thumb_input(thumb)
self.width = width
self.height = height
self.duration = duration
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.width = width
self.height = height
self.duration = duration
class InputMediaPhoto(InputMedia):
@ -202,15 +224,22 @@ class InputMediaPhoto(InputMedia):
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
|sequenceclassargs|
Attributes:
type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`.
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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
@ -221,7 +250,7 @@ class InputMediaPhoto(InputMedia):
media: Union[FileInput, PhotoSize],
caption: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
@ -238,6 +267,8 @@ class InputMediaPhoto(InputMedia):
api_kwargs=api_kwargs,
)
self._freeze()
class InputMediaVideo(InputMedia):
"""Represents a video to be sent.
@ -266,7 +297,11 @@ class InputMediaVideo(InputMedia):
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
|sequenceclassargs|
width (:obj:`int`, optional): Video width.
height (:obj:`int`, optional): Video height.
duration (:obj:`int`, optional): Video duration in seconds.
@ -283,8 +318,12 @@ 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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
width (:obj:`int`): Optional. Video width.
height (:obj:`int`): Optional. Video height.
duration (:obj:`int`): Optional. Video duration in seconds.
@ -306,7 +345,7 @@ class InputMediaVideo(InputMedia):
supports_streaming: bool = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb: FileInput = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
@ -330,11 +369,12 @@ class InputMediaVideo(InputMedia):
parse_mode,
api_kwargs=api_kwargs,
)
self.width = width
self.height = height
self.duration = duration
self.thumb = self._parse_thumb_input(thumb)
self.supports_streaming = supports_streaming
with self._unfrozen():
self.width = width
self.height = height
self.duration = duration
self.thumb = self._parse_thumb_input(thumb)
self.supports_streaming = supports_streaming
class InputMediaAudio(InputMedia):
@ -361,7 +401,11 @@ class InputMediaAudio(InputMedia):
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
|sequenceclassargs|
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
tags.
@ -377,8 +421,12 @@ 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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
duration (:obj:`int`): Duration of the audio in seconds.
performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
tags.
@ -398,7 +446,7 @@ class InputMediaAudio(InputMedia):
duration: int = None,
performer: str = None,
title: str = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
@ -421,10 +469,11 @@ class InputMediaAudio(InputMedia):
parse_mode,
api_kwargs=api_kwargs,
)
self.thumb = self._parse_thumb_input(thumb)
self.duration = duration
self.title = title
self.performer = performer
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.duration = duration
self.title = title
self.performer = performer
class InputMediaDocument(InputMedia):
@ -446,7 +495,11 @@ class InputMediaDocument(InputMedia):
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
|sequenceclassargs|
thumb (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
optional): |thumbdocstringnopath|
@ -461,8 +514,12 @@ 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 (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send.
disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side
content type detection for files uploaded using multipart/form-data. Always true, if
@ -479,7 +536,7 @@ class InputMediaDocument(InputMedia):
caption: str = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_content_type_detection: bool = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
caption_entities: Sequence[MessageEntity] = None,
filename: str = None,
*,
api_kwargs: JSONDict = None,
@ -495,5 +552,6 @@ class InputMediaDocument(InputMedia):
parse_mode,
api_kwargs=api_kwargs,
)
self.thumb = self._parse_thumb_input(thumb)
self.disable_content_type_detection = disable_content_type_detection
with self._unfrozen():
self.thumb = self._parse_thumb_input(thumb)
self.disable_content_type_detection = disable_content_type_detection

View file

@ -93,6 +93,8 @@ class Location(TelegramObject):
self._id_attrs = (self.longitude, self.latitude)
self._freeze()
HORIZONTAL_ACCURACY: ClassVar[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
""":const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`

View file

@ -68,6 +68,7 @@ class PhotoSize(_BaseMedium):
file_size=file_size,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
with self._unfrozen():
# Required
self.width = width
self.height = height

View file

@ -17,14 +17,14 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects that represent stickers."""
from typing import TYPE_CHECKING, ClassVar, List, Optional
from typing import TYPE_CHECKING, ClassVar, Optional, Sequence
from telegram import constants
from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._files.file import File
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -150,18 +150,19 @@ class Sticker(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.is_animated = is_animated
self.is_video = is_video
self.type = type
# Optional
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position
self.premium_animation = premium_animation
self.custom_emoji_id = custom_emoji_id
with self._unfrozen():
# Required
self.width = width
self.height = height
self.is_animated = is_animated
self.is_video = is_video
self.type = type
# Optional
self.emoji = emoji
self.set_name = set_name
self.mask_position = mask_position
self.premium_animation = premium_animation
self.custom_emoji_id = custom_emoji_id
REGULAR: ClassVar[str] = constants.StickerType.REGULAR
""":const:`telegram.constants.StickerType.REGULAR`"""
@ -206,7 +207,11 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
stickers (List[:class:`telegram.Sticker`]): List of all set stickers.
stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers.
.. versionchanged:: 20.0
|sequenceclassargs|
sticker_type (:obj:`str`): Type of stickers in the set, currently one of
:attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`,
:attr:`telegram.Sticker.CUSTOM_EMOJI`.
@ -222,7 +227,11 @@ class StickerSet(TelegramObject):
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
.. versionadded:: 13.11
stickers (List[:class:`telegram.Sticker`]): List of all set stickers.
stickers (Tuple[:class:`telegram.Sticker`]): List of all set stickers.
.. versionchanged:: 20.0
|tupleclassattrs|
sticker_type (:obj:`str`): Type of stickers in the set.
.. versionadded:: 20.0
@ -246,7 +255,7 @@ class StickerSet(TelegramObject):
name: str,
title: str,
is_animated: bool,
stickers: List[Sticker],
stickers: Sequence[Sticker],
is_video: bool,
sticker_type: str,
thumb: PhotoSize = None,
@ -258,13 +267,15 @@ class StickerSet(TelegramObject):
self.title = title
self.is_animated = is_animated
self.is_video = is_video
self.stickers = stickers
self.stickers = parse_sequence_arg(stickers)
self.sticker_type = sticker_type
# Optional
self.thumb = thumb
self._id_attrs = (self.name,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["StickerSet"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -339,3 +350,5 @@ class MaskPosition(TelegramObject):
self.scale = scale
self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale)
self._freeze()

View file

@ -97,6 +97,8 @@ class Venue(TelegramObject):
self._id_attrs = (self.location, self.title)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Venue"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -82,10 +82,11 @@ class Video(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name
with self._unfrozen():
# Required
self.width = width
self.height = height
self.duration = duration
# Optional
self.mime_type = mime_type
self.file_name = file_name

View file

@ -73,6 +73,7 @@ class VideoNote(_BaseThumbedMedium):
thumb=thumb,
api_kwargs=api_kwargs,
)
# Required
self.length = length
self.duration = duration
with self._unfrozen():
# Required
self.length = length
self.duration = duration

View file

@ -67,7 +67,8 @@ class Voice(_BaseMedium):
file_size=file_size,
api_kwargs=api_kwargs,
)
# Required
self.duration = duration
# Optional
self.mime_type = mime_type
with self._unfrozen():
# Required
self.duration = duration
# Optional
self.mime_type = mime_type

View file

@ -83,6 +83,8 @@ class ForceReply(TelegramObject):
self._id_attrs = (self.selective,)
self._freeze()
MIN_INPUT_FIELD_PLACEHOLDER: ClassVar[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER
""":const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER`

View file

@ -66,6 +66,8 @@ class ForumTopic(TelegramObject):
self._id_attrs = (self.message_thread_id, self.name, self.icon_color)
self._freeze()
class ForumTopicCreated(TelegramObject):
"""
@ -107,6 +109,8 @@ class ForumTopicCreated(TelegramObject):
self._id_attrs = (self.name, self.icon_color)
self._freeze()
class ForumTopicClosed(TelegramObject):
"""

View file

@ -17,14 +17,14 @@
# 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 Game."""
import sys
from typing import TYPE_CHECKING, Dict, List, Optional
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence
from telegram._files.animation import Animation
from telegram._files.photosize import PhotoSize
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -42,30 +42,46 @@ class Game(TelegramObject):
Args:
title (:obj:`str`): Title of the game.
description (:obj:`str`): Description of the game.
photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message
in chats.
photo (Sequence[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
message in chats.
.. versionchanged:: 20.0
|sequenceclassargs|
text (:obj:`str`, optional): Brief description of the game or high scores included in the
game message. Can be automatically edited to include current high scores for the game
when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
using :meth:`telegram.Bot.edit_message_text`.
0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
text_entities (List[:class:`telegram.MessageEntity`], optional): Special entities that
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
appear in text, such as usernames, URLs, bot commands, etc.
.. versionchanged:: 20.0
|sequenceclassargs|
animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the
game message in chats. Upload via `BotFather <https://t.me/BotFather>`_.
Attributes:
title (:obj:`str`): Title of the game.
description (:obj:`str`): Description of the game.
photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message
in chats.
photo (Tuple[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
message in chats.
.. versionchanged:: 20.0
|tupleclassattrs|
text (:obj:`str`): Optional. Brief description of the game or high scores included in the
game message. Can be automatically edited to include current high scores for the game
when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
using :meth:`telegram.Bot.edit_message_text`.
text_entities (List[:class:`telegram.MessageEntity`]): Special entities that
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.
.. versionchanged:: 20.0
|tupleclassattrs|
animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the
game message in chats. Upload via `BotFather <https://t.me/BotFather>`_.
@ -84,9 +100,9 @@ class Game(TelegramObject):
self,
title: str,
description: str,
photo: List[PhotoSize],
photo: Sequence[PhotoSize],
text: str = None,
text_entities: List[MessageEntity] = None,
text_entities: Sequence[MessageEntity] = None,
animation: Animation = None,
*,
api_kwargs: JSONDict = None,
@ -95,14 +111,16 @@ class Game(TelegramObject):
# Required
self.title = title
self.description = description
self.photo = photo
self.photo = parse_sequence_arg(photo)
# Optionals
self.text = text
self.text_entities = text_entities or []
self.text_entities = parse_sequence_arg(text_entities)
self.animation = animation
self._id_attrs = (self.title, self.description, self.photo)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Game"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -178,6 +196,3 @@ class Game(TelegramObject):
for entity in self.text_entities
if entity.type in types
}
def __hash__(self) -> int:
return hash((self.title, self.description, tuple(p for p in self.photo)))

View file

@ -56,6 +56,8 @@ class GameHighScore(TelegramObject):
self._id_attrs = (self.position, self.user, self.score)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["GameHighScore"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -202,6 +202,8 @@ class InlineKeyboardButton(TelegramObject):
self._id_attrs = ()
self._set_id_attrs()
self._freeze()
def _set_id_attrs(self) -> None:
self._id_attrs = (
self.text,
@ -239,8 +241,9 @@ class InlineKeyboardButton(TelegramObject):
Args:
callback_data (:class:`object`): The new callback data.
"""
self.callback_data = callback_data
self._set_id_attrs()
with self._unfrozen():
self.callback_data = callback_data
self._set_id_attrs()
MIN_CALLBACK_DATA: ClassVar[int] = constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA
""":const:`telegram.constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA`

View file

@ -17,8 +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
from typing import TYPE_CHECKING, List, Optional, Sequence
from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
from telegram._telegramobject import TelegramObject
@ -41,12 +40,20 @@ class InlineKeyboardMarkup(TelegramObject):
* :any:`Inline Keyboard 2 <examples.inlinekeyboard2>`
Args:
inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows,
each represented by a list of InlineKeyboardButton objects.
inline_keyboard (Sequence[Sequence[:class:`telegram.InlineKeyboardButton`]]): Sequence of
button rows, each represented by a sequence of :class:`~telegram.InlineKeyboardButton`
objects.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows,
each represented by a list of InlineKeyboardButton objects.
inline_keyboard (Tuple[Tuple[:class:`telegram.InlineKeyboardButton`]]): Tuple of
button rows, each represented by a tuple of :class:`~telegram.InlineKeyboardButton`
objects.
.. versionchanged:: 20.0
|tupleclassattrs|
"""
@ -54,21 +61,23 @@ class InlineKeyboardMarkup(TelegramObject):
def __init__(
self,
inline_keyboard: List[List[InlineKeyboardButton]],
inline_keyboard: Sequence[Sequence[InlineKeyboardButton]],
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
if not check_keyboard_type(inline_keyboard):
raise ValueError(
"The parameter `inline_keyboard` should be a list of "
"list of InlineKeyboardButtons"
"The parameter `inline_keyboard` should be a sequence of sequences of "
"InlineKeyboardButtons"
)
# Required
self.inline_keyboard = inline_keyboard
self.inline_keyboard = tuple(tuple(row) for row in inline_keyboard)
self._id_attrs = (self.inline_keyboard,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineKeyboardMarkup"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -134,6 +143,3 @@ class InlineKeyboardMarkup(TelegramObject):
"""
button_grid = [[button] for button in button_column]
return cls(button_grid, **kwargs) # type: ignore[arg-type]
def __hash__(self) -> int:
return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard))

View file

@ -106,6 +106,8 @@ class InlineQuery(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -64,6 +64,8 @@ class InlineQueryResult(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
MIN_ID_LENGTH: ClassVar[int] = constants.InlineQueryResultLimit.MIN_ID_LENGTH
""":const:`telegram.constants.InlineQueryResultLimit.MIN_ID_LENGTH`

View file

@ -102,14 +102,15 @@ class InlineQueryResultArticle(InlineQueryResult):
# Required
super().__init__(InlineQueryResultType.ARTICLE, id, api_kwargs=api_kwargs)
self.title = title
self.input_message_content = input_message_content
with self._unfrozen():
self.title = title
self.input_message_content = input_message_content
# Optional
self.reply_markup = reply_markup
self.url = url
self.hide_url = hide_url
self.description = description
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
# Optional
self.reply_markup = reply_markup
self.url = url
self.hide_url = hide_url
self.description = description
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultAudio."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -49,7 +49,10 @@ class InlineQueryResultAudio(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -68,7 +71,12 @@ class InlineQueryResultAudio(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -99,21 +107,22 @@ class InlineQueryResultAudio(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs)
self.audio_url = audio_url
self.title = title
with self._unfrozen():
self.audio_url = audio_url
self.title = title
# Optionals
self.performer = performer
self.audio_duration = audio_duration
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.performer = performer
self.audio_duration = audio_duration
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultCachedAudio."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -46,7 +46,11 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -61,8 +65,13 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
caption (:obj:`str`): Optional. Caption,
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
parsing.
parse_mode (:obj:`str`, optionals): |parse_mode|
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
parse_mode (:obj:`str`): Optional. |parse_mode|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -87,17 +96,18 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs)
self.audio_file_id = audio_file_id
with self._unfrozen():
self.audio_file_id = audio_file_id
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultCachedDocument."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -48,7 +48,11 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -66,7 +70,12 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -95,19 +104,20 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs)
self.title = title
self.document_file_id = document_file_id
with self._unfrozen():
self.title = title
self.document_file_id = document_file_id
# Optionals
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultCachedGif."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -48,7 +48,11 @@ class InlineQueryResultCachedGif(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -65,7 +69,12 @@ class InlineQueryResultCachedGif(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -92,18 +101,19 @@ class InlineQueryResultCachedGif(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs)
self.gif_file_id = gif_file_id
with self._unfrozen():
self.gif_file_id = gif_file_id
# Optionals
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultMpeg4Gif."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -48,7 +48,11 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -65,7 +69,12 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -92,18 +101,19 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs)
self.mpeg4_file_id = mpeg4_file_id
with self._unfrozen():
self.mpeg4_file_id = mpeg4_file_id
# Optionals
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultPhoto"""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -49,7 +49,11 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -67,7 +71,12 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -96,19 +105,20 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs)
self.photo_file_id = photo_file_id
with self._unfrozen():
self.photo_file_id = photo_file_id
# Optionals
self.title = title
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.title = title
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -71,8 +71,9 @@ class InlineQueryResultCachedSticker(InlineQueryResult):
):
# Required
super().__init__(InlineQueryResultType.STICKER, id, api_kwargs=api_kwargs)
self.sticker_file_id = sticker_file_id
with self._unfrozen():
self.sticker_file_id = sticker_file_id
# Optionals
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultCachedVideo."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -49,7 +49,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 (List[:class:`telegram.MessageEntity`], optional): |caption_entities|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -67,7 +67,12 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -96,19 +101,20 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs)
self.video_file_id = video_file_id
self.title = title
with self._unfrozen():
self.video_file_id = video_file_id
self.title = title
# Optionals
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultCachedVoice."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -47,7 +47,10 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -64,7 +67,12 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -91,18 +99,19 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs)
self.voice_file_id = voice_file_id
self.title = title
with self._unfrozen():
self.voice_file_id = voice_file_id
self.title = title
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -101,14 +101,15 @@ class InlineQueryResultContact(InlineQueryResult):
):
# Required
super().__init__(InlineQueryResultType.CONTACT, id, api_kwargs=api_kwargs)
self.phone_number = phone_number
self.first_name = first_name
with self._unfrozen():
self.phone_number = phone_number
self.first_name = first_name
# Optionals
self.last_name = last_name
self.vcard = vcard
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
# Optionals
self.last_name = last_name
self.vcard = vcard
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultDocument"""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -47,7 +47,11 @@ class InlineQueryResultDocument(InlineQueryResult):
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
|sequenceclassargs|
document_url (:obj:`str`): A valid URL for the file.
mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf"
or "application/zip".
@ -70,7 +74,12 @@ class InlineQueryResultDocument(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
document_url (:obj:`str`): A valid URL for the file.
mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf"
or "application/zip".
@ -114,23 +123,24 @@ class InlineQueryResultDocument(InlineQueryResult):
thumb_width: int = None,
thumb_height: int = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs)
self.document_url = document_url
self.title = title
self.mime_type = mime_type
with self._unfrozen():
self.document_url = document_url
self.title = title
self.mime_type = mime_type
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.description = description
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
# Optionals
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.description = description
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height

View file

@ -58,7 +58,8 @@ class InlineQueryResultGame(InlineQueryResult):
):
# Required
super().__init__(InlineQueryResultType.GAME, id, api_kwargs=api_kwargs)
self.id = id
self.game_short_name = game_short_name
with self._unfrozen():
self.id = id
self.game_short_name = game_short_name
self.reply_markup = reply_markup
self.reply_markup = reply_markup

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultGif."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -54,7 +54,11 @@ class InlineQueryResultGif(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -77,7 +81,12 @@ class InlineQueryResultGif(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -114,24 +123,25 @@ class InlineQueryResultGif(InlineQueryResult):
gif_duration: int = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb_mime_type: str = None,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs)
self.gif_url = gif_url
self.thumb_url = thumb_url
with self._unfrozen():
self.gif_url = gif_url
self.thumb_url = thumb_url
# Optionals
self.gif_width = gif_width
self.gif_height = gif_height
self.gif_duration = gif_duration
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_mime_type = thumb_mime_type
# Optionals
self.gif_width = gif_width
self.gif_height = gif_height
self.gif_duration = gif_duration
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_mime_type = thumb_mime_type

View file

@ -127,22 +127,23 @@ class InlineQueryResultLocation(InlineQueryResult):
):
# Required
super().__init__(constants.InlineQueryResultType.LOCATION, id, api_kwargs=api_kwargs)
self.latitude = latitude
self.longitude = longitude
self.title = title
with self._unfrozen():
self.latitude = latitude
self.longitude = longitude
self.title = title
# Optionals
self.live_period = live_period
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
self.horizontal_accuracy = horizontal_accuracy
self.heading = heading
self.proximity_alert_radius = (
int(proximity_alert_radius) if proximity_alert_radius else None
)
# Optionals
self.live_period = live_period
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
self.horizontal_accuracy = horizontal_accuracy
self.heading = heading
self.proximity_alert_radius = (
int(proximity_alert_radius) if proximity_alert_radius else None
)
HORIZONTAL_ACCURACY: ClassVar[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
""":const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultMpeg4Gif."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -54,7 +54,11 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -77,7 +81,13 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -114,24 +124,25 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
mpeg4_duration: int = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
thumb_mime_type: str = None,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs)
self.mpeg4_url = mpeg4_url
self.thumb_url = thumb_url
with self._unfrozen():
self.mpeg4_url = mpeg4_url
self.thumb_url = thumb_url
# Optional
self.mpeg4_width = mpeg4_width
self.mpeg4_height = mpeg4_height
self.mpeg4_duration = mpeg4_duration
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_mime_type = thumb_mime_type
# Optional
self.mpeg4_width = mpeg4_width
self.mpeg4_height = mpeg4_height
self.mpeg4_duration = mpeg4_duration
self.title = title
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_mime_type = thumb_mime_type

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultPhoto."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -52,7 +52,11 @@ class InlineQueryResultPhoto(InlineQueryResult):
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
|sequenceclassargs|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
@ -74,7 +78,12 @@ class InlineQueryResultPhoto(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
@ -109,22 +118,23 @@ class InlineQueryResultPhoto(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs)
self.photo_url = photo_url
self.thumb_url = thumb_url
with self._unfrozen():
self.photo_url = photo_url
self.thumb_url = thumb_url
# Optionals
self.photo_width = photo_width
self.photo_height = photo_height
self.title = title
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optionals
self.photo_width = photo_width
self.photo_height = photo_height
self.title = title
self.description = description
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -124,18 +124,19 @@ class InlineQueryResultVenue(InlineQueryResult):
# Required
super().__init__(InlineQueryResultType.VENUE, id, api_kwargs=api_kwargs)
self.latitude = latitude
self.longitude = longitude
self.title = title
self.address = address
with self._unfrozen():
self.latitude = latitude
self.longitude = longitude
self.title = title
self.address = address
# Optional
self.foursquare_id = foursquare_id
self.foursquare_type = foursquare_type
self.google_place_id = google_place_id
self.google_place_type = google_place_type
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height
# Optional
self.foursquare_id = foursquare_id
self.foursquare_type = foursquare_type
self.google_place_id = google_place_id
self.google_place_type = google_place_type
self.reply_markup = reply_markup
self.input_message_content = input_message_content
self.thumb_url = thumb_url
self.thumb_width = thumb_width
self.thumb_height = thumb_height

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultVideo."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -54,7 +54,11 @@ class InlineQueryResultVideo(InlineQueryResult):
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
|sequenceclassargs|
video_width (:obj:`int`, optional): Video width.
video_height (:obj:`int`, optional): Video height.
video_duration (:obj:`int`, optional): Video duration in seconds.
@ -75,18 +79,24 @@ class InlineQueryResultVideo(InlineQueryResult):
mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
thumb_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video.
title (:obj:`str`): Title for the result.
caption (:obj:`str`, optional): Caption of the video to be sent,
caption (:obj:`str`): Optional. Caption of the video to be sent,
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|
video_width (:obj:`int`, optional): Video width.
video_height (:obj:`int`, optional): Video height.
video_duration (:obj:`int`, optional): Video duration in seconds.
description (:obj:`str`, optional): Short description of the result.
parse_mode (:obj:`str`): Optional. |parse_mode|
caption_entities (Sequence[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
video_width (:obj:`int`): Optional. Video width.
video_height (:obj:`int`): Optional. Video height.
video_duration (:obj:`int`): Optional. Video duration in seconds.
description (:obj:`str`): Optional. Short description of the result.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
message to be sent instead of the video. This field is required if
InlineQueryResultVideo is used to send an HTML-page as a result
(e.g., a YouTube video).
@ -124,25 +134,26 @@ class InlineQueryResultVideo(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs)
self.video_url = video_url
self.mime_type = mime_type
self.thumb_url = thumb_url
self.title = title
with self._unfrozen():
self.video_url = video_url
self.mime_type = mime_type
self.thumb_url = thumb_url
self.title = title
# Optional
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.video_width = video_width
self.video_height = video_height
self.video_duration = video_duration
self.description = description
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optional
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.video_width = video_width
self.video_height = video_height
self.video_duration = video_duration
self.description = description
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -17,12 +17,12 @@
# 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 classes that represent Telegram InlineQueryResultVoice."""
from typing import TYPE_CHECKING, List, Tuple, Union
from typing import TYPE_CHECKING, Sequence
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
from telegram.constants import InlineQueryResultType
@ -48,7 +48,11 @@ class InlineQueryResultVoice(InlineQueryResult):
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
|sequenceclassargs|
voice_duration (:obj:`int`, optional): Recording duration in seconds.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message.
@ -66,7 +70,12 @@ class InlineQueryResultVoice(InlineQueryResult):
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 (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
voice_duration (:obj:`int`): Optional. Recording duration in seconds.
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
@ -96,20 +105,21 @@ class InlineQueryResultVoice(InlineQueryResult):
reply_markup: InlineKeyboardMarkup = None,
input_message_content: "InputMessageContent" = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
caption_entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
# Required
super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs)
self.voice_url = voice_url
self.title = title
with self._unfrozen():
self.voice_url = voice_url
self.title = title
# Optional
self.voice_duration = voice_duration
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.reply_markup = reply_markup
self.input_message_content = input_message_content
# Optional
self.voice_duration = voice_duration
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = parse_sequence_arg(caption_entities)
self.reply_markup = reply_markup
self.input_message_content = input_message_content

View file

@ -65,3 +65,5 @@ class InputContactMessageContent(InputMessageContent):
self.vcard = vcard
self._id_attrs = (self.phone_number,)
self._freeze()

View file

@ -17,11 +17,11 @@
# 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 a class that represents a Telegram InputInvoiceMessageContent."""
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence
from telegram._inline.inputmessagecontent import InputMessageContent
from telegram._payment.labeledprice import LabeledPrice
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -52,20 +52,30 @@ class InputInvoiceMessageContent(InputMessageContent):
`@Botfather <https://t.me/Botfather>`_.
currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_
prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus,
etc.)
.. versionchanged:: 20.0
|sequenceclassargs|
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 <https://core.telegram.org/bots/payments/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
suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested
amounts of tip in the *smallest* units of the currency (integer, **not** float/double).
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be
positive, passed in a strictly increased order and must not exceed
:attr:`max_tip_amount`.
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
provider_data (:obj:`str`, optional): An object for data about the invoice,
which will be shared with the payment provider. A detailed description of the required
fields should be provided by the payment provider.
@ -104,12 +114,20 @@ class InputInvoiceMessageContent(InputMessageContent):
`@Botfather <https://t.me/Botfather>`_.
currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
`currencies <https://core.telegram.org/bots/payments#supported-currencies>`_
prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
prices (Tuple[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
components.
.. versionchanged:: 20.0
|tupleclassattrs|
max_tip_amount (:obj:`int`): Optional. The maximum accepted amount for tips in the smallest
units of the currency (integer, not float/double).
suggested_tip_amounts (List[:obj:`int`]): Optional. An array of suggested
suggested_tip_amounts (Tuple[:obj:`int`]): Optional. An array of suggested
amounts of tip in the smallest units of the currency (integer, not float/double).
.. versionchanged:: 20.0
|tupleclassattrs|
provider_data (:obj:`str`): Optional. An object for data about the invoice,
which will be shared with the payment provider.
photo_url (:obj:`str`): Optional. URL of the product photo for the invoice.
@ -163,9 +181,9 @@ class InputInvoiceMessageContent(InputMessageContent):
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: str = None,
photo_url: str = None,
photo_size: int = None,
@ -188,10 +206,10 @@ class InputInvoiceMessageContent(InputMessageContent):
self.payload = payload
self.provider_token = provider_token
self.currency = currency
self.prices = prices
self.prices = parse_sequence_arg(prices)
# Optionals
self.max_tip_amount = max_tip_amount
self.suggested_tip_amounts = suggested_tip_amounts
self.suggested_tip_amounts = parse_sequence_arg(suggested_tip_amounts)
self.provider_data = provider_data
self.photo_url = photo_url
self.photo_size = photo_size
@ -214,19 +232,7 @@ class InputInvoiceMessageContent(InputMessageContent):
self.prices,
)
def __hash__(self) -> int:
# we override this as self.prices is a list and not hashable
prices = tuple(self.prices)
return hash(
(
self.title,
self.description,
self.payload,
self.provider_token,
self.currency,
prices,
)
)
self._freeze()
@classmethod
def de_json(

View file

@ -97,6 +97,8 @@ class InputLocationMessageContent(InputMessageContent):
self._id_attrs = (self.latitude, self.longitude)
self._freeze()
HORIZONTAL_ACCURACY: ClassVar[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
""":const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`

View file

@ -17,11 +17,11 @@
# 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 classes that represent Telegram InputTextMessageContent."""
from typing import List, Tuple, Union
from typing import Sequence
from telegram._inline.inputmessagecontent import InputMessageContent
from telegram._messageentity import MessageEntity
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
@ -42,7 +42,11 @@ class InputTextMessageContent(InputMessageContent):
: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): |caption_entities|
entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
.. versionchanged:: 20.0
|sequenceclassargs|
disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the
sent message.
@ -51,7 +55,12 @@ class InputTextMessageContent(InputMessageContent):
1-: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. |caption_entities|
entities (Tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in the
sent message.
@ -64,7 +73,7 @@ class InputTextMessageContent(InputMessageContent):
message_text: str,
parse_mode: ODVInput[str] = DEFAULT_NONE,
disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE,
entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None,
entities: Sequence[MessageEntity] = None,
*,
api_kwargs: JSONDict = None,
):
@ -73,7 +82,9 @@ class InputTextMessageContent(InputMessageContent):
self.message_text = message_text
# Optionals
self.parse_mode = parse_mode
self.entities = entities
self.entities = parse_sequence_arg(entities)
self.disable_web_page_preview = disable_web_page_preview
self._id_attrs = (self.message_text,)
self._freeze()

View file

@ -101,3 +101,5 @@ class InputVenueMessageContent(InputMessageContent):
self.longitude,
self.title,
)
self._freeze()

View file

@ -107,6 +107,8 @@ class KeyboardButton(TelegramObject):
self.web_app,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["KeyboardButton"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -48,3 +48,5 @@ class KeyboardButtonPollType(TelegramObject):
self.type = type
self._id_attrs = (self.type,)
self._freeze()

View file

@ -88,3 +88,5 @@ class LoginUrl(TelegramObject):
self.request_write_access = request_write_access
self._id_attrs = (self.url,)
self._freeze()

View file

@ -62,6 +62,8 @@ class MenuButton(TelegramObject):
self._id_attrs = (self.type,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MenuButton"]:
"""Converts JSON data to the appropriate :class:`MenuButton` object, i.e. takes
@ -114,6 +116,7 @@ class MenuButtonCommands(MenuButton):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=constants.MenuButtonType.COMMANDS, api_kwargs=api_kwargs)
self._freeze()
class MenuButtonWebApp(MenuButton):
@ -144,10 +147,11 @@ class MenuButtonWebApp(MenuButton):
def __init__(self, text: str, web_app: WebAppInfo, *, api_kwargs: JSONDict = None):
super().__init__(type=constants.MenuButtonType.WEB_APP, api_kwargs=api_kwargs)
self.text = text
self.web_app = web_app
with self._unfrozen():
self.text = text
self.web_app = web_app
self._id_attrs = (self.type, self.text, self.web_app)
self._id_attrs = (self.type, self.text, self.web_app)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MenuButtonWebApp"]:
@ -174,3 +178,4 @@ class MenuButtonDefault(MenuButton):
def __init__(self, *, api_kwargs: JSONDict = None):
super().__init__(type=constants.MenuButtonType.DEFAULT, api_kwargs=api_kwargs)
self._freeze()

View file

@ -21,7 +21,7 @@
import datetime
import sys
from html import escape
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, Union
from telegram._chat import Chat
from telegram._dice import Dice
@ -48,6 +48,7 @@ from telegram._poll import Poll
from telegram._proximityalerttriggered import ProximityAlertTriggered
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import from_timestamp
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
@ -140,15 +141,23 @@ class Message(TelegramObject):
message belongs to.
text (:obj:`str`, optional): For text messages, the actual UTF-8 text of the message,
0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special
entities (Sequence[:class:`telegram.MessageEntity`], optional): For text messages, special
entities like usernames, URLs, bot commands, etc. that appear in the text. See
:attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly.
This list is empty if the message does not contain entities.
caption_entities (List[:class:`telegram.MessageEntity`], optional): For messages with a
.. versionchanged:: 20.0
|sequenceclassargs|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): For messages with a
Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
methods for how to use properly. This list is empty if the message does not contain
caption entities.
.. versionchanged:: 20.0
|sequenceclassargs|
audio (:class:`telegram.Audio`, optional): Message is an audio file, information
about the file.
document (:class:`telegram.Document`, optional): Message is a general file, information
@ -157,8 +166,12 @@ class Message(TelegramObject):
about the animation. For backward compatibility, when this field is set, the document
field will also be set.
game (:class:`telegram.Game`, optional): Message is a game, information about the game.
photo (List[:class:`telegram.PhotoSize`], optional): Message is a photo, available sizes
of the photo. This list is empty if the message does not contain a photo.
photo (Sequence[:class:`telegram.PhotoSize`], optional): Message is a photo, available
sizes of the photo. This list is empty if the message does not contain a photo.
.. versionchanged:: 20.0
|sequenceclassargs|
sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information
about the sticker.
video (:class:`telegram.Video`, optional): Message is a video, information about the
@ -167,9 +180,13 @@ class Message(TelegramObject):
the file.
video_note (:class:`telegram.VideoNote`, optional): Message is a video note, information
about the video message.
new_chat_members (List[:class:`telegram.User`], optional): New members that were added to
the group or supergroup and information about them (the bot itself may be one of these
members). This list is empty if the message does not contain new chat members.
new_chat_members (Sequence[:class:`telegram.User`], optional): New members that were added
to the group or supergroup and information about them (the bot itself may be one of
these members). This list is empty if the message does not contain new chat members.
.. versionchanged:: 20.0
|sequenceclassargs|
caption (:obj:`str`, optional): Caption for the animation, audio, document, photo, video
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
contact (:class:`telegram.Contact`, optional): Message is a shared contact, information
@ -182,8 +199,12 @@ class Message(TelegramObject):
left_chat_member (:class:`telegram.User`, optional): A member was removed from the group,
information about them (this member may be the bot itself).
new_chat_title (:obj:`str`, optional): A chat title was changed to this value.
new_chat_photo (List[:class:`telegram.PhotoSize`], optional): A chat photo was changed to
this value. This list is empty if the message does not contain a new chat photo.
new_chat_photo (Sequence[:class:`telegram.PhotoSize`], optional): A chat photo was changed
to this value. This list is empty if the message does not contain a new chat photo.
.. versionchanged:: 20.0
|sequenceclassargs|
delete_chat_photo (:obj:`bool`, optional): Service message: The chat photo was deleted.
group_chat_created (:obj:`bool`, optional): Service message: The group has been created.
supergroup_chat_created (:obj:`bool`, optional): Service message: The supergroup has been
@ -309,15 +330,23 @@ class Message(TelegramObject):
message belongs to.
text (:obj:`str`): Optional. For text messages, the actual UTF-8 text of the message,
0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
entities (List[:class:`telegram.MessageEntity`]): Optional. For text messages, special
entities (Tuple[:class:`telegram.MessageEntity`]): Optional. For text messages, special
entities like usernames, URLs, bot commands, etc. that appear in the text. See
:attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly.
This list is empty if the message does not contain entities.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. For messages with a
.. versionchanged:: 20.0
|tupleclassattrs|
caption_entities (Tuple[:class:`telegram.MessageEntity`]): Optional. For messages with a
Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
methods for how to use properly. This list is empty if the message does not contain
caption entities.
.. versionchanged:: 20.0
|tupleclassattrs|
audio (:class:`telegram.Audio`): Optional. Message is an audio file, information
about the file.
document (:class:`telegram.Document`): Optional. Message is a general file, information
@ -326,8 +355,12 @@ class Message(TelegramObject):
about the animation. For backward compatibility, when this field is set, the document
field will also be set.
game (:class:`telegram.Game`): Optional. Message is a game, information about the game.
photo (List[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available sizes
of the photo. This list is empty if the message does not contain a photo.
photo (Tuple[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available
sizes of the photo. This list is empty if the message does not contain a photo.
.. versionchanged:: 20.0
|tupleclassattrs|
sticker (:class:`telegram.Sticker`): Optional. Message is a sticker, information
about the sticker.
video (:class:`telegram.Video`): Optional. Message is a video, information about the
@ -336,9 +369,13 @@ class Message(TelegramObject):
the file.
video_note (:class:`telegram.VideoNote`): Optional. Message is a video note, information
about the video message.
new_chat_members (List[:class:`telegram.User`]): Optional. New members that were added to
the group or supergroup and information about them (the bot itself may be one of these
members). This list is empty if the message does not contain new chat members.
new_chat_members (Tuple[:class:`telegram.User`]): Optional. New members that were added
to the group or supergroup and information about them (the bot itself may be one of
these members). This list is empty if the message does not contain new chat members.
.. versionchanged:: 20.0
|tupleclassattrs|
caption (:obj:`str`): Optional. Caption for the animation, audio, document, photo, video
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information
@ -351,8 +388,12 @@ class Message(TelegramObject):
left_chat_member (:class:`telegram.User`): Optional. A member was removed from the group,
information about them (this member may be the bot itself).
new_chat_title (:obj:`str`): Optional. A chat title was changed to this value.
new_chat_photo (List[:class:`telegram.PhotoSize`]): A chat photo was changed to
new_chat_photo (Tuple[:class:`telegram.PhotoSize`]): A chat photo was changed to
this value. This list is empty if the message does not contain a new chat photo.
.. versionchanged:: 20.0
|tupleclassattrs|
delete_chat_photo (:obj:`bool`): Optional. Service message: The chat photo was deleted.
group_chat_created (:obj:`bool`): Optional. Service message: The group has been created.
supergroup_chat_created (:obj:`bool`): Optional. Service message: The supergroup has been
@ -528,24 +569,24 @@ class Message(TelegramObject):
reply_to_message: "Message" = None,
edit_date: datetime.datetime = None,
text: str = None,
entities: List["MessageEntity"] = None,
caption_entities: List["MessageEntity"] = None,
entities: Sequence["MessageEntity"] = None,
caption_entities: Sequence["MessageEntity"] = None,
audio: Audio = None,
document: Document = None,
game: Game = None,
photo: List[PhotoSize] = None,
photo: Sequence[PhotoSize] = None,
sticker: Sticker = None,
video: Video = None,
voice: Voice = None,
video_note: VideoNote = None,
new_chat_members: List[User] = None,
new_chat_members: Sequence[User] = None,
caption: str = None,
contact: Contact = None,
location: Location = None,
venue: Venue = None,
left_chat_member: User = None,
new_chat_title: str = None,
new_chat_photo: List[PhotoSize] = None,
new_chat_photo: Sequence[PhotoSize] = None,
delete_chat_photo: bool = None,
group_chat_created: bool = None,
supergroup_chat_created: bool = None,
@ -601,12 +642,12 @@ class Message(TelegramObject):
self.edit_date = edit_date
self.has_protected_content = has_protected_content
self.text = text
self.entities = entities or []
self.caption_entities = caption_entities or []
self.entities = parse_sequence_arg(entities)
self.caption_entities = parse_sequence_arg(caption_entities)
self.audio = audio
self.game = game
self.document = document
self.photo = photo or []
self.photo = parse_sequence_arg(photo)
self.sticker = sticker
self.video = video
self.voice = voice
@ -615,10 +656,10 @@ class Message(TelegramObject):
self.contact = contact
self.location = location
self.venue = venue
self.new_chat_members = new_chat_members or []
self.new_chat_members = parse_sequence_arg(new_chat_members)
self.left_chat_member = left_chat_member
self.new_chat_title = new_chat_title
self.new_chat_photo = new_chat_photo or []
self.new_chat_photo = parse_sequence_arg(new_chat_photo)
self.delete_chat_photo = bool(delete_chat_photo)
self.group_chat_created = bool(group_chat_created)
self.supergroup_chat_created = bool(supergroup_chat_created)
@ -657,6 +698,8 @@ class Message(TelegramObject):
self._id_attrs = (self.message_id, self.chat)
self._freeze()
@property
def chat_id(self) -> int:
""":obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`."""
@ -1095,7 +1138,7 @@ class Message(TelegramObject):
caption: Optional[str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
) -> List["Message"]:
) -> Tuple["Message", ...]:
"""Shortcut for::
await bot.send_media_group(update.effective_message.chat_id, *args, **kwargs)
@ -1109,7 +1152,7 @@ class Message(TelegramObject):
chats.
Returns:
List[:class:`telegram.Message`]: An array of the sent Messages.
Tuple[:class:`telegram.Message`]: An array of the sent Messages.
Raises:
:class:`telegram.error.TelegramError`
@ -2596,7 +2639,7 @@ class Message(TelegramObject):
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List["GameHighScore"]:
) -> Tuple["GameHighScore", ...]:
"""Shortcut for::
await bot.get_game_high_scores(
@ -2612,7 +2655,7 @@ class Message(TelegramObject):
behaviour is undocumented and might be changed by Telegram.
Returns:
List[:class:`telegram.GameHighScore`]
Tuple[:class:`telegram.GameHighScore`]
"""
return await self.get_bot().get_game_high_scores(
chat_id=self.chat_id,

View file

@ -54,3 +54,5 @@ class MessageAutoDeleteTimerChanged(TelegramObject):
self.message_auto_delete_time = message_auto_delete_time
self._id_attrs = (self.message_auto_delete_time,)
self._freeze()

View file

@ -115,6 +115,8 @@ class MessageEntity(TelegramObject):
self._id_attrs = (self.type, self.offset, self.length)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MessageEntity"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -42,3 +42,5 @@ class MessageId(TelegramObject):
self.message_id = message_id
self._id_attrs = (self.message_id,)
self._freeze()

View file

@ -19,7 +19,7 @@
# pylint: disable=missing-module-docstring, redefined-builtin
import json
from base64 import b64decode
from typing import TYPE_CHECKING, List, Optional, no_type_check
from typing import TYPE_CHECKING, Optional, Sequence, no_type_check
try:
from cryptography.hazmat.backends import default_backend
@ -38,6 +38,7 @@ except ImportError:
CRYPTO_INSTALLED = False
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
from telegram.error import PassportDecryptionError
@ -155,6 +156,8 @@ class EncryptedCredentials(TelegramObject):
self._decrypted_secret: Optional[str] = None
self._decrypted_data: Optional["Credentials"] = None
self._freeze()
@property
def decrypted_secret(self) -> str:
"""
@ -226,6 +229,8 @@ class Credentials(TelegramObject):
self.secure_data = secure_data
self.nonce = nonce
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Credentials"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -312,6 +317,8 @@ class SecureData(TelegramObject):
self.passport = passport
self.personal_details = personal_details
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SecureData"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -356,14 +363,23 @@ class SecureValue(TelegramObject):
selfie (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted selfie
of the user with a document. Can be available for "passport", "driver_license",
"identity_card" and "internal_passport".
translation (List[:class:`telegram.FileCredentials`]): Optional. Credentials for an
translation (Tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for an
encrypted translation of the document. Available for "passport", "driver_license",
"identity_card", "internal_passport", "utility_bill", "bank_statement",
"rental_agreement", "passport_registration" and "temporary_registration".
files (List[:class:`telegram.FileCredentials`]): Optional. Credentials for encrypted
.. versionchanged:: 20.0
|tupleclassattrs|
files (Tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for encrypted
files. Available for "utility_bill", "bank_statement", "rental_agreement",
"passport_registration" and "temporary_registration" types.
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
__slots__ = ("data", "front_side", "reverse_side", "selfie", "files", "translation")
@ -374,8 +390,8 @@ class SecureValue(TelegramObject):
front_side: "FileCredentials" = None,
reverse_side: "FileCredentials" = None,
selfie: "FileCredentials" = None,
files: List["FileCredentials"] = None,
translation: List["FileCredentials"] = None,
files: Sequence["FileCredentials"] = None,
translation: Sequence["FileCredentials"] = None,
*,
api_kwargs: JSONDict = None,
):
@ -384,8 +400,10 @@ class SecureValue(TelegramObject):
self.front_side = front_side
self.reverse_side = reverse_side
self.selfie = selfie
self.files = files
self.translation = translation
self.files = parse_sequence_arg(files)
self.translation = parse_sequence_arg(translation)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SecureValue"]:
@ -414,12 +432,13 @@ class _CredentialsBase(TelegramObject):
self, hash: str, secret: str, *, api_kwargs: JSONDict = None # skipcq: PYL-W0622
):
super().__init__(api_kwargs=api_kwargs)
self.hash = hash
self.secret = secret
with self._unfrozen():
self.hash = hash
self.secret = secret
# Aliases just to be sure
self.file_hash = self.hash
self.data_hash = self.hash
# Aliases just to be sure
self.file_hash = self.hash
self.data_hash = self.hash
class DataCredentials(_CredentialsBase):
@ -440,6 +459,7 @@ class DataCredentials(_CredentialsBase):
def __init__(self, data_hash: str, secret: str, *, api_kwargs: JSONDict = None):
super().__init__(hash=data_hash, secret=secret, api_kwargs=api_kwargs)
self._freeze()
class FileCredentials(_CredentialsBase):
@ -460,3 +480,4 @@ class FileCredentials(_CredentialsBase):
def __init__(self, file_hash: str, secret: str, *, api_kwargs: JSONDict = None):
super().__init__(hash=file_hash, secret=secret, api_kwargs=api_kwargs)
self._freeze()

View file

@ -84,6 +84,8 @@ class PersonalDetails(TelegramObject):
self.last_name_native = last_name_native
self.middle_name_native = middle_name_native
self._freeze()
class ResidentialAddress(TelegramObject):
"""
@ -127,6 +129,8 @@ class ResidentialAddress(TelegramObject):
self.country_code = country_code
self.post_code = post_code
self._freeze()
class IdDocumentData(TelegramObject):
"""
@ -149,3 +153,5 @@ class IdDocumentData(TelegramObject):
super().__init__(api_kwargs=api_kwargs)
self.document_no = document_no
self.expiry_date = expiry_date
self._freeze()

View file

@ -18,12 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram EncryptedPassportElement."""
from base64 import b64decode
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence
from telegram._passport.credentials import decrypt_json
from telegram._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
from telegram._passport.passportfile import PassportFile
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -58,9 +59,14 @@ class EncryptedPassportElement(TelegramObject):
"phone_number" type.
email (:obj:`str`, optional): User's verified email address, available only for "email"
type.
files (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted files
files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted
files
with documents provided by the user, available for "utility_bill", "bank_statement",
"rental_agreement", "passport_registration" and "temporary_registration" types.
.. versionchanged:: 20.0
|sequenceclassargs|
front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
front side of the document, provided by the user. Available for "passport",
"driver_license", "identity_card" and "internal_passport".
@ -70,12 +76,16 @@ class EncryptedPassportElement(TelegramObject):
selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
selfie of the user holding a document, provided by the user; available for "passport",
"driver_license", "identity_card" and "internal_passport".
translation (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted
translation (Sequence[:class:`telegram.PassportFile`], optional): Array of
encrypted/decrypted
files with translated versions of documents provided by the user. Available if
requested for "passport", "driver_license", "identity_card", "internal_passport",
"utility_bill", "bank_statement", "rental_agreement", "passport_registration" and
"temporary_registration" types.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
@ -91,9 +101,16 @@ class EncryptedPassportElement(TelegramObject):
"phone_number" type.
email (:obj:`str`): Optional. User's verified email address, available only for "email"
type.
files (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted files
files (Tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted
files
with documents provided by the user, available for "utility_bill", "bank_statement",
"rental_agreement", "passport_registration" and "temporary_registration" types.
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
front side of the document, provided by the user. Available for "passport",
"driver_license", "identity_card" and "internal_passport".
@ -103,12 +120,18 @@ class EncryptedPassportElement(TelegramObject):
selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
selfie of the user holding a document, provided by the user; available for "passport",
"driver_license", "identity_card" and "internal_passport".
translation (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted
translation (Tuple[:class:`telegram.PassportFile`]): Optional. Array of
encrypted/decrypted
files with translated versions of documents provided by the user. Available if
requested for "passport", "driver_license", "identity_card", "internal_passport",
"utility_bill", "bank_statement", "rental_agreement", "passport_registration" and
"temporary_registration" types.
.. versionchanged:: 20.0
* |tupleclassattrs|
* |alwaystuple|
"""
__slots__ = (
@ -131,11 +154,11 @@ class EncryptedPassportElement(TelegramObject):
data: PersonalDetails = None,
phone_number: str = None,
email: str = None,
files: List[PassportFile] = None,
files: Sequence[PassportFile] = None,
front_side: PassportFile = None,
reverse_side: PassportFile = None,
selfie: PassportFile = None,
translation: List[PassportFile] = None,
translation: Sequence[PassportFile] = None,
credentials: "Credentials" = None, # pylint: disable=unused-argument
*,
api_kwargs: JSONDict = None,
@ -148,11 +171,11 @@ class EncryptedPassportElement(TelegramObject):
self.data = data
self.phone_number = phone_number
self.email = email
self.files = files
self.files = parse_sequence_arg(files)
self.front_side = front_side
self.reverse_side = reverse_side
self.selfie = selfie
self.translation = translation
self.translation = parse_sequence_arg(translation)
self.hash = hash
self._id_attrs = (
@ -166,6 +189,8 @@ class EncryptedPassportElement(TelegramObject):
self.selfie,
)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["EncryptedPassportElement"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -17,12 +17,12 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Contains information about Telegram Passport data shared with the bot by the user."""
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
from telegram._passport.credentials import EncryptedCredentials
from telegram._passport.encryptedpassportelement import EncryptedPassportElement
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -39,13 +39,23 @@ class PassportData(TelegramObject):
attribute :attr:`telegram.Credentials.nonce`.
Args:
data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information
about documents and other Telegram Passport elements that was shared with the bot.
data (Sequence[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
information about documents and other Telegram Passport elements that was shared with
the bot.
.. versionchanged:: 20.0
|sequenceclassargs|
credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials.
Attributes:
data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information
about documents and other Telegram Passport elements that was shared with the bot.
data (Tuple[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
information about documents and other Telegram Passport elements that was shared with
the bot.
.. versionchanged:: 20.0
|tupleclassattrs|
credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials.
@ -55,19 +65,21 @@ class PassportData(TelegramObject):
def __init__(
self,
data: List[EncryptedPassportElement],
data: Sequence[EncryptedPassportElement],
credentials: EncryptedCredentials,
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
self.data = data
self.data = parse_sequence_arg(data)
self.credentials = credentials
self._decrypted_data: Optional[List[EncryptedPassportElement]] = None
self._decrypted_data: Optional[Tuple[EncryptedPassportElement]] = None
self._id_attrs = tuple([x.type for x in data] + [credentials.hash])
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["PassportData"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -82,23 +94,26 @@ class PassportData(TelegramObject):
return super().de_json(data=data, bot=bot)
@property
def decrypted_data(self) -> List[EncryptedPassportElement]:
def decrypted_data(self) -> Tuple[EncryptedPassportElement, ...]:
"""
List[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information
Tuple[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information
about documents and other Telegram Passport elements which were shared with the bot.
.. versionchanged:: 20.0
Returns a tuple instead of a list.
Raises:
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
private/public key but can also suggest malformed/tampered data.
"""
if self._decrypted_data is None:
self._decrypted_data = [
EncryptedPassportElement.de_json_decrypted( # type: ignore[misc]
self._decrypted_data = tuple( # type: ignore[assignment]
EncryptedPassportElement.de_json_decrypted(
element.to_dict(), self.get_bot(), self.decrypted_credentials
)
for element in self.data
]
return self._decrypted_data
)
return self._decrypted_data # type: ignore[return-value]
@property
def decrypted_credentials(self) -> "Credentials":

View file

@ -54,6 +54,8 @@ class PassportElementError(TelegramObject):
self._id_attrs = (self.source, self.type)
self._freeze()
class PassportElementErrorDataField(PassportElementError):
"""
@ -95,10 +97,17 @@ class PassportElementErrorDataField(PassportElementError):
):
# Required
super().__init__("data", type, message, api_kwargs=api_kwargs)
self.field_name = field_name
self.data_hash = data_hash
with self._unfrozen():
self.field_name = field_name
self.data_hash = data_hash
self._id_attrs = (self.source, self.type, self.field_name, self.data_hash, self.message)
self._id_attrs = (
self.source,
self.type,
self.field_name,
self.data_hash,
self.message,
)
class PassportElementErrorFile(PassportElementError):
@ -131,9 +140,10 @@ class PassportElementErrorFile(PassportElementError):
def __init__(self, type: str, file_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("file", type, message, api_kwargs=api_kwargs)
self.file_hash = file_hash
with self._unfrozen():
self.file_hash = file_hash
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
class PassportElementErrorFiles(PassportElementError):
@ -166,9 +176,10 @@ class PassportElementErrorFiles(PassportElementError):
def __init__(self, type: str, file_hashes: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("files", type, message, api_kwargs=api_kwargs)
self.file_hashes = file_hashes
with self._unfrozen():
self.file_hashes = file_hashes
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
class PassportElementErrorFrontSide(PassportElementError):
@ -201,9 +212,10 @@ class PassportElementErrorFrontSide(PassportElementError):
def __init__(self, type: str, file_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("front_side", type, message, api_kwargs=api_kwargs)
self.file_hash = file_hash
with self._unfrozen():
self.file_hash = file_hash
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
class PassportElementErrorReverseSide(PassportElementError):
@ -236,9 +248,10 @@ class PassportElementErrorReverseSide(PassportElementError):
def __init__(self, type: str, file_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("reverse_side", type, message, api_kwargs=api_kwargs)
self.file_hash = file_hash
with self._unfrozen():
self.file_hash = file_hash
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
class PassportElementErrorSelfie(PassportElementError):
@ -269,9 +282,10 @@ class PassportElementErrorSelfie(PassportElementError):
def __init__(self, type: str, file_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("selfie", type, message, api_kwargs=api_kwargs)
self.file_hash = file_hash
with self._unfrozen():
self.file_hash = file_hash
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
class PassportElementErrorTranslationFile(PassportElementError):
@ -306,9 +320,10 @@ class PassportElementErrorTranslationFile(PassportElementError):
def __init__(self, type: str, file_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("translation_file", type, message, api_kwargs=api_kwargs)
self.file_hash = file_hash
with self._unfrozen():
self.file_hash = file_hash
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
class PassportElementErrorTranslationFiles(PassportElementError):
@ -343,9 +358,10 @@ class PassportElementErrorTranslationFiles(PassportElementError):
def __init__(self, type: str, file_hashes: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("translation_files", type, message, api_kwargs=api_kwargs)
self.file_hashes = file_hashes
with self._unfrozen():
self.file_hashes = file_hashes
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes)
class PassportElementErrorUnspecified(PassportElementError):
@ -374,6 +390,7 @@ class PassportElementErrorUnspecified(PassportElementError):
def __init__(self, type: str, element_hash: str, message: str, *, api_kwargs: JSONDict = None):
# Required
super().__init__("unspecified", type, message, api_kwargs=api_kwargs)
self.element_hash = element_hash
with self._unfrozen():
self.element_hash = element_hash
self._id_attrs = (self.source, self.type, self.element_hash, self.message)
self._id_attrs = (self.source, self.type, self.element_hash, self.message)

View file

@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Encrypted PassportFile."""
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, List, Optional, Tuple
from telegram._telegramobject import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
@ -87,6 +87,8 @@ class PassportFile(TelegramObject):
self._id_attrs = (self.file_unique_id,)
self._freeze()
@classmethod
def de_json_decrypted(
cls, data: Optional[JSONDict], bot: "Bot", credentials: "FileCredentials"
@ -115,26 +117,35 @@ class PassportFile(TelegramObject):
@classmethod
def de_list_decrypted(
cls, data: Optional[List[JSONDict]], bot: "Bot", credentials: List["FileCredentials"]
) -> List[Optional["PassportFile"]]:
) -> Tuple[Optional["PassportFile"], ...]:
"""Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account
passport credentials.
.. versionchanged:: 20.0
* Returns a tuple instead of a list.
* Filters out any :obj:`None` values
Args:
data (Dict[:obj:`str`, ...]): The JSON data.
data (List[Dict[:obj:`str`, ...]]): The JSON data.
bot (:class:`telegram.Bot`): The bot associated with these objects.
credentials (:class:`telegram.FileCredentials`): The credentials
Returns:
List[:class:`telegram.PassportFile`]:
Tuple[:class:`telegram.PassportFile`]:
"""
if not data:
return []
return ()
return [
cls.de_json_decrypted(passport_file, bot, credentials[i])
for i, passport_file in enumerate(data)
]
return tuple(
obj
for obj in (
cls.de_json_decrypted(passport_file, bot, credentials[i])
for i, passport_file in enumerate(data)
)
if obj is not None
)
async def get_file(
self,

View file

@ -87,6 +87,8 @@ class Invoice(TelegramObject):
self.total_amount,
)
self._freeze()
MIN_TITLE_LENGTH: ClassVar[int] = constants.InvoiceLimit.MIN_TITLE_LENGTH
""":const:`telegram.constants.InvoiceLimit.MIN_TITLE_LENGTH`

View file

@ -54,3 +54,5 @@ class LabeledPrice(TelegramObject):
self.amount = amount
self._id_attrs = (self.label, self.amount)
self._freeze()

View file

@ -68,6 +68,8 @@ class OrderInfo(TelegramObject):
self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["OrderInfo"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -100,6 +100,8 @@ class PreCheckoutQuery(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["PreCheckoutQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -83,3 +83,5 @@ class ShippingAddress(TelegramObject):
self.street_line2,
self.post_code,
)
self._freeze()

View file

@ -17,10 +17,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/].
"""This module contains an object that represents a Telegram ShippingOption."""
from typing import TYPE_CHECKING, List
from typing import TYPE_CHECKING, Sequence
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
@ -39,12 +39,18 @@ class ShippingOption(TelegramObject):
Args:
id (:obj:`str`): Shipping option identifier.
title (:obj:`str`): Option title.
prices (List[:class:`telegram.LabeledPrice`]): List of price portions.
prices (Sequence[:class:`telegram.LabeledPrice`]): List of price portions.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
id (:obj:`str`): Shipping option identifier.
title (:obj:`str`): Option title.
prices (List[:class:`telegram.LabeledPrice`]): List of price portions.
prices (Tuple[:class:`telegram.LabeledPrice`]): List of price portions.
.. versionchanged:: 20.0
|tupleclassattrs|
"""
@ -54,7 +60,7 @@ class ShippingOption(TelegramObject):
self,
id: str, # pylint: disable=redefined-builtin
title: str,
prices: List["LabeledPrice"],
prices: Sequence["LabeledPrice"],
*,
api_kwargs: JSONDict = None,
):
@ -62,6 +68,8 @@ class ShippingOption(TelegramObject):
self.id = id # pylint: disable=invalid-name
self.title = title
self.prices = prices
self.prices = parse_sequence_arg(prices)
self._id_attrs = (self.id,)
self._freeze()

View file

@ -74,6 +74,8 @@ class ShippingQuery(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ShippingQuery"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -95,6 +95,8 @@ class SuccessfulPayment(TelegramObject):
self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SuccessfulPayment"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -17,16 +17,16 @@
# 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 Poll."""
import datetime
import sys
from typing import TYPE_CHECKING, ClassVar, Dict, List, Optional
from typing import TYPE_CHECKING, ClassVar, Dict, List, Optional, Sequence
from telegram import constants
from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils import enum
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import from_timestamp
from telegram._utils.types import JSONDict
@ -64,6 +64,8 @@ class PollOption(TelegramObject):
self._id_attrs = (self.text, self.voter_count)
self._freeze()
MIN_LENGTH: ClassVar[int] = constants.PollLimit.MIN_OPTION_LENGTH
""":const:`telegram.constants.PollLimit.MIN_OPTION_LENGTH`
@ -86,28 +88,37 @@ class PollAnswer(TelegramObject):
Args:
poll_id (:obj:`str`): Unique poll identifier.
user (:class:`telegram.User`): The user, who changed the answer to the poll.
option_ids (List[:obj:`int`]): 0-based identifiers of answer options, chosen by the user.
May be empty if the user retracted their vote.
option_ids (Sequence[:obj:`int`]): 0-based identifiers of answer options, chosen by the
user. May be empty if the user retracted their vote.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
poll_id (:obj:`str`): Unique poll identifier.
user (:class:`telegram.User`): The user, who changed the answer to the poll.
option_ids (List[:obj:`int`]): Identifiers of answer options, chosen by the user.
option_ids (Tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May be
empty if the user retracted their vote.
.. versionchanged:: 20.0
|tupleclassattrs|
"""
__slots__ = ("option_ids", "user", "poll_id")
def __init__(
self, poll_id: str, user: User, option_ids: List[int], *, api_kwargs: JSONDict = None
self, poll_id: str, user: User, option_ids: Sequence[int], *, api_kwargs: JSONDict = None
):
super().__init__(api_kwargs=api_kwargs)
self.poll_id = poll_id
self.user = user
self.option_ids = option_ids
self.option_ids = parse_sequence_arg(option_ids)
self._id_attrs = (self.poll_id, self.user, tuple(self.option_ids))
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["PollAnswer"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -135,7 +146,10 @@ class Poll(TelegramObject):
id (:obj:`str`): Unique poll identifier.
question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
:tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters.
options (List[:class:`PollOption`]): List of poll options.
options (Sequence[:class:`PollOption`]): List of poll options.
.. versionchanged:: 20.0
|sequenceclassargs|
is_closed (:obj:`bool`): :obj:`True`, if the poll is closed.
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`.
@ -146,12 +160,15 @@ class Poll(TelegramObject):
explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect
answer or taps on the lamp icon in a quiz-style poll,
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
explanation_entities (List[:class:`telegram.MessageEntity`], optional): Special entities
like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`.
This list is empty if the message does not contain explanation entities.
explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special
entities like usernames, URLs, bot commands, etc. that appear in the
:attr:`explanation`. This list is empty if the message does not contain explanation
entities.
.. versionchanged:: 20.0
This attribute is now always a (possibly empty) list and never :obj:`None`.
* This attribute is now always a (possibly empty) list and never :obj:`None`.
* |sequenceclassargs|
open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active
after creation.
close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the
@ -161,7 +178,10 @@ class Poll(TelegramObject):
id (:obj:`str`): Unique poll identifier.
question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
:tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters.
options (List[:class:`PollOption`]): List of poll options.
options (Tuple[:class:`PollOption`]): List of poll options.
.. versionchanged:: 20.0
|tupleclassattrs|
total_voter_count (:obj:`int`): Total number of users that voted in the poll.
is_closed (:obj:`bool`): :obj:`True`, if the poll is closed.
is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous.
@ -173,10 +193,13 @@ class Poll(TelegramObject):
explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect
answer or taps on the lamp icon in a quiz-style poll,
0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters.
explanation_entities (List[:class:`telegram.MessageEntity`]): Special entities
explanation_entities (Tuple[:class:`telegram.MessageEntity`]): Special entities
like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`.
This list is empty if the message does not contain explanation entities.
.. versionchanged:: 20.0
|tupleclassattrs|
.. versionchanged:: 20.0
This attribute is now always a (possibly empty) list and never :obj:`None`.
open_period (:obj:`int`): Optional. Amount of time in seconds the poll will be active
@ -206,7 +229,7 @@ class Poll(TelegramObject):
self,
id: str, # pylint: disable=redefined-builtin
question: str,
options: List[PollOption],
options: Sequence[PollOption],
total_voter_count: int,
is_closed: bool,
is_anonymous: bool,
@ -214,7 +237,7 @@ class Poll(TelegramObject):
allows_multiple_answers: bool,
correct_option_id: int = None,
explanation: str = None,
explanation_entities: List[MessageEntity] = None,
explanation_entities: Sequence[MessageEntity] = None,
open_period: int = None,
close_date: datetime.datetime = None,
*,
@ -223,7 +246,7 @@ class Poll(TelegramObject):
super().__init__(api_kwargs=api_kwargs)
self.id = id # pylint: disable=invalid-name
self.question = question
self.options = options
self.options = parse_sequence_arg(options)
self.total_voter_count = total_voter_count
self.is_closed = is_closed
self.is_anonymous = is_anonymous
@ -231,12 +254,14 @@ class Poll(TelegramObject):
self.allows_multiple_answers = allows_multiple_answers
self.correct_option_id = correct_option_id
self.explanation = explanation
self.explanation_entities = explanation_entities or []
self.explanation_entities = parse_sequence_arg(explanation_entities)
self.open_period = open_period
self.close_date = close_date
self._id_attrs = (self.id,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Poll"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -59,6 +59,8 @@ class ProximityAlertTriggered(TelegramObject):
self._id_attrs = (self.traveler, self.watcher, self.distance)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ProximityAlertTriggered"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -41,8 +41,8 @@ class ReplyKeyboardMarkup(TelegramObject):
* :any:`Conversation Bot 2 <examples.conversationbot2>`
Args:
keyboard (List[List[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of button rows,
each represented by an Array of :class:`telegram.KeyboardButton` objects.
keyboard (Sequence[Sequence[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of
button rows, each represented by an Array of :class:`telegram.KeyboardButton` objects.
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 always of the
@ -70,7 +70,8 @@ class ReplyKeyboardMarkup(TelegramObject):
.. versionadded:: 13.7
Attributes:
keyboard (List[List[:class:`telegram.KeyboardButton` | :obj:`str`]]): Array of button rows.
keyboard (Tuple[Tuple[:class:`telegram.KeyboardButton` | :obj:`str`]]): Array of button
rows.
resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard.
one_time_keyboard (:obj:`bool`): Optional. Requests clients to hide the keyboard as soon as
it's been used.
@ -103,20 +104,15 @@ class ReplyKeyboardMarkup(TelegramObject):
super().__init__(api_kwargs=api_kwargs)
if not check_keyboard_type(keyboard):
raise ValueError(
"The parameter `keyboard` should be a list of list of "
"The parameter `keyboard` should be a sequence of sequences of "
"strings or KeyboardButtons"
)
# Required
self.keyboard = []
for row in keyboard:
button_row = []
for button in row:
if isinstance(button, KeyboardButton):
button_row.append(button) # telegram.KeyboardButton
else:
button_row.append(KeyboardButton(button)) # str
self.keyboard.append(button_row)
self.keyboard = tuple(
tuple(KeyboardButton(button) if isinstance(button, str) else button for button in row)
for row in keyboard
)
# Optionals
self.resize_keyboard = resize_keyboard
@ -126,6 +122,8 @@ class ReplyKeyboardMarkup(TelegramObject):
self._id_attrs = (self.keyboard,)
self._freeze()
@classmethod
def from_button(
cls,
@ -282,16 +280,6 @@ class ReplyKeyboardMarkup(TelegramObject):
**kwargs, # type: ignore[arg-type]
)
def __hash__(self) -> int:
return hash(
(
tuple(tuple(button for button in row) for row in self.keyboard),
self.resize_keyboard,
self.one_time_keyboard,
self.selective,
)
)
MIN_INPUT_FIELD_PLACEHOLDER: ClassVar[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER
""":const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER`

View file

@ -63,3 +63,5 @@ class ReplyKeyboardRemove(TelegramObject):
self.remove_keyboard = True
# Optionals
self.selective = selective
self._freeze()

View file

@ -49,3 +49,5 @@ class SentWebAppMessage(TelegramObject):
self.inline_message_id = inline_message_id
self._id_attrs = (self.inline_message_id,)
self._freeze()

View file

@ -20,16 +20,20 @@
import datetime
import inspect
import json
from collections.abc import Sized
from contextlib import contextmanager
from copy import deepcopy
from itertools import chain
from types import MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterator,
List,
Mapping,
Optional,
Set,
Sized,
Tuple,
Type,
TypeVar,
@ -61,6 +65,9 @@ class TelegramObject:
* String representations objects of this type was overhauled. See :meth:`__repr__` for
details. As this class doesn't implement :meth:`object.__str__`, the default
implementation will be used, which is equivalent to :meth:`__repr__`.
* Objects of this class (or subclasses) are now immutable. This means that you can't set
or delete attributes anymore. Moreover, attributes that were formerly of type
:obj:`list` are now of type :obj:`tuple`.
Arguments:
api_kwargs (Dict[:obj:`str`, any], optional): |toapikwargsarg|
@ -68,13 +75,13 @@ class TelegramObject:
.. versionadded:: 20.0
Attributes:
api_kwargs (Dict[:obj:`str`, any]): |toapikwargsattr|
api_kwargs (:obj:`types.MappingProxyType` [:obj:`str`, any]): |toapikwargsattr|
.. versionadded:: 20.0
"""
__slots__ = ("_id_attrs", "_bot", "api_kwargs")
__slots__ = ("_id_attrs", "_bot", "_frozen", "api_kwargs")
# Used to cache the names of the parameters of the __init__ method of the class
# Must be a private attribute to avoid name clashes between subclasses
@ -85,14 +92,34 @@ class TelegramObject:
__INIT_PARAMS_CHECK: Optional[Type["TelegramObject"]] = None
def __init__(self, *, api_kwargs: JSONDict = None) -> None:
self._frozen: bool = False
self._id_attrs: Tuple[object, ...] = ()
self._bot: Optional["Bot"] = None
# We don't do anything with api_kwargs here - see docstring of _apply_api_kwargs
self.api_kwargs: JSONDict = api_kwargs or {}
self.api_kwargs: Mapping[str, Any] = MappingProxyType(api_kwargs or {})
def _apply_api_kwargs(self) -> None:
def _freeze(self) -> None:
self._frozen = True
def _unfreeze(self) -> None:
self._frozen = False
@contextmanager
def _unfrozen(self: Tele_co) -> Iterator[Tele_co]:
"""Context manager to temporarily unfreeze the object. For internal use only.
Note:
with to._unfrozen() as other_to:
assert to is other_to
"""
self._unfreeze()
yield self
self._freeze()
def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None:
"""Loops through the api kwargs and for every key that exists as attribute of the
object (and is None), it moves the value from `api_kwargs` to the attribute.
*Edits `api_kwargs` in place!*
This method is currently only called in the unpickling process, i.e. not on "normal" init.
This is because
@ -105,9 +132,39 @@ class TelegramObject:
then you can pass everything as proper argument.
"""
# we convert to list to ensure that the list doesn't change length while we loop
for key in list(self.api_kwargs.keys()):
for key in list(api_kwargs.keys()):
if getattr(self, key, True) is None:
setattr(self, key, self.api_kwargs.pop(key))
setattr(self, key, api_kwargs.pop(key))
def __setattr__(self, key: str, value: object) -> None:
"""Overrides :meth:`object.__setattr__` to prevent the overriding of attributes.
Raises:
:exc:`AttributeError`
"""
# protected attributes can always be set for convenient internal use
if key[0] == "_" or not getattr(self, "_frozen", True):
super().__setattr__(key, value)
return
raise AttributeError(
f"Attribute `{key}` of class `{self.__class__.__name__}` can't be set!"
)
def __delattr__(self, key: str) -> None:
"""Overrides :meth:`object.__delattr__` to prevent the deletion of attributes.
Raises:
:exc:`AttributeError`
"""
# protected attributes can always be set for convenient internal use
if key[0] == "_" or not getattr(self, "_frozen", True):
super().__delattr__(key)
return
raise AttributeError(
f"Attribute `{key}` of class `{self.__class__.__name__}` can't be deleted!"
)
def __repr__(self) -> str:
"""Gives a string representation of this object in the form
@ -130,6 +187,9 @@ class TelegramObject:
if not self.api_kwargs:
# Drop api_kwargs from the representation, if empty
as_dict.pop("api_kwargs", None)
else:
# Otherwise, we want to skip the "mappingproxy" part of the repr
as_dict["api_kwargs"] = dict(self.api_kwargs)
contents = ", ".join(
f"{k}={as_dict[k]!r}"
@ -189,7 +249,11 @@ class TelegramObject:
Returns:
state (Dict[:obj:`str`, :obj:`object`]): The state of the object.
"""
return self._get_attrs(include_private=True, recursive=False, remove_bot=True)
out = self._get_attrs(include_private=True, recursive=False, remove_bot=True)
# MappingProxyType is not pickable, so we convert it to a dict and revert in
# __setstate__
out["api_kwargs"] = dict(self.api_kwargs)
return out
def __setstate__(self, state: dict) -> None:
"""
@ -208,19 +272,36 @@ class TelegramObject:
Args:
state (:obj:`dict`): The data to set as attributes of this object.
"""
self._unfreeze()
# Make sure that we have a `_bot` attribute. This is necessary, since __getstate__ omits
# this as Bots are not pickable.
setattr(self, "_bot", None)
setattr(self, "api_kwargs", state.pop("api_kwargs", {})) # assign api_kwargs first
# get api_kwargs first because we may need to add entries to it (see try-except below)
api_kwargs = state.pop("api_kwargs", {})
# get _frozen before the loop to avoid setting it to True in the loop
frozen = state.pop("_frozen", False)
for key, val in state.items():
try:
setattr(self, key, val)
except AttributeError: # catch cases when old attributes are removed from new versions
self.api_kwargs[key] = val # add it to api_kwargs as fallback
except AttributeError:
# catch cases when old attributes are removed from new versions
api_kwargs[key] = val # add it to api_kwargs as fallback
self._apply_api_kwargs()
# For api_kwargs we first apply any kwargs that are already attributes of the object
# and then set the rest as MappingProxyType attribute. Converting to MappingProxyType
# is necessary, since __getstate__ converts it to a dict as MPT is not pickable.
self._apply_api_kwargs(api_kwargs)
setattr(self, "api_kwargs", MappingProxyType(api_kwargs))
# Apply freezing if necessary
# we .get(…) the setting for backwards compatibility with objects that were pickled
# before the freeze feature was introduced
if frozen:
self._freeze()
def __deepcopy__(self: Tele_co, memodict: dict) -> Tele_co:
"""
@ -243,9 +324,19 @@ class TelegramObject:
result = cls.__new__(cls) # create a new instance
memodict[id(self)] = result # save the id of the object in the dict
for k in self._get_attrs_names(
include_private=True
): # now we set the attributes in the deepcopied object
setattr(result, "_frozen", False) # unfreeze the new object for setting the attributes
# now we set the attributes in the deepcopied object
for k in self._get_attrs_names(include_private=True):
if k == "_frozen":
# Setting the frozen status to True would prevent the attributes from being set
continue
if k == "api_kwargs":
# Need to copy api_kwargs manually, since it's a MappingProxyType is not
# pickable and deepcopy uses the pickle interface
setattr(result, k, MappingProxyType(deepcopy(dict(self.api_kwargs), memodict)))
continue
try:
setattr(result, k, deepcopy(getattr(self, k), memodict))
except AttributeError:
@ -254,6 +345,10 @@ class TelegramObject:
# did not have the attribute yet.
continue
# Apply freezing if necessary
if self._frozen:
result._freeze()
result.set_bot(bot) # Assign the bots back
self.set_bot(bot)
return result
@ -372,21 +467,26 @@ class TelegramObject:
@classmethod
def de_list(
cls: Type[Tele_co], data: Optional[List[JSONDict]], bot: "Bot"
) -> List[Optional[Tele_co]]:
"""Converts JSON data to a list of Telegram objects.
) -> Tuple[Tele_co, ...]:
"""Converts a list of JSON objects to a tuple of Telegram objects.
.. versionchanged:: 20.0
* Returns a tuple instead of a list.
* Filters out any :obj:`None` values.
Args:
data (Dict[:obj:`str`, ...]): The JSON data.
data (List[Dict[:obj:`str`, ...]]): The JSON data.
bot (:class:`telegram.Bot`): The bot associated with these objects.
Returns:
A list of Telegram objects.
A tuple of Telegram objects.
"""
if not data:
return []
return ()
return [cls.de_json(d, bot) for d in data]
return tuple(obj for obj in (cls.de_json(d, bot) for d in data) if obj is not None)
def to_json(self) -> str:
"""Gives a JSON representation of object.
@ -403,7 +503,9 @@ class TelegramObject:
"""Gives representation of object as :obj:`dict`.
.. versionchanged:: 20.0
Now includes all entries of :attr:`api_kwargs`.
* Now includes all entries of :attr:`api_kwargs`.
* Attributes whose values are empty sequences are no longer included.
Args:
recursive (:obj:`bool`, optional): If :obj:`True`, will convert any TelegramObjects
@ -420,13 +522,19 @@ class TelegramObject:
# Now we should convert TGObjects to dicts inside objects such as sequences, and convert
# datetimes to timestamps. This mostly eliminates the need for subclasses to override
# `to_dict`
pop_keys: Set[str] = set()
for key, value in out.items():
if isinstance(value, (tuple, list)) and value:
if isinstance(value, (tuple, list)):
if not value:
# not popping directly to avoid changing the dict size during iteration
pop_keys.add(key)
continue
val = [] # empty list to append our converted values to
for item in value:
if hasattr(item, "to_dict"):
val.append(item.to_dict(recursive=recursive))
# This branch is useful for e.g. List[List[PhotoSize|KeyboardButton]]
# This branch is useful for e.g. Tuple[Tuple[PhotoSize|KeyboardButton]]
elif isinstance(item, (tuple, list)):
val.append(
[
@ -441,6 +549,9 @@ class TelegramObject:
elif isinstance(value, datetime.datetime):
out[key] = to_timestamp(value)
for key in pop_keys:
out.pop(key)
# Effectively "unpack" api_kwargs into `out`:
out.update(out.pop("api_kwargs", {})) # type: ignore[call-overload]
return out

View file

@ -268,6 +268,8 @@ class Update(TelegramObject):
self._id_attrs = (self.update_id,)
self._freeze()
@property
def effective_user(self) -> Optional["User"]:
"""

View file

@ -158,6 +158,8 @@ class User(TelegramObject):
self._id_attrs = (self.id,)
self._freeze()
@property
def name(self) -> str:
""":obj:`str`: Convenience property. If available, returns the user's :attr:`username`
@ -482,7 +484,7 @@ class User(TelegramObject):
caption: Optional[str] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
caption_entities: Union[List["MessageEntity"], Tuple["MessageEntity", ...]] = None,
) -> List["Message"]:
) -> Tuple["Message", ...]:
"""Shortcut for::
await bot.send_media_group(update.effective_user.id, *args, **kwargs)
@ -490,7 +492,8 @@ class User(TelegramObject):
For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`.
Returns:
List[:class:`telegram.Message`:] On success, instance representing the message posted.
Tuple[:class:`telegram.Message`:] On success, a tuple of :class:`~telegram.Message`
instances that were sent is returned.
"""
return await self.get_bot().send_media_group(

View file

@ -17,8 +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 UserProfilePhotos."""
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence
from telegram._files.photosize import PhotoSize
from telegram._telegramobject import TelegramObject
@ -36,27 +35,40 @@ class UserProfilePhotos(TelegramObject):
Args:
total_count (:obj:`int`): Total number of profile pictures the target user has.
photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up to 4
sizes each).
photos (Sequence[Sequence[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up
to 4 sizes each).
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
total_count (:obj:`int`): Total number of profile pictures.
photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures.
photos (Tuple[Tuple[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up
to 4 sizes each).
.. versionchanged:: 20.0
|tupleclassattrs|
"""
__slots__ = ("photos", "total_count")
def __init__(
self, total_count: int, photos: List[List[PhotoSize]], *, api_kwargs: JSONDict = None
self,
total_count: int,
photos: Sequence[Sequence[PhotoSize]],
*,
api_kwargs: JSONDict = None,
):
super().__init__(api_kwargs=api_kwargs)
# Required
self.total_count = total_count
self.photos = photos
self.photos = tuple(tuple(sizes) for sizes in photos)
self._id_attrs = (self.total_count, self.photos)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["UserProfilePhotos"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
@ -68,6 +80,3 @@ class UserProfilePhotos(TelegramObject):
data["photos"] = [PhotoSize.de_list(photo, bot) for photo in data["photos"]]
return super().de_json(data=data, bot=bot)
def __hash__(self) -> int:
return hash(tuple(tuple(p for p in photo) for photo in self.photos))

View file

@ -0,0 +1,40 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# 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 helper functions related to parsing arguments for classes and methods.
Warning:
Contents of this module are intended to be used internally by the library and *not* by the
user. Changes to this module are not considered breaking changes and may not be documented in
the changelog.
"""
from typing import Optional, Sequence, Tuple, TypeVar
T = TypeVar("T")
def parse_sequence_arg(arg: Optional[Sequence[T]]) -> Tuple[T, ...]:
"""Parses an optional sequence into a tuple
Args:
arg (:obj:`Sequence`): The sequence to parse.
Returns:
:obj:`Tuple`: The sequence converted to a tuple or an empty tuple.
"""
return tuple(arg) if arg else ()

View file

@ -27,15 +27,19 @@ Warning:
user. Changes to this module are not considered breaking changes and may not be documented in
the changelog.
"""
from collections.abc import Sequence
def check_keyboard_type(keyboard: object) -> bool:
"""Checks if the keyboard provided is of the correct type - A list of lists.
Implicitly tested in the init-tests of `{Inline, Reply}KeyboardMarkup`
"""
if not isinstance(keyboard, list):
# string and bytes may actually be used for ReplyKeyboardMarkup in which case each button
# would contain a single character. But that use case should be discouraged and we don't
# allow it here.
if not isinstance(keyboard, Sequence) or isinstance(keyboard, (str, bytes)):
return False
for row in keyboard:
if not isinstance(row, list):
if not isinstance(row, Sequence) or isinstance(row, (str, bytes)):
return False
return True

View file

@ -17,12 +17,12 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains objects related to Telegram video chats."""
import datetime as dtm
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Optional, Sequence
from telegram._telegramobject import TelegramObject
from telegram._user import User
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import from_timestamp
from telegram._utils.types import JSONDict
@ -76,6 +76,8 @@ class VideoChatEnded(TelegramObject):
self.duration = duration
self._id_attrs = (self.duration,)
self._freeze()
class VideoChatParticipantsInvited(TelegramObject):
"""
@ -89,10 +91,16 @@ class VideoChatParticipantsInvited(TelegramObject):
This class was renamed from ``VoiceChatParticipantsInvited`` in accordance to Bot API 6.0.
Args:
users (List[:class:`telegram.User`]): New members that were invited to the video chat.
users (Sequence[:class:`telegram.User`]): New members that were invited to the video chat.
.. versionchanged:: 20.0
|sequenceclassargs|
Attributes:
users (List[:class:`telegram.User`]): New members that were invited to the video chat.
users (Tuple[:class:`telegram.User`]): New members that were invited to the video chat.
.. versionchanged:: 20.0
|tupleclassattrs|
"""
@ -100,14 +108,16 @@ class VideoChatParticipantsInvited(TelegramObject):
def __init__(
self,
users: List[User],
users: Sequence[User],
*,
api_kwargs: JSONDict = None,
) -> None:
super().__init__(api_kwargs=api_kwargs)
self.users = users
self.users = parse_sequence_arg(users)
self._id_attrs = (self.users,)
self._freeze()
@classmethod
def de_json(
cls, data: Optional[JSONDict], bot: "Bot"
@ -121,9 +131,6 @@ class VideoChatParticipantsInvited(TelegramObject):
data["users"] = User.de_list(data.get("users", []), bot)
return super().de_json(data=data, bot=bot)
def __hash__(self) -> int:
return hash(None) if self.users is None else hash(tuple(self.users))
class VideoChatScheduled(TelegramObject):
"""This object represents a service message about a video chat scheduled in the chat.
@ -156,6 +163,8 @@ class VideoChatScheduled(TelegramObject):
self._id_attrs = (self.start_date,)
self._freeze()
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["VideoChatScheduled"]:
"""See :meth:`telegram.TelegramObject.de_json`."""

View file

@ -58,3 +58,5 @@ class WebAppData(TelegramObject):
self.button_text = button_text
self._id_attrs = (self.data, self.button_text)
self._freeze()

View file

@ -53,3 +53,5 @@ class WebAppInfo(TelegramObject):
self.url = url
self._id_attrs = (self.url,)
self._freeze()

Some files were not shown because too many files have changed in this diff Show more