Fix Signatures and Improve test_official (#2643)

This commit is contained in:
Harshil 2021-08-29 21:47:06 +05:30 committed by Hinrich Mahler
parent 641f931f19
commit 5c500fb6fd
23 changed files with 543 additions and 722 deletions

View file

@ -1850,7 +1850,7 @@ class Bot(TelegramObject):
:obj:`title` and :obj:`address` and optionally :obj:`foursquare_id` and
:obj:`foursquare_type` or optionally :obj:`google_place_id` and
:obj:`google_place_type`.
* Foursquare details and Google Pace details are mutually exclusive. However, this
* Foursquare details and Google Place details are mutually exclusive. However, this
behaviour is undocumented and might be changed by Telegram.
Args:
@ -2850,10 +2850,10 @@ class Bot(TelegramObject):
@log
def edit_message_media(
self,
media: 'InputMedia',
chat_id: Union[str, int] = None,
message_id: int = None,
inline_message_id: int = None,
media: 'InputMedia' = None,
reply_markup: InlineKeyboardMarkup = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
@ -2866,6 +2866,8 @@ class Bot(TelegramObject):
``file_id`` or specify a URL.
Args:
media (:class:`telegram.InputMedia`): An object for a new media content
of the message.
chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not
specified. Unique identifier for the target chat or username of the target channel
(in the format ``@channelusername``).
@ -2873,8 +2875,6 @@ class Bot(TelegramObject):
Identifier of the message to edit.
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
specified. Identifier of the inline message.
media (:class:`telegram.InputMedia`): An object for a new media content
of the message.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized
object for an inline keyboard.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
@ -2884,7 +2884,7 @@ class Bot(TelegramObject):
Telegram API.
Returns:
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
:class:`telegram.Message`: On success, if edited message is not an inline message, the
edited Message is returned, otherwise :obj:`True` is returned.
Raises:
@ -3061,7 +3061,7 @@ class Bot(TelegramObject):
@log
def set_webhook(
self,
url: str = None,
url: str,
certificate: FileInput = None,
timeout: ODVInput[float] = DEFAULT_NONE,
max_connections: int = 40,
@ -3132,10 +3132,8 @@ class Bot(TelegramObject):
.. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks
"""
data: JSONDict = {}
data: JSONDict = {'url': url}
if url is not None:
data['url'] = url
if certificate:
data['certificate'] = parse_file_input(certificate)
if max_connections is not None:
@ -4553,7 +4551,7 @@ class Bot(TelegramObject):
def set_chat_description(
self,
chat_id: Union[str, int],
description: str,
description: str = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
@ -4565,7 +4563,7 @@ class Bot(TelegramObject):
Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target channel (in the format ``@channelusername``).
description (:obj:`str`): New chat description, 0-255 characters.
description (:obj:`str`, optional): New chat description, 0-255 characters.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
@ -4579,7 +4577,10 @@ class Bot(TelegramObject):
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {'chat_id': chat_id, 'description': description}
data: JSONDict = {'chat_id': chat_id}
if description is not None:
data['description'] = description
result = self._post('setChatDescription', data, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -319,7 +319,7 @@ class CallbackQuery(TelegramObject):
def edit_message_media(
self,
media: 'InputMedia' = None,
media: 'InputMedia',
reply_markup: 'InlineKeyboardMarkup' = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
@ -337,7 +337,7 @@ class CallbackQuery(TelegramObject):
:meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`.
Returns:
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
:class:`telegram.Message`: On success, if edited message is not an inline message, the
edited Message is returned, otherwise :obj:`True` is returned.
"""

View file

@ -32,14 +32,23 @@ class ChatInviteLink(TelegramObject):
"""This object represents an invite link for a chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`is_primary` and
:attr:`is_revoked` are equal.
considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`creates_join_request`,
:attr:`is_primary` and :attr:`is_revoked` are equal.
.. versionadded:: 13.4
.. versionchanged:: 14.0
* The argument & attribute :attr:`creates_join_request` is now required to comply with the
Bot API.
* Comparing objects of this class now also takes :attr:`creates_join_request` into account.
Args:
invite_link (:obj:`str`): The invite link.
creator (:class:`telegram.User`): Creator of the link.
creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via
the link need to be approved by chat administrators.
.. versionadded:: 13.8
is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or
@ -48,10 +57,6 @@ class ChatInviteLink(TelegramObject):
chat simultaneously after joining the chat via this invite link; 1-99999.
name (:obj:`str`, optional): Invite link name.
.. versionadded:: 13.8
creates_join_request (:obj:`bool`, optional): :obj:`True`, if users joining the chat via
the link need to be approved by chat administrators.
.. versionadded:: 13.8
pending_join_request_count (:obj:`int`, optional): Number of pending join requests
created using this link.
@ -62,6 +67,10 @@ class ChatInviteLink(TelegramObject):
invite_link (:obj:`str`): The invite link. If the link was created by another chat
administrator, then the second part of the link will be replaced with ``''``.
creator (:class:`telegram.User`): Creator of the link.
creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via
the link need to be approved by chat administrators.
.. versionadded:: 13.8
is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or
@ -70,10 +79,6 @@ class ChatInviteLink(TelegramObject):
of the chat simultaneously after joining the chat via this invite link; 1-99999.
name (:obj:`str`): Optional. Invite link name.
.. versionadded:: 13.8
creates_join_request (:obj:`bool`): Optional. :obj:`True`, if users joining the chat via
the link need to be approved by chat administrators.
.. versionadded:: 13.8
pending_join_request_count (:obj:`int`): Optional. Number of pending join requests
created using this link.
@ -98,18 +103,19 @@ class ChatInviteLink(TelegramObject):
self,
invite_link: str,
creator: User,
creates_join_request: bool,
is_primary: bool,
is_revoked: bool,
expire_date: datetime.datetime = None,
member_limit: int = None,
name: str = None,
creates_join_request: bool = None,
pending_join_request_count: int = None,
**_kwargs: Any,
):
# Required
self.invite_link = invite_link
self.creator = creator
self.creates_join_request = creates_join_request
self.is_primary = is_primary
self.is_revoked = is_revoked
@ -117,11 +123,16 @@ class ChatInviteLink(TelegramObject):
self.expire_date = expire_date
self.member_limit = int(member_limit) if member_limit is not None else None
self.name = name
self.creates_join_request = creates_join_request
self.pending_join_request_count = (
int(pending_join_request_count) if pending_join_request_count is not None else None
)
self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked)
self._id_attrs = (
self.invite_link,
self.creates_join_request,
self.creator,
self.is_primary,
self.is_revoked,
)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']:

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 Telegram ChatMember."""
import datetime
from typing import TYPE_CHECKING, Any, Optional, ClassVar, Dict, Type
from typing import TYPE_CHECKING, Optional, ClassVar, Dict, Type
from telegram import TelegramObject, User, constants
from telegram.utils.helpers import from_timestamp, to_timestamp
@ -42,10 +42,10 @@ class ChatMember(TelegramObject):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`user` and :attr:`status` are equal.
Note:
As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses
.. versionchanged:: 14.0
As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses
listed above and is no longer returned directly by :meth:`~telegram.Bot.get_chat`.
Therefore, most of the arguments and attributes were deprecated and you should no longer
Therefore, most of the arguments and attributes were removed and you should no longer
use :class:`ChatMember` directly.
Args:
@ -54,240 +54,14 @@ class ChatMember(TelegramObject):
:attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.CREATOR`,
:attr:`~telegram.ChatMember.KICKED`, :attr:`~telegram.ChatMember.LEFT`,
:attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`.
custom_title (:obj:`str`, optional): Owner and administrators only.
Custom title for this user.
.. deprecated:: 13.7
is_anonymous (:obj:`bool`, optional): Owner and administrators only. :obj:`True`, if the
user's presence in the chat is hidden.
.. deprecated:: 13.7
until_date (:class:`datetime.datetime`, optional): Restricted and kicked only. Date when
restrictions will be lifted for this user.
.. deprecated:: 13.7
can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is
allowed to edit administrator privileges of that user.
.. deprecated:: 13.7
can_manage_chat (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can access the chat event log, chat statistics, message statistics in
channels, see channel members, see anonymous administrators in supergroups and ignore
slow mode. Implied by any other administrator privilege.
.. versionadded:: 13.4
.. deprecated:: 13.7
can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can manage voice chats.
.. versionadded:: 13.4
.. deprecated:: 13.7
can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
if the user can change the chat title, photo and other settings.
.. deprecated:: 13.7
can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can post in the channel, channels only.
.. deprecated:: 13.7
can_edit_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can edit messages of other users and can pin messages; channels only.
.. deprecated:: 13.7
can_delete_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can delete messages of other users.
.. deprecated:: 13.7
can_invite_users (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
if the user can invite new users to the chat.
.. deprecated:: 13.7
can_restrict_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can restrict, ban or unban chat members.
.. deprecated:: 13.7
can_pin_messages (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
if the user can pin messages, groups and supergroups only.
.. deprecated:: 13.7
can_promote_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
administrator can add new administrators with a subset of his own privileges or demote
administrators that he has promoted, directly or indirectly (promoted by administrators
that were appointed by the user).
.. deprecated:: 13.7
is_member (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is a member of
the chat at the moment of the request.
.. deprecated:: 13.7
can_send_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user can
send text messages, contacts, locations and venues.
.. deprecated:: 13.7
can_send_media_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user
can send audios, documents, photos, videos, video notes and voice notes.
.. deprecated:: 13.7
can_send_polls (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is
allowed to send polls.
.. deprecated:: 13.7
can_send_other_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user
can send animations, games, stickers and use inline bots.
.. deprecated:: 13.7
can_add_web_page_previews (:obj:`bool`, optional): Restricted only. :obj:`True`, if user
may add web page previews to his messages.
.. deprecated:: 13.7
Attributes:
user (:class:`telegram.User`): Information about the user.
status (:obj:`str`): The member's status in the chat.
custom_title (:obj:`str`): Optional. Custom title for owner and administrators.
.. deprecated:: 13.7
is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's presence in the chat is
hidden.
.. deprecated:: 13.7
until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted
for this user.
.. deprecated:: 13.7
can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
privileges of that user.
.. deprecated:: 13.7
can_manage_chat (:obj:`bool`): Optional. If the administrator can access the chat event
log, chat statistics, message statistics in channels, see channel members, see
anonymous administrators in supergroups and ignore slow mode.
.. versionadded:: 13.4
.. deprecated:: 13.7
can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage
voice chats.
.. versionadded:: 13.4
.. deprecated:: 13.7
can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and
other settings.
.. deprecated:: 13.7
can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel.
.. deprecated:: 13.7
can_edit_messages (:obj:`bool`): Optional. If the administrator can edit messages of other
users.
.. deprecated:: 13.7
can_delete_messages (:obj:`bool`): Optional. If the administrator can delete messages of
other users.
.. deprecated:: 13.7
can_invite_users (:obj:`bool`): Optional. If the user can invite new users to the chat.
.. deprecated:: 13.7
can_restrict_members (:obj:`bool`): Optional. If the administrator can restrict, ban or
unban chat members.
.. deprecated:: 13.7
can_pin_messages (:obj:`bool`): Optional. If the user can pin messages.
.. deprecated:: 13.7
can_promote_members (:obj:`bool`): Optional. If the administrator can add new
administrators.
.. deprecated:: 13.7
is_member (:obj:`bool`): Optional. Restricted only. :obj:`True`, if the user is a member of
the chat at the moment of the request.
.. deprecated:: 13.7
can_send_messages (:obj:`bool`): Optional. If the user can send text messages, contacts,
locations and venues.
.. deprecated:: 13.7
can_send_media_messages (:obj:`bool`): Optional. If the user can send media messages,
implies can_send_messages.
.. deprecated:: 13.7
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
send polls.
.. deprecated:: 13.7
can_send_other_messages (:obj:`bool`): Optional. If the user can send animations, games,
stickers and use inline bots, implies can_send_media_messages.
.. deprecated:: 13.7
can_add_web_page_previews (:obj:`bool`): Optional. If user may add web page previews to his
messages, implies can_send_media_messages
.. deprecated:: 13.7
"""
__slots__ = (
'is_member',
'can_restrict_members',
'can_delete_messages',
'custom_title',
'can_be_edited',
'can_post_messages',
'can_send_messages',
'can_edit_messages',
'can_send_media_messages',
'is_anonymous',
'can_add_web_page_previews',
'can_send_other_messages',
'can_invite_users',
'can_send_polls',
'user',
'can_promote_members',
'status',
'can_change_info',
'can_pin_messages',
'can_manage_chat',
'can_manage_voice_chats',
'until_date',
)
__slots__ = ('user', 'status')
ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR
""":const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`"""
@ -302,58 +76,11 @@ class ChatMember(TelegramObject):
RESTRICTED: ClassVar[str] = constants.CHATMEMBER_RESTRICTED
""":const:`telegram.constants.CHATMEMBER_RESTRICTED`"""
def __init__(
self,
user: User,
status: str,
until_date: datetime.datetime = None,
can_be_edited: bool = None,
can_change_info: bool = None,
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_delete_messages: bool = None,
can_invite_users: bool = None,
can_restrict_members: bool = None,
can_pin_messages: bool = None,
can_promote_members: bool = None,
can_send_messages: bool = None,
can_send_media_messages: bool = None,
can_send_polls: bool = None,
can_send_other_messages: bool = None,
can_add_web_page_previews: bool = None,
is_member: bool = None,
custom_title: str = None,
is_anonymous: bool = None,
can_manage_chat: bool = None,
can_manage_voice_chats: bool = None,
**_kwargs: Any,
):
# Required
def __init__(self, user: User, status: str, **_kwargs: object):
# Required by all subclasses
self.user = user
self.status = status
# Optionals
self.custom_title = custom_title
self.is_anonymous = is_anonymous
self.until_date = until_date
self.can_be_edited = can_be_edited
self.can_change_info = can_change_info
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_delete_messages = can_delete_messages
self.can_invite_users = can_invite_users
self.can_restrict_members = can_restrict_members
self.can_pin_messages = can_pin_messages
self.can_promote_members = can_promote_members
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.is_member = is_member
self.can_manage_chat = can_manage_chat
self.can_manage_voice_chats = can_manage_voice_chats
self._id_attrs = (self.user, self.status)
@classmethod
@ -384,7 +111,8 @@ class ChatMember(TelegramObject):
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data['until_date'] = to_timestamp(self.until_date)
if data.get('until_date', False):
data['until_date'] = to_timestamp(data['until_date'])
return data
@ -398,35 +126,32 @@ class ChatMemberOwner(ChatMember):
Args:
user (:class:`telegram.User`): Information about the user.
custom_title (:obj:`str`, optional): Custom title for this user.
is_anonymous (:obj:`bool`, optional): :obj:`True`, if the
is_anonymous (:obj:`bool`): :obj:`True`, if the
user's presence in the chat is hidden.
custom_title (:obj:`str`, optional): Custom title for this user.
Attributes:
status (:obj:`str`): The member's status in the chat,
always :attr:`telegram.ChatMember.CREATOR`.
user (:class:`telegram.User`): Information about the user.
is_anonymous (:obj:`bool`): :obj:`True`, if the user's
presence in the chat is hidden.
custom_title (:obj:`str`): Optional. Custom title for
this user.
is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's
presence in the chat is hidden.
"""
__slots__ = ()
__slots__ = ('is_anonymous', 'custom_title')
def __init__(
self,
user: User,
is_anonymous: bool,
custom_title: str = None,
is_anonymous: bool = None,
**_kwargs: Any,
**_kwargs: object,
):
super().__init__(
status=ChatMember.CREATOR,
user=user,
custom_title=custom_title,
is_anonymous=is_anonymous,
)
super().__init__(status=ChatMember.CREATOR, user=user)
self.is_anonymous = is_anonymous
self.custom_title = custom_title
class ChatMemberAdministrator(ChatMember):
@ -437,110 +162,121 @@ class ChatMemberAdministrator(ChatMember):
Args:
user (:class:`telegram.User`): Information about the user.
can_be_edited (:obj:`bool`, optional): :obj:`True`, if the bot
can_be_edited (:obj:`bool`): :obj:`True`, if the bot
is allowed to edit administrator privileges of that user.
custom_title (:obj:`str`, optional): Custom title for this user.
is_anonymous (:obj:`bool`, optional): :obj:`True`, if the user's
is_anonymous (:obj:`bool`): :obj:`True`, if the user's
presence in the chat is hidden.
can_manage_chat (:obj:`bool`, optional): :obj:`True`, if the administrator
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator
can access the chat event log, chat statistics, message statistics in
channels, see channel members, see anonymous administrators in supergroups
and ignore slow mode. Implied by any other administrator privilege.
can_delete_messages (:obj:`bool`): :obj:`True`, if the
administrator can delete messages of other users.
can_manage_voice_chats (:obj:`bool`): :obj:`True`, if the
administrator can manage voice chats.
can_restrict_members (:obj:`bool`): :obj:`True`, if the
administrator can restrict, ban or unban chat members.
can_promote_members (:obj:`bool`): :obj:`True`, if the administrator
can add new administrators with a subset of his own privileges or demote
administrators that he has promoted, directly or indirectly (promoted by
administrators that were appointed by the user).
can_change_info (:obj:`bool`): :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
new users to the chat.
can_post_messages (:obj:`bool`, optional): :obj:`True`, if the
administrator can post in the channel, channels only.
can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the
administrator can edit messages of other users and can pin
messages; channels only.
can_delete_messages (:obj:`bool`, optional): :obj:`True`, if the
administrator can delete messages of other users.
can_manage_voice_chats (:obj:`bool`, optional): :obj:`True`, if the
administrator can manage voice chats.
can_restrict_members (:obj:`bool`, optional): :obj:`True`, if the
administrator can restrict, ban or unban chat members.
can_promote_members (:obj:`bool`, optional): :obj:`True`, if the administrator
can add new administrators with a subset of his own privileges or demote
administrators that he has promoted, directly or indirectly (promoted by
administrators that were appointed by the user).
can_change_info (:obj:`bool`, optional): :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user can invite
new users to the chat.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
custom_title (:obj:`str`, optional): Custom title for this user.
Attributes:
status (:obj:`str`): The member's status in the chat,
always :attr:`telegram.ChatMember.ADMINISTRATOR`.
user (:class:`telegram.User`): Information about the user.
can_be_edited (:obj:`bool`): Optional. :obj:`True`, if the bot
can_be_edited (:obj:`bool`): :obj:`True`, if the bot
is allowed to edit administrator privileges of that user.
custom_title (:obj:`str`): Optional. Custom title for this user.
is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's
is_anonymous (:obj:`bool`): :obj:`True`, if the user's
presence in the chat is hidden.
can_manage_chat (:obj:`bool`): Optional. :obj:`True`, if the administrator
can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator
can access the chat event log, chat statistics, message statistics in
channels, see channel members, see anonymous administrators in supergroups
and ignore slow mode. Implied by any other administrator privilege.
can_delete_messages (:obj:`bool`): :obj:`True`, if the
administrator can delete messages of other users.
can_manage_voice_chats (:obj:`bool`): :obj:`True`, if the
administrator can manage voice chats.
can_restrict_members (:obj:`bool`): :obj:`True`, if the
administrator can restrict, ban or unban chat members.
can_promote_members (:obj:`bool`): :obj:`True`, if the administrator
can add new administrators with a subset of his own privileges or demote
administrators that he has promoted, directly or indirectly (promoted by
administrators that were appointed by the user).
can_change_info (:obj:`bool`): :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
new users to the chat.
can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the
administrator can post in the channel, channels only.
can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the
administrator can edit messages of other users and can pin
messages; channels only.
can_delete_messages (:obj:`bool`): Optional. :obj:`True`, if the
administrator can delete messages of other users.
can_manage_voice_chats (:obj:`bool`): Optional. :obj:`True`, if the
administrator can manage voice chats.
can_restrict_members (:obj:`bool`): Optional. :obj:`True`, if the
administrator can restrict, ban or unban chat members.
can_promote_members (:obj:`bool`): Optional. :obj:`True`, if the administrator
can add new administrators with a subset of his own privileges or demote
administrators that he has promoted, directly or indirectly (promoted by
administrators that were appointed by the user).
can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user can invite
new users to the chat.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
custom_title (:obj:`str`): Optional. Custom title for this user.
"""
__slots__ = ()
__slots__ = (
'can_be_edited',
'is_anonymous',
'can_manage_chat',
'can_delete_messages',
'can_manage_voice_chats',
'can_restrict_members',
'can_promote_members',
'can_change_info',
'can_invite_users',
'can_post_messages',
'can_edit_messages',
'can_pin_messages',
'custom_title',
)
def __init__(
self,
user: User,
can_be_edited: bool = None,
custom_title: str = None,
is_anonymous: bool = None,
can_manage_chat: bool = None,
can_be_edited: bool,
is_anonymous: bool,
can_manage_chat: bool,
can_delete_messages: bool,
can_manage_voice_chats: bool,
can_restrict_members: bool,
can_promote_members: bool,
can_change_info: bool,
can_invite_users: bool,
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_delete_messages: bool = None,
can_manage_voice_chats: bool = None,
can_restrict_members: bool = None,
can_promote_members: bool = None,
can_change_info: bool = None,
can_invite_users: bool = None,
can_pin_messages: bool = None,
**_kwargs: Any,
custom_title: str = None,
**_kwargs: object,
):
super().__init__(
status=ChatMember.ADMINISTRATOR,
user=user,
can_be_edited=can_be_edited,
custom_title=custom_title,
is_anonymous=is_anonymous,
can_manage_chat=can_manage_chat,
can_post_messages=can_post_messages,
can_edit_messages=can_edit_messages,
can_delete_messages=can_delete_messages,
can_manage_voice_chats=can_manage_voice_chats,
can_restrict_members=can_restrict_members,
can_promote_members=can_promote_members,
can_change_info=can_change_info,
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages,
)
super().__init__(status=ChatMember.ADMINISTRATOR, user=user)
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_voice_chats = can_manage_voice_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.custom_title = custom_title
class ChatMemberMember(ChatMember):
@ -562,7 +298,7 @@ class ChatMemberMember(ChatMember):
__slots__ = ()
def __init__(self, user: User, **_kwargs: Any):
def __init__(self, user: User, **_kwargs: object):
super().__init__(status=ChatMember.MEMBER, user=user)
@ -575,85 +311,93 @@ class ChatMemberRestricted(ChatMember):
Args:
user (:class:`telegram.User`): Information about the user.
is_member (:obj:`bool`, optional): :obj:`True`, if the user is a
is_member (:obj:`bool`): :obj:`True`, if the user is a
member of the chat at the moment of the request.
can_change_info (:obj:`bool`, optional): :obj:`True`, if the user can change
can_change_info (:obj:`bool`): :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user can invite
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
new users to the chat.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send text messages, contacts, locations and venues.
can_send_media_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
can_send_media_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send audios, documents, photos, videos, video notes and voice notes.
can_send_polls (:obj:`bool`, optional): :obj:`True`, if the user is allowed
can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed
to send polls.
can_send_other_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send animations, games, stickers and use inline bots.
can_add_web_page_previews (:obj:`bool`, optional): :obj:`True`, if the user is
can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
allowed to add web page previews to their messages.
until_date (:class:`datetime.datetime`, optional): Date when restrictions
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
Attributes:
status (:obj:`str`): The member's status in the chat,
always :attr:`telegram.ChatMember.RESTRICTED`.
user (:class:`telegram.User`): Information about the user.
is_member (:obj:`bool`): Optional. :obj:`True`, if the user is a
is_member (:obj:`bool`): :obj:`True`, if the user is a
member of the chat at the moment of the request.
can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user can change
can_change_info (:obj:`bool`): :obj:`True`, if the user can change
the chat title, photo and other settings.
can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user can invite
can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
new users to the chat.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send text messages, contacts, locations and venues.
can_send_media_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
can_send_media_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send audios, documents, photos, videos, video notes and voice notes.
can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed
to send polls.
can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed
to send animations, games, stickers and use inline bots.
can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is
can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
allowed to add web page previews to their messages.
until_date (:class:`datetime.datetime`): Optional. Date when restrictions
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
"""
__slots__ = ()
__slots__ = (
'is_member',
'can_change_info',
'can_invite_users',
'can_pin_messages',
'can_send_messages',
'can_send_media_messages',
'can_send_polls',
'can_send_other_messages',
'can_add_web_page_previews',
'until_date',
)
def __init__(
self,
user: User,
is_member: bool = None,
can_change_info: bool = None,
can_invite_users: bool = None,
can_pin_messages: bool = None,
can_send_messages: bool = None,
can_send_media_messages: bool = None,
can_send_polls: bool = None,
can_send_other_messages: bool = None,
can_add_web_page_previews: bool = None,
until_date: datetime.datetime = None,
**_kwargs: Any,
is_member: bool,
can_change_info: bool,
can_invite_users: bool,
can_pin_messages: bool,
can_send_messages: bool,
can_send_media_messages: bool,
can_send_polls: bool,
can_send_other_messages: bool,
can_add_web_page_previews: bool,
until_date: datetime.datetime,
**_kwargs: object,
):
super().__init__(
status=ChatMember.RESTRICTED,
user=user,
is_member=is_member,
can_change_info=can_change_info,
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages,
can_send_messages=can_send_messages,
can_send_media_messages=can_send_media_messages,
can_send_polls=can_send_polls,
can_send_other_messages=can_send_other_messages,
can_add_web_page_previews=can_add_web_page_previews,
until_date=until_date,
)
super().__init__(status=ChatMember.RESTRICTED, user=user)
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.until_date = until_date
class ChatMemberLeft(ChatMember):
@ -674,7 +418,7 @@ class ChatMemberLeft(ChatMember):
__slots__ = ()
def __init__(self, user: User, **_kwargs: Any):
def __init__(self, user: User, **_kwargs: object):
super().__init__(status=ChatMember.LEFT, user=user)
@ -687,28 +431,20 @@ class ChatMemberBanned(ChatMember):
Args:
user (:class:`telegram.User`): Information about the user.
until_date (:class:`datetime.datetime`, optional): Date when restrictions
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
Attributes:
status (:obj:`str`): The member's status in the chat,
always :attr:`telegram.ChatMember.KICKED`.
user (:class:`telegram.User`): Information about the user.
until_date (:class:`datetime.datetime`): Optional. Date when restrictions
until_date (:class:`datetime.datetime`): Date when restrictions
will be lifted for this user.
"""
__slots__ = ()
__slots__ = ('until_date',)
def __init__(
self,
user: User,
until_date: datetime.datetime = None,
**_kwargs: Any,
):
super().__init__(
status=ChatMember.KICKED,
user=user,
until_date=until_date,
)
def __init__(self, user: User, until_date: datetime.datetime, **_kwargs: object):
super().__init__(status=ChatMember.KICKED, user=user)
self.until_date = until_date

View file

@ -33,6 +33,10 @@ class ForceReply(ReplyMarkup):
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`selective` is equal.
.. versionchanged:: 14.0
The (undocumented) argument ``force_reply`` was removed and instead :attr:`force_reply`
is now always set to :obj:`True` as expected by the Bot API.
Args:
selective (:obj:`bool`, optional): Use this parameter if you want to force reply from
specific users only. Targets:
@ -64,14 +68,11 @@ class ForceReply(ReplyMarkup):
def __init__(
self,
force_reply: bool = True,
selective: bool = False,
input_field_placeholder: str = None,
**_kwargs: Any,
):
# Required
self.force_reply = bool(force_reply)
# Optionals
self.force_reply = True
self.selective = bool(selective)
self.input_field_placeholder = input_field_placeholder

View file

@ -2067,7 +2067,7 @@ class Message(TelegramObject):
def edit_media(
self,
media: 'InputMedia' = None,
media: 'InputMedia',
reply_markup: InlineKeyboardMarkup = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
@ -2088,14 +2088,14 @@ class Message(TelegramObject):
behaviour is undocumented and might be changed by Telegram.
Returns:
:class:`telegram.Message`: On success, if edited message is sent by the bot, the
:class:`telegram.Message`: On success, if edited message is not an inline message, the
edited Message is returned, otherwise ``True`` is returned.
"""
return self.bot.edit_message_media(
media=media,
chat_id=self.chat_id,
message_id=self.message_id,
media=media,
reply_markup=reply_markup,
timeout=timeout,
api_kwargs=api_kwargs,

View file

@ -52,6 +52,8 @@ class EncryptedPassportElement(TelegramObject):
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
"email".
hash (:obj:`str`): Base64-encoded element hash for using in
:class:`telegram.PassportElementErrorUnspecified`.
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \
:class:`telegram.ResidentialAddress` | :obj:`str`, optional):
Decrypted or encrypted data, available for "personal_details", "passport",
@ -77,8 +79,6 @@ class EncryptedPassportElement(TelegramObject):
requested for "passport", "driver_license", "identity_card", "internal_passport",
"utility_bill", "bank_statement", "rental_agreement", "passport_registration" and
"temporary_registration" types.
hash (:obj:`str`): Base64-encoded element hash for using in
:class:`telegram.PassportElementErrorUnspecified`.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
@ -87,6 +87,8 @@ class EncryptedPassportElement(TelegramObject):
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
"email".
hash (:obj:`str`): Base64-encoded element hash for using in
:class:`telegram.PassportElementErrorUnspecified`.
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \
:class:`telegram.ResidentialAddress` | :obj:`str`):
Optional. Decrypted or encrypted data, available for "personal_details", "passport",
@ -112,8 +114,6 @@ class EncryptedPassportElement(TelegramObject):
requested for "passport", "driver_license", "identity_card", "internal_passport",
"utility_bill", "bank_statement", "rental_agreement", "passport_registration" and
"temporary_registration" types.
hash (:obj:`str`): Base64-encoded element hash for using in
:class:`telegram.PassportElementErrorUnspecified`.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
@ -135,6 +135,7 @@ class EncryptedPassportElement(TelegramObject):
def __init__(
self,
type: str, # pylint: disable=W0622
hash: str, # pylint: disable=W0622
data: PersonalDetails = None,
phone_number: str = None,
email: str = None,
@ -143,7 +144,6 @@ class EncryptedPassportElement(TelegramObject):
reverse_side: PassportFile = None,
selfie: PassportFile = None,
translation: List[PassportFile] = None,
hash: str = None, # pylint: disable=W0622
bot: 'Bot' = None,
credentials: 'Credentials' = None, # pylint: disable=W0613
**_kwargs: Any,

View file

@ -45,7 +45,6 @@ class PassportElementError(TelegramObject):
"""
# All subclasses of this class won't have _id_attrs in slots since it's added here.
__slots__ = ('message', 'source', 'type')
def __init__(self, source: str, type: str, message: str, **_kwargs: Any):

View file

@ -72,7 +72,7 @@ class PassportFile(TelegramObject):
file_id: str,
file_unique_id: str,
file_date: int,
file_size: int = None,
file_size: int,
bot: 'Bot' = None,
credentials: 'FileCredentials' = None,
**_kwargs: Any,

View file

@ -20,7 +20,7 @@
"""This module contains objects related to Telegram voice chats."""
import datetime as dtm
from typing import TYPE_CHECKING, Any, Optional, List
from typing import TYPE_CHECKING, Optional, List
from telegram import TelegramObject, User
from telegram.utils.helpers import from_timestamp, to_timestamp
@ -40,7 +40,7 @@ class VoiceChatStarted(TelegramObject):
__slots__ = ()
def __init__(self, **_kwargs: Any): # skipcq: PTC-W0049
def __init__(self, **_kwargs: object): # skipcq: PTC-W0049
pass
@ -66,7 +66,7 @@ class VoiceChatEnded(TelegramObject):
__slots__ = ('duration',)
def __init__(self, duration: int, **_kwargs: Any) -> None:
def __init__(self, duration: int, **_kwargs: object) -> None:
self.duration = int(duration) if duration is not None else None
self._id_attrs = (self.duration,)
@ -83,25 +83,22 @@ class VoiceChatParticipantsInvited(TelegramObject):
.. versionadded:: 13.4
Args:
users (List[:class:`telegram.User`]): New members that
users (List[:class:`telegram.User`], optional): New members that
were invited to the voice chat.
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
users (List[:class:`telegram.User`]): New members that
users (List[:class:`telegram.User`]): Optional. New members that
were invited to the voice chat.
"""
__slots__ = ('users',)
def __init__(self, users: List[User], **_kwargs: Any) -> None:
def __init__(self, users: List[User] = None, **_kwargs: object) -> None:
self.users = users
self._id_attrs = (self.users,)
def __hash__(self) -> int:
return hash(tuple(self.users))
@classmethod
def de_json(
cls, data: Optional[JSONDict], bot: 'Bot'
@ -119,9 +116,13 @@ class VoiceChatParticipantsInvited(TelegramObject):
"""See :meth:`telegram.TelegramObject.to_dict`."""
data = super().to_dict()
data["users"] = [u.to_dict() for u in self.users]
if self.users is not None:
data["users"] = [u.to_dict() for u in self.users]
return data
def __hash__(self) -> int:
return hash(None) if self.users is None else hash(tuple(self.users))
class VoiceChatScheduled(TelegramObject):
"""This object represents a service message about a voice chat scheduled in the chat.
@ -142,7 +143,7 @@ class VoiceChatScheduled(TelegramObject):
__slots__ = ('start_date',)
def __init__(self, start_date: dtm.datetime, **_kwargs: Any) -> None:
def __init__(self, start_date: dtm.datetime, **_kwargs: object) -> None:
self.start_date = start_date
self._id_attrs = (self.start_date,)

View file

@ -1368,7 +1368,7 @@ class TestBot:
monkeypatch.setattr(bot.request, 'post', assertion)
assert bot.set_webhook(drop_pending_updates=drop_pending_updates)
assert bot.set_webhook('', drop_pending_updates=drop_pending_updates)
assert bot.delete_webhook(drop_pending_updates=drop_pending_updates)
@flaky(3, 1)
@ -1916,7 +1916,6 @@ class TestBot:
def test_set_chat_description(self, bot, channel_id):
assert bot.set_chat_description(channel_id, 'Time: ' + str(time.time()))
# TODO: Add bot to group to test there too
@flaky(3, 1)
def test_pin_and_unpin_message(self, bot, super_group_id):
message1 = bot.send_message(super_group_id, text="test_pin_message_1")

View file

@ -34,6 +34,7 @@ def invite_link(creator):
return ChatInviteLink(
TestChatInviteLink.link,
creator,
TestChatInviteLink.creates_join_request,
TestChatInviteLink.primary,
TestChatInviteLink.revoked,
expire_date=TestChatInviteLink.expire_date,
@ -46,6 +47,7 @@ def invite_link(creator):
class TestChatInviteLink:
link = "thisialink"
creates_join_request = (False,)
primary = True
revoked = False
expire_date = datetime.datetime.utcnow()
@ -62,6 +64,7 @@ class TestChatInviteLink:
json_dict = {
'invite_link': self.link,
'creator': creator.to_dict(),
'creates_join_request': self.creates_join_request,
'is_primary': self.primary,
'is_revoked': self.revoked,
}
@ -70,6 +73,7 @@ class TestChatInviteLink:
assert invite_link.invite_link == self.link
assert invite_link.creator == creator
assert invite_link.creates_join_request == self.creates_join_request
assert invite_link.is_primary == self.primary
assert invite_link.is_revoked == self.revoked
@ -77,6 +81,7 @@ class TestChatInviteLink:
json_dict = {
'invite_link': self.link,
'creator': creator.to_dict(),
'creates_join_request': self.creates_join_request,
'is_primary': self.primary,
'is_revoked': self.revoked,
'expire_date': to_timestamp(self.expire_date),
@ -89,6 +94,7 @@ class TestChatInviteLink:
assert invite_link.invite_link == self.link
assert invite_link.creator == creator
assert invite_link.creates_join_request == self.creates_join_request
assert invite_link.is_primary == self.primary
assert invite_link.is_revoked == self.revoked
assert pytest.approx(invite_link.expire_date == self.expire_date)
@ -102,6 +108,7 @@ class TestChatInviteLink:
assert isinstance(invite_link_dict, dict)
assert invite_link_dict['creator'] == invite_link.creator.to_dict()
assert invite_link_dict['invite_link'] == invite_link.invite_link
assert invite_link_dict['creates_join_request'] == invite_link.creates_join_request
assert invite_link_dict['is_primary'] == self.primary
assert invite_link_dict['is_revoked'] == self.revoked
assert invite_link_dict['expire_date'] == to_timestamp(self.expire_date)
@ -110,19 +117,25 @@ class TestChatInviteLink:
assert invite_link_dict['pending_join_request_count'] == self.pending_join_request_count
def test_equality(self):
a = ChatInviteLink("link", User(1, '', False), True, True)
b = ChatInviteLink("link", User(1, '', False), True, True)
d = ChatInviteLink("link", User(2, '', False), False, True)
d2 = ChatInviteLink("notalink", User(1, '', False), False, True)
d3 = ChatInviteLink("notalink", User(1, '', False), True, True)
e = User(1, '', False)
a = ChatInviteLink("link", User(1, '', False), True, True, True)
b = ChatInviteLink("link", User(1, '', False), True, True, True)
c = ChatInviteLink("link", User(2, '', False), True, True, True)
d1 = ChatInviteLink("link", User(1, '', False), False, True, True)
d2 = ChatInviteLink("link", User(1, '', False), True, False, True)
d3 = ChatInviteLink("link", User(1, '', False), True, True, False)
e = ChatInviteLink("notalink", User(1, '', False), True, False, True)
f = ChatInviteLink("notalink", User(1, '', False), True, True, True)
g = User(1, '', False)
assert a == b
assert hash(a) == hash(b)
assert a is not b
assert a != d
assert hash(a) != hash(d)
assert a != c
assert hash(a) != hash(c)
assert a != d1
assert hash(a) != hash(d1)
assert a != d2
assert hash(a) != hash(d2)
@ -132,3 +145,9 @@ class TestChatInviteLink:
assert a != e
assert hash(a) != hash(e)
assert a != f
assert hash(a) != hash(f)
assert a != g
assert hash(a) != hash(g)

View file

@ -50,6 +50,7 @@ class TestChatJoinRequest:
invite_link = ChatInviteLink(
'https://invite.link',
User(42, 'creator', False),
creates_join_request=False,
name='InviteLink',
is_revoked=False,
is_primary=False,

View file

@ -85,6 +85,7 @@ def chat_join_request(time, bot):
invite_link=ChatInviteLink(
'https://invite.link',
User(42, 'creator', False),
creates_join_request=False,
name='InviteLink',
is_revoked=False,
is_primary=False,

View file

@ -17,6 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import datetime
import inspect
from copy import deepcopy
import pytest
@ -34,202 +35,197 @@ from telegram import (
Dice,
)
@pytest.fixture(scope='class')
def user():
return User(1, 'First name', False)
ignored = ['self', '_kwargs']
@pytest.fixture(
scope="class",
params=[
(ChatMemberOwner, ChatMember.CREATOR),
(ChatMemberAdministrator, ChatMember.ADMINISTRATOR),
(ChatMemberMember, ChatMember.MEMBER),
(ChatMemberRestricted, ChatMember.RESTRICTED),
(ChatMemberLeft, ChatMember.LEFT),
(ChatMemberBanned, ChatMember.KICKED),
],
ids=[
ChatMember.CREATOR,
ChatMember.ADMINISTRATOR,
ChatMember.MEMBER,
ChatMember.RESTRICTED,
ChatMember.LEFT,
ChatMember.KICKED,
class CMDefaults:
user = User(1, 'First name', False)
custom_title: str = 'PTB'
is_anonymous: bool = True
until_date: datetime.datetime = to_timestamp(datetime.datetime.utcnow())
can_be_edited: bool = False
can_change_info: bool = True
can_post_messages: bool = True
can_edit_messages: bool = True
can_delete_messages: bool = True
can_invite_users: bool = True
can_restrict_members: bool = True
can_pin_messages: bool = True
can_promote_members: bool = True
can_send_messages: bool = True
can_send_media_messages: bool = True
can_send_polls: bool = True
can_send_other_messages: bool = True
can_add_web_page_previews: bool = True
is_member: bool = True
can_manage_chat: bool = True
can_manage_voice_chats: bool = True
def chat_member_owner():
return ChatMemberOwner(CMDefaults.user, CMDefaults.is_anonymous, CMDefaults.custom_title)
def chat_member_administrator():
return ChatMemberAdministrator(
CMDefaults.user,
CMDefaults.can_be_edited,
CMDefaults.is_anonymous,
CMDefaults.can_manage_chat,
CMDefaults.can_delete_messages,
CMDefaults.can_manage_voice_chats,
CMDefaults.can_restrict_members,
CMDefaults.can_promote_members,
CMDefaults.can_change_info,
CMDefaults.can_invite_users,
CMDefaults.can_post_messages,
CMDefaults.can_edit_messages,
CMDefaults.can_pin_messages,
CMDefaults.custom_title,
)
def chat_member_member():
return ChatMemberMember(CMDefaults.user)
def chat_member_restricted():
return ChatMemberRestricted(
CMDefaults.user,
CMDefaults.is_member,
CMDefaults.can_change_info,
CMDefaults.can_invite_users,
CMDefaults.can_pin_messages,
CMDefaults.can_send_messages,
CMDefaults.can_send_media_messages,
CMDefaults.can_send_polls,
CMDefaults.can_send_other_messages,
CMDefaults.can_add_web_page_previews,
CMDefaults.until_date,
)
def chat_member_left():
return ChatMemberLeft(CMDefaults.user)
def chat_member_banned():
return ChatMemberBanned(CMDefaults.user, CMDefaults.until_date)
def make_json_dict(instance: ChatMember, include_optional_args: bool = False) -> dict:
"""Used to make the json dict which we use for testing de_json. Similar to iter_args()"""
json_dict = {'status': instance.status}
sig = inspect.signature(instance.__class__.__init__)
for param in sig.parameters.values():
if param.name in ignored: # ignore irrelevant params
continue
val = getattr(instance, param.name)
# Compulsory args-
if param.default is inspect.Parameter.empty:
if hasattr(val, 'to_dict'): # convert the user object or any future ones to dict.
val = val.to_dict()
json_dict[param.name] = val
# If we want to test all args (for de_json)-
elif param.default is not inspect.Parameter.empty and include_optional_args:
json_dict[param.name] = val
return json_dict
def iter_args(instance: ChatMember, de_json_inst: ChatMember, include_optional: bool = False):
"""
We accept both the regular instance and de_json created instance and iterate over them for
easy one line testing later one.
"""
yield instance.status, de_json_inst.status # yield this here cause it's not available in sig.
sig = inspect.signature(instance.__class__.__init__)
for param in sig.parameters.values():
if param.name in ignored:
continue
inst_at, json_at = getattr(instance, param.name), getattr(de_json_inst, param.name)
if isinstance(json_at, datetime.datetime): # Convert datetime to int
json_at = to_timestamp(json_at)
if param.default is not inspect.Parameter.empty and include_optional:
yield inst_at, json_at
elif param.default is inspect.Parameter.empty:
yield inst_at, json_at
@pytest.fixture
def chat_member_type(request):
return request.param()
@pytest.mark.parametrize(
"chat_member_type",
[
chat_member_owner,
chat_member_administrator,
chat_member_member,
chat_member_restricted,
chat_member_left,
chat_member_banned,
],
indirect=True,
)
def chat_member_class_and_status(request):
return request.param
@pytest.fixture(scope='class')
def chat_member_types(chat_member_class_and_status, user):
return chat_member_class_and_status[0](status=chat_member_class_and_status[1], user=user)
class TestChatMember:
def test_slot_behaviour(self, chat_member_types, mro_slots):
for attr in chat_member_types.__slots__:
assert getattr(chat_member_types, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(chat_member_types)) == len(
set(mro_slots(chat_member_types))
), "duplicate slot"
def test_de_json_required_args(self, bot, chat_member_class_and_status, user):
cls = chat_member_class_and_status[0]
status = chat_member_class_and_status[1]
class TestChatMemberTypes:
def test_slot_behaviour(self, chat_member_type, mro_slots):
inst = chat_member_type
for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
def test_de_json_required_args(self, bot, chat_member_type):
cls = chat_member_type.__class__
assert cls.de_json({}, bot) is None
json_dict = {'status': status, 'user': user.to_dict()}
chat_member_type = ChatMember.de_json(json_dict, bot)
json_dict = make_json_dict(chat_member_type)
const_chat_member = ChatMember.de_json(json_dict, bot)
assert isinstance(chat_member_type, ChatMember)
assert isinstance(chat_member_type, cls)
assert chat_member_type.status == status
assert chat_member_type.user == user
assert isinstance(const_chat_member, ChatMember)
assert isinstance(const_chat_member, cls)
for chat_mem_type_at, const_chat_mem_at in iter_args(chat_member_type, const_chat_member):
assert chat_mem_type_at == const_chat_mem_at
def test_de_json_all_args(self, bot, chat_member_class_and_status, user):
cls = chat_member_class_and_status[0]
status = chat_member_class_and_status[1]
time = datetime.datetime.utcnow()
def test_de_json_all_args(self, bot, chat_member_type):
json_dict = make_json_dict(chat_member_type, include_optional_args=True)
const_chat_member = ChatMember.de_json(json_dict, bot)
json_dict = {
'user': user.to_dict(),
'status': status,
'custom_title': 'PTB',
'is_anonymous': True,
'until_date': to_timestamp(time),
'can_be_edited': False,
'can_change_info': True,
'can_post_messages': False,
'can_edit_messages': True,
'can_delete_messages': True,
'can_invite_users': False,
'can_restrict_members': True,
'can_pin_messages': False,
'can_promote_members': True,
'can_send_messages': False,
'can_send_media_messages': True,
'can_send_polls': False,
'can_send_other_messages': True,
'can_add_web_page_previews': False,
'can_manage_chat': True,
'can_manage_voice_chats': True,
}
chat_member_type = ChatMember.de_json(json_dict, bot)
assert isinstance(const_chat_member, ChatMember)
assert isinstance(const_chat_member, chat_member_type.__class__)
for c_mem_type_at, const_c_mem_at in iter_args(chat_member_type, const_chat_member, True):
assert c_mem_type_at == const_c_mem_at
assert isinstance(chat_member_type, ChatMember)
assert isinstance(chat_member_type, cls)
assert chat_member_type.user == user
assert chat_member_type.status == status
if chat_member_type.custom_title is not None:
assert chat_member_type.custom_title == 'PTB'
assert type(chat_member_type) in {ChatMemberOwner, ChatMemberAdministrator}
if chat_member_type.is_anonymous is not None:
assert chat_member_type.is_anonymous is True
assert type(chat_member_type) in {ChatMemberOwner, ChatMemberAdministrator}
if chat_member_type.until_date is not None:
assert type(chat_member_type) in {ChatMemberBanned, ChatMemberRestricted}
if chat_member_type.can_be_edited is not None:
assert chat_member_type.can_be_edited is False
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_change_info is not None:
assert chat_member_type.can_change_info is True
assert type(chat_member_type) in {ChatMemberAdministrator, ChatMemberRestricted}
if chat_member_type.can_post_messages is not None:
assert chat_member_type.can_post_messages is False
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_edit_messages is not None:
assert chat_member_type.can_edit_messages is True
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_delete_messages is not None:
assert chat_member_type.can_delete_messages is True
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_invite_users is not None:
assert chat_member_type.can_invite_users is False
assert type(chat_member_type) in {ChatMemberAdministrator, ChatMemberRestricted}
if chat_member_type.can_restrict_members is not None:
assert chat_member_type.can_restrict_members is True
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_pin_messages is not None:
assert chat_member_type.can_pin_messages is False
assert type(chat_member_type) in {ChatMemberAdministrator, ChatMemberRestricted}
if chat_member_type.can_promote_members is not None:
assert chat_member_type.can_promote_members is True
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_send_messages is not None:
assert chat_member_type.can_send_messages is False
assert type(chat_member_type) == ChatMemberRestricted
if chat_member_type.can_send_media_messages is not None:
assert chat_member_type.can_send_media_messages is True
assert type(chat_member_type) == ChatMemberRestricted
if chat_member_type.can_send_polls is not None:
assert chat_member_type.can_send_polls is False
assert type(chat_member_type) == ChatMemberRestricted
if chat_member_type.can_send_other_messages is not None:
assert chat_member_type.can_send_other_messages is True
assert type(chat_member_type) == ChatMemberRestricted
if chat_member_type.can_add_web_page_previews is not None:
assert chat_member_type.can_add_web_page_previews is False
assert type(chat_member_type) == ChatMemberRestricted
if chat_member_type.can_manage_chat is not None:
assert chat_member_type.can_manage_chat is True
assert type(chat_member_type) == ChatMemberAdministrator
if chat_member_type.can_manage_voice_chats is not None:
assert chat_member_type.can_manage_voice_chats is True
assert type(chat_member_type) == ChatMemberAdministrator
def test_de_json_invalid_status(self, bot, user):
json_dict = {'status': 'invalid', 'user': user.to_dict()}
def test_de_json_invalid_status(self, chat_member_type, bot):
json_dict = {'status': 'invalid', 'user': CMDefaults.user.to_dict()}
chat_member_type = ChatMember.de_json(json_dict, bot)
assert type(chat_member_type) is ChatMember
assert chat_member_type.status == 'invalid'
def test_de_json_subclass(self, chat_member_class_and_status, bot, chat_id, user):
def test_de_json_subclass(self, chat_member_type, bot, chat_id):
"""This makes sure that e.g. ChatMemberAdministrator(data, bot) never returns a
ChatMemberKicked instance."""
cls = chat_member_class_and_status[0]
time = datetime.datetime.utcnow()
json_dict = {
'user': user.to_dict(),
'status': 'status',
'custom_title': 'PTB',
'is_anonymous': True,
'until_date': to_timestamp(time),
'can_be_edited': False,
'can_change_info': True,
'can_post_messages': False,
'can_edit_messages': True,
'can_delete_messages': True,
'can_invite_users': False,
'can_restrict_members': True,
'can_pin_messages': False,
'can_promote_members': True,
'can_send_messages': False,
'can_send_media_messages': True,
'can_send_polls': False,
'can_send_other_messages': True,
'can_add_web_page_previews': False,
'can_manage_chat': True,
'can_manage_voice_chats': True,
}
ChatMemberBanned instance."""
cls = chat_member_type.__class__
json_dict = make_json_dict(chat_member_type, True)
assert type(cls.de_json(json_dict, bot)) is cls
def test_to_dict(self, chat_member_types, user):
chat_member_dict = chat_member_types.to_dict()
def test_to_dict(self, chat_member_type):
chat_member_dict = chat_member_type.to_dict()
assert isinstance(chat_member_dict, dict)
assert chat_member_dict['status'] == chat_member_types.status
assert chat_member_dict['user'] == user.to_dict()
assert chat_member_dict['status'] == chat_member_type.status
assert chat_member_dict['user'] == chat_member_type.user.to_dict()
def test_equality(self, chat_member_types, user):
a = ChatMember(status='status', user=user)
b = ChatMember(status='status', user=user)
c = chat_member_types
d = deepcopy(chat_member_types)
def test_equality(self, chat_member_type):
a = ChatMember(status='status', user=CMDefaults.user)
b = ChatMember(status='status', user=CMDefaults.user)
c = chat_member_type
d = deepcopy(chat_member_type)
e = Dice(4, 'emoji')
assert a == b

View file

@ -22,7 +22,14 @@ import inspect
import pytest
import pytz
from telegram import User, ChatMember, Chat, ChatMemberUpdated, ChatInviteLink
from telegram import (
User,
ChatMember,
ChatMemberAdministrator,
Chat,
ChatMemberUpdated,
ChatInviteLink,
)
from telegram.utils.helpers import to_timestamp
@ -43,7 +50,19 @@ def old_chat_member(user):
@pytest.fixture(scope='class')
def new_chat_member(user):
return ChatMember(user, TestChatMemberUpdated.new_status)
return ChatMemberAdministrator(
user,
TestChatMemberUpdated.new_status,
True,
True,
True,
True,
True,
True,
True,
True,
True,
)
@pytest.fixture(scope='class')
@ -53,7 +72,7 @@ def time():
@pytest.fixture(scope='class')
def invite_link(user):
return ChatInviteLink('link', user, True, True)
return ChatInviteLink('link', user, False, True, True)
@pytest.fixture(scope='class')

View file

@ -26,6 +26,7 @@ from telegram import EncryptedPassportElement, PassportFile, PassportElementErro
def encrypted_passport_element():
return EncryptedPassportElement(
TestEncryptedPassportElement.type_,
'this is a hash',
data=TestEncryptedPassportElement.data,
phone_number=TestEncryptedPassportElement.phone_number,
email=TestEncryptedPassportElement.email,
@ -38,13 +39,14 @@ def encrypted_passport_element():
class TestEncryptedPassportElement:
type_ = 'type'
hash = 'this is a hash'
data = 'data'
phone_number = 'phone_number'
email = 'email'
files = [PassportFile('file_id', 50, 0)]
front_side = PassportFile('file_id', 50, 0)
reverse_side = PassportFile('file_id', 50, 0)
selfie = PassportFile('file_id', 50, 0)
files = [PassportFile('file_id', 50, 0, 25)]
front_side = PassportFile('file_id', 50, 0, 25)
reverse_side = PassportFile('file_id', 50, 0, 25)
selfie = PassportFile('file_id', 50, 0, 25)
def test_slot_behaviour(self, encrypted_passport_element, mro_slots):
inst = encrypted_passport_element
@ -54,6 +56,7 @@ class TestEncryptedPassportElement:
def test_expected_values(self, encrypted_passport_element):
assert encrypted_passport_element.type == self.type_
assert encrypted_passport_element.hash == self.hash
assert encrypted_passport_element.data == self.data
assert encrypted_passport_element.phone_number == self.phone_number
assert encrypted_passport_element.email == self.email
@ -88,8 +91,8 @@ class TestEncryptedPassportElement:
)
def test_equality(self):
a = EncryptedPassportElement(self.type_, data=self.data)
b = EncryptedPassportElement(self.type_, data=self.data)
a = EncryptedPassportElement(self.type_, self.hash, data=self.data)
b = EncryptedPassportElement(self.type_, self.hash, data=self.data)
c = EncryptedPassportElement(self.data, '')
d = PassportElementError('source', 'type', 'message')

View file

@ -26,7 +26,6 @@ from telegram import ForceReply, ReplyKeyboardRemove
@pytest.fixture(scope='class')
def force_reply():
return ForceReply(
TestForceReply.force_reply,
TestForceReply.selective,
TestForceReply.input_field_placeholder,
)
@ -62,16 +61,16 @@ class TestForceReply:
assert force_reply_dict['input_field_placeholder'] == force_reply.input_field_placeholder
def test_equality(self):
a = ForceReply(True, False)
b = ForceReply(False, False)
c = ForceReply(True, True)
a = ForceReply(True, 'test')
b = ForceReply(False, 'pass')
c = ForceReply(True)
d = ReplyKeyboardRemove()
assert a == b
assert hash(a) == hash(b)
assert a != b
assert hash(a) != hash(b)
assert a != c
assert hash(a) != hash(c)
assert a == c
assert hash(a) == hash(c)
assert a != d
assert hash(a) != hash(d)

View file

@ -643,9 +643,9 @@ class TestSendMediaGroup:
message = default_bot.send_photo(chat_id, photo)
message = default_bot.edit_message_media(
build_media(parse_mode=ParseMode.HTML, med_type=media_type),
message.chat_id,
message.message_id,
media=build_media(parse_mode=ParseMode.HTML, med_type=media_type),
)
assert message.caption == test_caption
assert message.caption_entities == test_entities
@ -654,9 +654,9 @@ class TestSendMediaGroup:
message.edit_caption()
message = default_bot.edit_message_media(
build_media(parse_mode=ParseMode.MARKDOWN_V2, med_type=media_type),
message.chat_id,
message.message_id,
media=build_media(parse_mode=ParseMode.MARKDOWN_V2, med_type=media_type),
)
assert message.caption == test_caption
assert message.caption_entities == test_entities
@ -665,9 +665,9 @@ class TestSendMediaGroup:
message.edit_caption()
message = default_bot.edit_message_media(
build_media(parse_mode=None, med_type=media_type),
message.chat_id,
message.message_id,
media=build_media(parse_mode=None, med_type=media_type),
)
assert message.caption == markdown_caption
assert message.caption_entities == []

View file

@ -18,6 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
import os
import inspect
from typing import List
import certifi
import pytest
@ -40,6 +41,13 @@ IGNORED_PARAMETERS = {
'kwargs',
}
ignored_param_requirements = { # Ignore these since there's convenience params in them (eg. Venue)
'send_location': {'latitude', 'longitude'},
'edit_message_live_location': {'latitude', 'longitude'},
'send_venue': {'latitude', 'longitude', 'title', 'address'},
'send_contact': {'phone_number', 'first_name'},
}
def find_next_sibling_until(tag, name, until):
for sibling in tag.next_siblings:
@ -49,7 +57,8 @@ def find_next_sibling_until(tag, name, until):
return sibling
def parse_table(h4):
def parse_table(h4) -> List[List[str]]:
"""Parses the Telegram doc table and has an output of a 2D list."""
table = find_next_sibling_until(h4, 'table', h4.find_next_sibling('h4'))
if not table:
return []
@ -60,8 +69,8 @@ def parse_table(h4):
def check_method(h4):
name = h4.text
method = getattr(telegram.Bot, name)
name = h4.text # name of the method in telegram's docs.
method = getattr(telegram.Bot, name) # Retrieve our lib method
table = parse_table(h4)
# Check arguments based on source
@ -71,8 +80,11 @@ def check_method(h4):
for parameter in table:
param = sig.parameters.get(parameter[0])
assert param is not None, f"Parameter {parameter[0]} not found in {method.__name__}"
# TODO: Check type via docstring
# TODO: Check if optional or required
assert check_required_param(
parameter, param.name, sig, method.__name__
), f'Param {param.name!r} of method {method.__name__!r} requirement mismatch!'
checked.append(parameter[0])
ignored = IGNORED_PARAMETERS.copy()
@ -91,8 +103,6 @@ def check_method(h4):
]
):
ignored |= {'filename'} # Convenience parameter
elif name == 'setGameScore':
ignored |= {'edit_message'} # TODO: Now deprecated, so no longer in telegrams docs
elif name == 'sendContact':
ignored |= {'contact'} # Added for ease of use
elif name in ['sendLocation', 'editMessageLiveLocation']:
@ -113,7 +123,7 @@ def check_object(h4):
# Check arguments based on source. Makes sure to only check __init__'s signature & nothing else
sig = inspect.signature(obj.__init__, follow_wrapped=True)
checked = []
checked = set()
for parameter in table:
field = parameter[0]
if field == 'from':
@ -124,18 +134,22 @@ def check_object(h4):
or name.startswith('BotCommandScope')
) and field == 'type':
continue
elif (name.startswith('ChatMember')) and field == 'status':
elif (name.startswith('ChatMember')) and field == 'status': # We autofill the status
continue
elif (
name.startswith('PassportElementError') and field == 'source'
) or field == 'remove_keyboard':
continue
elif name.startswith('ForceReply') and field == 'force_reply': # this param is always True
continue
param = sig.parameters.get(field)
assert param is not None, f"Attribute {field} not found in {obj.__name__}"
# TODO: Check type via docstring
# TODO: Check if optional or required
checked.append(field)
assert check_required_param(
parameter, field, sig, obj.__name__
), f"{obj.__name__!r} parameter {param.name!r} requirement mismatch"
checked.add(field)
ignored = IGNORED_PARAMETERS.copy()
if name == 'InputFile':
@ -144,33 +158,8 @@ def check_object(h4):
ignored |= {'id', 'type'} # attributes common to all subclasses
if name == 'ChatMember':
ignored |= {'user', 'status'} # attributes common to all subclasses
if name == 'ChatMember':
ignored |= {
'can_add_web_page_previews', # for backwards compatibility
'can_be_edited',
'can_change_info',
'can_delete_messages',
'can_edit_messages',
'can_invite_users',
'can_manage_chat',
'can_manage_voice_chats',
'can_pin_messages',
'can_post_messages',
'can_promote_members',
'can_restrict_members',
'can_send_media_messages',
'can_send_messages',
'can_send_other_messages',
'can_send_polls',
'custom_title',
'is_anonymous',
'is_member',
'until_date',
}
if name == 'BotCommandScope':
ignored |= {'type'} # attributes common to all subclasses
elif name == 'User':
ignored |= {'type'} # TODO: Deprecation
elif name in ('PassportFile', 'EncryptedPassportElement'):
ignored |= {'credentials'}
elif name == 'PassportElementError':
@ -181,6 +170,26 @@ def check_object(h4):
assert (sig.parameters.keys() ^ checked) - ignored == set()
def check_required_param(
param_desc: List[str], param_name: str, sig: inspect.Signature, method_or_obj_name: str
) -> bool:
"""Checks if the method/class parameter is a required/optional param as per Telegram docs."""
if len(param_desc) == 4: # this means that there is a dedicated 'Required' column present.
# Handle cases where we provide convenience intentionally-
if param_name in ignored_param_requirements.get(method_or_obj_name, {}):
return True
is_required = True if param_desc[2] in {'Required', 'Yes'} else False
is_ours_required = sig.parameters[param_name].default is inspect.Signature.empty
return is_required is is_ours_required
if len(param_desc) == 3: # The docs mention the requirement in the description for classes...
if param_name in ignored_param_requirements.get(method_or_obj_name, {}):
return True
is_required = False if param_desc[2].split('.', 1)[0] == 'Optional' else True
is_ours_required = sig.parameters[param_name].default is inspect.Signature.empty
return is_required is is_ours_required
argvalues = []
names = []
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())

View file

@ -47,9 +47,11 @@ RAW_PASSPORT_DATA = {
{
'data': 'QRfzWcCN4WncvRO3lASG+d+c5gzqXtoCinQ1PgtYiZMKXCksx9eB9Ic1bOt8C/un9/XaX220PjJSO7Kuba+nXXC51qTsjqP9rnLKygnEIWjKrfiDdklzgcukpRzFSjiOAvhy86xFJZ1PfPSrFATy/Gp1RydLzbrBd2ZWxZqXrxcMoA0Q2UTTFXDoCYerEAiZoD69i79tB/6nkLBcUUvN5d52gKd/GowvxWqAAmdO6l1N7jlo6aWjdYQNBAK1KHbJdbRZMJLxC1MqMuZXAYrPoYBRKr5xAnxDTmPn/LEZKLc3gwwZyEgR5x7e9jp5heM6IEMmsv3O/6SUeEQs7P0iVuRSPLMJLfDdwns8Tl3fF2M4IxKVovjCaOVW+yHKsADDAYQPzzH2RcrWVD0TP5I64mzpK64BbTOq3qm3Hn51SV9uA/+LvdGbCp7VnzHx4EdUizHsVyilJULOBwvklsrDRvXMiWmh34ZSR6zilh051tMEcRf0I+Oe7pIxVJd/KKfYA2Z/eWVQTCn5gMuAInQNXFSqDIeIqBX+wca6kvOCUOXB7J2uRjTpLaC4DM9s/sNjSBvFixcGAngt+9oap6Y45rQc8ZJaNN/ALqEJAmkphW8=',
'type': 'personal_details',
'hash': 'What to put here?',
},
{
'reverse_side': {
'file_size': 32424112,
'file_date': 1534074942,
'file_id': 'DgADBAADNQQAAtoagFPf4wwmFZdmyQI',
'file_unique_id': 'adc3145fd2e84d95b64d68eaa22aa33e',
@ -82,6 +84,7 @@ RAW_PASSPORT_DATA = {
'file_unique_id': 'd4e390cca57b4da5a65322b304762a12',
},
'data': 'eJUOFuY53QKmGqmBgVWlLBAQCUQJ79n405SX6M5aGFIIodOPQqnLYvMNqTwTrXGDlW+mVLZcbu+y8luLVO8WsJB/0SB7q5WaXn/IMt1G9lz5G/KMLIZG/x9zlnimsaQLg7u8srG6L4KZzv+xkbbHjZdETrxU8j0N/DoS4HvLMRSJAgeFUrY6v2YW9vSRg+fSxIqQy1jR2VKpzAT8OhOz7A==',
'hash': 'We seriously need to improve this mess! took so long to debug!',
},
{
'translation': [
@ -113,12 +116,14 @@ RAW_PASSPORT_DATA = {
},
],
'type': 'utility_bill',
'hash': 'Wow over 30 minutes spent debugging passport stuff.',
},
{
'data': 'j9SksVkSj128DBtZA+3aNjSFNirzv+R97guZaMgae4Gi0oDVNAF7twPR7j9VSmPedfJrEwL3O889Ei+a5F1xyLLyEI/qEBljvL70GFIhYGitS0JmNabHPHSZrjOl8b4s/0Z0Px2GpLO5siusTLQonimdUvu4UPjKquYISmlKEKhtmGATy+h+JDjNCYuOkhakeNw0Rk0BHgj0C3fCb7WZNQSyVb+2GTu6caR6eXf/AFwFp0TV3sRz3h0WIVPW8bna',
'type': 'address',
'hash': 'at least I get the pattern now',
},
{'email': 'fb3e3i47zt@dispostable.com', 'type': 'email'},
{'email': 'fb3e3i47zt@dispostable.com', 'type': 'email', 'hash': 'this should be it.'},
],
}
@ -126,13 +131,18 @@ RAW_PASSPORT_DATA = {
@pytest.fixture(scope='function')
def all_passport_data():
return [
{'type': 'personal_details', 'data': RAW_PASSPORT_DATA['data'][0]['data']},
{
'type': 'personal_details',
'data': RAW_PASSPORT_DATA['data'][0]['data'],
'hash': 'what to put here?',
},
{
'type': 'passport',
'data': RAW_PASSPORT_DATA['data'][1]['data'],
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
'translation': RAW_PASSPORT_DATA['data'][1]['translation'],
'hash': 'more data arghh',
},
{
'type': 'internal_passport',
@ -140,6 +150,7 @@ def all_passport_data():
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
'translation': RAW_PASSPORT_DATA['data'][1]['translation'],
'hash': 'more data arghh',
},
{
'type': 'driver_license',
@ -148,6 +159,7 @@ def all_passport_data():
'reverse_side': RAW_PASSPORT_DATA['data'][1]['reverse_side'],
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
'translation': RAW_PASSPORT_DATA['data'][1]['translation'],
'hash': 'more data arghh',
},
{
'type': 'identity_card',
@ -156,35 +168,49 @@ def all_passport_data():
'reverse_side': RAW_PASSPORT_DATA['data'][1]['reverse_side'],
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
'translation': RAW_PASSPORT_DATA['data'][1]['translation'],
'hash': 'more data arghh',
},
{
'type': 'utility_bill',
'files': RAW_PASSPORT_DATA['data'][2]['files'],
'translation': RAW_PASSPORT_DATA['data'][2]['translation'],
'hash': 'more data arghh',
},
{
'type': 'bank_statement',
'files': RAW_PASSPORT_DATA['data'][2]['files'],
'translation': RAW_PASSPORT_DATA['data'][2]['translation'],
'hash': 'more data arghh',
},
{
'type': 'rental_agreement',
'files': RAW_PASSPORT_DATA['data'][2]['files'],
'translation': RAW_PASSPORT_DATA['data'][2]['translation'],
'hash': 'more data arghh',
},
{
'type': 'passport_registration',
'files': RAW_PASSPORT_DATA['data'][2]['files'],
'translation': RAW_PASSPORT_DATA['data'][2]['translation'],
'hash': 'more data arghh',
},
{
'type': 'temporary_registration',
'files': RAW_PASSPORT_DATA['data'][2]['files'],
'translation': RAW_PASSPORT_DATA['data'][2]['translation'],
'hash': 'more data arghh',
},
{
'type': 'address',
'data': RAW_PASSPORT_DATA['data'][3]['data'],
'hash': 'more data arghh',
},
{'type': 'email', 'email': 'fb3e3i47zt@dispostable.com', 'hash': 'more data arghh'},
{
'type': 'phone_number',
'phone_number': 'fb3e3i47zt@dispostable.com',
'hash': 'more data arghh',
},
{'type': 'address', 'data': RAW_PASSPORT_DATA['data'][3]['data']},
{'type': 'email', 'email': 'fb3e3i47zt@dispostable.com'},
{'type': 'phone_number', 'phone_number': 'fb3e3i47zt@dispostable.com'},
]

View file

@ -33,7 +33,7 @@ from telegram import (
Poll,
PollOption,
ChatMemberUpdated,
ChatMember,
ChatMemberOwner,
ChatJoinRequest,
)
from telegram.poll import PollAnswer
@ -44,8 +44,8 @@ chat_member_updated = ChatMemberUpdated(
Chat(1, 'chat'),
User(1, '', False),
from_timestamp(int(time.time())),
ChatMember(User(1, '', False), ChatMember.CREATOR),
ChatMember(User(1, '', False), ChatMember.CREATOR),
ChatMemberOwner(User(1, '', False), True),
ChatMemberOwner(User(1, '', False), True),
)

View file

@ -95,7 +95,7 @@ class TestVoiceChatEnded:
class TestVoiceChatParticipantsInvited:
def test_slot_behaviour(self, mro_slots):
def test_slot_behaviour(self, mro_slots, user1):
action = VoiceChatParticipantsInvited([user1])
for attr in action.__slots__:
assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'"
@ -124,7 +124,7 @@ class TestVoiceChatParticipantsInvited:
a = VoiceChatParticipantsInvited([user1])
b = VoiceChatParticipantsInvited([user1])
c = VoiceChatParticipantsInvited([user1, user2])
d = VoiceChatParticipantsInvited([user2])
d = VoiceChatParticipantsInvited(None)
e = VoiceChatStarted()
assert a == b