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:
Harshil 2023-09-03 15:43:44 +04:00 committed by GitHub
parent caffb9d66e
commit bd24da29cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 446 additions and 38 deletions

View file

@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot/ :target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions :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 :target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions :alt: Supported Bot API versions
@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support 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 Installing
========== ==========

View file

@ -14,7 +14,7 @@
:target: https://pypi.org/project/python-telegram-bot-raw/ :target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions :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 :target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions :alt: Supported Bot API versions
@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
Telegram API support 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 Installing
========== ==========

View file

@ -328,6 +328,8 @@
- Used to reopen the general topic - Used to reopen the general topic
* - :meth:`~telegram.Bot.unpin_all_forum_topic_messages` * - :meth:`~telegram.Bot.unpin_all_forum_topic_messages`
- Used to unpin all messages in a forum topic - 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 .. raw:: html

View file

@ -79,6 +79,7 @@ Available Types
telegram.replykeyboardmarkup telegram.replykeyboardmarkup
telegram.replykeyboardremove telegram.replykeyboardremove
telegram.sentwebappmessage telegram.sentwebappmessage
telegram.story
telegram.switchinlinequerychosenchat telegram.switchinlinequerychosenchat
telegram.telegramobject telegram.telegramobject
telegram.update telegram.update

View file

@ -0,0 +1,6 @@
Story
=====
.. autoclass:: telegram.Story
:members:
:show-inheritance:

View file

