diff --git a/README.rst b/README.rst index 1d6b20aafea..3344d171211 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.2-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.2** are supported. +All types and methods of the Telegram Bot API **7.3** are supported. Installing ========== diff --git a/README_RAW.rst b/README_RAW.rst index df1312e4857..7539408e7c8 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot-raw/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.2-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.3-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -85,7 +85,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.2** are supported. +All types and methods of the Telegram Bot API **7.3** are supported. Installing ========== diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index 3d78292588a..7e240de0041 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -36,6 +36,7 @@ Available Types telegram.chatboostsourcegiveaway telegram.chatboostsourcepremium telegram.chatboostupdated + telegram.chatfullinfo telegram.chatinvitelink telegram.chatjoinrequest telegram.chatlocation diff --git a/docs/source/telegram.chatfullinfo.rst b/docs/source/telegram.chatfullinfo.rst new file mode 100644 index 00000000000..f15dbeedaa1 --- /dev/null +++ b/docs/source/telegram.chatfullinfo.rst @@ -0,0 +1,6 @@ +ChatFullInfo +============ + +.. autoclass:: telegram.ChatFullInfo + :members: + :show-inheritance: \ No newline at end of file diff --git a/telegram/__init__.py b/telegram/__init__.py index 304425c4d61..5054cd8863c 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -54,6 +54,7 @@ "ChatBoostSourceGiveaway", "ChatBoostSourcePremium", "ChatBoostUpdated", + "ChatFullInfo", "ChatInviteLink", "ChatJoinRequest", "ChatLocation", @@ -269,6 +270,7 @@ ChatBoostUpdated, UserChatBoosts, ) +from ._chatfullinfo import ChatFullInfo from ._chatinvitelink import ChatInviteLink from ._chatjoinrequest import ChatJoinRequest from ._chatlocation import ChatLocation diff --git a/telegram/_bot.py b/telegram/_bot.py index 8bb4af23de7..41849cbd029 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -58,9 +58,9 @@ from telegram._botdescription import BotDescription, BotShortDescription from telegram._botname import BotName from telegram._business import BusinessConnection -from telegram._chat import Chat from telegram._chatadministratorrights import ChatAdministratorRights from telegram._chatboost import UserChatBoosts +from telegram._chatfullinfo import ChatFullInfo from telegram._chatinvitelink import ChatInviteLink from telegram._chatmember import ChatMember from telegram._chatpermissions import ChatPermissions @@ -4434,16 +4434,19 @@ async def get_chat( connect_timeout: ODVInput[float] = DEFAULT_NONE, pool_timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: Optional[JSONDict] = None, - ) -> Chat: + ) -> ChatFullInfo: """ Use this method to get up to date information about the chat (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.). + .. versionchanged:: NEXT.VERSION + In accordance to Bot API 7.3, this method now returns a :class:`telegram.ChatFullInfo`. + Args: chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| Returns: - :class:`telegram.Chat` + :class:`telegram.ChatFullInfo` Raises: :class:`telegram.error.TelegramError` @@ -4461,7 +4464,7 @@ async def get_chat( api_kwargs=api_kwargs, ) - return Chat.de_json(result, self) # type: ignore[return-value] + return ChatFullInfo.de_json(result, self) # type: ignore[return-value] async def get_chat_administrators( self, diff --git a/telegram/_chat.py b/telegram/_chat.py index 94991c9b391..9723e7edf9f 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -20,7 +20,7 @@ """This module contains an object that represents a Telegram Chat.""" from datetime import datetime from html import escape -from typing import TYPE_CHECKING, Final, Optional, Sequence, Tuple, Union +from typing import TYPE_CHECKING, Any, Final, Optional, Sequence, Tuple, Union from telegram import constants from telegram._birthdate import Birthdate @@ -36,9 +36,11 @@ from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup +from telegram._utils.warnings import warn from telegram.helpers import escape_markdown from telegram.helpers import mention_html as helpers_mention_html from telegram.helpers import mention_markdown as helpers_mention_markdown +from telegram.warnings import PTBDeprecationWarning if TYPE_CHECKING: from telegram import ( @@ -74,6 +76,45 @@ ) +_deprecated_attrs = ( + "accent_color_id", + "active_usernames", + "available_reactions", + "background_custom_emoji_id", + "bio", + "birthdate", + "business_intro", + "business_location", + "business_opening_hours", + "can_set_sticker_set", + "custom_emoji_sticker_set_name", + "description", + "emoji_status_custom_emoji_id", + "emoji_status_expiration_date", + "has_aggressive_anti_spam_enabled", + "has_hidden_members", + "has_private_forwards", + "has_protected_content", + "has_restricted_voice_and_video_messages", + "has_visible_history", + "invite_link", + "join_by_request", + "join_to_send_messages", + "linked_chat_id", + "location", + "message_auto_delete_time", + "permissions", + "personal_chat", + "photo", + "pinned_message", + "profile_accent_color_id", + "profile_background_custom_emoji_id", + "slow_mode_delay", + "sticker_set_name", + "unrestrict_boost_count", +) + + class Chat(TelegramObject): """This object represents a chat. @@ -107,62 +148,134 @@ class Chat(TelegramObject): last_name (:obj:`str`, optional): Last name of the other party in a private chat. photo (:class:`telegram.ChatPhoto`, optional): Chat photo. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. bio (:obj:`str`, optional): Bio of the other party in a private chat. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_private_forwards (:obj:`bool`, optional): :obj:`True`, if privacy settings of the other party in the private chat allows to use ``tg://user?id=`` links only in chats with the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.9 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. description (:obj:`str`, optional): Description, for groups, supergroups and channel chats. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and channel. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. pinned_message (:class:`telegram.Message`, optional): The most recent pinned message (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between consecutive messages sent by each unprivileged user. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.4 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_protected_content (:obj:`bool`, optional): :obj:`True`, if messages from the chat can't be forwarded to other chats. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.9 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_visible_history (:obj:`bool`, optional): :obj:`True`, if new chat members will have access to old messages; available only to chat administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the sticker set. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the discussion group identifier for a channel and vice versa; for supergroups and channel chats. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. join_to_send_messages (:obj:`bool`, optional): :obj:`True`, if users need to join the supergroup before they can send messages. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. join_by_request (:obj:`bool`, optional): :obj:`True`, if all users directly joining the supergroup need to be approved by supergroup administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_restricted_voice_and_video_messages (:obj:`bool`, optional): :obj:`True`, if the privacy settings of the other party restrict sending voice and video note messages in the private chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum (has topics_ enabled). @@ -173,27 +286,47 @@ class Chat(TelegramObject): only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_intro (:class:`telegram.BusinessIntro`, optional): For private chats with business accounts, the intro of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_location (:class:`telegram.BusinessLocation`, optional): For private chats with business accounts, the location of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_opening_hours (:class:`telegram.BusinessOpeningHours`, optional): For private chats with business accounts, the opening hours of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. available_reactions (Sequence[:class:`telegram.ReactionType`], optional): List of available reactions allowed in the chat. If omitted, then all of :const:`telegram.constants.ReactionEmoji` are allowed. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. accent_color_id (:obj:`int`, optional): Identifier of the :class:`accent color ` for the chat name and backgrounds of the chat photo, reply header, and link preview. See `accent colors`_ @@ -201,62 +334,110 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. profile_accent_color_id (:obj:`int`, optional): Identifier of the :class:`accent color ` for the chat's profile background. See profile `accent colors`_ for more details. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. profile_background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of the emoji chosen by the chat for its profile background. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji status of the chat or the other party in a private chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of emoji status of the chat or the other party in a private chat, in seconds. Returned only in :meth:`telegram.Bot.get_chat`. |datetime_localization| .. versionadded:: 20.5 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive anti-spam checks are enabled in the supergroup. The field is only available to chat administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_hidden_members (:obj:`bool`, optional): :obj:`True`, if non-administrators can only get the list of bots and administrators in the chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be used by all users and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. birthdate (:obj:`telegram.Birthdate`, optional): For private chats, the date of birth of the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. personal_chat (:obj:`telegram.Chat`, optional): For private chats, the personal channel of the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. + Attributes: id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. @@ -271,62 +452,134 @@ class Chat(TelegramObject): last_name (:obj:`str`): Optional. Last name of the other party in a private chat. photo (:class:`telegram.ChatPhoto`): Optional. Chat photo. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_private_forwards (:obj:`bool`): Optional. :obj:`True`, if privacy settings of the other party in the private chat allows to use ``tg://user?id=`` links only in chats with the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.9 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and channel. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between consecutive messages sent by each unprivileged user. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.4 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_protected_content (:obj:`bool`): Optional. :obj:`True`, if messages from the chat can't be forwarded to other chats. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 13.9 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_visible_history (:obj:`bool`): Optional. :obj:`True`, if new chat members will have access to old messages; available only to chat administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the sticker set. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the discussion group identifier for a channel and vice versa; for supergroups and channel chats. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. join_to_send_messages (:obj:`bool`): Optional. :obj:`True`, if users need to join the supergroup before they can send messages. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. join_by_request (:obj:`bool`): Optional. :obj:`True`, if all users directly joining the supergroup need to be approved by supergroup administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_restricted_voice_and_video_messages (:obj:`bool`): Optional. :obj:`True`, if the privacy settings of the other party restrict sending voice and video note messages in the private chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. is_forum (:obj:`bool`): Optional. :obj:`True`, if the supergroup chat is a forum (has topics_ enabled). @@ -339,27 +592,47 @@ class Chat(TelegramObject): obtained via :meth:`~telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_intro (:class:`telegram.BusinessIntro`): Optional. For private chats with business accounts, the intro of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_location (:class:`telegram.BusinessLocation`): Optional. For private chats with business accounts, the location of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. business_opening_hours (:class:`telegram.BusinessOpeningHours`): Optional. For private chats with business accounts, the opening hours of the business. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. available_reactions (Tuple[:class:`telegram.ReactionType`]): Optional. List of available reactions allowed in the chat. If omitted, then all of :const:`telegram.constants.ReactionEmoji` are allowed. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. accent_color_id (:obj:`int`): Optional. Identifier of the :class:`accent color ` for the chat name and backgrounds of the chat photo, reply header, and link preview. See `accent colors`_ @@ -367,62 +640,110 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. profile_accent_color_id (:obj:`int`): Optional. Identifier of the :class:`accent color ` for the chat's profile background. See profile `accent colors`_ for more details. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. profile_background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.8 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji status of the chat or the other party in a private chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. emoji_status_expiration_date (:class:`datetime.datetime`): Optional. Expiration date of emoji status of the chat or the other party in a private chat, in seconds. Returned only in :meth:`telegram.Bot.get_chat`. |datetime_localization| .. versionadded:: 20.5 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive anti-spam checks are enabled in the supergroup. The field is only available to chat administrators. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. has_hidden_members (:obj:`bool`): Optional. :obj:`True`, if non-administrators can only get the list of bots and administrators in the chat. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be used by all users and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.0 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. birthdate (:obj:`telegram.Birthdate`): Optional. For private chats, the date of birth of the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. personal_chat (:obj:`telegram.Chat`): Optional. For private chats, the personal channel of the user. Returned only in :meth:`telegram.Bot.get_chat`. .. versionadded:: 21.1 + .. deprecated:: NEXT.VERSION + In accordance to Bot API 7.3, this attribute will be moved to + :class:`telegram.ChatFullInfo`. + .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups .. _accent colors: https://core.telegram.org/bots/api#accent-colors """ @@ -471,7 +792,6 @@ class Chat(TelegramObject): "unrestrict_boost_count", "username", ) - SENDER: Final[str] = constants.ChatType.SENDER """:const:`telegram.constants.ChatType.SENDER` @@ -518,7 +838,7 @@ def __init__( has_aggressive_anti_spam_enabled: Optional[bool] = None, has_hidden_members: Optional[bool] = None, available_reactions: Optional[Sequence[ReactionType]] = None, - accent_color_id: Optional[int] = None, + accent_color_id: Optional[int] = None, # required in API 7.3 - Optional for back compat background_custom_emoji_id: Optional[str] = None, profile_accent_color_id: Optional[int] = None, profile_background_custom_emoji_id: Optional[str] = None, @@ -585,10 +905,30 @@ def __init__( self.business_location: Optional["BusinessLocation"] = business_location self.business_opening_hours: Optional["BusinessOpeningHours"] = business_opening_hours + if self.__class__ is Chat: + for arg in _deprecated_attrs: + if (val := object.__getattribute__(self, arg)) is not None and val != (): + warn( + f"The argument `{arg}` is deprecated and will only be available via " + "`ChatFullInfo` in the future.", + stacklevel=2, + category=PTBDeprecationWarning, + ) + self._id_attrs = (self.id,) self._freeze() + def __getattribute__(self, name: str) -> Any: + if name in _deprecated_attrs and self.__class__ is Chat: + warn( + f"The attribute `{name}` is deprecated and will only be accessible via " + "`ChatFullInfo` in the future.", + stacklevel=2, + category=PTBDeprecationWarning, + ) + return super().__getattribute__(name) + @property def effective_name(self) -> Optional[str]: """ @@ -658,7 +998,7 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Chat"]: data["location"] = ChatLocation.de_json(data.get("location"), bot) data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot) data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot) - data["personal_chat"] = cls.de_json(data.get("personal_chat"), bot) + data["personal_chat"] = Chat.de_json(data.get("personal_chat"), bot) data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot) data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot) data["business_opening_hours"] = BusinessOpeningHours.de_json( diff --git a/telegram/_chatfullinfo.py b/telegram/_chatfullinfo.py new file mode 100644 index 00000000000..7b7c686b086 --- /dev/null +++ b/telegram/_chatfullinfo.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# pylint: disable=redefined-builtin +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatFullInfo.""" +from datetime import datetime +from typing import TYPE_CHECKING, Optional, Sequence + +from telegram._birthdate import Birthdate +from telegram._chat import Chat +from telegram._chatlocation import ChatLocation +from telegram._chatpermissions import ChatPermissions +from telegram._files.chatphoto import ChatPhoto +from telegram._reaction import ReactionType +from telegram._utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import BusinessIntro, BusinessLocation, BusinessOpeningHours, Message + + +class ChatFullInfo(Chat): + """ + This object contains full information about a chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`~telegram.Chat.id` is equal. + + .. versionadded:: NEXT.VERSION + + Caution: + This class is a subclass of :class:`telegram.Chat` and inherits all attributes and methods + for backwards compatibility. In the future, this class will *NOT* inherit from + :class:`telegram.Chat`. + + .. seealso:: + All arguments and attributes can be found in :class:`telegram.Chat`. + + Args: + max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a + message in the chat. + + .. versionadded:: NEXT.VERSION + + Attributes: + max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a + message in the chat. + + .. versionadded:: NEXT.VERSION + """ + + __slots__ = ("max_reaction_count",) + + def __init__( + self, + id: int, + type: str, + accent_color_id: int, # API 7.3 made this argument required + max_reaction_count: int, # NEW arg in api 7.3 and is required + title: Optional[str] = None, + username: Optional[str] = None, + first_name: Optional[str] = None, + last_name: Optional[str] = None, + is_forum: Optional[bool] = None, + photo: Optional[ChatPhoto] = None, + active_usernames: Optional[Sequence[str]] = None, + birthdate: Optional[Birthdate] = None, + business_intro: Optional["BusinessIntro"] = None, + business_location: Optional["BusinessLocation"] = None, + business_opening_hours: Optional["BusinessOpeningHours"] = None, + personal_chat: Optional["Chat"] = None, + available_reactions: Optional[Sequence[ReactionType]] = None, + background_custom_emoji_id: Optional[str] = None, + profile_accent_color_id: Optional[int] = None, + profile_background_custom_emoji_id: Optional[str] = None, + emoji_status_custom_emoji_id: Optional[str] = None, + emoji_status_expiration_date: Optional[datetime] = None, + bio: Optional[str] = None, + has_private_forwards: Optional[bool] = None, + has_restricted_voice_and_video_messages: Optional[bool] = None, + join_to_send_messages: Optional[bool] = None, + join_by_request: Optional[bool] = None, + description: Optional[str] = None, + invite_link: Optional[str] = None, + pinned_message: Optional["Message"] = None, + permissions: Optional[ChatPermissions] = None, + slow_mode_delay: Optional[int] = None, + unrestrict_boost_count: Optional[int] = None, + message_auto_delete_time: Optional[int] = None, + has_aggressive_anti_spam_enabled: Optional[bool] = None, + has_hidden_members: Optional[bool] = None, + has_protected_content: Optional[bool] = None, + has_visible_history: Optional[bool] = None, + sticker_set_name: Optional[str] = None, + can_set_sticker_set: Optional[bool] = None, + custom_emoji_sticker_set_name: Optional[str] = None, + linked_chat_id: Optional[int] = None, + location: Optional[ChatLocation] = None, + *, + api_kwargs: Optional[JSONDict] = None, + ): + super().__init__( + id=id, + type=type, + title=title, + username=username, + first_name=first_name, + last_name=last_name, + photo=photo, + description=description, + invite_link=invite_link, + pinned_message=pinned_message, + permissions=permissions, + sticker_set_name=sticker_set_name, + can_set_sticker_set=can_set_sticker_set, + slow_mode_delay=slow_mode_delay, + bio=bio, + linked_chat_id=linked_chat_id, + location=location, + message_auto_delete_time=message_auto_delete_time, + has_private_forwards=has_private_forwards, + has_protected_content=has_protected_content, + join_to_send_messages=join_to_send_messages, + join_by_request=join_by_request, + has_restricted_voice_and_video_messages=has_restricted_voice_and_video_messages, + is_forum=is_forum, + active_usernames=active_usernames, + emoji_status_custom_emoji_id=emoji_status_custom_emoji_id, + emoji_status_expiration_date=emoji_status_expiration_date, + has_aggressive_anti_spam_enabled=has_aggressive_anti_spam_enabled, + has_hidden_members=has_hidden_members, + available_reactions=available_reactions, + accent_color_id=accent_color_id, + background_custom_emoji_id=background_custom_emoji_id, + profile_accent_color_id=profile_accent_color_id, + profile_background_custom_emoji_id=profile_background_custom_emoji_id, + has_visible_history=has_visible_history, + unrestrict_boost_count=unrestrict_boost_count, + custom_emoji_sticker_set_name=custom_emoji_sticker_set_name, + birthdate=birthdate, + personal_chat=personal_chat, + business_intro=business_intro, + business_location=business_location, + business_opening_hours=business_opening_hours, + api_kwargs=api_kwargs, + ) + + # Required and unique to this class- + with self._unfrozen(): + self.max_reaction_count = max_reaction_count + + self._freeze() diff --git a/telegram/constants.py b/telegram/constants.py index 8bf1f9eac54..e7ff6d03823 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -142,7 +142,7 @@ class _AccentColor(NamedTuple): #: :data:`telegram.__bot_api_version_info__`. #: #: .. versionadded:: 20.0 -BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=2) +BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=3) #: :obj:`str`: Telegram Bot API #: version supported by this version of `python-telegram-bot`. Also available as #: :data:`telegram.__bot_api_version__`. diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index 7b5649ebea3..f51d33f45b5 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -50,8 +50,8 @@ BotShortDescription, BusinessConnection, CallbackQuery, - Chat, ChatAdministratorRights, + ChatFullInfo, ChatInviteLink, ChatMember, ChatPermissions, @@ -113,7 +113,7 @@ ) from telegram.ext import BaseRateLimiter, Defaults -HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, Chat]) +HandledTypes = TypeVar("HandledTypes", bound=Union[Message, CallbackQuery, ChatFullInfo]) KT = TypeVar("KT", bound=ReplyMarkup) @@ -554,7 +554,7 @@ def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: self.callback_data_cache.process_message(message=obj) return obj # type: ignore[return-value] - if isinstance(obj, Chat) and obj.pinned_message: + if isinstance(obj, ChatFullInfo) and obj.pinned_message: self.callback_data_cache.process_message(obj.pinned_message) return obj @@ -853,7 +853,7 @@ async def get_chat( pool_timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: Optional[JSONDict] = None, rate_limit_args: Optional[RLARGS] = None, - ) -> Chat: + ) -> ChatFullInfo: # We override this method to call self._insert_callback_data result = await super().get_chat( chat_id=chat_id, diff --git a/tests/test_bot.py b/tests/test_bot.py index 34f25e6ce39..efc21b54bf8 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -43,6 +43,7 @@ CallbackQuery, Chat, ChatAdministratorRights, + ChatFullInfo, ChatPermissions, Dice, InlineKeyboardButton, @@ -2921,10 +2922,10 @@ async def test_leave_chat(self, bot): await bot.leave_chat(-123456) async def test_get_chat(self, bot, super_group_id): - chat = await bot.get_chat(super_group_id) - assert chat.type == "supergroup" - assert chat.title == f">>> telegram.Bot(test) @{bot.username}" - assert chat.id == int(super_group_id) + cfi = await bot.get_chat(super_group_id) + assert cfi.type == "supergroup" + assert cfi.title == f">>> telegram.Bot(test) @{bot.username}" + assert cfi.id == int(super_group_id) async def test_get_chat_administrators(self, bot, channel_id): admins = await bot.get_chat_administrators(channel_id) @@ -3900,9 +3901,9 @@ async def test_get_chat_arbitrary_callback_data(self, channel_id, cdc_bot): ) assert data == "callback_data" - chat = await bot.get_chat(channel_id) - assert chat.pinned_message == message - assert chat.pinned_message.reply_markup == reply_markup + cfi = await bot.get_chat(channel_id) + assert cfi.pinned_message == message + assert cfi.pinned_message.reply_markup == reply_markup assert await message.unpin() # (not placed in finally block since msg can be unbound) finally: bot.callback_data_cache.clear_callback_data() @@ -3915,11 +3916,11 @@ async def test_arbitrary_callback_data_get_chat_no_pinned_message( await bot.unpin_all_chat_messages(super_group_id) try: - chat = await bot.get_chat(super_group_id) + cfi = await bot.get_chat(super_group_id) - assert isinstance(chat, Chat) - assert int(chat.id) == int(super_group_id) - assert chat.pinned_message is None + assert isinstance(cfi, ChatFullInfo) + assert int(cfi.id) == int(super_group_id) + assert cfi.pinned_message is None finally: bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_queries() diff --git a/tests/test_chat.py b/tests/test_chat.py index 11ef38dda15..7af7a677ce0 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -16,7 +16,9 @@ # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. + import datetime +import warnings import pytest @@ -35,9 +37,11 @@ ReactionTypeEmoji, User, ) +from telegram._chat import _deprecated_attrs from telegram._utils.datetime import UTC, to_timestamp from telegram.constants import ChatAction, ChatType, ReactionEmoji from telegram.helpers import escape_markdown +from telegram.warnings import PTBDeprecationWarning from tests.auxil.bot_method_checks import ( check_defaults_handling, check_shortcut_call, @@ -84,6 +88,8 @@ def chat(bot): business_opening_hours=TestChatBase.business_opening_hours, birthdate=Birthdate(1, 1), personal_chat=TestChatBase.personal_chat, + first_name=TestChatBase.first_name, + last_name=TestChatBase.last_name, ) chat.set_bot(bot) chat._unfreeze() @@ -137,6 +143,8 @@ class TestChatBase: custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name" birthdate = Birthdate(1, 1) personal_chat = Chat(3, "private", "private") + first_name = "first" + last_name = "last" class TestChatWithoutRequest(TestChatBase): @@ -185,6 +193,8 @@ def test_de_json(self, bot): "custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name, "birthdate": self.birthdate.to_dict(), "personal_chat": self.personal_chat.to_dict(), + "first_name": self.first_name, + "last_name": self.last_name, } chat = Chat.de_json(json_dict, bot) @@ -230,6 +240,8 @@ def test_de_json(self, bot): assert chat.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name assert chat.birthdate == self.birthdate assert chat.personal_chat == self.personal_chat + assert chat.first_name == self.first_name + assert chat.last_name == self.last_name def test_de_json_localization(self, bot, raw_bot, tz_bot): json_dict = { @@ -251,6 +263,15 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): assert chat_bot_raw.emoji_status_expiration_date.tzinfo == UTC assert emoji_expire_offset_tz == emoji_expire_offset + def test_always_tuples_attributes(self): + chat = Chat( + id=123, + title="title", + type=Chat.PRIVATE, + ) + assert isinstance(chat.active_usernames, tuple) + assert chat.active_usernames == () + def test_to_dict(self, chat): chat_dict = chat.to_dict() @@ -300,15 +321,25 @@ def test_to_dict(self, chat): assert chat_dict["unrestrict_boost_count"] == chat.unrestrict_boost_count assert chat_dict["birthdate"] == chat.birthdate.to_dict() assert chat_dict["personal_chat"] == chat.personal_chat.to_dict() - - def test_always_tuples_attributes(self): - chat = Chat( - id=123, - title="title", - type=Chat.PRIVATE, - ) - assert isinstance(chat.active_usernames, tuple) - assert chat.active_usernames == () + assert chat_dict["first_name"] == chat.first_name + assert chat_dict["last_name"] == chat.last_name + + def test_deprecated_attributes(self, chat): + for depr_attr in _deprecated_attrs: + with pytest.warns(PTBDeprecationWarning, match="deprecated and will only be accessib"): + getattr(chat, depr_attr) + with warnings.catch_warnings(): # No warning should be raised + warnings.simplefilter("error") + chat.id + chat.first_name + + def test_deprecated_arguments(self): + for depr_attr in _deprecated_attrs: + with pytest.warns(PTBDeprecationWarning, match="deprecated and will only be availabl"): + Chat(1, "type", **{depr_attr: "1"}) + with warnings.catch_warnings(): # No warning should be raised + warnings.simplefilter("error") + Chat(1, "type", first_name="first_name") def test_enum_init(self): chat = Chat(id=1, type="foo") @@ -348,10 +379,7 @@ def test_full_name(self): assert chat.full_name == "first\u2022name last\u2022name" chat = Chat(id=1, type=Chat.PRIVATE, first_name="first\u2022name") assert chat.full_name == "first\u2022name" - chat = Chat( - id=1, - type=Chat.PRIVATE, - ) + chat = Chat(id=1, type=Chat.PRIVATE) assert chat.full_name is None def test_effective_name(self): @@ -588,7 +616,7 @@ async def make_assertion(*_, **kwargs): async def test_set_permissions(self, monkeypatch, chat): async def make_assertion(*_, **kwargs): chat_id = kwargs["chat_id"] == chat.id - permissions = kwargs["permissions"] == self.permissions + permissions = kwargs["permissions"] == ChatPermissions.all_permissions() return chat_id and permissions assert check_shortcut_signature( @@ -600,7 +628,7 @@ async def make_assertion(*_, **kwargs): assert await check_defaults_handling(chat.set_permissions, chat.get_bot()) monkeypatch.setattr(chat.get_bot(), "set_chat_permissions", make_assertion) - assert await chat.set_permissions(permissions=self.permissions) + assert await chat.set_permissions(permissions=ChatPermissions.all_permissions()) async def test_set_administrator_custom_title(self, monkeypatch, chat): async def make_assertion(*_, **kwargs): diff --git a/tests/test_chatfullinfo.py b/tests/test_chatfullinfo.py new file mode 100644 index 00000000000..f42642e4ed2 --- /dev/null +++ b/tests/test_chatfullinfo.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +import datetime +import warnings + +import pytest + +from telegram import ( + Birthdate, + BusinessIntro, + BusinessLocation, + BusinessOpeningHours, + BusinessOpeningHoursInterval, + Chat, + ChatFullInfo, + ChatLocation, + ChatPermissions, + Location, + ReactionTypeCustomEmoji, + ReactionTypeEmoji, +) +from telegram._chat import _deprecated_attrs +from telegram._utils.datetime import UTC, to_timestamp +from telegram.constants import ReactionEmoji +from tests.auxil.slots import mro_slots + + +@pytest.fixture(scope="module") +def chat_full_info(bot): + chat = ChatFullInfo( + TestChatInfoBase.id_, + type=TestChatInfoBase.type_, + accent_color_id=TestChatInfoBase.accent_color_id, + max_reaction_count=TestChatInfoBase.max_reaction_count, + title=TestChatInfoBase.title, + username=TestChatInfoBase.username, + sticker_set_name=TestChatInfoBase.sticker_set_name, + can_set_sticker_set=TestChatInfoBase.can_set_sticker_set, + permissions=TestChatInfoBase.permissions, + slow_mode_delay=TestChatInfoBase.slow_mode_delay, + bio=TestChatInfoBase.bio, + linked_chat_id=TestChatInfoBase.linked_chat_id, + location=TestChatInfoBase.location, + has_private_forwards=True, + has_protected_content=True, + has_visible_history=True, + join_to_send_messages=True, + join_by_request=True, + has_restricted_voice_and_video_messages=True, + is_forum=True, + active_usernames=TestChatInfoBase.active_usernames, + emoji_status_custom_emoji_id=TestChatInfoBase.emoji_status_custom_emoji_id, + emoji_status_expiration_date=TestChatInfoBase.emoji_status_expiration_date, + has_aggressive_anti_spam_enabled=TestChatInfoBase.has_aggressive_anti_spam_enabled, + has_hidden_members=TestChatInfoBase.has_hidden_members, + available_reactions=TestChatInfoBase.available_reactions, + background_custom_emoji_id=TestChatInfoBase.background_custom_emoji_id, + profile_accent_color_id=TestChatInfoBase.profile_accent_color_id, + profile_background_custom_emoji_id=TestChatInfoBase.profile_background_custom_emoji_id, + unrestrict_boost_count=TestChatInfoBase.unrestrict_boost_count, + custom_emoji_sticker_set_name=TestChatInfoBase.custom_emoji_sticker_set_name, + business_intro=TestChatInfoBase.business_intro, + business_location=TestChatInfoBase.business_location, + business_opening_hours=TestChatInfoBase.business_opening_hours, + birthdate=Birthdate(1, 1), + personal_chat=TestChatInfoBase.personal_chat, + ) + chat.set_bot(bot) + chat._unfreeze() + return chat + + +class TestChatInfoBase: + id_ = -28767330 + max_reaction_count = 2 + title = "ToledosPalaceBot - Group" + type_ = "group" + username = "username" + all_members_are_administrators = False + sticker_set_name = "stickers" + can_set_sticker_set = False + permissions = ChatPermissions( + can_send_messages=True, + can_change_info=False, + can_invite_users=True, + ) + slow_mode_delay = 30 + bio = "I'm a Barbie Girl in a Barbie World" + linked_chat_id = 11880 + location = ChatLocation(Location(123, 456), "Barbie World") + has_protected_content = True + has_visible_history = True + has_private_forwards = True + join_to_send_messages = True + join_by_request = True + has_restricted_voice_and_video_messages = True + is_forum = True + active_usernames = ["These", "Are", "Usernames!"] + emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID" + emoji_status_expiration_date = datetime.datetime.now(tz=UTC).replace(microsecond=0) + has_aggressive_anti_spam_enabled = True + has_hidden_members = True + available_reactions = [ + ReactionTypeEmoji(ReactionEmoji.THUMBS_DOWN), + ReactionTypeCustomEmoji("custom_emoji_id"), + ] + business_intro = BusinessIntro("Title", "Description", None) + business_location = BusinessLocation("Address", Location(123, 456)) + business_opening_hours = BusinessOpeningHours( + "Country/City", + [BusinessOpeningHoursInterval(opening, opening + 60) for opening in (0, 24 * 60)], + ) + accent_color_id = 1 + background_custom_emoji_id = "background_custom_emoji_id" + profile_accent_color_id = 2 + profile_background_custom_emoji_id = "profile_background_custom_emoji_id" + unrestrict_boost_count = 100 + custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name" + birthdate = Birthdate(1, 1) + personal_chat = Chat(3, "private", "private") + + +class TestChatWithoutRequest(TestChatInfoBase): + def test_slot_behaviour(self, chat_full_info): + cfi = chat_full_info + for attr in cfi.__slots__: + assert getattr(cfi, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(cfi)) == len(set(mro_slots(cfi))), "duplicate slot" + + def test_de_json(self, bot): + json_dict = { + "id": self.id_, + "title": self.title, + "type": self.type_, + "accent_color_id": self.accent_color_id, + "max_reaction_count": self.max_reaction_count, + "username": self.username, + "all_members_are_administrators": self.all_members_are_administrators, + "sticker_set_name": self.sticker_set_name, + "can_set_sticker_set": self.can_set_sticker_set, + "permissions": self.permissions.to_dict(), + "slow_mode_delay": self.slow_mode_delay, + "bio": self.bio, + "business_intro": self.business_intro.to_dict(), + "business_location": self.business_location.to_dict(), + "business_opening_hours": self.business_opening_hours.to_dict(), + "has_protected_content": self.has_protected_content, + "has_visible_history": self.has_visible_history, + "has_private_forwards": self.has_private_forwards, + "linked_chat_id": self.linked_chat_id, + "location": self.location.to_dict(), + "join_to_send_messages": self.join_to_send_messages, + "join_by_request": self.join_by_request, + "has_restricted_voice_and_video_messages": ( + self.has_restricted_voice_and_video_messages + ), + "is_forum": self.is_forum, + "active_usernames": self.active_usernames, + "emoji_status_custom_emoji_id": self.emoji_status_custom_emoji_id, + "emoji_status_expiration_date": to_timestamp(self.emoji_status_expiration_date), + "has_aggressive_anti_spam_enabled": self.has_aggressive_anti_spam_enabled, + "has_hidden_members": self.has_hidden_members, + "available_reactions": [reaction.to_dict() for reaction in self.available_reactions], + "background_custom_emoji_id": self.background_custom_emoji_id, + "profile_accent_color_id": self.profile_accent_color_id, + "profile_background_custom_emoji_id": self.profile_background_custom_emoji_id, + "unrestrict_boost_count": self.unrestrict_boost_count, + "custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name, + "birthdate": self.birthdate.to_dict(), + "personal_chat": self.personal_chat.to_dict(), + } + cfi = ChatFullInfo.de_json(json_dict, bot) + assert cfi.max_reaction_count == self.max_reaction_count + + def test_to_dict(self, chat_full_info): + cfi = chat_full_info + cfi_dict = cfi.to_dict() + + assert isinstance(cfi_dict, dict) + assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count + + def test_attr_access_no_warning(self, chat_full_info): + cfi = chat_full_info + for depr_attr in _deprecated_attrs: + with warnings.catch_warnings(): # No warning should be raised + warnings.simplefilter("error") + getattr(cfi, depr_attr) + + def test_cfi_creation_no_warning(self, chat_full_info): + cfi = chat_full_info + with warnings.catch_warnings(): + dict = cfi.to_dict() + ChatFullInfo(**dict) diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index 89892741bd4..e6dba1dae47 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -170,6 +170,43 @@ def ignored_param_requirements(object_name: str) -> set[str]: "create_new_sticker_set": {"sticker_format"}, # removed by bot api 7.2 "StickerSet": {"is_animated", "is_video"}, # removed by bot api 7.2 "UsersShared": {"user_ids", "users"}, # removed/added by bot api 7.2 + "Chat": { + "background_custom_emoji_id", + "has_private_forwards", + "invite_link", + "has_hidden_members", + "permissions", + "custom_emoji_sticker_set_name", + "pinned_message", + "birthdate", + "emoji_status_custom_emoji_id", + "join_by_request", + "business_intro", + "business_opening_hours", + "description", + "has_protected_content", + "available_reactions", + "has_aggressive_anti_spam_enabled", + "slow_mode_delay", + "profile_background_custom_emoji_id", + "linked_chat_id", + "bio", + "accent_color_id", + "unrestrict_boost_count", + "can_set_sticker_set", + "has_restricted_voice_and_video_messages", + "emoji_status_expiration_date", + "photo", + "join_to_send_messages", + "message_auto_delete_time", + "location", + "active_usernames", + "profile_accent_color_id", + "sticker_set_name", + "has_visible_history", + "business_location", + "personal_chat", + }, # removed by bot api 7.3 } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy