mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
API 6.8 (#3853)
Co-authored-by: Aditya <clot27@apx_managed.vanilla> Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
This commit is contained in:
parent
caffb9d66e
commit
bd24da29cd
23 changed files with 446 additions and 38 deletions
|
@ -14,7 +14,7 @@
|
|||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.8-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -93,7 +93,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 **6.7** are supported.
|
||||
All types and methods of the Telegram Bot API **6.8** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.8-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
|||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **6.7** are supported.
|
||||
All types and methods of the Telegram Bot API **6.8** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
|
|
@ -328,6 +328,8 @@
|
|||
- Used to reopen the general topic
|
||||
* - :meth:`~telegram.Bot.unpin_all_forum_topic_messages`
|
||||
- Used to unpin all messages in a forum topic
|
||||
* - :meth:`~telegram.Bot.unpin_all_general_forum_topic_messages`
|
||||
- Used to unpin all messages in the general forum topic
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ Available Types
|
|||
telegram.replykeyboardmarkup
|
||||
telegram.replykeyboardremove
|
||||
telegram.sentwebappmessage
|
||||
telegram.story
|
||||
telegram.switchinlinequerychosenchat
|
||||
telegram.telegramobject
|
||||
telegram.update
|
||||
|
|
6
docs/source/telegram.story.rst
Normal file
6
docs/source/telegram.story.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
Story
|
||||
=====
|
||||
|
||||
.. autoclass:: telegram.Story
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -170,6 +170,7 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
"ShippingQuery",
|
||||
"Sticker",
|
||||
"StickerSet",
|
||||
"Story",
|
||||
"SuccessfulPayment",
|
||||
"SwitchInlineQueryChosenChat",
|
||||
"TelegramObject",
|
||||
|
@ -341,6 +342,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
|||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
from ._sentwebappmessage import SentWebAppMessage
|
||||
from ._shared import ChatShared, UserShared
|
||||
from ._story import Story
|
||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from ._telegramobject import TelegramObject
|
||||
from ._update import Update
|
||||
|
|
|
@ -7814,6 +7814,46 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
@_log
|
||||
async def unpin_all_general_forum_topic_messages(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Use this method to clear the list of pinned messages in a General forum topic. The bot must
|
||||
be an administrator in the chat for this to work and must have
|
||||
:paramref:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights in the
|
||||
supergroup.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {"chat_id": chat_id}
|
||||
|
||||
return await self._post(
|
||||
"unpinAllGeneralForumTopicMessages",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
@_log
|
||||
async def edit_general_forum_topic(
|
||||
self,
|
||||
|
@ -8527,3 +8567,5 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""Alias for :meth:`set_my_name`"""
|
||||
getMyName = get_my_name
|
||||
"""Alias for :meth:`get_my_name`"""
|
||||
unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages
|
||||
"""Alias for :meth:`unpin_all_general_forum_topic_messages`"""
|
||||
|
|
|
@ -31,6 +31,7 @@ from telegram._menubutton import MenuButton
|
|||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import (
|
||||
CorrectOptionID,
|
||||
|
@ -172,6 +173,12 @@ class Chat(TelegramObject):
|
|||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of
|
||||
emoji status of the other party in a private chat, in seconds. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive
|
||||
anti-spam checks are enabled in the supergroup. The field is only available to chat
|
||||
administrators. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
@ -265,6 +272,12 @@ class Chat(TelegramObject):
|
|||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of
|
||||
emoji status of the other party in a private chat, in seconds. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|datetime_localization|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive
|
||||
anti-spam checks are enabled in the supergroup. The field is only available to chat
|
||||
administrators. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
@ -306,6 +319,7 @@ class Chat(TelegramObject):
|
|||
"is_forum",
|
||||
"active_usernames",
|
||||
"emoji_status_custom_emoji_id",
|
||||
"emoji_status_expiration_date",
|
||||
"has_hidden_members",
|
||||
"has_aggressive_anti_spam_enabled",
|
||||
)
|
||||
|
@ -352,6 +366,7 @@ class Chat(TelegramObject):
|
|||
is_forum: Optional[bool] = None,
|
||||
active_usernames: Optional[Sequence[str]] = None,
|
||||
emoji_status_custom_emoji_id: Optional[str] = None,
|
||||
emoji_status_expiration_date: Optional[datetime] = None,
|
||||
has_aggressive_anti_spam_enabled: Optional[bool] = None,
|
||||
has_hidden_members: Optional[bool] = None,
|
||||
*,
|
||||
|
@ -390,6 +405,7 @@ class Chat(TelegramObject):
|
|||
self.is_forum: Optional[bool] = is_forum
|
||||
self.active_usernames: Tuple[str, ...] = parse_sequence_arg(active_usernames)
|
||||
self.emoji_status_custom_emoji_id: Optional[str] = emoji_status_custom_emoji_id
|
||||
self.emoji_status_expiration_date: Optional[datetime] = emoji_status_expiration_date
|
||||
self.has_aggressive_anti_spam_enabled: Optional[bool] = has_aggressive_anti_spam_enabled
|
||||
self.has_hidden_members: Optional[bool] = has_hidden_members
|
||||
|
||||
|
@ -446,6 +462,13 @@ class Chat(TelegramObject):
|
|||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["emoji_status_expiration_date"] = from_timestamp(
|
||||
data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo
|
||||
)
|
||||
|
||||
data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
|
||||
from telegram import Message # pylint: disable=import-outside-toplevel
|
||||
|
||||
|
@ -2904,6 +2927,37 @@ class Chat(TelegramObject):
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def unpin_all_general_forum_topic_messages(
|
||||
self,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> bool:
|
||||
"""Shortcut for::
|
||||
|
||||
await bot.unpin_all_general_forum_topic_messages(chat_id=update.effective_chat.id,
|
||||
*args, **kwargs)
|
||||
|
||||
For the documentation of the arguments, please see
|
||||
:meth:`telegram.Bot.unpin_all_general_forum_topic_messages`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
"""
|
||||
return await self.get_bot().unpin_all_general_forum_topic_messages(
|
||||
chat_id=self.id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def edit_general_forum_topic(
|
||||
self,
|
||||
name: str,
|
||||
|
|
|
@ -53,6 +53,7 @@ from telegram._payment.successfulpayment import SuccessfulPayment
|
|||
from telegram._poll import Poll
|
||||
from telegram._proximityalerttriggered import ProximityAlertTriggered
|
||||
from telegram._shared import ChatShared, UserShared
|
||||
from telegram._story import Story
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
|
@ -201,6 +202,9 @@ class Message(TelegramObject):
|
|||
|
||||
sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information
|
||||
about the sticker.
|
||||
story (:class:`telegram.Story`, optional): Message is a forwarded story.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
video (:class:`telegram.Video`, optional): Message is a video, information about the
|
||||
video.
|
||||
voice (:class:`telegram.Voice`, optional): Message is a voice message, information about
|
||||
|
@ -435,6 +439,9 @@ class Message(TelegramObject):
|
|||
about the sticker.
|
||||
|
||||
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||
story (:class:`telegram.Story`): Optional. Message is a forwarded story.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
video (:class:`telegram.Video`): Optional. Message is a video, information about the
|
||||
video.
|
||||
|
||||
|
@ -671,6 +678,7 @@ class Message(TelegramObject):
|
|||
"has_media_spoiler",
|
||||
"user_shared",
|
||||
"chat_shared",
|
||||
"story",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
@ -746,6 +754,7 @@ class Message(TelegramObject):
|
|||
has_media_spoiler: Optional[bool] = None,
|
||||
user_shared: Optional[UserShared] = None,
|
||||
chat_shared: Optional[ChatShared] = None,
|
||||
story: Optional[Story] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -834,6 +843,7 @@ class Message(TelegramObject):
|
|||
self.has_media_spoiler: Optional[bool] = has_media_spoiler
|
||||
self.user_shared: Optional[UserShared] = user_shared
|
||||
self.chat_shared: Optional[ChatShared] = chat_shared
|
||||
self.story: Optional[Story] = story
|
||||
|
||||
self._effective_attachment = DEFAULT_NONE
|
||||
|
||||
|
@ -903,6 +913,7 @@ class Message(TelegramObject):
|
|||
data["game"] = Game.de_json(data.get("game"), bot)
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||
data["story"] = Story.de_json(data.get("story"), bot)
|
||||
data["video"] = Video.de_json(data.get("video"), bot)
|
||||
data["voice"] = Voice.de_json(data.get("voice"), bot)
|
||||
data["video_note"] = VideoNote.de_json(data.get("video_note"), bot)
|
||||
|
@ -973,6 +984,7 @@ class Message(TelegramObject):
|
|||
Sequence[PhotoSize],
|
||||
Poll,
|
||||
Sticker,
|
||||
Story,
|
||||
SuccessfulPayment,
|
||||
Venue,
|
||||
Video,
|
||||
|
@ -995,6 +1007,7 @@ class Message(TelegramObject):
|
|||
* List[:class:`telegram.PhotoSize`]
|
||||
* :class:`telegram.Poll`
|
||||
* :class:`telegram.Sticker`
|
||||
* :class:`telegram.Story`
|
||||
* :class:`telegram.SuccessfulPayment`
|
||||
* :class:`telegram.Venue`
|
||||
* :class:`telegram.Video`
|
||||
|
|
|
@ -21,6 +21,7 @@ import datetime
|
|||
from typing import TYPE_CHECKING, Dict, Final, List, Optional, Sequence, Tuple
|
||||
|
||||
from telegram import constants
|
||||
from telegram._chat import Chat
|
||||
from telegram._messageentity import MessageEntity
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
|
@ -28,6 +29,8 @@ from telegram._utils import enum
|
|||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
@ -84,42 +87,86 @@ class PollAnswer(TelegramObject):
|
|||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`option_ids` are equal.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
The order of :paramref:`option_ids` and :paramref:`user` is changed in
|
||||
NEXT.VERSION as the latter one became optional. We currently provide
|
||||
backward compatibility for this but it will be removed in the future.
|
||||
Please update your code to use the new order.
|
||||
|
||||
Args:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
user (:class:`telegram.User`): The user, who changed the answer to the poll.
|
||||
option_ids (Sequence[:obj:`int`]): 0-based identifiers of answer options, chosen by the
|
||||
user. May be empty if the user retracted their vote.
|
||||
option_ids (Sequence[:obj:`int`]): Identifiers of answer options, chosen by the user. May
|
||||
be empty if the user retracted their vote.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
user (:class:`telegram.User`, optional): The user that changed the answer to the poll,
|
||||
if the voter isn't anonymous. If the voter is anonymous, this field will contain the
|
||||
user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
:paramref:`user` became optional.
|
||||
voter_chat (:class:`telegram.Chat`, optional): The chat that changed the answer to the
|
||||
poll, if the voter is anonymous.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
poll_id (:obj:`str`): Unique poll identifier.
|
||||
user (:class:`telegram.User`): The user, who changed the answer to the poll.
|
||||
option_ids (Tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May be
|
||||
empty if the user retracted their vote.
|
||||
option_ids (Tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May
|
||||
be empty if the user retracted their vote.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|tupleclassattrs|
|
||||
user (:class:`telegram.User`): Optional. The user, who changed the answer to the
|
||||
poll, if the voter isn't anonymous. If the voter is anonymous, this field will contain
|
||||
the user :tg-const:`telegram.constants.ChatID.FAKE_CHANNEL` for backwards compatibility
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
:paramref:`user` became optional.
|
||||
voter_chat (:class:`telegram.Chat`): Optional. The chat that changed the answer to the
|
||||
poll, if the voter is anonymous.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("option_ids", "user", "poll_id")
|
||||
__slots__ = ("option_ids", "poll_id", "user", "voter_chat")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
poll_id: str,
|
||||
user: User,
|
||||
option_ids: Sequence[int],
|
||||
user: Optional[User] = None,
|
||||
voter_chat: Optional[Chat] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.poll_id: str = poll_id
|
||||
self.user: User = user
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg(option_ids)
|
||||
self.voter_chat: Optional[Chat] = voter_chat
|
||||
|
||||
self._id_attrs = (self.poll_id, self.user, tuple(self.option_ids))
|
||||
if isinstance(option_ids, User) or isinstance(user, tuple):
|
||||
warn(
|
||||
"From v20.5 the order of `option_ids` and `user` is changed as the latter one"
|
||||
" became optional. Please update your code to use the new order.",
|
||||
category=PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg(user)
|
||||
self.user: Optional[User] = option_ids
|
||||
else:
|
||||
self.option_ids: Tuple[int, ...] = parse_sequence_arg( # type: ignore[no-redef]
|
||||
option_ids
|
||||
)
|
||||
self.user: Optional[User] = user # type: ignore[no-redef]
|
||||
|
||||
self._id_attrs = (
|
||||
self.poll_id,
|
||||
self.option_ids,
|
||||
self.user,
|
||||
self.voter_chat,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
@ -132,6 +179,7 @@ class PollAnswer(TelegramObject):
|
|||
return None
|
||||
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
data["voter_chat"] = Chat.de_json(data.get("voter_chat"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
|
41
telegram/_story.py
Normal file
41
telegram/_story.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 related to a Telegram Story."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class Story(TelegramObject):
|
||||
"""
|
||||
This object represents a message about a forwarded story in the chat. Currently holds no
|
||||
information.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
self._freeze()
|
|
@ -116,7 +116,7 @@ class _BotAPIVersion(NamedTuple):
|
|||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=6, minor=7)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=6, minor=8)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
|
@ -285,7 +285,8 @@ class ChatID(IntEnum):
|
|||
__slots__ = ()
|
||||
|
||||
ANONYMOUS_ADMIN = 1087968824
|
||||
""":obj:`int`: User ID in groups for messages sent by anonymous admins.
|
||||
""":obj:`int`: User ID in groups for messages sent by anonymous admins. Telegram chat:
|
||||
`@GroupAnonymousBot <https://t.me/GroupAnonymousBot>`_.
|
||||
|
||||
Note:
|
||||
:attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
|
||||
|
@ -293,19 +294,21 @@ class ChatID(IntEnum):
|
|||
"""
|
||||
SERVICE_CHAT = 777000
|
||||
""":obj:`int`: Telegram service chat, that also acts as sender of channel posts forwarded to
|
||||
discussion groups.
|
||||
discussion groups. Telegram chat: `Telegram <https://t.me/+42777>`_.
|
||||
|
||||
Note:
|
||||
:attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
|
||||
It's recommended to use :attr:`telegram.Message.sender_chat` instead.
|
||||
"""
|
||||
FAKE_CHANNEL = 136817688
|
||||
""":obj:`int`: User ID in groups when message is sent on behalf of a channel.
|
||||
""":obj:`int`: User ID in groups when message is sent on behalf of a channel, or when a channel
|
||||
votes on a poll. Telegram chat: `@Channel_Bot <https://t.me/Channel_Bot>`_.
|
||||
|
||||
Note:
|
||||
* :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
|
||||
It's recommended to use :attr:`telegram.Message.sender_chat` instead.
|
||||
* This value is undocumented and might be changed by Telegram.
|
||||
* :attr:`telegram.PollAnswer.user` will contain this ID for backwards compatibility only.
|
||||
It's recommended to use :attr:`telegram.PollAnswer.voter_chat` instead.
|
||||
"""
|
||||
|
||||
|
||||
|
@ -1065,6 +1068,8 @@ class MessageAttachmentType(StringEnum):
|
|||
""":obj:`str`: Messages with :attr:`telegram.Message.poll`."""
|
||||
STICKER = "sticker"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
|
||||
STORY = "story"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.story`."""
|
||||
SUCCESSFUL_PAYMENT = "successful_payment"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.successful_payment`."""
|
||||
VIDEO = "video"
|
||||
|
@ -1219,6 +1224,8 @@ class MessageType(StringEnum):
|
|||
""":obj:`str`: Messages with :attr:`telegram.Message.poll`."""
|
||||
STICKER = "sticker"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
|
||||
STORY = "story"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.story`."""
|
||||
SUCCESSFUL_PAYMENT = "successful_payment"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.successful_payment`."""
|
||||
VIDEO = "video"
|
||||
|
|
|
@ -3486,6 +3486,26 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def unpin_all_general_forum_topic_messages(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> bool:
|
||||
return await super().unpin_all_general_forum_topic_messages(
|
||||
chat_id=chat_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def upload_sticker_file(
|
||||
self,
|
||||
user_id: Union[str, int],
|
||||
|
@ -3884,3 +3904,4 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
setStickerMaskPosition = set_sticker_mask_position
|
||||
setMyName = set_my_name
|
||||
getMyName = get_my_name
|
||||
unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages
|
||||
|
|
|
@ -72,6 +72,7 @@ __all__ = (
|
|||
"REPLY",
|
||||
"Regex",
|
||||
"Sticker",
|
||||
"STORY",
|
||||
"SUCCESSFUL_PAYMENT",
|
||||
"SenderChat",
|
||||
"StatusUpdate",
|
||||
|
@ -2143,6 +2144,20 @@ class Sticker:
|
|||
# neither mask nor emoji can be a message.sticker, so no filters for them
|
||||
|
||||
|
||||
class _Story(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.story)
|
||||
|
||||
|
||||
STORY = _Story(name="filters.STORY")
|
||||
"""Messages that contain :attr:`telegram.Message.story`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
|
||||
class _SuccessfulPayment(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ class TestFiles:
|
|||
@pytest.mark.parametrize(
|
||||
("string", "expected"),
|
||||
[
|
||||
(str(data_file("game.gif")), True),
|
||||
(str(TEST_DATA_PATH), False),
|
||||
(str(data_file("game.gif")), True),
|
||||
(str(TEST_DATA_PATH), False),
|
||||
(data_file("game.gif"), True),
|
||||
|
|
|
@ -884,6 +884,11 @@ class TestFilters:
|
|||
assert filters.Sticker.VIDEO.check_update(update)
|
||||
assert filters.Sticker.PREMIUM.check_update(update)
|
||||
|
||||
def test_filters_story(self, update):
|
||||
assert not filters.STORY.check_update(update)
|
||||
update.message.story = "test"
|
||||
assert filters.STORY.check_update(update)
|
||||
|
||||
def test_filters_video(self, update):
|
||||
assert not filters.VIDEO.check_update(update)
|
||||
update.message.video = "test"
|
||||
|
|
|
@ -69,7 +69,7 @@ def false_update(request):
|
|||
|
||||
@pytest.fixture()
|
||||
def poll_answer(bot):
|
||||
return Update(0, poll_answer=PollAnswer(1, User(2, "test user", False), [0, 1]))
|
||||
return Update(0, poll_answer=PollAnswer(1, [0, 1], User(2, "test user", False), Chat(1, "")))
|
||||
|
||||
|
||||
class TestPollAnswerHandler:
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Bot, Chat, ChatLocation, ChatPermissions, Location, User
|
||||
from telegram._utils.datetime import UTC, from_timestamp
|
||||
from telegram.constants import ChatAction, ChatType
|
||||
from telegram.helpers import escape_markdown
|
||||
from tests.auxil.bot_method_checks import (
|
||||
|
@ -52,6 +54,7 @@ def chat(bot):
|
|||
is_forum=True,
|
||||
active_usernames=TestChatBase.active_usernames,
|
||||
emoji_status_custom_emoji_id=TestChatBase.emoji_status_custom_emoji_id,
|
||||
emoji_status_expiration_date=TestChatBase.emoji_status_expiration_date,
|
||||
has_aggressive_anti_spam_enabled=TestChatBase.has_aggressive_anti_spam_enabled,
|
||||
has_hidden_members=TestChatBase.has_hidden_members,
|
||||
)
|
||||
|
@ -85,6 +88,7 @@ class TestChatBase:
|
|||
is_forum = True
|
||||
active_usernames = ["These", "Are", "Usernames!"]
|
||||
emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID"
|
||||
emoji_status_expiration_date = time.time()
|
||||
has_aggressive_anti_spam_enabled = True
|
||||
has_hidden_members = True
|
||||
|
||||
|
@ -119,6 +123,7 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"is_forum": self.is_forum,
|
||||
"active_usernames": self.active_usernames,
|
||||
"emoji_status_custom_emoji_id": self.emoji_status_custom_emoji_id,
|
||||
"emoji_status_expiration_date": self.emoji_status_expiration_date,
|
||||
"has_aggressive_anti_spam_enabled": self.has_aggressive_anti_spam_enabled,
|
||||
"has_hidden_members": self.has_hidden_members,
|
||||
}
|
||||
|
@ -150,9 +155,32 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.is_forum == self.is_forum
|
||||
assert chat.active_usernames == tuple(self.active_usernames)
|
||||
assert chat.emoji_status_custom_emoji_id == self.emoji_status_custom_emoji_id
|
||||
assert chat.emoji_status_expiration_date == from_timestamp(
|
||||
self.emoji_status_expiration_date
|
||||
)
|
||||
assert chat.has_aggressive_anti_spam_enabled == self.has_aggressive_anti_spam_enabled
|
||||
assert chat.has_hidden_members == self.has_hidden_members
|
||||
|
||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"type": self.type_,
|
||||
"emoji_status_expiration_date": self.emoji_status_expiration_date,
|
||||
}
|
||||
chat_bot = Chat.de_json(json_dict, bot)
|
||||
chat_bot_raw = Chat.de_json(json_dict, raw_bot)
|
||||
chat_bot_tz = Chat.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
||||
emoji_expire_offset = chat_bot_tz.emoji_status_expiration_date.utcoffset()
|
||||
emoji_expire_offset_tz = tz_bot.defaults.tzinfo.utcoffset(
|
||||
chat_bot_tz.emoji_status_expiration_date.replace(tzinfo=None)
|
||||
)
|
||||
|
||||
assert chat_bot.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert chat_bot_raw.emoji_status_expiration_date.tzinfo == UTC
|
||||
assert emoji_expire_offset_tz == emoji_expire_offset
|
||||
|
||||
def test_to_dict(self, chat):
|
||||
chat_dict = chat.to_dict()
|
||||
|
||||
|
@ -177,6 +205,7 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat_dict["is_forum"] == chat.is_forum
|
||||
assert chat_dict["active_usernames"] == list(chat.active_usernames)
|
||||
assert chat_dict["emoji_status_custom_emoji_id"] == chat.emoji_status_custom_emoji_id
|
||||
assert chat_dict["emoji_status_expiration_date"] == chat.emoji_status_expiration_date
|
||||
assert (
|
||||
chat_dict["has_aggressive_anti_spam_enabled"] == chat.has_aggressive_anti_spam_enabled
|
||||
)
|
||||
|
@ -1075,6 +1104,31 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
monkeypatch.setattr(chat.get_bot(), "unpin_all_forum_topic_messages", make_assertion)
|
||||
assert await chat.unpin_all_forum_topic_messages(message_thread_id=42)
|
||||
|
||||
async def test_unpin_all_general_forum_topic_messages(self, monkeypatch, chat):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["chat_id"] == chat.id
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Chat.unpin_all_general_forum_topic_messages,
|
||||
Bot.unpin_all_general_forum_topic_messages,
|
||||
["chat_id"],
|
||||
[],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
chat.unpin_all_general_forum_topic_messages,
|
||||
chat.get_bot(),
|
||||
"unpin_all_general_forum_topic_messages",
|
||||
shortcut_kwargs=["chat_id"],
|
||||
)
|
||||
assert await check_defaults_handling(
|
||||
chat.unpin_all_general_forum_topic_messages, chat.get_bot()
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
chat.get_bot(), "unpin_all_general_forum_topic_messages", make_assertion
|
||||
)
|
||||
assert await chat.unpin_all_general_forum_topic_messages()
|
||||
|
||||
async def test_edit_general_forum_topic(self, monkeypatch, chat):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
return kwargs["chat_id"] == chat.id and kwargs["name"] == "WhatAName"
|
||||
|
|
|
@ -236,6 +236,7 @@ class TestForumMethodsWithRequest:
|
|||
assert result is True, "Failed to reopen forum topic"
|
||||
|
||||
async def test_unpin_all_forum_topic_messages(self, bot, forum_group_id, real_topic):
|
||||
# We need 2 or more pinned msgs for this to work, else we get Chat_not_modified error
|
||||
message_thread_id = real_topic.message_thread_id
|
||||
pin_msg_tasks = set()
|
||||
|
||||
|
@ -249,10 +250,23 @@ class TestForumMethodsWithRequest:
|
|||
|
||||
assert all([await task for task in pin_msg_tasks]) is True, "Message(s) were not pinned"
|
||||
|
||||
# We need 2 or more pinned msgs for this to work, else we get Chat_not_modified error
|
||||
result = await bot.unpin_all_forum_topic_messages(forum_group_id, message_thread_id)
|
||||
assert result is True, "Failed to unpin all the messages in forum topic"
|
||||
|
||||
async def test_unpin_all_general_forum_topic_messages(self, bot, forum_group_id):
|
||||
# We need 2 or more pinned msgs for this to work, else we get Chat_not_modified error
|
||||
pin_msg_tasks = set()
|
||||
|
||||
awaitables = {bot.send_message(forum_group_id, TEST_MSG_TEXT) for _ in range(2)}
|
||||
for coro in asyncio.as_completed(awaitables):
|
||||
msg = await coro
|
||||
pin_msg_tasks.add(asyncio.create_task(msg.pin()))
|
||||
|
||||
assert all([await task for task in pin_msg_tasks]) is True, "Message(s) were not pinned"
|
||||
|
||||
result = await bot.unpin_all_general_forum_topic_messages(forum_group_id)
|
||||
assert result is True, "Failed to unpin all the messages in forum topic"
|
||||
|
||||
async def test_edit_general_forum_topic(self, bot, forum_group_id):
|
||||
result = await bot.edit_general_forum_topic(
|
||||
chat_id=forum_group_id,
|
||||
|
|
|
@ -42,6 +42,7 @@ from telegram import (
|
|||
PollOption,
|
||||
ProximityAlertTriggered,
|
||||
Sticker,
|
||||
Story,
|
||||
SuccessfulPayment,
|
||||
Update,
|
||||
User,
|
||||
|
@ -123,6 +124,7 @@ def message(bot):
|
|||
},
|
||||
{"photo": [PhotoSize("photo_id", "unique_id", 50, 50)], "caption": "photo_file"},
|
||||
{"sticker": Sticker("sticker_id", "unique_id", 50, 50, True, False, Sticker.REGULAR)},
|
||||
{"story": Story()},
|
||||
{"video": Video("video_id", "unique_id", 12, 12, 12), "caption": "video_file"},
|
||||
{"voice": Voice("voice_id", "unique_id", 5)},
|
||||
{"video_note": VideoNote("video_note_id", "unique_id", 20, 12)},
|
||||
|
@ -227,6 +229,7 @@ def message(bot):
|
|||
"game",
|
||||
"photo",
|
||||
"sticker",
|
||||
"story",
|
||||
"video",
|
||||
"voice",
|
||||
"video_note",
|
||||
|
@ -989,6 +992,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"photo",
|
||||
"poll",
|
||||
"sticker",
|
||||
"story",
|
||||
"successful_payment",
|
||||
"video",
|
||||
"video_note",
|
||||
|
|
|
@ -19,9 +19,10 @@ from datetime import datetime, timedelta, timezone
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import MessageEntity, Poll, PollAnswer, PollOption, User
|
||||
from telegram import Chat, MessageEntity, Poll, PollAnswer, PollOption, User
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from telegram.constants import PollType
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
|
@ -81,50 +82,58 @@ class TestPollOptionWithoutRequest(TestPollOptionBase):
|
|||
@pytest.fixture(scope="module")
|
||||
def poll_answer():
|
||||
return PollAnswer(
|
||||
TestPollAnswerBase.poll_id, TestPollAnswerBase.user, TestPollAnswerBase.poll_id
|
||||
TestPollAnswerBase.poll_id,
|
||||
TestPollAnswerBase.option_ids,
|
||||
TestPollAnswerBase.user,
|
||||
TestPollAnswerBase.voter_chat,
|
||||
)
|
||||
|
||||
|
||||
class TestPollAnswerBase:
|
||||
poll_id = "id"
|
||||
user = User(1, "", False)
|
||||
option_ids = [2]
|
||||
user = User(1, "", False)
|
||||
voter_chat = Chat(1, "")
|
||||
|
||||
|
||||
class TestPollAnswerWithoutRequest(TestPollAnswerBase):
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"poll_id": self.poll_id,
|
||||
"user": self.user.to_dict(),
|
||||
"option_ids": self.option_ids,
|
||||
"user": self.user.to_dict(),
|
||||
"voter_chat": self.voter_chat.to_dict(),
|
||||
}
|
||||
poll_answer = PollAnswer.de_json(json_dict, None)
|
||||
assert poll_answer.api_kwargs == {}
|
||||
|
||||
assert poll_answer.poll_id == self.poll_id
|
||||
assert poll_answer.user == self.user
|
||||
assert poll_answer.option_ids == tuple(self.option_ids)
|
||||
assert poll_answer.user == self.user
|
||||
assert poll_answer.voter_chat == self.voter_chat
|
||||
|
||||
def test_to_dict(self, poll_answer):
|
||||
poll_answer_dict = poll_answer.to_dict()
|
||||
|
||||
assert isinstance(poll_answer_dict, dict)
|
||||
assert poll_answer_dict["poll_id"] == poll_answer.poll_id
|
||||
assert poll_answer_dict["user"] == poll_answer.user.to_dict()
|
||||
assert poll_answer_dict["option_ids"] == list(poll_answer.option_ids)
|
||||
assert poll_answer_dict["user"] == poll_answer.user.to_dict()
|
||||
assert poll_answer_dict["voter_chat"] == poll_answer.voter_chat.to_dict()
|
||||
|
||||
def test_equality(self):
|
||||
a = PollAnswer(123, self.user, [2])
|
||||
b = PollAnswer(123, User(1, "first", False), [2])
|
||||
c = PollAnswer(123, self.user, [1, 2])
|
||||
d = PollAnswer(456, self.user, [2])
|
||||
e = PollOption("Text", 1)
|
||||
a = PollAnswer(123, [2], self.user, self.voter_chat)
|
||||
b = PollAnswer(123, [2], self.user, Chat(1, ""))
|
||||
c = PollAnswer(123, [2], User(1, "first", False), self.voter_chat)
|
||||
d = PollAnswer(123, [1, 2], self.user, self.voter_chat)
|
||||
e = PollAnswer(456, [2], self.user, self.voter_chat)
|
||||
f = PollOption("Text", 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
@ -132,6 +141,22 @@ class TestPollAnswerWithoutRequest(TestPollAnswerBase):
|
|||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
||||
|
||||
def test_order_warning(self, recwarn):
|
||||
expected_warning = (
|
||||
"From v20.5 the order of `option_ids` and `user` is changed as the latter one"
|
||||
" became optional. Please update your code to use the new order."
|
||||
)
|
||||
PollAnswer(123, [2], self.user, self.voter_chat)
|
||||
assert len(recwarn) == 0
|
||||
PollAnswer(123, self.user, [2], self.voter_chat)
|
||||
assert len(recwarn) == 1
|
||||
assert str(recwarn[0].message) == expected_warning
|
||||
assert recwarn[0].category is PTBDeprecationWarning
|
||||
assert recwarn[0].filename == __file__, "wrong stacklevel"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def poll():
|
||||
|
|
45
tests/test_story.py
Normal file
45
tests/test_story.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env python
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 Story
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def story():
|
||||
return Story()
|
||||
|
||||
|
||||
class TestStoryWithoutRequest:
|
||||
def test_slot_behaviour(self):
|
||||
story = Story()
|
||||
for attr in story.__slots__:
|
||||
assert getattr(story, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(story)) == len(set(mro_slots(story))), "duplicate slot"
|
||||
|
||||
def test_de_json(self):
|
||||
story = Story.de_json({}, None)
|
||||
assert story.api_kwargs == {}
|
||||
assert isinstance(story, Story)
|
||||
|
||||
def test_to_dict(self):
|
||||
story = Story()
|
||||
story_dict = story.to_dict()
|
||||
assert story_dict == {}
|
|
@ -70,7 +70,18 @@ params = [
|
|||
{"shipping_query": ShippingQuery("id", User(1, "", False), "", None)},
|
||||
{"pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "")},
|
||||
{"poll": Poll("id", "?", [PollOption(".", 1)], False, False, False, Poll.REGULAR, True)},
|
||||
{"poll_answer": PollAnswer("id", User(1, "", False), [1])},
|
||||
{
|
||||
"poll_answer": PollAnswer(
|
||||
"id",
|
||||
[1],
|
||||
User(
|
||||
1,
|
||||
"",
|
||||
False,
|
||||
),
|
||||
Chat(1, ""),
|
||||
)
|
||||
},
|
||||
{"my_chat_member": chat_member_updated},
|
||||
{"chat_member": chat_member_updated},
|
||||
{"chat_join_request": chat_join_request},
|
||||
|
|
Loading…
Reference in a new issue