@ -170,6 +170,7 @@ __all__ = ( # Keep this alphabetically ordered
"ShippingQuery", "ShippingQuery",
"Sticker", "Sticker",
"StickerSet", "StickerSet",
"Story",
"SuccessfulPayment", "SuccessfulPayment",
"SwitchInlineQueryChosenChat", "SwitchInlineQueryChosenChat",
"TelegramObject", "TelegramObject",
@ -341,6 +342,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup
from ._replykeyboardremove import ReplyKeyboardRemove from ._replykeyboardremove import ReplyKeyboardRemove
from ._sentwebappmessage import SentWebAppMessage from ._sentwebappmessage import SentWebAppMessage
from ._shared import ChatShared, UserShared from ._shared import ChatShared, UserShared
from ._story import Story
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
from ._telegramobject import TelegramObject from ._telegramobject import TelegramObject
from ._update import Update from ._update import Update

View file

@ -7814,6 +7814,46 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
api_kwargs=api_kwargs, 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 @_log
async def edit_general_forum_topic( async def edit_general_forum_topic(
self, self,
@ -8527,3 +8567,5 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
"""Alias for :meth:`set_my_name`""" """Alias for :meth:`set_my_name`"""
getMyName = get_my_name getMyName = get_my_name
"""Alias for :meth:`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`"""

View file

@ -31,6 +31,7 @@ from telegram._menubutton import MenuButton
from telegram._telegramobject import TelegramObject from telegram._telegramobject import TelegramObject
from telegram._utils import enum from telegram._utils import enum
from telegram._utils.argumentparsing import parse_sequence_arg 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.defaultvalue import DEFAULT_NONE
from telegram._utils.types import ( from telegram._utils.types import (
CorrectOptionID, CorrectOptionID,
@ -172,6 +173,12 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat`. :meth:`telegram.Bot.get_chat`.
.. versionadded:: 20.0 .. 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 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 anti-spam checks are enabled in the supergroup. The field is only available to chat
administrators. Returned only in :meth:`telegram.Bot.get_chat`. administrators. Returned only in :meth:`telegram.Bot.get_chat`.
@ -265,6 +272,12 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat`. :meth:`telegram.Bot.get_chat`.
.. versionadded:: 20.0 .. 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 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 anti-spam checks are enabled in the supergroup. The field is only available to chat
administrators. Returned only in :meth:`telegram.Bot.get_chat`. administrators. Returned only in :meth:`telegram.Bot.get_chat`.
@ -306,6 +319,7 @@ class Chat(TelegramObject):
"is_forum", "is_forum",
"active_usernames", "active_usernames",
"emoji_status_custom_emoji_id", "emoji_status_custom_emoji_id",
"emoji_status_expiration_date",
"has_hidden_members", "has_hidden_members",
"has_aggressive_anti_spam_enabled", "has_aggressive_anti_spam_enabled",
) )
@ -352,6 +366,7 @@ class Chat(TelegramObject):
is_forum: Optional[bool] = None, is_forum: Optional[bool] = None,
active_usernames: Optional[Sequence[str]] = None, active_usernames: Optional[Sequence[str]] = None,
emoji_status_custom_emoji_id: Optional[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_aggressive_anti_spam_enabled: Optional[bool] = None,
has_hidden_members: Optional[bool] = None, has_hidden_members: Optional[bool] = None,
*, *,
@ -390,6 +405,7 @@ class Chat(TelegramObject):
self.is_forum: Optional[bool] = is_forum self.is_forum: Optional[bool] = is_forum
self.active_usernames: Tuple[str, ...] = parse_sequence_arg(active_usernames) 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_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_aggressive_anti_spam_enabled: Optional[bool] = has_aggressive_anti_spam_enabled
self.has_hidden_members: Optional[bool] = has_hidden_members self.has_hidden_members: Optional[bool] = has_hidden_members
@ -446,6 +462,13 @@ class Chat(TelegramObject):
if not data: if not data:
return None 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) data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
from telegram import Message # pylint: disable=import-outside-toplevel from telegram import Message # pylint: disable=import-outside-toplevel
@ -2904,6 +2927,37 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs, 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( async def edit_general_forum_topic(
self, self,
name: str, name: str,

View file

@ -53,6 +53,7 @@ from telegram._payment.successfulpayment import SuccessfulPayment
from telegram._poll import Poll from telegram._poll import Poll
from telegram._proximityalerttriggered import ProximityAlertTriggered from telegram._proximityalerttriggered import ProximityAlertTriggered
from telegram._shared import ChatShared, UserShared from telegram._shared import ChatShared, UserShared
from telegram._story import Story
from telegram._telegramobject import TelegramObject from telegram._telegramobject import TelegramObject
from telegram._user import User from telegram._user import User
from telegram._utils.argumentparsing import parse_sequence_arg 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 sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information
about the sticker. 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 (:class:`telegram.Video`, optional): Message is a video, information about the
video. video.
voice (:class:`telegram.Voice`, optional): Message is a voice message, information about voice (:class:`telegram.Voice`, optional): Message is a voice message, information about
@ -435,6 +439,9 @@ class Message(TelegramObject):
about the sticker. about the sticker.
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>` .. 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 (:class:`telegram.Video`): Optional. Message is a video, information about the
video. video.
@ -671,6 +678,7 @@ class Message(TelegramObject):
"has_media_spoiler", "has_media_spoiler",
"user_shared", "user_shared",
"chat_shared", "chat_shared",
"story",
) )
def __init__( def __init__(
@ -746,6 +754,7 @@ class Message(TelegramObject):
has_media_spoiler: Optional[bool] = None, has_media_spoiler: Optional[bool] = None,
user_shared: Optional[UserShared] = None, user_shared: Optional[UserShared] = None,
chat_shared: Optional[ChatShared] = None, chat_shared: Optional[ChatShared] = None,
story: Optional[Story] = None,
*, *,
api_kwargs: Optional[JSONDict] = None, api_kwargs: Optional[JSONDict] = None,
): ):
@ -834,6 +843,7 @@ class Message(TelegramObject):
self.has_media_spoiler: Optional[bool] = has_media_spoiler self.has_media_spoiler: Optional[bool] = has_media_spoiler
self.user_shared: Optional[UserShared] = user_shared self.user_shared: Optional[UserShared] = user_shared
self.chat_shared: Optional[ChatShared] = chat_shared self.chat_shared: Optional[ChatShared] = chat_shared
self.story: Optional[Story] = story
self._effective_attachment = DEFAULT_NONE self._effective_attachment = DEFAULT_NONE
@ -903,6 +913,7 @@ class Message(TelegramObject):
data["game"] = Game.de_json(data.get("game"), bot) data["game"] = Game.de_json(data.get("game"), bot)
data["photo"] = PhotoSize.de_list(data.get("photo"), bot) data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
data["sticker"] = Sticker.de_json(data.get("sticker"), 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["video"] = Video.de_json(data.get("video"), bot)
data["voice"] = Voice.de_json(data.get("voice"), bot) data["voice"] = Voice.de_json(data.get("voice"), bot)
data["video_note"] = VideoNote.de_json(data.get("video_note"), bot) data["video_note"] = VideoNote.de_json(data.get("video_note"), bot)
@ -973,6 +984,7 @@ class Message(TelegramObject):
Sequence[PhotoSize], Sequence[PhotoSize],
Poll, Poll,
Sticker, Sticker,
Story,
SuccessfulPayment, SuccessfulPayment,
Venue, Venue,
Video, Video,
@ -995,6 +1007,7 @@ class Message(TelegramObject):
* List[:class:`telegram.PhotoSize`] * List[:class:`telegram.PhotoSize`]
* :class:`telegram.Poll` * :class:`telegram.Poll`
* :class:`telegram.Sticker` * :class:`telegram.Sticker`
* :class:`telegram.Story`
* :class:`telegram.SuccessfulPayment` * :class:`telegram.SuccessfulPayment`
* :class:`telegram.Venue` * :class:`telegram.Venue`
* :class:`telegram.Video` * :class:`telegram.Video`

View file

@ -21,6 +21,7 @@ import datetime
from typing import TYPE_CHECKING, Dict, Final, List, Optional, Sequence, Tuple from typing import TYPE_CHECKING, Dict, Final, List, Optional, Sequence, Tuple
from telegram import constants from telegram import constants
from telegram._chat import Chat
from telegram._messageentity import MessageEntity from telegram._messageentity import MessageEntity
from telegram._telegramobject import TelegramObject from telegram._telegramobject import TelegramObject
from telegram._user import User 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.argumentparsing import parse_sequence_arg
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
from telegram._utils.types import JSONDict from telegram._utils.types import JSONDict
from telegram._utils.warnings import warn
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot 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 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. 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: Args:
poll_id (:obj:`str`): Unique poll identifier. 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`]): Identifiers of answer options, chosen by the user. May
option_ids (Sequence[:obj:`int`]): 0-based identifiers of answer options, chosen by the be empty if the user retracted their vote.
user. May be empty if the user retracted their vote.
.. versionchanged:: 20.0 .. versionchanged:: 20.0
|sequenceclassargs| |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: Attributes:
poll_id (:obj:`str`): Unique poll identifier. 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
option_ids (Tuple[:obj:`int`]): Identifiers of answer options, chosen by the user. May be be empty if the user retracted their vote.
empty if the user retracted their vote.
.. versionchanged:: 20.0 .. versionchanged:: 20.0
|tupleclassattrs| |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__( def __init__(
self, self,
poll_id: str, poll_id: str,
user: User,
option_ids: Sequence[int], option_ids: Sequence[int],
user: Optional[User] = None,
voter_chat: Optional[Chat] = None,
*, *,
api_kwargs: Optional[JSONDict] = None, api_kwargs: Optional[JSONDict] = None,
): ):
super().__init__(api_kwargs=api_kwargs) super().__init__(api_kwargs=api_kwargs)
self.poll_id: str = poll_id self.poll_id: str = poll_id
self.user: User = user self.voter_chat: Optional[Chat] = voter_chat
self.option_ids: Tuple[int, ...] = parse_sequence_arg(option_ids)
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() self._freeze()
@ -132,6 +179,7 @@ class PollAnswer(TelegramObject):
return None return None
data["user"] = User.de_json(data.get("user"), bot) 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) return super().de_json(data=data, bot=bot)

41
telegram/_story.py Normal file
View 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()

View file

@ -116,7 +116,7 @@ class _BotAPIVersion(NamedTuple):
#: :data:`telegram.__bot_api_version_info__`. #: :data:`telegram.__bot_api_version_info__`.
#: #:
#: .. versionadded:: 20.0 #: .. 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 #: :obj:`str`: Telegram Bot API
#: version supported by this version of `python-telegram-bot`. Also available as #: version supported by this version of `python-telegram-bot`. Also available as
#: :data:`telegram.__bot_api_version__`. #: :data:`telegram.__bot_api_version__`.
@ -285,7 +285,8 @@ class ChatID(IntEnum):
__slots__ = () __slots__ = ()
ANONYMOUS_ADMIN = 1087968824 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: Note:
:attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
@ -293,19 +294,21 @@ class ChatID(IntEnum):
""" """
SERVICE_CHAT = 777000 SERVICE_CHAT = 777000
""":obj:`int`: Telegram service chat, that also acts as sender of channel posts forwarded to """: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: Note:
:attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
It's recommended to use :attr:`telegram.Message.sender_chat` instead. It's recommended to use :attr:`telegram.Message.sender_chat` instead.
""" """
FAKE_CHANNEL = 136817688 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: Note:
* :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only. * :attr:`telegram.Message.from_user` will contain this ID for backwards compatibility only.
It's recommended to use :attr:`telegram.Message.sender_chat` instead. 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`.""" """:obj:`str`: Messages with :attr:`telegram.Message.poll`."""
STICKER = "sticker" STICKER = "sticker"
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" """:obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
STORY = "story"
""":obj:`str`: Messages with :attr:`telegram.Message.story`."""
SUCCESSFUL_PAYMENT = "successful_payment" SUCCESSFUL_PAYMENT = "successful_payment"
""":obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`."""
VIDEO = "video" VIDEO = "video"
@ -1219,6 +1224,8 @@ class MessageType(StringEnum):
""":obj:`str`: Messages with :attr:`telegram.Message.poll`.""" """:obj:`str`: Messages with :attr:`telegram.Message.poll`."""
STICKER = "sticker" STICKER = "sticker"
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" """:obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
STORY = "story"
""":obj:`str`: Messages with :attr:`telegram.Message.story`."""
SUCCESSFUL_PAYMENT = "successful_payment" SUCCESSFUL_PAYMENT = "successful_payment"
""":obj:`str`: Messages with :attr:`telegram.Message.successful_payment`.""" """:obj:`str`: Messages with :attr:`telegram.Message.successful_payment`."""
VIDEO = "video" VIDEO = "video"

View file

@ -3486,6 +3486,26 @@ class ExtBot(Bot, Generic[RLARGS]):
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), 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( async def upload_sticker_file(
self, self,
user_id: Union[str, int], user_id: Union[str, int],
@ -3884,3 +3904,4 @@ class ExtBot(Bot, Generic[RLARGS]):
setStickerMaskPosition = set_sticker_mask_position setStickerMaskPosition = set_sticker_mask_position
setMyName = set_my_name setMyName = set_my_name
getMyName = get_my_name getMyName = get_my_name
unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages

View file

@ -72,6 +72,7 @@ __all__ = (
"REPLY", "REPLY",
"Regex", "Regex",
"Sticker", "Sticker",
"STORY",
"SUCCESSFUL_PAYMENT", "SUCCESSFUL_PAYMENT",
"SenderChat", "SenderChat",
"StatusUpdate", "StatusUpdate",
@ -2143,6 +2144,20 @@ class Sticker:
# neither mask nor emoji can be a message.sticker, so no filters for them # 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): class _SuccessfulPayment(MessageFilter):
__slots__ = () __slots__ = ()

View file

@ -33,8 +33,6 @@ class TestFiles:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("string", "expected"), ("string", "expected"),
[ [
(str(data_file("game.gif")), True),
(str(TEST_DATA_PATH), False),
(str(data_file("game.gif")), True), (str(data_file("game.gif")), True),
(str(TEST_DATA_PATH), False), (str(TEST_DATA_PATH), False),
(data_file("game.gif"), True), (data_file("game.gif"), True),

View file

@ -884,6 +884,11 @@ class TestFilters:
assert filters.Sticker.VIDEO.check_update(update) assert filters.Sticker.VIDEO.check_update(update)
assert filters.Sticker.PREMIUM.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): def test_filters_video(self, update):
assert not filters.VIDEO.check_update(update) assert not filters.VIDEO.check_update(update)
update.message.video = "test" update.message.video = "test"

View file

@ -69,7 +69,7 @@ def false_update(request):
@pytest.fixture() @pytest.fixture()
def poll_answer(bot): 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: class TestPollAnswerHandler:

View file

@ -16,10 +16,12 @@
# #
# You should have received a copy of the GNU Lesser Public License # You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
import time
import pytest import pytest
from telegram import Bot, Chat, ChatLocation, ChatPermissions, Location, User 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.constants import ChatAction, ChatType
from telegram.helpers import escape_markdown from telegram.helpers import escape_markdown
from tests.auxil.bot_method_checks import ( from tests.auxil.bot_method_checks import (
@ -52,6 +54,7 @@ def chat(bot):
is_forum=True, is_forum=True,
active_usernames=TestChatBase.active_usernames, active_usernames=TestChatBase.active_usernames,
emoji_status_custom_emoji_id=TestChatBase.emoji_status_custom_emoji_id, 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_aggressive_anti_spam_enabled=TestChatBase.has_aggressive_anti_spam_enabled,
has_hidden_members=TestChatBase.has_hidden_members, has_hidden_members=TestChatBase.has_hidden_members,
) )
@ -85,6 +88,7 @@ class TestChatBase:
is_forum = True is_forum = True
active_usernames = ["These", "Are", "Usernames!"] active_usernames = ["These", "Are", "Usernames!"]
emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID" emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID"
emoji_status_expiration_date = time.time()
has_aggressive_anti_spam_enabled = True has_aggressive_anti_spam_enabled = True
has_hidden_members = True has_hidden_members = True
@ -119,6 +123,7 @@ class TestChatWithoutRequest(TestChatBase):
"is_forum": self.is_forum, "is_forum": self.is_forum,
"active_usernames": self.active_usernames, "active_usernames": self.active_usernames,
"emoji_status_custom_emoji_id": self.emoji_status_custom_emoji_id, "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_aggressive_anti_spam_enabled": self.has_aggressive_anti_spam_enabled,
"has_hidden_members": self.has_hidden_members, "has_hidden_members": self.has_hidden_members,
} }
@ -150,9 +155,32 @@ class TestChatWithoutRequest(TestChatBase):
assert chat.is_forum == self.is_forum assert chat.is_forum == self.is_forum
assert chat.active_usernames == tuple(self.active_usernames) 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_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_aggressive_anti_spam_enabled == self.has_aggressive_anti_spam_enabled
assert chat.has_hidden_members == self.has_hidden_members 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): def test_to_dict(self, chat):
chat_dict = chat.to_dict() chat_dict = chat.to_dict()
@ -177,6 +205,7 @@ class TestChatWithoutRequest(TestChatBase):
assert chat_dict["is_forum"] == chat.is_forum assert chat_dict["is_forum"] == chat.is_forum
assert chat_dict["active_usernames"] == list(chat.active_usernames) 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_custom_emoji_id"] == chat.emoji_status_custom_emoji_id
assert chat_dict["emoji_status_expiration_date"] == chat.emoji_status_expiration_date
assert ( assert (
chat_dict["has_aggressive_anti_spam_enabled"] == chat.has_aggressive_anti_spam_enabled 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) monkeypatch.setattr(chat.get_bot(), "unpin_all_forum_topic_messages", make_assertion)
assert await chat.unpin_all_forum_topic_messages(message_thread_id=42) 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 test_edit_general_forum_topic(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs): async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["name"] == "WhatAName" return kwargs["chat_id"] == chat.id and kwargs["name"] == "WhatAName"

View file

@ -236,6 +236,7 @@ class TestForumMethodsWithRequest:
assert result is True, "Failed to reopen forum topic" assert result is True, "Failed to reopen forum topic"
async def test_unpin_all_forum_topic_messages(self, bot, forum_group_id, real_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 message_thread_id = real_topic.message_thread_id
pin_msg_tasks = set() 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" 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) 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" 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): async def test_edit_general_forum_topic(self, bot, forum_group_id):
result = await bot.edit_general_forum_topic( result = await bot.edit_general_forum_topic(
chat_id=forum_group_id, chat_id=forum_group_id,

View file

@ -42,6 +42,7 @@ from telegram import (
PollOption, PollOption,
ProximityAlertTriggered, ProximityAlertTriggered,
Sticker, Sticker,
Story,
SuccessfulPayment, SuccessfulPayment,
Update, Update,
User, User,
@ -123,6 +124,7 @@ def message(bot):
}, },
{"photo": [PhotoSize("photo_id", "unique_id", 50, 50)], "caption": "photo_file"}, {"photo": [PhotoSize("photo_id", "unique_id", 50, 50)], "caption": "photo_file"},
{"sticker": Sticker("sticker_id", "unique_id", 50, 50, True, False, Sticker.REGULAR)}, {"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"}, {"video": Video("video_id", "unique_id", 12, 12, 12), "caption": "video_file"},
{"voice": Voice("voice_id", "unique_id", 5)}, {"voice": Voice("voice_id", "unique_id", 5)},
{"video_note": VideoNote("video_note_id", "unique_id", 20, 12)}, {"video_note": VideoNote("video_note_id", "unique_id", 20, 12)},
@ -227,6 +229,7 @@ def message(bot):
"game", "game",
"photo", "photo",
"sticker", "sticker",
"story",
"video", "video",
"voice", "voice",
"video_note", "video_note",
@ -989,6 +992,7 @@ class TestMessageWithoutRequest(TestMessageBase):
"photo", "photo",
"poll", "poll",
"sticker", "sticker",
"story",
"successful_payment", "successful_payment",
"video", "video",
"video_note", "video_note",

View file

@ -19,9 +19,10 @@ from datetime import datetime, timedelta, timezone
import pytest 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._utils.datetime import UTC, to_timestamp
from telegram.constants import PollType from telegram.constants import PollType
from telegram.warnings import PTBDeprecationWarning
from tests.auxil.slots import mro_slots from tests.auxil.slots import mro_slots
@ -81,50 +82,58 @@ class TestPollOptionWithoutRequest(TestPollOptionBase):
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def poll_answer(): def poll_answer():
return PollAnswer( return PollAnswer(
TestPollAnswerBase.poll_id, TestPollAnswerBase.user, TestPollAnswerBase.poll_id TestPollAnswerBase.poll_id,
TestPollAnswerBase.option_ids,
TestPollAnswerBase.user,
TestPollAnswerBase.voter_chat,
) )
class TestPollAnswerBase: class TestPollAnswerBase:
poll_id = "id" poll_id = "id"
user = User(1, "", False)
option_ids = [2] option_ids = [2]
user = User(1, "", False)
voter_chat = Chat(1, "")
class TestPollAnswerWithoutRequest(TestPollAnswerBase): class TestPollAnswerWithoutRequest(TestPollAnswerBase):
def test_de_json(self): def test_de_json(self):
json_dict = { json_dict = {
"poll_id": self.poll_id, "poll_id": self.poll_id,
"user": self.user.to_dict(),
"option_ids": self.option_ids, "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) poll_answer = PollAnswer.de_json(json_dict, None)
assert poll_answer.api_kwargs == {} assert poll_answer.api_kwargs == {}
assert poll_answer.poll_id == self.poll_id 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.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): def test_to_dict(self, poll_answer):
poll_answer_dict = poll_answer.to_dict() poll_answer_dict = poll_answer.to_dict()
assert isinstance(poll_answer_dict, dict) assert isinstance(poll_answer_dict, dict)
assert poll_answer_dict["poll_id"] == poll_answer.poll_id 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["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): def test_equality(self):
a = PollAnswer(123, self.user, [2]) a = PollAnswer(123, [2], self.user, self.voter_chat)
b = PollAnswer(123, User(1, "first", False), [2]) b = PollAnswer(123, [2], self.user, Chat(1, ""))
c = PollAnswer(123, self.user, [1, 2]) c = PollAnswer(123, [2], User(1, "first", False), self.voter_chat)
d = PollAnswer(456, self.user, [2]) d = PollAnswer(123, [1, 2], self.user, self.voter_chat)
e = PollOption("Text", 1) e = PollAnswer(456, [2], self.user, self.voter_chat)
f = PollOption("Text", 1)
assert a == b assert a == b
assert hash(a) == hash(b) assert hash(a) == hash(b)
assert a != c assert a == c
assert hash(a) != hash(c) assert hash(a) == hash(c)
assert a != d assert a != d
assert hash(a) != hash(d) assert hash(a) != hash(d)
@ -132,6 +141,22 @@ class TestPollAnswerWithoutRequest(TestPollAnswerBase):
assert a != e assert a != e
assert hash(a) != hash(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") @pytest.fixture(scope="module")
def poll(): def poll():

45
tests/test_story.py Normal file
View 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 == {}

View file

@ -70,7 +70,18 @@ params = [
{"shipping_query": ShippingQuery("id", User(1, "", False), "", None)}, {"shipping_query": ShippingQuery("id", User(1, "", False), "", None)},
{"pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "")}, {"pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "")},
{"poll": Poll("id", "?", [PollOption(".", 1)], False, False, False, Poll.REGULAR, True)}, {"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}, {"my_chat_member": chat_member_updated},
{"chat_member": chat_member_updated}, {"chat_member": chat_member_updated},
{"chat_join_request": chat_join_request}, {"chat_join_request": chat_join_request},