mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-28 07:20:17 +01:00
API 5.1 (#2424)
* Feat: New invite links * Fix: doc strings Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> * new dice, new admin privilege, revoke_messages, update and fix some docs * add missing param to shortcut * Add ChatMemberUpdated * Add voicechat related objects Signed-off-by: starry69 <starry369126@outlook.com> * add versionadd tags Signed-off-by: starry69 <starry369126@outlook.com> * Fix filter tests * Update tg.Update * ChatMemberHandler * Add versioning directives * add can_manage_voice_chats attr and fix docs Signed-off-by: starry69 <starry369126@outlook.com> * fix chat shortcut Signed-off-by: starry69 <starry369126@outlook.com> * address review * MADTC * Chat.message_auto_delete_time * Some doc fixes * address review Signed-off-by: starry69 <starry369126@outlook.com> * welp Signed-off-by: starry69 <starry369126@outlook.com> * Add voicechat related filters Signed-off-by: starry69 <starry369126@outlook.com> * Fix: Addressing review change place of version adding, added obj:True as doc string, changing how member limit is initiated * feat: adding chat shortcuts for invite links * fix: changing equality of chatinviteobjects * Non-test comments * Some test fixes * A bit more tests * Bump API version in both readmes * Increase coverage * Add Bot API Version in telegram.constants (#2429) * add bot api version in constants Signed-off-by: starry69 <starry369126@outlook.com> * addressing review Signed-off-by: starry69 <starry369126@outlook.com> * add versioning directive Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> * pre-commit & coverage Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Harshil <ilovebhagwan@gmail.com> Co-authored-by: starry69 <starry369126@outlook.com>
This commit is contained in:
parent
3a9a0ab96d
commit
ac02bce109
47 changed files with 2109 additions and 64 deletions
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
|
@ -27,4 +27,4 @@ Hey! You're PRing? Cool! Please have a look at the below checklist. It's here to
|
|||
- [ ] Added new handlers for new update types
|
||||
- [ ] Added new filters for new message (sub)types
|
||||
- [ ] Added or updated documentation for the changed class(es) and/or method(s)
|
||||
- [ ] Updated the Bot API version number in all places in `README.rst` and `README_RAW.rst`, including the badge
|
||||
- [ ] Updated the Bot API version number in all places: `README.rst` and `README_RAW.rst` (including the badge), as well as `telegram.constants.BOT_API_VERSION`
|
||||
|
|
|
@ -20,7 +20,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
|||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.0-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -111,7 +111,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 **5.0** are supported.
|
||||
All types and methods of the Telegram Bot API **5.1** are supported.
|
||||
|
||||
==========
|
||||
Installing
|
||||
|
|
|
@ -20,7 +20,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
|||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.0-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-5.1-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -105,7 +105,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 **5.0** are supported.
|
||||
All types and methods of the Telegram Bot API **5.1** are supported.
|
||||
|
||||
==========
|
||||
Installing
|
||||
|
|
6
docs/source/telegram.chatinvitelink.rst
Normal file
6
docs/source/telegram.chatinvitelink.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
telegram.ChatInviteLink
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.ChatInviteLink
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.chatmemberupdated.rst
Normal file
6
docs/source/telegram.chatmemberupdated.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
telegram.ChatMemberUpdated
|
||||
==========================
|
||||
|
||||
.. autoclass:: telegram.ChatMemberUpdated
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.ext.chatmemberhandler.rst
Normal file
6
docs/source/telegram.ext.chatmemberhandler.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
telegram.ext.ChatMemberHandler
|
||||
==============================
|
||||
|
||||
.. autoclass:: telegram.ext.ChatMemberHandler
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -21,6 +21,7 @@ Handlers
|
|||
telegram.ext.handler
|
||||
telegram.ext.callbackqueryhandler
|
||||
telegram.ext.choseninlineresulthandler
|
||||
telegram.ext.chatmemberhandler
|
||||
telegram.ext.commandhandler
|
||||
telegram.ext.conversationhandler
|
||||
telegram.ext.inlinequeryhandler
|
||||
|
|
6
docs/source/telegram.messageautodeletetimerchanged.rst
Normal file
6
docs/source/telegram.messageautodeletetimerchanged.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
telegram.MessageAutoDeleteTimerChanged
|
||||
======================================
|
||||
|
||||
.. autoclass:: telegram.MessageAutoDeleteTimerChanged
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -13,8 +13,10 @@ telegram package
|
|||
telegram.callbackquery
|
||||
telegram.chat
|
||||
telegram.chataction
|
||||
telegram.chatinvitelink
|
||||
telegram.chatlocation
|
||||
telegram.chatmember
|
||||
telegram.chatmemberupdated
|
||||
telegram.chatpermissions
|
||||
telegram.chatphoto
|
||||
telegram.constants
|
||||
|
@ -38,6 +40,7 @@ telegram package
|
|||
telegram.location
|
||||
telegram.loginurl
|
||||
telegram.message
|
||||
telegram.messageautodeletetimerchanged
|
||||
telegram.messageid
|
||||
telegram.messageentity
|
||||
telegram.parsemode
|
||||
|
@ -57,6 +60,9 @@ telegram package
|
|||
telegram.video
|
||||
telegram.videonote
|
||||
telegram.voice
|
||||
telegram.voicechatstarted
|
||||
telegram.voicechatended
|
||||
telegram.voicechatparticipantsinvited
|
||||
telegram.webhookinfo
|
||||
|
||||
Stickers
|
||||
|
|
7
docs/source/telegram.voicechatended.rst
Normal file
7
docs/source/telegram.voicechatended.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
telegram.VoiceChatEnded
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatEnded
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
7
docs/source/telegram.voicechatparticipantsinvited.rst
Normal file
7
docs/source/telegram.voicechatparticipantsinvited.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
telegram.VoiceChatParticipantsInvited
|
||||
=====================================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatParticipantsInvited
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
7
docs/source/telegram.voicechatstarted.rst
Normal file
7
docs/source/telegram.voicechatstarted.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
telegram.VoiceChatStarted
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.VoiceChatStarted
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
|
@ -24,7 +24,9 @@ from .user import User
|
|||
from .files.chatphoto import ChatPhoto
|
||||
from .chat import Chat
|
||||
from .chatlocation import ChatLocation
|
||||
from .chatinvitelink import ChatInviteLink
|
||||
from .chatmember import ChatMember
|
||||
from .chatmemberupdated import ChatMemberUpdated
|
||||
from .chatpermissions import ChatPermissions
|
||||
from .files.photosize import PhotoSize
|
||||
from .files.audio import Audio
|
||||
|
@ -54,6 +56,7 @@ from .messageentity import MessageEntity
|
|||
from .messageid import MessageId
|
||||
from .games.game import Game
|
||||
from .poll import Poll, PollOption, PollAnswer
|
||||
from .voicechat import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited
|
||||
from .loginurl import LoginUrl
|
||||
from .proximityalerttriggered import ProximityAlertTriggered
|
||||
from .games.callbackgame import CallbackGame
|
||||
|
@ -68,6 +71,7 @@ from .passport.encryptedpassportelement import EncryptedPassportElement
|
|||
from .passport.passportdata import PassportData
|
||||
from .inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from .messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
|
||||
from .message import Message
|
||||
from .callbackquery import CallbackQuery
|
||||
from .choseninlineresult import ChosenInlineResult
|
||||
|
@ -144,7 +148,7 @@ from .passport.credentials import (
|
|||
TelegramDecryptionError,
|
||||
)
|
||||
from .bot import Bot
|
||||
from .version import __version__ # noqa: F401
|
||||
from .version import __version__, bot_api_version # noqa: F401
|
||||
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
|
||||
|
@ -157,8 +161,10 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
'CallbackQuery',
|
||||
'Chat',
|
||||
'ChatAction',
|
||||
'ChatInviteLink',
|
||||
'ChatLocation',
|
||||
'ChatMember',
|
||||
'ChatMemberUpdated',
|
||||
'ChatPermissions',
|
||||
'ChatPhoto',
|
||||
'ChosenInlineResult',
|
||||
|
@ -226,6 +232,7 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
'MAX_MESSAGE_LENGTH',
|
||||
'MaskPosition',
|
||||
'Message',
|
||||
'MessageAutoDeleteTimerChanged',
|
||||
'MessageEntity',
|
||||
'MessageId',
|
||||
'OrderInfo',
|
||||
|
@ -272,5 +279,8 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
'Video',
|
||||
'VideoNote',
|
||||
'Voice',
|
||||
'VoiceChatStarted',
|
||||
'VoiceChatEnded',
|
||||
'VoiceChatParticipantsInvited',
|
||||
'WebhookInfo',
|
||||
)
|
||||
|
|
|
@ -24,6 +24,7 @@ from typing import Optional
|
|||
import certifi
|
||||
|
||||
from . import __version__ as telegram_ver
|
||||
from .constants import BOT_API_VERSION
|
||||
|
||||
|
||||
def _git_revision() -> Optional[str]:
|
||||
|
@ -39,6 +40,7 @@ def _git_revision() -> Optional[str]:
|
|||
def print_ver_info() -> None:
|
||||
git_revision = _git_revision()
|
||||
print(f'python-telegram-bot {telegram_ver}' + (f' ({git_revision})' if git_revision else ''))
|
||||
print(f'Bot API {BOT_API_VERSION}')
|
||||
print(f'certifi {certifi.__version__}') # type: ignore[attr-defined]
|
||||
sys_version = sys.version.replace('\n', ' ')
|
||||
print(f'Python {sys_version}')
|
||||
|
|
|
@ -46,15 +46,13 @@ class TelegramObject:
|
|||
|
||||
@staticmethod
|
||||
def parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
|
||||
if not data:
|
||||
return None
|
||||
return data.copy()
|
||||
return None if data is None else data.copy()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
if cls == TelegramObject:
|
||||
|
|
267
telegram/bot.py
267
telegram/bot.py
|
@ -85,6 +85,7 @@ from telegram import (
|
|||
Voice,
|
||||
WebhookInfo,
|
||||
InlineKeyboardMarkup,
|
||||
ChatInviteLink,
|
||||
)
|
||||
from telegram.constants import MAX_INLINE_QUERY_RESULTS
|
||||
from telegram.error import InvalidToken, TelegramError
|
||||
|
@ -297,7 +298,7 @@ class Bot(TelegramObject):
|
|||
if result is True:
|
||||
return result
|
||||
|
||||
return Message.de_json(result, self) # type: ignore[arg-type,return-value]
|
||||
return Message.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@property
|
||||
def request(self) -> Request:
|
||||
|
@ -406,7 +407,7 @@ class Bot(TelegramObject):
|
|||
"""
|
||||
result = self._post('getMe', timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
self._bot = User.de_json(result, self) # type: ignore
|
||||
self._bot = User.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
return self._bot # type: ignore[return-value]
|
||||
|
||||
|
@ -2185,7 +2186,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('getUserProfilePhotos', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return UserProfilePhotos.de_json(result, self) # type: ignore
|
||||
return UserProfilePhotos.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def get_file(
|
||||
|
@ -2245,7 +2246,7 @@ class Bot(TelegramObject):
|
|||
self.base_file_url, result['file_path'] # type: ignore[index]
|
||||
)
|
||||
|
||||
return File.de_json(result, self) # type: ignore
|
||||
return File.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def kick_chat_member(
|
||||
|
@ -2255,25 +2256,33 @@ class Bot(TelegramObject):
|
|||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
until_date: Union[int, datetime] = None,
|
||||
api_kwargs: JSONDict = None,
|
||||
revoke_messages: bool = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Use this method to kick a user from a group or a supergroup or a channel. In the case of
|
||||
Use this method to kick a user from a group, supergroup or a channel. In the case of
|
||||
supergroups and channels, the user will not be able to return to the group on their own
|
||||
using invite links, etc., unless unbanned first. The bot must be an administrator in the
|
||||
group for this to work.
|
||||
chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username
|
||||
of the target supergroup or channel (in the format @channelusername).
|
||||
user_id (:obj:`int`): Unique identifier of the target user.
|
||||
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).
|
||||
until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will
|
||||
be unbanned, unix time. If user is banned for more than 366 days or less than 30
|
||||
seconds from the current time they are considered to be banned forever.
|
||||
seconds from the current time they are considered to be banned forever. Applied
|
||||
for supergroups and channels only.
|
||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
||||
bot will be used.
|
||||
revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from
|
||||
the chat for the user that is being removed. If :obj:`False`, the user will be able
|
||||
to see messages in the group that were sent before the user was removed.
|
||||
Always :obj:`True` for supergroups and channels.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
|
@ -2293,6 +2302,9 @@ class Bot(TelegramObject):
|
|||
)
|
||||
data['until_date'] = until_date
|
||||
|
||||
if revoke_messages is not None:
|
||||
data['revoke_messages'] = revoke_messages
|
||||
|
||||
result = self._post('kickChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return result # type: ignore[return-value]
|
||||
|
@ -2711,10 +2723,11 @@ class Bot(TelegramObject):
|
|||
updates you want your bot to receive. For example, specify ["message",
|
||||
"edited_channel_post", "callback_query"] to only receive updates of these types.
|
||||
See :class:`telegram.Update` for a complete list of available update types.
|
||||
Specify an empty list to receive all updates regardless of type (default). If not
|
||||
specified, the previous setting will be used. Please note that this parameter
|
||||
doesn't affect updates created before the call to the get_updates, so unwanted
|
||||
updates may be received for a short period of time.
|
||||
Specify an empty list to receive all updates except
|
||||
:attr:`telegram.Update.chat_member` (default). If not specified, the previous
|
||||
setting will be used. Please note that this parameter doesn't affect updates
|
||||
created before the call to the get_updates, so unwanted updates may be received for
|
||||
a short period of time.
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
|
@ -2799,10 +2812,11 @@ class Bot(TelegramObject):
|
|||
updates you want your bot to receive. For example, specify ["message",
|
||||
"edited_channel_post", "callback_query"] to only receive updates of these types.
|
||||
See :class:`telegram.Update` for a complete list of available update types.
|
||||
Specify an empty list to receive all updates regardless of type (default). If not
|
||||
specified, the previous setting will be used. Please note that this parameter
|
||||
doesn't affect updates created before the call to the set_webhook, so unwanted
|
||||
updates may be received for a short period of time.
|
||||
Specify an empty list to receive all updates except
|
||||
:attr:`telegram.Update.chat_member` (default). If not specified, the previous
|
||||
setting will be used. Please note that this parameter doesn't affect updates
|
||||
created before the call to the set_webhook, so unwanted updates may be received for
|
||||
a short period of time.
|
||||
drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending
|
||||
updates.
|
||||
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||
|
@ -2948,7 +2962,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('getChat', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return Chat.de_json(result, self) # type: ignore
|
||||
return Chat.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def get_chat_administrators(
|
||||
|
@ -3047,7 +3061,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('getChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return ChatMember.de_json(result, self) # type: ignore
|
||||
return ChatMember.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def set_chat_sticker_set(
|
||||
|
@ -3132,7 +3146,7 @@ class Bot(TelegramObject):
|
|||
"""
|
||||
result = self._post('getWebhookInfo', None, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return WebhookInfo.de_json(result, self) # type: ignore
|
||||
return WebhookInfo.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def set_game_score(
|
||||
|
@ -3588,6 +3602,8 @@ class Bot(TelegramObject):
|
|||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
is_anonymous: bool = None,
|
||||
can_manage_chat: bool = None,
|
||||
can_manage_voice_chats: bool = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Use this method to promote or demote a user in a supergroup or a channel. The bot must be
|
||||
|
@ -3596,16 +3612,28 @@ class Bot(TelegramObject):
|
|||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target supergroup (in the format @supergroupusername).
|
||||
of the target channel (in the format @channelusername).
|
||||
user_id (:obj:`int`): Unique identifier of the target user.
|
||||
is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence
|
||||
in the chat is hidden.
|
||||
can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
access the chat event log, chat statistics, 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
|
||||
|
||||
can_manage_voice_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator
|
||||
can manage voice chats, supergroups only.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
change chat title, photo and other settings.
|
||||
can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
create channel posts, channels only.
|
||||
can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
edit messages of other users, channels only.
|
||||
edit messages of other users and can pin messages, channels only.
|
||||
can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
delete messages of other users.
|
||||
can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
|
||||
|
@ -3651,6 +3679,10 @@ class Bot(TelegramObject):
|
|||
data['can_pin_messages'] = can_pin_messages
|
||||
if can_promote_members is not None:
|
||||
data['can_promote_members'] = can_promote_members
|
||||
if can_manage_chat is not None:
|
||||
data['can_manage_chat'] = can_manage_chat
|
||||
if can_manage_voice_chats is not None:
|
||||
data['can_manage_voice_chats'] = can_manage_voice_chats
|
||||
|
||||
result = self._post('promoteChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
|
@ -3740,9 +3772,9 @@ class Bot(TelegramObject):
|
|||
api_kwargs: JSONDict = None,
|
||||
) -> str:
|
||||
"""
|
||||
Use this method to generate a new invite link for a chat; any previously generated link
|
||||
is revoked. The bot must be an administrator in the chat for this to work and must have
|
||||
the appropriate admin rights.
|
||||
Use this method to generate a new primary invite link for a chat; any previously generated
|
||||
link is revoked. The bot must be an administrator in the chat for this to work and must
|
||||
have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
|
@ -3753,6 +3785,13 @@ class Bot(TelegramObject):
|
|||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
Note:
|
||||
Each administrator in a chat generates their own invite links. Bots can't use invite
|
||||
links generated by other administrators. If you want your bot to work with invite
|
||||
links, it will need to generate its own link using :meth:`export_chat_invite_link` or
|
||||
by calling the :meth:`get_chat` method. If your bot needs to generate a new primary
|
||||
invite link replacing its previous one, use :attr:`export_chat_invite_link` again.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: New invite link on success.
|
||||
|
||||
|
@ -3766,6 +3805,155 @@ class Bot(TelegramObject):
|
|||
|
||||
return result # type: ignore[return-value]
|
||||
|
||||
@log
|
||||
def create_chat_invite_link(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
expire_date: Union[int, datetime] = None,
|
||||
member_limit: int = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> ChatInviteLink:
|
||||
"""
|
||||
Use this method to create an additional invite link for a chat. The bot must be an
|
||||
administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
The link can be revoked using the method :meth:`revoke_chat_invite_link`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
||||
expire.
|
||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
||||
bot will be used.
|
||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
||||
the chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
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).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {
|
||||
'chat_id': chat_id,
|
||||
}
|
||||
|
||||
if expire_date is not None:
|
||||
if isinstance(expire_date, datetime):
|
||||
expire_date = to_timestamp(
|
||||
expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None
|
||||
)
|
||||
data['expire_date'] = expire_date
|
||||
|
||||
if member_limit is not None:
|
||||
data['member_limit'] = member_limit
|
||||
|
||||
result = self._post('createChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def edit_chat_invite_link(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
invite_link: str,
|
||||
expire_date: Union[int, datetime] = None,
|
||||
member_limit: int = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> ChatInviteLink:
|
||||
"""
|
||||
Use this method to edit a non-primary invite link created by the bot. The bot must be an
|
||||
administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
invite_link (:obj:`str`): The invite link to edit.
|
||||
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
||||
expire.
|
||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
||||
bot will be used.
|
||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
||||
the chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
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).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link}
|
||||
|
||||
if expire_date is not None:
|
||||
if isinstance(expire_date, datetime):
|
||||
expire_date = to_timestamp(
|
||||
expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None
|
||||
)
|
||||
data['expire_date'] = expire_date
|
||||
|
||||
if member_limit is not None:
|
||||
data['member_limit'] = member_limit
|
||||
|
||||
result = self._post('editChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def revoke_chat_invite_link(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
invite_link: str,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> ChatInviteLink:
|
||||
"""
|
||||
Use this method to revoke an invite link created by the bot. If the primary link is
|
||||
revoked, a new link is automatically generated. The bot must be an administrator in the
|
||||
chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
invite_link (:obj:`str`): The invite link to edit.
|
||||
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).
|
||||
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
|
||||
Telegram API.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link}
|
||||
|
||||
result = self._post('revokeChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def set_chat_photo(
|
||||
self,
|
||||
|
@ -4061,7 +4249,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('getStickerSet', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return StickerSet.de_json(result, self) # type: ignore
|
||||
return StickerSet.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def upload_sticker_file(
|
||||
|
@ -4106,7 +4294,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('uploadStickerFile', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return File.de_json(result, self) # type: ignore
|
||||
return File.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def create_new_sticker_set(
|
||||
|
@ -4599,7 +4787,7 @@ class Bot(TelegramObject):
|
|||
|
||||
result = self._post('stopPoll', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
|
||||
return Poll.de_json(result, self) # type: ignore
|
||||
return Poll.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
@log
|
||||
def send_dice(
|
||||
|
@ -4614,15 +4802,18 @@ class Bot(TelegramObject):
|
|||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
) -> Message:
|
||||
"""
|
||||
Use this method to send an animated emoji, which will have a random value. On success, the
|
||||
sent Message is returned.
|
||||
Use this method to send an animated emoji that will display a random value.
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target private chat.
|
||||
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||
of the target channel (in the format @channelusername).
|
||||
emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based.
|
||||
Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, or “🎰”. Dice can have values 1-6
|
||||
for “🎲” and “🎯”, values 1-5 for “🏀” and “⚽”, and values 1-64 for “🎰”. Defaults
|
||||
to “🎲”.
|
||||
Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, "🎳", or “🎰”. Dice can have
|
||||
values 1-6 for “🎲”, “🎯” and "🎳", values 1-5 for “🏀” and “⚽”, and values 1-64
|
||||
for “🎰”. Defaults to “🎲”.
|
||||
|
||||
.. versionchanged:: 13.4
|
||||
Added the "🎳" emoji.
|
||||
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
|
||||
receive a notification with no sound.
|
||||
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
|
||||
|
@ -4852,7 +5043,7 @@ class Bot(TelegramObject):
|
|||
data['reply_markup'] = reply_markup
|
||||
|
||||
result = self._post('copyMessage', data, timeout=timeout, api_kwargs=api_kwargs)
|
||||
return MessageId.de_json(result, self) # type: ignore
|
||||
return MessageId.de_json(result, self) # type: ignore[return-value, arg-type]
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data: JSONDict = {'id': self.id, 'username': self.username, 'first_name': self.first_name}
|
||||
|
@ -4971,6 +5162,12 @@ class Bot(TelegramObject):
|
|||
"""Alias for :attr:`set_chat_administrator_custom_title`"""
|
||||
exportChatInviteLink = export_chat_invite_link
|
||||
"""Alias for :attr:`export_chat_invite_link`"""
|
||||
createChatInviteLink = create_chat_invite_link
|
||||
"""Alias for :attr:`create_chat_invite_link`"""
|
||||
editChatInviteLink = edit_chat_invite_link
|
||||
"""Alias for :attr:`edit_chat_invite_link`"""
|
||||
revokeChatInviteLink = revoke_chat_invite_link
|
||||
"""Alias for :attr:`revoke_chat_invite_link`"""
|
||||
setChatPhoto = set_chat_photo
|
||||
"""Alias for :attr:`set_chat_photo`"""
|
||||
deleteChatPhoto = delete_chat_photo
|
||||
|
|
|
@ -47,7 +47,7 @@ class CallbackQuery(TelegramObject):
|
|||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
* In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
* Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present.
|
||||
* After the user presses an inline button, Telegram clients will display a progress bar
|
||||
until you call :attr:`answer`. It is, therefore, necessary to react
|
||||
|
|
135
telegram/chat.py
135
telegram/chat.py
|
@ -32,6 +32,7 @@ if TYPE_CHECKING:
|
|||
from telegram import (
|
||||
Bot,
|
||||
ChatMember,
|
||||
ChatInviteLink,
|
||||
Message,
|
||||
MessageId,
|
||||
ReplyMarkup,
|
||||
|
@ -80,10 +81,8 @@ class Chat(TelegramObject):
|
|||
:meth:`telegram.Bot.get_chat`.
|
||||
description (:obj:`str`, optional): Description, for groups, supergroups and channel chats.
|
||||
Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
invite_link (:obj:`str`, optional): Chat invite link, for groups, supergroups and channel
|
||||
chats. Each administrator in a chat generates their own invite links, so the bot must
|
||||
first generate the link using ``export_chat_invite_link()``. Returned only
|
||||
in :meth:`telegram.Bot.get_chat`.
|
||||
invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and
|
||||
channel. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
pinned_message (:class:`telegram.Message`, optional): The most recent pinned message
|
||||
(by sending date). Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
|
@ -91,6 +90,11 @@ class Chat(TelegramObject):
|
|||
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`.
|
||||
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
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
|
||||
Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
@ -114,7 +118,8 @@ class Chat(TelegramObject):
|
|||
bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats.
|
||||
invite_link (:obj:`str`): Optional. Chat invite link, for supergroups and channel chats.
|
||||
invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and
|
||||
channel. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message
|
||||
(by sending date). Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
|
||||
|
@ -122,6 +127,11 @@ class Chat(TelegramObject):
|
|||
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`.
|
||||
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
|
||||
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
|
||||
can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
|
||||
sticker set.
|
||||
|
@ -162,6 +172,7 @@ class Chat(TelegramObject):
|
|||
bio: str = None,
|
||||
linked_chat_id: int = None,
|
||||
location: ChatLocation = None,
|
||||
message_auto_delete_time: int = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
|
@ -181,6 +192,9 @@ class Chat(TelegramObject):
|
|||
self.pinned_message = pinned_message
|
||||
self.permissions = permissions
|
||||
self.slow_mode_delay = slow_mode_delay
|
||||
self.message_auto_delete_time = (
|
||||
int(message_auto_delete_time) if message_auto_delete_time is not None else None
|
||||
)
|
||||
self.sticker_set_name = sticker_set_name
|
||||
self.can_set_sticker_set = can_set_sticker_set
|
||||
self.linked_chat_id = linked_chat_id
|
||||
|
@ -216,7 +230,7 @@ class Chat(TelegramObject):
|
|||
return None
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: JSONDict, bot: 'Bot') -> Optional['Chat']:
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Chat']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
|
@ -320,6 +334,7 @@ class Chat(TelegramObject):
|
|||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
until_date: Union[int, datetime] = None,
|
||||
api_kwargs: JSONDict = None,
|
||||
revoke_messages: bool = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
|
@ -343,6 +358,7 @@ class Chat(TelegramObject):
|
|||
timeout=timeout,
|
||||
until_date=until_date,
|
||||
api_kwargs=api_kwargs,
|
||||
revoke_messages=revoke_messages,
|
||||
)
|
||||
|
||||
def unban_member(
|
||||
|
@ -384,6 +400,8 @@ class Chat(TelegramObject):
|
|||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
is_anonymous: bool = None,
|
||||
can_manage_chat: bool = None,
|
||||
can_manage_voice_chats: bool = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
|
@ -412,6 +430,8 @@ class Chat(TelegramObject):
|
|||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
is_anonymous=is_anonymous,
|
||||
can_manage_chat=can_manage_chat,
|
||||
can_manage_voice_chats=can_manage_voice_chats,
|
||||
)
|
||||
|
||||
def restrict_member(
|
||||
|
@ -1391,3 +1411,106 @@ class Chat(TelegramObject):
|
|||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def export_invite_link(
|
||||
self,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> str:
|
||||
"""Shortcut for::
|
||||
|
||||
bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.export_chat_invite_link`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Returns:
|
||||
:obj:`str`: New invite link on success.
|
||||
|
||||
"""
|
||||
return self.bot.export_chat_invite_link(
|
||||
chat_id=self.id, timeout=timeout, api_kwargs=api_kwargs
|
||||
)
|
||||
|
||||
def create_invite_link(
|
||||
self,
|
||||
expire_date: Union[int, datetime] = None,
|
||||
member_limit: int = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> 'ChatInviteLink':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.create_chat_invite_link`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
"""
|
||||
return self.bot.create_chat_invite_link(
|
||||
chat_id=self.id,
|
||||
expire_date=expire_date,
|
||||
member_limit=member_limit,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def edit_invite_link(
|
||||
self,
|
||||
invite_link: str,
|
||||
expire_date: Union[int, datetime] = None,
|
||||
member_limit: int = None,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> 'ChatInviteLink':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.edit_chat_invite_link`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
"""
|
||||
return self.bot.edit_chat_invite_link(
|
||||
chat_id=self.id,
|
||||
invite_link=invite_link,
|
||||
expire_date=expire_date,
|
||||
member_limit=member_limit,
|
||||
timeout=timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def revoke_invite_link(
|
||||
self,
|
||||
invite_link: str,
|
||||
timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: JSONDict = None,
|
||||
) -> 'ChatInviteLink':
|
||||
"""Shortcut for::
|
||||
|
||||
bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.revoke_chat_invite_link`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Returns:
|
||||
:class:`telegram.ChatInviteLink`
|
||||
|
||||
"""
|
||||
return self.bot.revoke_chat_invite_link(
|
||||
chat_id=self.id, invite_link=invite_link, timeout=timeout, api_kwargs=api_kwargs
|
||||
)
|
||||
|
|
102
telegram/chatinvitelink.py
Normal file
102
telegram/chatinvitelink.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents an invite link for a chat."""
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import TelegramObject, User
|
||||
from telegram.utils.helpers import from_timestamp, to_timestamp
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
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.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
invite_link (:obj:`str`): The invite link.
|
||||
creator (:class:`telegram.User`): Creator of the link.
|
||||
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
|
||||
has been expired.
|
||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of the
|
||||
chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
|
||||
Attributes:
|
||||
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.
|
||||
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
|
||||
has been expired.
|
||||
member_limit (:obj:`int`): Optional. Maximum number of users that can be members
|
||||
of the chat simultaneously after joining the chat via this invite link; 1-99999.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
invite_link: str,
|
||||
creator: User,
|
||||
is_primary: bool,
|
||||
is_revoked: bool,
|
||||
expire_date: datetime.datetime = None,
|
||||
member_limit: int = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.invite_link = invite_link
|
||||
self.creator = creator
|
||||
self.is_primary = is_primary
|
||||
self.is_revoked = is_revoked
|
||||
|
||||
# Optionals
|
||||
self.expire_date = expire_date
|
||||
self.member_limit = int(member_limit) if member_limit is not None else None
|
||||
|
||||
self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['creator'] = User.de_json(data.get('creator'), bot)
|
||||
data['expire_date'] = from_timestamp(data.get('expire_date', None))
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data['expire_date'] = to_timestamp(self.expire_date)
|
||||
|
||||
return data
|
|
@ -46,6 +46,18 @@ class ChatMember(TelegramObject):
|
|||
restrictions will be lifted for this user.
|
||||
can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is
|
||||
allowed to edit administrator privileges of that user.
|
||||
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
|
||||
|
||||
can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
|
||||
administrator can manage voice chats.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
|
||||
if the user can change the chat title, photo and other settings.
|
||||
can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
|
||||
|
@ -87,6 +99,17 @@ class ChatMember(TelegramObject):
|
|||
for this user.
|
||||
can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
|
||||
privileges of that user.
|
||||
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
|
||||
|
||||
can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage
|
||||
voice chats.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and
|
||||
other settings.
|
||||
can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel.
|
||||
|
@ -150,6 +173,8 @@ class ChatMember(TelegramObject):
|
|||
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
|
||||
|
@ -175,6 +200,8 @@ class ChatMember(TelegramObject):
|
|||
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)
|
||||
|
||||
|
|
115
telegram/chatmemberupdated.py
Normal file
115
telegram/chatmemberupdated.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram ChatMemberUpdated."""
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from telegram import TelegramObject, User, Chat, ChatMember, ChatInviteLink
|
||||
from telegram.utils.helpers import from_timestamp, to_timestamp
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class ChatMemberUpdated(TelegramObject):
|
||||
"""This object represents changes in the status of a chat member.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`,
|
||||
:attr:`old_chat_member` and :attr:`new_chat_member` are equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Note:
|
||||
In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
chat (:class:`telegram.Chat`): Chat the user belongs to.
|
||||
from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
|
||||
date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
|
||||
new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
|
||||
invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used
|
||||
by the user to join the chat. For joining by invite link events only.
|
||||
|
||||
Attributes:
|
||||
chat (:class:`telegram.Chat`): Chat the user belongs to.
|
||||
from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
|
||||
date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
|
||||
:class:`datetime.datetime`.
|
||||
old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
|
||||
new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
|
||||
invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used
|
||||
by the user to join the chat.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
chat: Chat,
|
||||
from_user: User,
|
||||
date: datetime.datetime,
|
||||
old_chat_member: ChatMember,
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: ChatInviteLink = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.chat = chat
|
||||
self.from_user = from_user
|
||||
self.date = date
|
||||
self.old_chat_member = old_chat_member
|
||||
self.new_chat_member = new_chat_member
|
||||
|
||||
# Optionals
|
||||
self.invite_link = invite_link
|
||||
|
||||
self._id_attrs = (
|
||||
self.chat,
|
||||
self.from_user,
|
||||
self.date,
|
||||
self.old_chat_member,
|
||||
self.new_chat_member,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMemberUpdated']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
||||
data['from_user'] = User.de_json(data.get('from'), bot)
|
||||
data['date'] = from_timestamp(data.get('date'))
|
||||
data['old_chat_member'] = ChatMember.de_json(data.get('old_chat_member'), bot)
|
||||
data['new_chat_member'] = ChatMember.de_json(data.get('new_chat_member'), bot)
|
||||
data['invite_link'] = ChatInviteLink.de_json(data.get('invite_link'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
# Required
|
||||
data['date'] = to_timestamp(self.date)
|
||||
|
||||
return data
|
|
@ -37,7 +37,7 @@ class ChosenInlineResult(TelegramObject):
|
|||
considered equal, if their :attr:`result_id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
* In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
* It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in
|
||||
order to receive these objects in updates.
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ The following constants were extracted from the
|
|||
`Telegram Bots API <https://core.telegram.org/bots/api>`_.
|
||||
|
||||
Attributes:
|
||||
BOT_API_VERSION (:obj:`str`): `5.1`. Telegram Bot API version supported by this
|
||||
version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
MAX_MESSAGE_LENGTH (:obj:`int`): 4096
|
||||
MAX_CAPTION_LENGTH (:obj:`int`): 1024
|
||||
SUPPORTED_WEBHOOK_PORTS (List[:obj:`int`]): [443, 80, 88, 8443]
|
||||
|
@ -88,8 +92,14 @@ Attributes:
|
|||
DICE_BASKETBALL (:obj:`str`): '🏀'
|
||||
DICE_FOOTBALL (:obj:`str`): '⚽'
|
||||
DICE_SLOT_MACHINE (:obj:`str`): '🎰'
|
||||
DICE_BOWLING (:obj:`str`): '🎳'
|
||||
|
||||
.. versionadded:: 13.4
|
||||
DICE_ALL_EMOJI (List[:obj:`str`]): List of all supported base emoji.
|
||||
|
||||
.. versionchanged:: 13.4
|
||||
Added :attr:`DICE_BOWLING`
|
||||
|
||||
:class:`telegram.MessageEntity`:
|
||||
|
||||
Attributes:
|
||||
|
@ -136,6 +146,7 @@ Attributes:
|
|||
"""
|
||||
from typing import List
|
||||
|
||||
BOT_API_VERSION: str = '5.1'
|
||||
MAX_MESSAGE_LENGTH: int = 4096
|
||||
MAX_CAPTION_LENGTH: int = 1024
|
||||
ANONYMOUS_ADMIN_ID: int = 1087968824
|
||||
|
@ -182,12 +193,14 @@ DICE_DARTS: str = '🎯'
|
|||
DICE_BASKETBALL: str = '🏀'
|
||||
DICE_FOOTBALL: str = '⚽'
|
||||
DICE_SLOT_MACHINE: str = '🎰'
|
||||
DICE_BOWLING: str = '🎳'
|
||||
DICE_ALL_EMOJI: List[str] = [
|
||||
DICE_DICE,
|
||||
DICE_DARTS,
|
||||
DICE_BASKETBALL,
|
||||
DICE_FOOTBALL,
|
||||
DICE_SLOT_MACHINE,
|
||||
DICE_BOWLING,
|
||||
]
|
||||
|
||||
MESSAGEENTITY_MENTION: str = 'mention'
|
||||
|
|
|
@ -45,13 +45,17 @@ class Dice(TelegramObject):
|
|||
3 indicates that the goal was missed. However, this behaviour is undocumented and might
|
||||
be changed by Telegram.
|
||||
|
||||
If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all
|
||||
the pins were missed. However, this behaviour is undocumented and might be changed by
|
||||
Telegram.
|
||||
|
||||
If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which
|
||||
can be found at our `wiki <https://git.io/JkeC6>`_. However, this behaviour is undocumented
|
||||
and might be changed by Telegram.
|
||||
|
||||
Args:
|
||||
value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball and
|
||||
football/soccer ball, 1-64 for slot machine.
|
||||
value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for
|
||||
basketball and football/soccer ball, 1-64 for slot machine.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
|
||||
Attributes:
|
||||
|
@ -76,5 +80,11 @@ class Dice(TelegramObject):
|
|||
""":const:`telegram.constants.DICE_FOOTBALL`"""
|
||||
SLOT_MACHINE: ClassVar[str] = constants.DICE_SLOT_MACHINE
|
||||
""":const:`telegram.constants.DICE_SLOT_MACHINE`"""
|
||||
BOWLING: ClassVar[str] = constants.DICE_BOWLING
|
||||
"""
|
||||
:const:`telegram.constants.DICE_BOWLING`
|
||||
|
||||
.. versionadded:: 13.4
|
||||
"""
|
||||
ALL_EMOJI: ClassVar[List[str]] = constants.DICE_ALL_EMOJI
|
||||
""":const:`telegram.constants.DICE_ALL_EMOJI`"""
|
||||
|
|
|
@ -43,6 +43,7 @@ from .messagequeue import MessageQueue
|
|||
from .messagequeue import DelayQueue
|
||||
from .pollanswerhandler import PollAnswerHandler
|
||||
from .pollhandler import PollHandler
|
||||
from .chatmemberhandler import ChatMemberHandler
|
||||
from .defaults import Defaults
|
||||
|
||||
__all__ = (
|
||||
|
@ -78,5 +79,6 @@ __all__ = (
|
|||
'PrefixHandler',
|
||||
'PollAnswerHandler',
|
||||
'PollHandler',
|
||||
'ChatMemberHandler',
|
||||
'Defaults',
|
||||
)
|
||||
|
|
146
telegram/ext/chatmemberhandler.py
Normal file
146
telegram/ext/chatmemberhandler.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2019-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the ChatMemberHandler classes."""
|
||||
from typing import ClassVar, TypeVar, Union, Callable, TYPE_CHECKING
|
||||
|
||||
from telegram import Update
|
||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||
from .handler import Handler
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
class ChatMemberHandler(Handler[Update]):
|
||||
"""Handler class to handle Telegram updates that contain a chat member update.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Note:
|
||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
||||
can use to keep any data in will be sent to the :attr:`callback` function. Related to
|
||||
either the user or the chat that the update was sent in. For each update from the same user
|
||||
or in the same chat, it will be the same ``dict``.
|
||||
|
||||
Note that this is DEPRECATED, and you should use context based callbacks. See
|
||||
https://git.io/fxJuV for more info.
|
||||
|
||||
Warning:
|
||||
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
|
||||
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
|
||||
|
||||
Args:
|
||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||
:attr:`check_update` has determined that an update should be processed by this handler.
|
||||
Callback signature for context based API:
|
||||
|
||||
``def callback(update: Update, context: CallbackContext)``
|
||||
|
||||
The return value of the callback is usually ignored except for the special case of
|
||||
:class:`telegram.ext.ConversationHandler`.
|
||||
chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`,
|
||||
:attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle
|
||||
only updates with :attr:`telegram.Update.my_chat_member`,
|
||||
:attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`.
|
||||
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``update_queue`` will be passed to the callback function. It will be the ``Queue``
|
||||
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
|
||||
that contains new updates which can be used to insert updates. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``job_queue`` will be passed to the callback function. It will be a
|
||||
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
|
||||
which can be used to schedule new jobs. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``user_data`` will be passed to the callback function. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
|
||||
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
|
||||
DEPRECATED: Please switch to context based callbacks.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
Defaults to :obj:`False`.
|
||||
|
||||
Attributes:
|
||||
callback (:obj:`callable`): The callback function for this handler.
|
||||
chat_member_types (:obj:`int`, optional): Specifies if this handler should handle
|
||||
only updates with :attr:`telegram.Update.my_chat_member`,
|
||||
:attr:`telegram.Update.chat_member` or both.
|
||||
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
|
||||
passed to the callback function.
|
||||
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
|
||||
the callback function.
|
||||
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
|
||||
the callback function.
|
||||
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
|
||||
the callback function.
|
||||
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
|
||||
|
||||
"""
|
||||
|
||||
MY_CHAT_MEMBER: ClassVar[int] = -1
|
||||
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
|
||||
CHAT_MEMBER: ClassVar[int] = 0
|
||||
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`."""
|
||||
ANY_CHAT_MEMBER: ClassVar[int] = 1
|
||||
""":obj:`int`: Used as a constant to handle bot :attr:`telegram.Update.my_chat_member`
|
||||
and :attr:`telegram.Update.chat_member`."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[Update, 'CallbackContext'], RT],
|
||||
chat_member_types: int = MY_CHAT_MEMBER,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
self.chat_member_types = chat_member_types
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update):
|
||||
if not (update.my_chat_member or update.chat_member):
|
||||
return False
|
||||
if self.chat_member_types == self.ANY_CHAT_MEMBER:
|
||||
return True
|
||||
if self.chat_member_types == self.CHAT_MEMBER:
|
||||
return bool(update.chat_member)
|
||||
return bool(update.my_chat_member)
|
||||
return False
|
|
@ -1005,6 +1005,15 @@ officedocument.wordprocessingml.document")``.
|
|||
:attr: `telegram.Message.supergroup_chat_created` or
|
||||
:attr: `telegram.Message.channel_chat_created`."""
|
||||
|
||||
class _MessageAutoDeleteTimerChanged(MessageFilter):
|
||||
name = 'MessageAutoDeleteTimerChanged'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.message_auto_delete_timer_changed)
|
||||
|
||||
message_auto_delete_timer_changed = _MessageAutoDeleteTimerChanged()
|
||||
"""Messages that contain :attr:`message_auto_delete_timer_changed`"""
|
||||
|
||||
class _Migrate(MessageFilter):
|
||||
name = 'Filters.status_update.migrate'
|
||||
|
||||
|
@ -1042,6 +1051,33 @@ officedocument.wordprocessingml.document")``.
|
|||
proximity_alert_triggered = _ProximityAlertTriggered()
|
||||
"""Messages that contain :attr:`telegram.Message.proximity_alert_triggered`."""
|
||||
|
||||
class _VoiceChatStarted(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_started'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_started)
|
||||
|
||||
voice_chat_started = _VoiceChatStarted()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_started`."""
|
||||
|
||||
class _VoiceChatEnded(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_ended'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_ended)
|
||||
|
||||
voice_chat_ended = _VoiceChatEnded()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_ended`."""
|
||||
|
||||
class _VoiceChatParticipantsInvited(MessageFilter):
|
||||
name = 'Filters.status_update.voice_chat_participants_invited'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.voice_chat_participants_invited)
|
||||
|
||||
voice_chat_participants_invited = _VoiceChatParticipantsInvited()
|
||||
"""Messages that contain :attr:`telegram.Message.voice_chat_participants_invited`."""
|
||||
|
||||
name = 'Filters.status_update'
|
||||
|
||||
def filter(self, message: Update) -> bool:
|
||||
|
@ -1052,10 +1088,14 @@ officedocument.wordprocessingml.document")``.
|
|||
or self.new_chat_photo(message)
|
||||
or self.delete_chat_photo(message)
|
||||
or self.chat_created(message)
|
||||
or self.message_auto_delete_timer_changed(message)
|
||||
or self.migrate(message)
|
||||
or self.pinned_message(message)
|
||||
or self.connected_website(message)
|
||||
or self.proximity_alert_triggered(message)
|
||||
or self.voice_chat_started(message)
|
||||
or self.voice_chat_ended(message)
|
||||
or self.voice_chat_participants_invited(message)
|
||||
)
|
||||
|
||||
status_update = _StatusUpdate()
|
||||
|
@ -1085,10 +1125,27 @@ officedocument.wordprocessingml.document")``.
|
|||
:attr:`telegram.Message.new_chat_photo`.
|
||||
new_chat_title: Messages that contain
|
||||
:attr:`telegram.Message.new_chat_title`.
|
||||
message_auto_delete_timer_changed: Messages that contain
|
||||
:attr:`message_auto_delete_timer_changed`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
pinned_message: Messages that contain
|
||||
:attr:`telegram.Message.pinned_message`.
|
||||
proximity_alert_triggered: Messages that contain
|
||||
:attr:`telegram.Message.proximity_alert_triggered`.
|
||||
voice_chat_started: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_started`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_ended: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_ended`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_participants_invited: Messages that contain
|
||||
:attr:`telegram.Message.voice_chat_participants_invited`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
"""
|
||||
|
||||
class _Forwarded(MessageFilter):
|
||||
|
@ -1831,6 +1888,7 @@ officedocument.wordprocessingml.document")``.
|
|||
basketball = _DiceEmoji('🏀', 'basketball')
|
||||
football = _DiceEmoji('⚽')
|
||||
slot_machine = _DiceEmoji('🎰')
|
||||
bowling = _DiceEmoji('🎳', 'bowling')
|
||||
|
||||
dice = _Dice()
|
||||
"""Dice Messages. If an integer or a list of integers is passed, it filters messages to only
|
||||
|
@ -1863,6 +1921,11 @@ officedocument.wordprocessingml.document")``.
|
|||
as for :attr:`Filters.dice`.
|
||||
slot_machine: Dice messages with the emoji 🎰. Passing a list of integers is supported just
|
||||
as for :attr:`Filters.dice`.
|
||||
bowling: Dice messages with the emoji 🎳. Passing a list of integers is supported just
|
||||
as for :attr:`Filters.dice`.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
"""
|
||||
|
||||
class language(MessageFilter):
|
||||
|
|
|
@ -38,7 +38,7 @@ class InlineQuery(TelegramObject):
|
|||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
* In Python `from` is a reserved word, use `from_user` instead.
|
||||
* In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier for this query.
|
||||
|
|
|
@ -31,6 +31,10 @@ class InlineQueryResult(TelegramObject):
|
|||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
All URLs passed in inline query results will be available to end users and therefore must
|
||||
be assumed to be public.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of the result.
|
||||
id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
|
||||
|
|
|
@ -47,8 +47,12 @@ from telegram import (
|
|||
Video,
|
||||
VideoNote,
|
||||
Voice,
|
||||
VoiceChatStarted,
|
||||
VoiceChatEnded,
|
||||
VoiceChatParticipantsInvited,
|
||||
ProximityAlertTriggered,
|
||||
ReplyMarkup,
|
||||
MessageAutoDeleteTimerChanged,
|
||||
)
|
||||
from telegram.utils.helpers import (
|
||||
escape_markdown,
|
||||
|
@ -83,7 +87,7 @@ class Message(TelegramObject):
|
|||
considered equal, if their :attr:`message_id` and :attr:`chat` are equal.
|
||||
|
||||
Note:
|
||||
In Python `from` is a reserved word, use `from_user` instead.
|
||||
In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
message_id (:obj:`int`): Unique message identifier inside this chat.
|
||||
|
@ -165,6 +169,10 @@ class Message(TelegramObject):
|
|||
created. This field can't be received in a message coming through updates, because bot
|
||||
can't be a member of a channel when it is created. It can only be found in
|
||||
:attr:`reply_to_message` if someone replies to a very first message in a channel.
|
||||
message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \
|
||||
optional): Service message: auto-delete timer settings changed in the chat.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup with
|
||||
the specified identifier. This number may be greater than 32 bits and some programming
|
||||
languages may have difficulty/silent defects in interpreting it. But it is smaller than
|
||||
|
@ -196,6 +204,18 @@ class Message(TelegramObject):
|
|||
proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service
|
||||
message. A user in the chat triggered another user's proximity alert while sharing
|
||||
Live Location.
|
||||
voice_chat_started (:class:`telegram.VoiceChatStarted`, optional): Service message: voice
|
||||
chat started.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_ended (:class:`telegram.VoiceChatEnded`, optional): Service message: voice chat
|
||||
ended.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited` optional):
|
||||
Service message: new participants invited to a voice chat.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
|
||||
to the message. ``login_url`` buttons are represented as ordinary url buttons.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
|
@ -257,6 +277,10 @@ class Message(TelegramObject):
|
|||
group_chat_created (:obj:`bool`): Optional. The group has been created.
|
||||
supergroup_chat_created (:obj:`bool`): Optional. The supergroup has been created.
|
||||
channel_chat_created (:obj:`bool`): Optional. The channel has been created.
|
||||
message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`):
|
||||
Optional. Service message: auto-delete timer settings changed in the chat.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup with
|
||||
the specified identifier.
|
||||
migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group
|
||||
|
@ -281,6 +305,18 @@ class Message(TelegramObject):
|
|||
proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service
|
||||
message. A user in the chat triggered another user's proximity alert while sharing
|
||||
Live Location.
|
||||
voice_chat_started (:class:`telegram.VoiceChatStarted`): Optional. Service message: voice
|
||||
chat started
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_ended (:class:`telegram.VoiceChatEnded`): Optional. Service message: voice chat
|
||||
ended.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited`): Optional.
|
||||
Service message: new participants invited to a voice chat.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
|
||||
to the message.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
@ -316,6 +352,7 @@ class Message(TelegramObject):
|
|||
'group_chat_created',
|
||||
'supergroup_chat_created',
|
||||
'channel_chat_created',
|
||||
'message_auto_delete_timer_changed',
|
||||
'migrate_to_chat_id',
|
||||
'migrate_from_chat_id',
|
||||
'pinned_message',
|
||||
|
@ -323,6 +360,9 @@ class Message(TelegramObject):
|
|||
'dice',
|
||||
'passport_data',
|
||||
'proximity_alert_triggered',
|
||||
'voice_chat_started',
|
||||
'voice_chat_ended',
|
||||
'voice_chat_participants_invited',
|
||||
] + ATTACHMENT_TYPES
|
||||
|
||||
def __init__(
|
||||
|
@ -379,6 +419,10 @@ class Message(TelegramObject):
|
|||
via_bot: User = None,
|
||||
proximity_alert_triggered: ProximityAlertTriggered = None,
|
||||
sender_chat: Chat = None,
|
||||
voice_chat_started: VoiceChatStarted = None,
|
||||
voice_chat_ended: VoiceChatEnded = None,
|
||||
voice_chat_participants_invited: VoiceChatParticipantsInvited = None,
|
||||
message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
|
@ -418,6 +462,7 @@ class Message(TelegramObject):
|
|||
self.migrate_to_chat_id = migrate_to_chat_id
|
||||
self.migrate_from_chat_id = migrate_from_chat_id
|
||||
self.channel_chat_created = bool(channel_chat_created)
|
||||
self.message_auto_delete_timer_changed = message_auto_delete_timer_changed
|
||||
self.pinned_message = pinned_message
|
||||
self.forward_from_message_id = forward_from_message_id
|
||||
self.invoice = invoice
|
||||
|
@ -433,6 +478,9 @@ class Message(TelegramObject):
|
|||
self.dice = dice
|
||||
self.via_bot = via_bot
|
||||
self.proximity_alert_triggered = proximity_alert_triggered
|
||||
self.voice_chat_started = voice_chat_started
|
||||
self.voice_chat_ended = voice_chat_ended
|
||||
self.voice_chat_participants_invited = voice_chat_participants_invited
|
||||
self.reply_markup = reply_markup
|
||||
self.bot = bot
|
||||
|
||||
|
@ -489,6 +537,9 @@ class Message(TelegramObject):
|
|||
data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot)
|
||||
data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot)
|
||||
data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot)
|
||||
data['message_auto_delete_timer_changed'] = MessageAutoDeleteTimerChanged.de_json(
|
||||
data.get('message_auto_delete_timer_changed'), bot
|
||||
)
|
||||
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
|
||||
data['invoice'] = Invoice.de_json(data.get('invoice'), bot)
|
||||
data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
|
||||
|
@ -500,7 +551,11 @@ class Message(TelegramObject):
|
|||
data.get('proximity_alert_triggered'), bot
|
||||
)
|
||||
data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot)
|
||||
|
||||
data['voice_chat_started'] = VoiceChatStarted.de_json(data.get('voice_chat_started'), bot)
|
||||
data['voice_chat_ended'] = VoiceChatEnded.de_json(data.get('voice_chat_ended'), bot)
|
||||
data['voice_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json(
|
||||
data.get('voice_chat_participants_invited'), bot
|
||||
)
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
@property
|
||||
|
|
53
telegram/messageautodeletetimerchanged.py
Normal file
53
telegram/messageautodeletetimerchanged.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a change in the Telegram message auto
|
||||
deletion."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class MessageAutoDeleteTimerChanged(TelegramObject):
|
||||
"""This object represents a service message about a change in auto-delete timer settings.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`message_auto_delete_time` is equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
|
||||
chat.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
|
||||
chat.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message_auto_delete_time: int,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
self.message_auto_delete_time = int(message_auto_delete_time)
|
||||
|
||||
self._id_attrs = (self.message_auto_delete_time,)
|
|
@ -35,7 +35,7 @@ class PreCheckoutQuery(TelegramObject):
|
|||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
In Python `from` is a reserved word, use `from_user` instead.
|
||||
In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique query identifier.
|
||||
|
|
|
@ -35,7 +35,7 @@ class ShippingQuery(TelegramObject):
|
|||
considered equal, if their :attr:`id` is equal.
|
||||
|
||||
Note:
|
||||
In Python `from` is a reserved word, use `from_user` instead.
|
||||
In Python ``from`` is a reserved word, use ``from_user`` instead.
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique query identifier.
|
||||
|
|
|
@ -29,6 +29,7 @@ from telegram import (
|
|||
PreCheckoutQuery,
|
||||
ShippingQuery,
|
||||
TelegramObject,
|
||||
ChatMemberUpdated,
|
||||
)
|
||||
from telegram.poll import PollAnswer
|
||||
from telegram.utils.types import JSONDict
|
||||
|
@ -74,6 +75,19 @@ class Update(TelegramObject):
|
|||
poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer
|
||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
||||
by the bot itself.
|
||||
my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member
|
||||
status was updated in a chat. For private chats, this update is received only when the
|
||||
bot is blocked or unblocked by the user.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was
|
||||
updated in a chat. The bot must be an administrator in the chat and must explicitly
|
||||
specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these
|
||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
||||
:meth:`telegram.ext.Updater.start_polling` and
|
||||
:meth:`telegram.ext.Updater.start_webhook`).
|
||||
|
||||
.. versionadded:: 13.4
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
Attributes:
|
||||
|
@ -94,6 +108,19 @@ class Update(TelegramObject):
|
|||
poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer
|
||||
in a non-anonymous poll. Bots receive new votes only in polls that were sent
|
||||
by the bot itself.
|
||||
my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member
|
||||
status was updated in a chat. For private chats, this update is received only when the
|
||||
bot is blocked or unblocked by the user.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was
|
||||
updated in a chat. The bot must be an administrator in the chat and must explicitly
|
||||
specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these
|
||||
updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
|
||||
:meth:`telegram.ext.Updater.start_polling` and
|
||||
:meth:`telegram.ext.Updater.start_webhook`).
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
"""
|
||||
|
||||
|
@ -111,6 +138,8 @@ class Update(TelegramObject):
|
|||
pre_checkout_query: PreCheckoutQuery = None,
|
||||
poll: Poll = None,
|
||||
poll_answer: PollAnswer = None,
|
||||
my_chat_member: ChatMemberUpdated = None,
|
||||
chat_member: ChatMemberUpdated = None,
|
||||
**_kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
|
@ -127,6 +156,8 @@ class Update(TelegramObject):
|
|||
self.edited_channel_post = edited_channel_post
|
||||
self.poll = poll
|
||||
self.poll_answer = poll_answer
|
||||
self.my_chat_member = my_chat_member
|
||||
self.chat_member = chat_member
|
||||
|
||||
self._effective_user: Optional['User'] = None
|
||||
self._effective_chat: Optional['Chat'] = None
|
||||
|
@ -170,6 +201,12 @@ class Update(TelegramObject):
|
|||
elif self.poll_answer:
|
||||
user = self.poll_answer.user
|
||||
|
||||
elif self.my_chat_member:
|
||||
user = self.my_chat_member.from_user
|
||||
|
||||
elif self.chat_member:
|
||||
user = self.chat_member.from_user
|
||||
|
||||
self._effective_user = user
|
||||
return user
|
||||
|
||||
|
@ -203,6 +240,12 @@ class Update(TelegramObject):
|
|||
elif self.edited_channel_post:
|
||||
chat = self.edited_channel_post.chat
|
||||
|
||||
elif self.my_chat_member:
|
||||
chat = self.my_chat_member.chat
|
||||
|
||||
elif self.chat_member:
|
||||
chat = self.chat_member.chat
|
||||
|
||||
self._effective_chat = chat
|
||||
return chat
|
||||
|
||||
|
@ -259,5 +302,7 @@ class Update(TelegramObject):
|
|||
data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot)
|
||||
data['poll'] = Poll.de_json(data.get('poll'), bot)
|
||||
data['poll_answer'] = PollAnswer.de_json(data.get('poll_answer'), bot)
|
||||
data['my_chat_member'] = ChatMemberUpdated.de_json(data.get('my_chat_member'), bot)
|
||||
data['chat_member'] = ChatMemberUpdated.de_json(data.get('chat_member'), bot)
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -18,4 +18,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=C0114
|
||||
|
||||
from telegram import constants
|
||||
|
||||
__version__ = '13.3'
|
||||
bot_api_version = constants.BOT_API_VERSION # pylint: disable=C0103
|
||||
|
|
111
telegram/voicechat.py
Normal file
111
telegram/voicechat.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains objects related to Telegram voice chats."""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Optional, List
|
||||
|
||||
from telegram import TelegramObject, User
|
||||
from telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class VoiceChatStarted(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about a voice
|
||||
chat started in the chat. Currently holds no information.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
"""
|
||||
|
||||
def __init__(self, **_kwargs: Any):
|
||||
pass
|
||||
|
||||
|
||||
class VoiceChatEnded(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about a
|
||||
voice chat ended in the chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`duration` are equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
duration (:obj:`int`): Voice chat duration in seconds.
|
||||
|
||||
Attributes:
|
||||
duration (:obj:`int`): Voice chat duration in seconds.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, duration: int, **_kwargs: Any) -> None:
|
||||
self.duration = int(duration) if duration is not None else None
|
||||
self._id_attrs = (self.duration,)
|
||||
|
||||
|
||||
class VoiceChatParticipantsInvited(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about
|
||||
new members invited to a voice chat.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`users` are equal.
|
||||
|
||||
.. versionadded:: 13.4
|
||||
|
||||
Args:
|
||||
users (List[:class:`telegram.User`]): New members that
|
||||
were invited to the voice chat.
|
||||
|
||||
Attributes:
|
||||
users (List[:class:`telegram.User`]): New members that
|
||||
were invited to the voice chat.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, users: List[User], **_kwargs: Any) -> 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'
|
||||
) -> Optional['VoiceChatParticipantsInvited']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data['users'] = User.de_list(data.get('users', []), bot)
|
||||
return cls(**data)
|
||||
|
||||
def to_dict(self) -> JSONDict:
|
||||
data = super().to_dict()
|
||||
|
||||
data["users"] = [u.to_dict() for u in self.users]
|
||||
return data
|
|
@ -23,6 +23,7 @@ from pathlib import Path
|
|||
from platform import python_implementation
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
from flaky import flaky
|
||||
|
||||
from telegram import (
|
||||
|
@ -868,13 +869,14 @@ class TestBot:
|
|||
assert bot.token not in resulting_path
|
||||
assert resulting_path == path
|
||||
|
||||
# TODO: Needs improvement. No feasable way to test until bots can add members.
|
||||
# TODO: Needs improvement. No feasible way to test until bots can add members.
|
||||
def test_kick_chat_member(self, monkeypatch, bot):
|
||||
def test(url, data, *args, **kwargs):
|
||||
chat_id = data['chat_id'] == 2
|
||||
user_id = data['user_id'] == 32
|
||||
until_date = data.get('until_date', 1577887200) == 1577887200
|
||||
return chat_id and user_id and until_date
|
||||
revoke_msgs = data.get('revoke_messages', True) is True
|
||||
return chat_id and user_id and until_date and revoke_msgs
|
||||
|
||||
monkeypatch.setattr(bot.request, 'post', test)
|
||||
until = from_timestamp(1577887200)
|
||||
|
@ -882,6 +884,7 @@ class TestBot:
|
|||
assert bot.kick_chat_member(2, 32)
|
||||
assert bot.kick_chat_member(2, 32, until_date=until)
|
||||
assert bot.kick_chat_member(2, 32, until_date=1577887200)
|
||||
assert bot.kick_chat_member(2, 32, revoke_messages=True)
|
||||
|
||||
def test_kick_chat_member_default_tz(self, monkeypatch, tz_bot):
|
||||
until = dtm.datetime(2020, 1, 11, 16, 13)
|
||||
|
@ -1497,7 +1500,7 @@ class TestBot:
|
|||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_promote_chat_member(self, bot, channel_id):
|
||||
def test_promote_chat_member(self, bot, channel_id, monkeypatch):
|
||||
# TODO: Add bot to supergroup so this can be tested properly / give bot perms
|
||||
with pytest.raises(BadRequest, match='Not enough rights'):
|
||||
assert bot.promote_chat_member(
|
||||
|
@ -1512,8 +1515,46 @@ class TestBot:
|
|||
can_restrict_members=True,
|
||||
can_pin_messages=True,
|
||||
can_promote_members=True,
|
||||
can_manage_chat=True,
|
||||
can_manage_voice_chats=True,
|
||||
)
|
||||
|
||||
# Test that we pass the correct params to TG
|
||||
def make_assertion(*args, **_):
|
||||
data = args[1]
|
||||
return (
|
||||
data.get('chat_id') == channel_id
|
||||
and data.get('user_id') == 95205500
|
||||
and data.get('is_anonymous') == 1
|
||||
and data.get('can_change_info') == 2
|
||||
and data.get('can_post_messages') == 3
|
||||
and data.get('can_edit_messages') == 4
|
||||
and data.get('can_delete_messages') == 5
|
||||
and data.get('can_invite_users') == 6
|
||||
and data.get('can_restrict_members') == 7
|
||||
and data.get('can_pin_messages') == 8
|
||||
and data.get('can_promote_members') == 9
|
||||
and data.get('can_manage_chat') == 10
|
||||
and data.get('can_manage_voice_chats') == 11
|
||||
)
|
||||
|
||||
monkeypatch.setattr(bot, '_post', make_assertion)
|
||||
assert bot.promote_chat_member(
|
||||
channel_id,
|
||||
95205500,
|
||||
is_anonymous=1,
|
||||
can_change_info=2,
|
||||
can_post_messages=3,
|
||||
can_edit_messages=4,
|
||||
can_delete_messages=5,
|
||||
can_invite_users=6,
|
||||
can_restrict_members=7,
|
||||
can_pin_messages=8,
|
||||
can_promote_members=9,
|
||||
can_manage_chat=10,
|
||||
can_manage_voice_chats=11,
|
||||
)
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_export_chat_invite_link(self, bot, channel_id):
|
||||
|
@ -1522,6 +1563,72 @@ class TestBot:
|
|||
assert isinstance(invite_link, str)
|
||||
assert invite_link != ''
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
@pytest.mark.parametrize('datetime', argvalues=[True, False], ids=['datetime', 'integer'])
|
||||
def test_advanced_chat_invite_links(self, bot, channel_id, datetime):
|
||||
# we are testing this all in one function in order to save api calls
|
||||
timestamp = dtm.datetime.utcnow()
|
||||
add_seconds = dtm.timedelta(0, 70)
|
||||
time_in_future = timestamp + add_seconds
|
||||
expire_time = time_in_future if datetime else to_timestamp(time_in_future)
|
||||
aware_time_in_future = pytz.UTC.localize(time_in_future)
|
||||
|
||||
invite_link = bot.create_chat_invite_link(
|
||||
channel_id, expire_date=expire_time, member_limit=10
|
||||
)
|
||||
assert invite_link.invite_link != ''
|
||||
assert not invite_link.invite_link.endswith('...')
|
||||
assert pytest.approx(invite_link.expire_date == aware_time_in_future)
|
||||
assert invite_link.member_limit == 10
|
||||
|
||||
add_seconds = dtm.timedelta(0, 80)
|
||||
time_in_future = timestamp + add_seconds
|
||||
expire_time = time_in_future if datetime else to_timestamp(time_in_future)
|
||||
aware_time_in_future = pytz.UTC.localize(time_in_future)
|
||||
|
||||
edited_invite_link = bot.edit_chat_invite_link(
|
||||
channel_id, invite_link.invite_link, expire_date=expire_time, member_limit=20
|
||||
)
|
||||
assert edited_invite_link.invite_link == invite_link.invite_link
|
||||
assert pytest.approx(edited_invite_link.expire_date == aware_time_in_future)
|
||||
assert edited_invite_link.member_limit == 20
|
||||
|
||||
revoked_invite_link = bot.revoke_chat_invite_link(channel_id, invite_link.invite_link)
|
||||
assert revoked_invite_link.invite_link == invite_link.invite_link
|
||||
assert revoked_invite_link.is_revoked is True
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_advanced_chat_invite_links_default_tzinfo(self, tz_bot, channel_id):
|
||||
# we are testing this all in one function in order to save api calls
|
||||
add_seconds = dtm.timedelta(0, 70)
|
||||
aware_expire_date = dtm.datetime.now(tz=tz_bot.defaults.tzinfo) + add_seconds
|
||||
time_in_future = aware_expire_date.replace(tzinfo=None)
|
||||
|
||||
invite_link = tz_bot.create_chat_invite_link(
|
||||
channel_id, expire_date=time_in_future, member_limit=10
|
||||
)
|
||||
assert invite_link.invite_link != ''
|
||||
assert not invite_link.invite_link.endswith('...')
|
||||
assert pytest.approx(invite_link.expire_date == aware_expire_date)
|
||||
assert invite_link.member_limit == 10
|
||||
|
||||
add_seconds = dtm.timedelta(0, 80)
|
||||
aware_expire_date += add_seconds
|
||||
time_in_future = aware_expire_date.replace(tzinfo=None)
|
||||
|
||||
edited_invite_link = tz_bot.edit_chat_invite_link(
|
||||
channel_id, invite_link.invite_link, expire_date=time_in_future, member_limit=20
|
||||
)
|
||||
assert edited_invite_link.invite_link == invite_link.invite_link
|
||||
assert pytest.approx(edited_invite_link.expire_date == aware_expire_date)
|
||||
assert edited_invite_link.member_limit == 20
|
||||
|
||||
revoked_invite_link = tz_bot.revoke_chat_invite_link(channel_id, invite_link.invite_link)
|
||||
assert revoked_invite_link.invite_link == invite_link.invite_link
|
||||
assert revoked_invite_link.is_revoked is True
|
||||
|
||||
@flaky(3, 1)
|
||||
@pytest.mark.timeout(10)
|
||||
def test_set_chat_photo(self, bot, channel_id):
|
||||
|
|
|
@ -37,6 +37,7 @@ def chat(bot):
|
|||
can_set_sticker_set=TestChat.can_set_sticker_set,
|
||||
permissions=TestChat.permissions,
|
||||
slow_mode_delay=TestChat.slow_mode_delay,
|
||||
message_auto_delete_time=TestChat.message_auto_delete_time,
|
||||
bio=TestChat.bio,
|
||||
linked_chat_id=TestChat.linked_chat_id,
|
||||
location=TestChat.location,
|
||||
|
@ -57,6 +58,7 @@ class TestChat:
|
|||
can_invite_users=True,
|
||||
)
|
||||
slow_mode_delay = 30
|
||||
message_auto_delete_time = 42
|
||||
bio = "I'm a Barbie Girl in a Barbie World"
|
||||
linked_chat_id = 11880
|
||||
location = ChatLocation(Location(123, 456), 'Barbie World')
|
||||
|
@ -72,6 +74,7 @@ class TestChat:
|
|||
'can_set_sticker_set': self.can_set_sticker_set,
|
||||
'permissions': self.permissions.to_dict(),
|
||||
'slow_mode_delay': self.slow_mode_delay,
|
||||
'message_auto_delete_time': self.message_auto_delete_time,
|
||||
'bio': self.bio,
|
||||
'linked_chat_id': self.linked_chat_id,
|
||||
'location': self.location.to_dict(),
|
||||
|
@ -87,6 +90,7 @@ class TestChat:
|
|||
assert chat.can_set_sticker_set == self.can_set_sticker_set
|
||||
assert chat.permissions == self.permissions
|
||||
assert chat.slow_mode_delay == self.slow_mode_delay
|
||||
assert chat.message_auto_delete_time == self.message_auto_delete_time
|
||||
assert chat.bio == self.bio
|
||||
assert chat.linked_chat_id == self.linked_chat_id
|
||||
assert chat.location.location == self.location.location
|
||||
|
@ -103,6 +107,7 @@ class TestChat:
|
|||
assert chat_dict['all_members_are_administrators'] == chat.all_members_are_administrators
|
||||
assert chat_dict['permissions'] == chat.permissions.to_dict()
|
||||
assert chat_dict['slow_mode_delay'] == chat.slow_mode_delay
|
||||
assert chat_dict['message_auto_delete_time'] == chat.message_auto_delete_time
|
||||
assert chat_dict['bio'] == chat.bio
|
||||
assert chat_dict['linked_chat_id'] == chat.linked_chat_id
|
||||
assert chat_dict['location'] == chat.location.to_dict()
|
||||
|
@ -556,6 +561,62 @@ class TestChat:
|
|||
monkeypatch.setattr(chat.bot, 'copy_message', make_assertion)
|
||||
assert chat.copy_message(chat_id='test_copy', message_id=42)
|
||||
|
||||
def test_export_invite_link(self, monkeypatch, chat):
|
||||
def make_assertion(*_, **kwargs):
|
||||
return kwargs['chat_id'] == chat.id
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Chat.export_invite_link, Bot.export_chat_invite_link, ['chat_id'], []
|
||||
)
|
||||
assert check_shortcut_call(chat.export_invite_link, chat.bot, 'export_chat_invite_link')
|
||||
assert check_defaults_handling(chat.export_invite_link, chat.bot)
|
||||
|
||||
monkeypatch.setattr(chat.bot, 'export_chat_invite_link', make_assertion)
|
||||
assert chat.export_invite_link()
|
||||
|
||||
def test_create_invite_link(self, monkeypatch, chat):
|
||||
def make_assertion(*_, **kwargs):
|
||||
return kwargs['chat_id'] == chat.id
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Chat.create_invite_link, Bot.create_chat_invite_link, ['chat_id'], []
|
||||
)
|
||||
assert check_shortcut_call(chat.create_invite_link, chat.bot, 'create_chat_invite_link')
|
||||
assert check_defaults_handling(chat.create_invite_link, chat.bot)
|
||||
|
||||
monkeypatch.setattr(chat.bot, 'create_chat_invite_link', make_assertion)
|
||||
assert chat.create_invite_link()
|
||||
|
||||
def test_edit_invite_link(self, monkeypatch, chat):
|
||||
link = "ThisIsALink"
|
||||
|
||||
def make_assertion(*_, **kwargs):
|
||||
return kwargs['chat_id'] == chat.id and kwargs['invite_link'] == link
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Chat.edit_invite_link, Bot.edit_chat_invite_link, ['chat_id'], []
|
||||
)
|
||||
assert check_shortcut_call(chat.edit_invite_link, chat.bot, 'edit_chat_invite_link')
|
||||
assert check_defaults_handling(chat.edit_invite_link, chat.bot)
|
||||
|
||||
monkeypatch.setattr(chat.bot, 'edit_chat_invite_link', make_assertion)
|
||||
assert chat.edit_invite_link(invite_link=link)
|
||||
|
||||
def test_revoke_invite_link(self, monkeypatch, chat):
|
||||
link = "ThisIsALink"
|
||||
|
||||
def make_assertion(*_, **kwargs):
|
||||
return kwargs['chat_id'] == chat.id and kwargs['invite_link'] == link
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Chat.revoke_invite_link, Bot.revoke_chat_invite_link, ['chat_id'], []
|
||||
)
|
||||
assert check_shortcut_call(chat.revoke_invite_link, chat.bot, 'revoke_chat_invite_link')
|
||||
assert check_defaults_handling(chat.revoke_invite_link, chat.bot)
|
||||
|
||||
monkeypatch.setattr(chat.bot, 'revoke_chat_invite_link', make_assertion)
|
||||
assert chat.revoke_invite_link(invite_link=link)
|
||||
|
||||
def test_equality(self):
|
||||
a = Chat(self.id_, self.title, self.type_)
|
||||
b = Chat(self.id_, self.title, self.type_)
|
||||
|
|
119
tests/test_chatinvitelink.py
Normal file
119
tests/test_chatinvitelink.py
Normal file
|
@ -0,0 +1,119 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import User, ChatInviteLink
|
||||
from telegram.utils.helpers import to_timestamp
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def creator():
|
||||
return User(1, 'First name', False)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def invite_link(creator):
|
||||
return ChatInviteLink(
|
||||
TestChatInviteLink.link,
|
||||
creator,
|
||||
TestChatInviteLink.primary,
|
||||
TestChatInviteLink.revoked,
|
||||
expire_date=TestChatInviteLink.expire_date,
|
||||
member_limit=TestChatInviteLink.member_limit,
|
||||
)
|
||||
|
||||
|
||||
class TestChatInviteLink:
|
||||
|
||||
link = "thisialink"
|
||||
primary = True
|
||||
revoked = False
|
||||
expire_date = datetime.datetime.utcnow()
|
||||
member_limit = 42
|
||||
|
||||
def test_de_json_required_args(self, bot, creator):
|
||||
json_dict = {
|
||||
'invite_link': self.link,
|
||||
'creator': creator.to_dict(),
|
||||
'is_primary': self.primary,
|
||||
'is_revoked': self.revoked,
|
||||
}
|
||||
|
||||
invite_link = ChatInviteLink.de_json(json_dict, bot)
|
||||
|
||||
assert invite_link.invite_link == self.link
|
||||
assert invite_link.creator == creator
|
||||
assert invite_link.is_primary == self.primary
|
||||
assert invite_link.is_revoked == self.revoked
|
||||
|
||||
def test_de_json_all_args(self, bot, creator):
|
||||
json_dict = {
|
||||
'invite_link': self.link,
|
||||
'creator': creator.to_dict(),
|
||||
'is_primary': self.primary,
|
||||
'is_revoked': self.revoked,
|
||||
'expire_date': to_timestamp(self.expire_date),
|
||||
'member_limit': self.member_limit,
|
||||
}
|
||||
|
||||
invite_link = ChatInviteLink.de_json(json_dict, bot)
|
||||
|
||||
assert invite_link.invite_link == self.link
|
||||
assert invite_link.creator == creator
|
||||
assert invite_link.is_primary == self.primary
|
||||
assert invite_link.is_revoked == self.revoked
|
||||
assert pytest.approx(invite_link.expire_date == self.expire_date)
|
||||
assert to_timestamp(invite_link.expire_date) == to_timestamp(self.expire_date)
|
||||
assert invite_link.member_limit == self.member_limit
|
||||
|
||||
def test_to_dict(self, invite_link):
|
||||
invite_link_dict = invite_link.to_dict()
|
||||
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['is_primary'] == self.primary
|
||||
assert invite_link_dict['is_revoked'] == self.revoked
|
||||
assert invite_link_dict['expire_date'] == to_timestamp(self.expire_date)
|
||||
assert invite_link_dict['member_limit'] == self.member_limit
|
||||
|
||||
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)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != d2
|
||||
assert hash(a) != hash(d2)
|
||||
|
||||
assert d2 != d3
|
||||
assert hash(d2) != hash(d3)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
|
@ -69,6 +69,8 @@ class TestChatMember:
|
|||
'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 = ChatMember.de_json(json_dict, bot)
|
||||
|
@ -91,6 +93,8 @@ class TestChatMember:
|
|||
assert chat_member.can_send_polls is False
|
||||
assert chat_member.can_send_other_messages is True
|
||||
assert chat_member.can_add_web_page_previews is False
|
||||
assert chat_member.can_manage_chat is True
|
||||
assert chat_member.can_manage_voice_chats is True
|
||||
|
||||
def test_to_dict(self, chat_member):
|
||||
chat_member_dict = chat_member.to_dict()
|
||||
|
|
221
tests/test_chatmemberhandler.py
Normal file
221
tests/test_chatmemberhandler.py
Normal file
|
@ -0,0 +1,221 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import time
|
||||
from queue import Queue
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Update,
|
||||
Bot,
|
||||
Message,
|
||||
User,
|
||||
Chat,
|
||||
CallbackQuery,
|
||||
ChosenInlineResult,
|
||||
ShippingQuery,
|
||||
PreCheckoutQuery,
|
||||
ChatMemberUpdated,
|
||||
ChatMember,
|
||||
)
|
||||
from telegram.ext import CallbackContext, JobQueue, ChatMemberHandler
|
||||
from telegram.utils.helpers import from_timestamp
|
||||
|
||||
message = Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
|
||||
|
||||
params = [
|
||||
{'message': message},
|
||||
{'edited_message': message},
|
||||
{'callback_query': CallbackQuery(1, User(1, '', False), 'chat', message=message)},
|
||||
{'channel_post': message},
|
||||
{'edited_channel_post': message},
|
||||
{'chosen_inline_result': ChosenInlineResult('id', User(1, '', False), '')},
|
||||
{'shipping_query': ShippingQuery('id', User(1, '', False), '', None)},
|
||||
{'pre_checkout_query': PreCheckoutQuery('id', User(1, '', False), '', 0, '')},
|
||||
{'callback_query': CallbackQuery(1, User(1, '', False), 'chat')},
|
||||
]
|
||||
|
||||
ids = (
|
||||
'message',
|
||||
'edited_message',
|
||||
'callback_query',
|
||||
'channel_post',
|
||||
'edited_channel_post',
|
||||
'chosen_inline_result',
|
||||
'shipping_query',
|
||||
'pre_checkout_query',
|
||||
'callback_query_without_message',
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class', params=params, ids=ids)
|
||||
def false_update(request):
|
||||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def chat_member_updated():
|
||||
return ChatMemberUpdated(
|
||||
Chat(1, 'chat'),
|
||||
User(1, '', False),
|
||||
from_timestamp(int(time.time())),
|
||||
ChatMember(User(1, '', False), ChatMember.CREATOR),
|
||||
ChatMember(User(1, '', False), ChatMember.CREATOR),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def chat_member(bot, chat_member_updated):
|
||||
return Update(0, my_chat_member=chat_member_updated)
|
||||
|
||||
|
||||
class TestChatMemberHandler:
|
||||
test_flag = False
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
def callback_basic(self, bot, update):
|
||||
test_bot = isinstance(bot, Bot)
|
||||
test_update = isinstance(update, Update)
|
||||
self.test_flag = test_bot and test_update
|
||||
|
||||
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
|
||||
self.test_flag = (user_data is not None) or (chat_data is not None)
|
||||
|
||||
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
|
||||
self.test_flag = (user_data is not None) and (chat_data is not None)
|
||||
|
||||
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
|
||||
self.test_flag = (job_queue is not None) or (update_queue is not None)
|
||||
|
||||
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
|
||||
self.test_flag = (job_queue is not None) and (update_queue is not None)
|
||||
|
||||
def callback_context(self, update, context):
|
||||
self.test_flag = (
|
||||
isinstance(context, CallbackContext)
|
||||
and isinstance(context.bot, Bot)
|
||||
and isinstance(update, Update)
|
||||
and isinstance(context.update_queue, Queue)
|
||||
and isinstance(context.job_queue, JobQueue)
|
||||
and isinstance(context.user_data, dict)
|
||||
and isinstance(context.chat_data, dict)
|
||||
and isinstance(context.bot_data, dict)
|
||||
and isinstance(update.chat_member or update.my_chat_member, ChatMemberUpdated)
|
||||
)
|
||||
|
||||
def test_basic(self, dp, chat_member):
|
||||
handler = ChatMemberHandler(self.callback_basic)
|
||||
dp.add_handler(handler)
|
||||
|
||||
assert handler.check_update(chat_member)
|
||||
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames=['allowed_types', 'expected'],
|
||||
argvalues=[
|
||||
(ChatMemberHandler.MY_CHAT_MEMBER, (True, False)),
|
||||
(ChatMemberHandler.CHAT_MEMBER, (False, True)),
|
||||
(ChatMemberHandler.ANY_CHAT_MEMBER, (True, True)),
|
||||
],
|
||||
ids=['MY_CHAT_MEMBER', 'CHAT_MEMBER', 'ANY_CHAT_MEMBER'],
|
||||
)
|
||||
def test_chat_member_types(
|
||||
self, dp, chat_member_updated, chat_member, expected, allowed_types
|
||||
):
|
||||
result_1, result_2 = expected
|
||||
|
||||
handler = ChatMemberHandler(self.callback_basic, chat_member_types=allowed_types)
|
||||
dp.add_handler(handler)
|
||||
|
||||
assert handler.check_update(chat_member) == result_1
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag == result_1
|
||||
|
||||
self.test_flag = False
|
||||
chat_member.my_chat_member = None
|
||||
chat_member.chat_member = chat_member_updated
|
||||
|
||||
assert handler.check_update(chat_member) == result_2
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag == result_2
|
||||
|
||||
def test_pass_user_or_chat_data(self, dp, chat_member):
|
||||
handler = ChatMemberHandler(self.callback_data_1, pass_user_data=True)
|
||||
dp.add_handler(handler)
|
||||
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
dp.remove_handler(handler)
|
||||
handler = ChatMemberHandler(self.callback_data_1, pass_chat_data=True)
|
||||
dp.add_handler(handler)
|
||||
|
||||
self.test_flag = False
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
dp.remove_handler(handler)
|
||||
handler = ChatMemberHandler(self.callback_data_2, pass_chat_data=True, pass_user_data=True)
|
||||
dp.add_handler(handler)
|
||||
|
||||
self.test_flag = False
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
def test_pass_job_or_update_queue(self, dp, chat_member):
|
||||
handler = ChatMemberHandler(self.callback_queue_1, pass_job_queue=True)
|
||||
dp.add_handler(handler)
|
||||
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
dp.remove_handler(handler)
|
||||
handler = ChatMemberHandler(self.callback_queue_1, pass_update_queue=True)
|
||||
dp.add_handler(handler)
|
||||
|
||||
self.test_flag = False
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
dp.remove_handler(handler)
|
||||
handler = ChatMemberHandler(
|
||||
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
|
||||
)
|
||||
dp.add_handler(handler)
|
||||
|
||||
self.test_flag = False
|
||||
dp.process_update(chat_member)
|
||||
assert self.test_flag
|
||||
|
||||
def test_other_update_types(self, false_update):
|
||||
handler = ChatMemberHandler(self.callback_basic)
|
||||
assert not handler.check_update(false_update)
|
||||
assert not handler.check_update(True)
|
||||
|
||||
def test_context(self, cdp, chat_member):
|
||||
handler = ChatMemberHandler(self.callback_context)
|
||||
cdp.add_handler(handler)
|
||||
|
||||
cdp.process_update(chat_member)
|
||||
assert self.test_flag
|
177
tests/test_chatmemberupdated.py
Normal file
177
tests/test_chatmemberupdated.py
Normal file
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from telegram import User, ChatMember, Chat, ChatMemberUpdated, ChatInviteLink
|
||||
from telegram.utils.helpers import to_timestamp
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def user():
|
||||
return User(1, 'First name', False)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def chat():
|
||||
return Chat(1, Chat.SUPERGROUP, 'Chat')
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def old_chat_member(user):
|
||||
return ChatMember(user, TestChatMemberUpdated.old_status)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def new_chat_member(user):
|
||||
return ChatMember(user, TestChatMemberUpdated.new_status)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def time():
|
||||
return datetime.datetime.now(tz=pytz.utc)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def invite_link(user):
|
||||
return ChatInviteLink('link', user, True, True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def chat_member_updated(user, chat, old_chat_member, new_chat_member, invite_link, time):
|
||||
return ChatMemberUpdated(chat, user, time, old_chat_member, new_chat_member, invite_link)
|
||||
|
||||
|
||||
class TestChatMemberUpdated:
|
||||
old_status = ChatMember.MEMBER
|
||||
new_status = ChatMember.ADMINISTRATOR
|
||||
|
||||
def test_de_json_required_args(self, bot, user, chat, old_chat_member, new_chat_member, time):
|
||||
json_dict = {
|
||||
'chat': chat.to_dict(),
|
||||
'from': user.to_dict(),
|
||||
'date': to_timestamp(time),
|
||||
'old_chat_member': old_chat_member.to_dict(),
|
||||
'new_chat_member': new_chat_member.to_dict(),
|
||||
}
|
||||
|
||||
chat_member_updated = ChatMemberUpdated.de_json(json_dict, bot)
|
||||
|
||||
assert chat_member_updated.chat == chat
|
||||
assert chat_member_updated.from_user == user
|
||||
assert pytest.approx(chat_member_updated.date == time)
|
||||
assert to_timestamp(chat_member_updated.date) == to_timestamp(time)
|
||||
assert chat_member_updated.old_chat_member == old_chat_member
|
||||
assert chat_member_updated.new_chat_member == new_chat_member
|
||||
assert chat_member_updated.invite_link is None
|
||||
|
||||
def test_de_json_all_args(
|
||||
self, bot, user, time, invite_link, chat, old_chat_member, new_chat_member
|
||||
):
|
||||
json_dict = {
|
||||
'chat': chat.to_dict(),
|
||||
'from': user.to_dict(),
|
||||
'date': to_timestamp(time),
|
||||
'old_chat_member': old_chat_member.to_dict(),
|
||||
'new_chat_member': new_chat_member.to_dict(),
|
||||
'invite_link': invite_link.to_dict(),
|
||||
}
|
||||
|
||||
chat_member_updated = ChatMemberUpdated.de_json(json_dict, bot)
|
||||
|
||||
assert chat_member_updated.chat == chat
|
||||
assert chat_member_updated.from_user == user
|
||||
assert pytest.approx(chat_member_updated.date == time)
|
||||
assert to_timestamp(chat_member_updated.date) == to_timestamp(time)
|
||||
assert chat_member_updated.old_chat_member == old_chat_member
|
||||
assert chat_member_updated.new_chat_member == new_chat_member
|
||||
assert chat_member_updated.invite_link == invite_link
|
||||
|
||||
def test_to_dict(self, chat_member_updated):
|
||||
chat_member_updated_dict = chat_member_updated.to_dict()
|
||||
assert isinstance(chat_member_updated_dict, dict)
|
||||
assert chat_member_updated_dict['chat'] == chat_member_updated.chat.to_dict()
|
||||
assert chat_member_updated_dict['from'] == chat_member_updated.from_user.to_dict()
|
||||
assert chat_member_updated_dict['date'] == to_timestamp(chat_member_updated.date)
|
||||
assert (
|
||||
chat_member_updated_dict['old_chat_member']
|
||||
== chat_member_updated.old_chat_member.to_dict()
|
||||
)
|
||||
assert (
|
||||
chat_member_updated_dict['new_chat_member']
|
||||
== chat_member_updated.new_chat_member.to_dict()
|
||||
)
|
||||
assert chat_member_updated_dict['invite_link'] == chat_member_updated.invite_link.to_dict()
|
||||
|
||||
def test_equality(self, time, old_chat_member, new_chat_member, invite_link):
|
||||
a = ChatMemberUpdated(
|
||||
Chat(1, 'chat'),
|
||||
User(1, '', False),
|
||||
time,
|
||||
old_chat_member,
|
||||
new_chat_member,
|
||||
invite_link,
|
||||
)
|
||||
b = ChatMemberUpdated(
|
||||
Chat(1, 'chat'), User(1, '', False), time, old_chat_member, new_chat_member
|
||||
)
|
||||
# wrong date
|
||||
c = ChatMemberUpdated(
|
||||
Chat(1, 'chat'),
|
||||
User(1, '', False),
|
||||
time + datetime.timedelta(hours=1),
|
||||
old_chat_member,
|
||||
new_chat_member,
|
||||
)
|
||||
# wrong chat & form_user
|
||||
d = ChatMemberUpdated(
|
||||
Chat(42, 'wrong_chat'),
|
||||
User(42, 'wrong_user', False),
|
||||
time,
|
||||
old_chat_member,
|
||||
new_chat_member,
|
||||
)
|
||||
# wrong old_chat_member
|
||||
e = ChatMemberUpdated(
|
||||
Chat(1, 'chat'),
|
||||
User(1, '', False),
|
||||
time,
|
||||
ChatMember(User(1, '', False), ChatMember.CREATOR),
|
||||
new_chat_member,
|
||||
)
|
||||
# wrong new_chat_member
|
||||
f = ChatMemberUpdated(
|
||||
Chat(1, 'chat'),
|
||||
User(1, '', False),
|
||||
time,
|
||||
old_chat_member,
|
||||
ChatMember(User(1, '', False), ChatMember.CREATOR),
|
||||
)
|
||||
# wrong type
|
||||
g = ChatMember(User(1, '', False), ChatMember.CREATOR)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
for other in [c, d, e, f, g]:
|
||||
assert a != other
|
||||
assert hash(a) != hash(other)
|
|
@ -44,7 +44,7 @@ def update():
|
|||
|
||||
@pytest.fixture(scope='function', params=MessageEntity.ALL_TYPES)
|
||||
def message_entity(request):
|
||||
return MessageEntity(request.param, 0, 0, url='', user='')
|
||||
return MessageEntity(request.param, 0, 0, url='', user=User(1, 'first_name', False))
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
|
@ -828,6 +828,11 @@ class TestFilters:
|
|||
assert Filters.status_update.chat_created(update)
|
||||
update.message.channel_chat_created = False
|
||||
|
||||
update.message.message_auto_delete_timer_changed = True
|
||||
assert Filters.status_update(update)
|
||||
assert Filters.status_update.message_auto_delete_timer_changed(update)
|
||||
update.message.message_auto_delete_timer_changed = False
|
||||
|
||||
update.message.migrate_to_chat_id = 100
|
||||
assert Filters.status_update(update)
|
||||
assert Filters.status_update.migrate(update)
|
||||
|
@ -853,6 +858,21 @@ class TestFilters:
|
|||
assert Filters.status_update.proximity_alert_triggered(update)
|
||||
update.message.proximity_alert_triggered = None
|
||||
|
||||
update.message.voice_chat_started = 'hello'
|
||||
assert Filters.status_update(update)
|
||||
assert Filters.status_update.voice_chat_started(update)
|
||||
update.message.voice_chat_started = None
|
||||
|
||||
update.message.voice_chat_ended = 'bye'
|
||||
assert Filters.status_update(update)
|
||||
assert Filters.status_update.voice_chat_ended(update)
|
||||
update.message.voice_chat_ended = None
|
||||
|
||||
update.message.voice_chat_participants_invited = 'invited'
|
||||
assert Filters.status_update(update)
|
||||
assert Filters.status_update.voice_chat_participants_invited(update)
|
||||
update.message.voice_chat_participants_invited = None
|
||||
|
||||
def test_filters_forwarded(self, update):
|
||||
assert not Filters.forwarded(update)
|
||||
update.message.forward_date = datetime.datetime.utcnow()
|
||||
|
@ -1453,6 +1473,13 @@ class TestFilters:
|
|||
assert not Filters.dice.darts(update)
|
||||
assert not Filters.dice.slot_machine([4])(update)
|
||||
|
||||
update.message.dice = Dice(5, '🎳')
|
||||
assert Filters.dice.bowling(update)
|
||||
assert Filters.dice.bowling([4, 5])(update)
|
||||
assert not Filters.dice.dice(update)
|
||||
assert not Filters.dice.darts(update)
|
||||
assert not Filters.dice.bowling([4])(update)
|
||||
|
||||
def test_language_filter_single(self, update):
|
||||
update.message.from_user.language_code = 'en_US'
|
||||
assert (Filters.language('en_US'))(update)
|
||||
|
|
|
@ -48,6 +48,10 @@ from telegram import (
|
|||
Dice,
|
||||
Bot,
|
||||
ChatAction,
|
||||
VoiceChatStarted,
|
||||
VoiceChatEnded,
|
||||
VoiceChatParticipantsInvited,
|
||||
MessageAutoDeleteTimerChanged,
|
||||
)
|
||||
from telegram.ext import Defaults
|
||||
from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling
|
||||
|
@ -115,6 +119,7 @@ def message(bot):
|
|||
{'group_chat_created': True},
|
||||
{'supergroup_chat_created': True},
|
||||
{'channel_chat_created': True},
|
||||
{'message_auto_delete_timer_changed': MessageAutoDeleteTimerChanged(42)},
|
||||
{'migrate_to_chat_id': -12345},
|
||||
{'migrate_from_chat_id': -54321},
|
||||
{'pinned_message': Message(7, None, None, None)},
|
||||
|
@ -166,6 +171,13 @@ def message(bot):
|
|||
User(1, 'John', False), User(2, 'Doe', False), 42
|
||||
)
|
||||
},
|
||||
{'voice_chat_started': VoiceChatStarted()},
|
||||
{'voice_chat_ended': VoiceChatEnded(100)},
|
||||
{
|
||||
'voice_chat_participants_invited': VoiceChatParticipantsInvited(
|
||||
[User(1, 'Rem', False), User(2, 'Emilia', False)]
|
||||
)
|
||||
},
|
||||
{'sender_chat': Chat(-123, 'discussion_channel')},
|
||||
],
|
||||
ids=[
|
||||
|
@ -195,6 +207,7 @@ def message(bot):
|
|||
'group_created',
|
||||
'supergroup_created',
|
||||
'channel_created',
|
||||
'message_auto_delete_timer_changed',
|
||||
'migrated_to',
|
||||
'migrated_from',
|
||||
'pinned',
|
||||
|
@ -211,6 +224,9 @@ def message(bot):
|
|||
'dice',
|
||||
'via_bot',
|
||||
'proximity_alert_triggered',
|
||||
'voice_chat_started',
|
||||
'voice_chat_ended',
|
||||
'voice_chat_participants_invited',
|
||||
'sender_chat',
|
||||
],
|
||||
)
|
||||
|
|
51
tests/test_messageautodeletetimerchanged.py
Normal file
51
tests/test_messageautodeletetimerchanged.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
from telegram import MessageAutoDeleteTimerChanged, VoiceChatEnded
|
||||
|
||||
|
||||
class TestMessageAutoDeleteTimerChanged:
|
||||
message_auto_delete_time = 100
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {'message_auto_delete_time': self.message_auto_delete_time}
|
||||
madtc = MessageAutoDeleteTimerChanged.de_json(json_dict, None)
|
||||
|
||||
assert madtc.message_auto_delete_time == self.message_auto_delete_time
|
||||
|
||||
def test_to_dict(self):
|
||||
madtc = MessageAutoDeleteTimerChanged(self.message_auto_delete_time)
|
||||
madtc_dict = madtc.to_dict()
|
||||
|
||||
assert isinstance(madtc_dict, dict)
|
||||
assert madtc_dict["message_auto_delete_time"] == self.message_auto_delete_time
|
||||
|
||||
def test_equality(self):
|
||||
a = MessageAutoDeleteTimerChanged(100)
|
||||
b = MessageAutoDeleteTimerChanged(100)
|
||||
c = MessageAutoDeleteTimerChanged(50)
|
||||
d = VoiceChatEnded(25)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
|
@ -16,6 +16,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 time
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -31,10 +32,20 @@ from telegram import (
|
|||
PreCheckoutQuery,
|
||||
Poll,
|
||||
PollOption,
|
||||
ChatMemberUpdated,
|
||||
ChatMember,
|
||||
)
|
||||
from telegram.poll import PollAnswer
|
||||
from telegram.utils.helpers import from_timestamp
|
||||
|
||||
message = Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
|
||||
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),
|
||||
)
|
||||
|
||||
params = [
|
||||
{'message': message},
|
||||
|
@ -49,6 +60,8 @@ params = [
|
|||
{'callback_query': CallbackQuery(1, User(1, '', False), 'chat')},
|
||||
{'poll': Poll('id', '?', [PollOption('.', 1)], False, False, False, Poll.REGULAR, True)},
|
||||
{'poll_answer': PollAnswer("id", User(1, '', False), [1])},
|
||||
{'my_chat_member': chat_member_updated},
|
||||
{'chat_member': chat_member_updated},
|
||||
]
|
||||
|
||||
all_types = (
|
||||
|
@ -63,6 +76,8 @@ all_types = (
|
|||
'pre_checkout_query',
|
||||
'poll',
|
||||
'poll_answer',
|
||||
'my_chat_member',
|
||||
'chat_member',
|
||||
)
|
||||
|
||||
ids = all_types + ('callback_query_without_message',)
|
||||
|
@ -146,6 +161,8 @@ class TestUpdate:
|
|||
or update.pre_checkout_query is not None
|
||||
or update.poll is not None
|
||||
or update.poll_answer is not None
|
||||
or update.my_chat_member is not None
|
||||
or update.chat_member is not None
|
||||
):
|
||||
assert eff_message.message_id == message.message_id
|
||||
else:
|
||||
|
|
114
tests/test_voicechat.py
Normal file
114
tests/test_voicechat.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env python
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2021
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited, User
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def user1():
|
||||
return User(first_name='Misses Test', id=123, is_bot=False)
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def user2():
|
||||
return User(first_name='Mister Test', id=124, is_bot=False)
|
||||
|
||||
|
||||
class TestVoiceChatStarted:
|
||||
def test_de_json(self):
|
||||
voice_chat_started = VoiceChatStarted.de_json({}, None)
|
||||
assert isinstance(voice_chat_started, VoiceChatStarted)
|
||||
|
||||
def test_to_dict(self):
|
||||
voice_chat_started = VoiceChatStarted()
|
||||
voice_chat_dict = voice_chat_started.to_dict()
|
||||
assert voice_chat_dict == {}
|
||||
|
||||
|
||||
class TestVoiceChatEnded:
|
||||
duration = 100
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {'duration': self.duration}
|
||||
voice_chat_ended = VoiceChatEnded.de_json(json_dict, None)
|
||||
|
||||
assert voice_chat_ended.duration == self.duration
|
||||
|
||||
def test_to_dict(self):
|
||||
voice_chat_ended = VoiceChatEnded(self.duration)
|
||||
voice_chat_dict = voice_chat_ended.to_dict()
|
||||
|
||||
assert isinstance(voice_chat_dict, dict)
|
||||
assert voice_chat_dict["duration"] == self.duration
|
||||
|
||||
def test_equality(self):
|
||||
a = VoiceChatEnded(100)
|
||||
b = VoiceChatEnded(100)
|
||||
c = VoiceChatEnded(50)
|
||||
d = VoiceChatStarted()
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
|
||||
class TestVoiceChatParticipantsInvited:
|
||||
def test_de_json(self, user1, user2, bot):
|
||||
json_data = {"users": [user1.to_dict(), user2.to_dict()]}
|
||||
voice_chat_participants = VoiceChatParticipantsInvited.de_json(json_data, bot)
|
||||
|
||||
assert isinstance(voice_chat_participants.users, list)
|
||||
assert voice_chat_participants.users[0] == user1
|
||||
assert voice_chat_participants.users[1] == user2
|
||||
assert voice_chat_participants.users[0].id == user1.id
|
||||
assert voice_chat_participants.users[1].id == user2.id
|
||||
|
||||
def test_to_dict(self, user1, user2):
|
||||
voice_chat_participants = VoiceChatParticipantsInvited([user1, user2])
|
||||
voice_chat_dict = voice_chat_participants.to_dict()
|
||||
|
||||
assert isinstance(voice_chat_dict, dict)
|
||||
assert voice_chat_dict["users"] == [user1.to_dict(), user2.to_dict()]
|
||||
assert voice_chat_dict["users"][0]["id"] == user1.id
|
||||
assert voice_chat_dict["users"][1]["id"] == user2.id
|
||||
|
||||
def test_equality(self, user1, user2):
|
||||
a = VoiceChatParticipantsInvited([user1])
|
||||
b = VoiceChatParticipantsInvited([user1])
|
||||
c = VoiceChatParticipantsInvited([user1, user2])
|
||||
d = VoiceChatParticipantsInvited([user2])
|
||||
e = VoiceChatStarted()
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
Loading…
Reference in a new issue