Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
This commit is contained in:
Poolitzer 2022-12-06 10:13:06 +01:00 committed by GitHub
parent 01167c805b
commit d6c6cc231e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1956 additions and 29 deletions

View file

@ -14,7 +14,7 @@ repos:
args:
- --diff
- --check
- repo: https://gitlab.com/pycqa/flake8
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
hooks:
- id: flake8

View file

@ -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-6.2-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.3-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions

View file

@ -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-6.2-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.3-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions

View file

@ -13,6 +13,7 @@
# serve to show the default.
import sys
import os
from pathlib import Path
# import telegram
# If extensions (or modules to document with autodoc) are in another directory,
@ -50,6 +51,9 @@ source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# Global substitutions
rst_prolog = (Path.cwd() / "substitutions/global.rst").read_text(encoding="utf-8")
# General information about the project.
project = u'python-telegram-bot'
copyright = u'2015-2022, Leandro Toledo'

View file

@ -0,0 +1,5 @@
.. |message_thread_id| replace:: Unique identifier for the target message thread of the forum topic.
.. |message_thread_id_arg| replace:: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only.
.. |chat_id_group| replace:: Unique identifier for the target chat or username of the target supergroup (in the format ``@supergroupusername``).

View file

@ -0,0 +1,8 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.x/telegram/forumtopic.py
telegram.ForumTopic
===================
.. autoclass:: telegram.ForumTopic
:members:
:show-inheritance:

View file

@ -0,0 +1,8 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.x/telegram/forumtopic.py
telegram.ForumTopicClosed
=========================
.. autoclass:: telegram.ForumTopicClosed
:members:
:show-inheritance:

View file

@ -0,0 +1,8 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.x/telegram/forumtopic.py
telegram.ForumTopicCreated
==========================
.. autoclass:: telegram.ForumTopicCreated
:members:
:show-inheritance:

View file

@ -0,0 +1,8 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.x/telegram/forumtopic.py
telegram.ForumTopicReopened
===========================
.. autoclass:: telegram.ForumTopicReopened
:members:
:show-inheritance:

View file

@ -39,6 +39,10 @@ telegram package
telegram.error
telegram.file
telegram.forcereply
telegram.forumtopic
telegram.forumtopicclosed
telegram.forumtopiccreated
telegram.forumtopicreopened
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inputfile

View file

@ -64,6 +64,7 @@ from .replymarkup import ReplyMarkup
from .replykeyboardmarkup import ReplyKeyboardMarkup
from .replykeyboardremove import ReplyKeyboardRemove
from .forcereply import ForceReply
from .forumtopic import ForumTopic, ForumTopicClosed, ForumTopicCreated, ForumTopicReopened
from .error import TelegramError
from .files.inputfile import InputFile
from .files.file import File
@ -230,6 +231,10 @@ __all__ = ( # Keep this alphabetically ordered
'File',
'FileCredentials',
'ForceReply',
'ForumTopic',
'ForumTopicClosed',
'ForumTopicCreated',
'ForumTopicReopened',
'Game',
'GameHighScore',
'IdDocumentData',

View file

@ -94,6 +94,7 @@ from telegram import (
)
from telegram.constants import MAX_INLINE_QUERY_RESULTS
from telegram.error import InvalidToken, TelegramError
from telegram.forumtopic import ForumTopic
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.helpers import (
DEFAULT_NONE,
@ -310,6 +311,7 @@ class Bot(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Union[bool, Message]:
if reply_to_message_id is not None:
data['reply_to_message_id'] = reply_to_message_id
@ -317,6 +319,9 @@ class Bot(TelegramObject):
if protect_content:
data['protect_content'] = protect_content
if message_thread_id is not None:
data["message_thread_id"] = message_thread_id
# We don't check if (DEFAULT_)None here, so that _put is able to insert the defaults
# correctly, if necessary
data['disable_notification'] = disable_notification
@ -471,6 +476,7 @@ class Bot(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send text messages.
@ -492,6 +498,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message
@ -532,6 +541,7 @@ class Bot(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -547,6 +557,8 @@ class Bot(TelegramObject):
limitations:
- A message can only be deleted if it was sent less than 48 hours ago.
- Service messages about a supergroup, channel, or forum topic creation can't be
deleted.
- A dice message in a private chat can only be deleted if it was sent more than 24
hours ago.
- Bots can delete outgoing messages in private chats, groups, and supergroups.
@ -590,6 +602,7 @@ class Bot(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to forward messages of any kind. Service messages can't be forwarded.
@ -613,6 +626,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
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
@ -642,6 +658,7 @@ class Bot(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -660,6 +677,7 @@ class Bot(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send photos.
@ -698,6 +716,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -739,6 +760,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -761,6 +783,7 @@ class Bot(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send audio files, if you want Telegram clients to display them in the
@ -809,6 +832,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -867,6 +893,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -887,6 +914,7 @@ class Bot(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send general files.
@ -929,6 +957,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -983,6 +1014,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -997,6 +1029,7 @@ class Bot(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send static ``.WEBP``, animated ``.TGS``, or video ``.WEBM`` stickers.
@ -1023,6 +1056,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1054,6 +1090,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1077,6 +1114,7 @@ class Bot(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send video files, Telegram clients support mp4 videos
@ -1128,6 +1166,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1187,6 +1228,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1205,6 +1247,7 @@ class Bot(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
@ -1243,6 +1286,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1293,6 +1339,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1315,6 +1362,7 @@ class Bot(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
@ -1323,7 +1371,7 @@ class Bot(TelegramObject):
Note:
``thumb`` will be ignored for small files, for which Telegram can easily
generate thumb nails. However, this behaviour is undocumented and might be changed
generate thumbnails. However, this behaviour is undocumented and might be changed
by Telegram.
Args:
@ -1369,6 +1417,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1417,6 +1468,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1436,6 +1488,7 @@ class Bot(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send audio files, if you want Telegram clients to display the file
@ -1479,6 +1532,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1522,6 +1578,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1537,6 +1594,7 @@ class Bot(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> List[Message]:
"""Use this method to send a group of photos or videos as an album.
@ -1552,6 +1610,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1587,6 +1648,9 @@ class Bot(TelegramObject):
if protect_content:
data['protect_content'] = protect_content
if message_thread_id:
data["message_thread_id"] = message_thread_id
result = self._post('sendMediaGroup', data, timeout=timeout, api_kwargs=api_kwargs)
return Message.de_list(result, self) # type: ignore
@ -1609,6 +1673,7 @@ class Bot(TelegramObject):
proximity_alert_radius: int = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send point on the map.
@ -1636,6 +1701,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1692,6 +1760,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1853,6 +1922,7 @@ class Bot(TelegramObject):
google_place_type: str = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send information about a venue.
@ -1886,6 +1956,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -1950,6 +2023,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -1968,6 +2042,7 @@ class Bot(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send phone contacts.
@ -1990,6 +2065,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -2043,6 +2121,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -2057,6 +2136,7 @@ class Bot(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send a game.
@ -2070,6 +2150,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -2103,6 +2186,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -2246,9 +2330,8 @@ class Bot(TelegramObject):
current_offset: str = None,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to send answers to an inline query. No more than 50 results per query are
allowed.
"""Use this method to send answers to an inline query. No more than 50 results per query
are allowed.
Warning:
In most use cases :attr:`current_offset` should not be passed manually. Instead of
@ -3627,6 +3710,7 @@ class Bot(TelegramObject):
max_tip_amount: int = None,
suggested_tip_amounts: List[int] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""Use this method to send invoices.
@ -3705,6 +3789,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -3779,6 +3866,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -4031,6 +4119,7 @@ class Bot(TelegramObject):
can_manage_chat: bool = None,
can_manage_voice_chats: bool = None,
can_manage_video_chats: bool = None,
can_manage_topics: bool = None,
) -> bool:
"""
Use this method to promote or demote a user in a supergroup or a channel. The bot must be
@ -4086,6 +4175,10 @@ class Bot(TelegramObject):
the connection pool).
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
Telegram API.
can_manage_topics (:obj:`bool`, optional): Pass :obj:`True`, if the user is
allowed to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@ -4125,6 +4218,8 @@ class Bot(TelegramObject):
data['can_manage_video_chats'] = can_manage_voice_chats
if can_manage_video_chats is not None:
data['can_manage_video_chats'] = can_manage_video_chats
if can_manage_topics is not None:
data["can_manage_topics"] = can_manage_topics
result = self._post('promoteChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
@ -5273,6 +5368,7 @@ class Bot(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send a native poll.
@ -5315,6 +5411,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -5376,6 +5475,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -5436,6 +5536,7 @@ class Bot(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> Message:
"""
Use this method to send an animated emoji that will display a random value.
@ -5456,6 +5557,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -5492,6 +5596,7 @@ class Bot(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
@log
@ -5813,6 +5918,7 @@ class Bot(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> MessageId:
"""
Use this method to copy messages of any kind. Service messages and invoice messages can't
@ -5838,6 +5944,9 @@ class Bot(TelegramObject):
forwarding and saving.
.. versionadded:: 13.10
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
.. versionadded:: 13.15
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
original message.
@ -5881,6 +5990,8 @@ class Bot(TelegramObject):
data['reply_markup'] = reply_markup.to_json()
else:
data['reply_markup'] = reply_markup
if message_thread_id:
data["message_thread_id"] = message_thread_id
result = self._post('copyMessage', data, timeout=timeout, api_kwargs=api_kwargs)
return MessageId.de_json(result, self) # type: ignore[return-value, arg-type]
@ -6096,6 +6207,338 @@ class Bot(TelegramObject):
api_kwargs=api_kwargs,
)
@log
def get_forum_topic_icon_stickers(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> List[Sticker]:
"""Use this method to get custom emoji stickers, which can be used as a forum topic
icon by any user. Requires no parameters.
.. versionadded:: 13.15
Args:
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:
List[:class:`telegram.Sticker`]
Raises:
:class:`telegram.error.TelegramError`
"""
result = self._post(
"getForumTopicIconStickers",
timeout=timeout,
api_kwargs=api_kwargs,
)
return Sticker.de_list(result, self) # type: ignore[return-value, arg-type]
@log
def create_forum_topic(
self,
chat_id: Union[str, int],
name: str,
icon_color: int = None,
icon_custom_emoji_id: str = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> ForumTopic:
"""
Use this method to create a topic in a forum supergroup chat. The bot must be
an administrator in the chat for this to work and must have
:attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
.. seealso:: :meth:`telegram.Chat.create_forum_topic`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
name (:obj:`str`): New topic name, 1-128 characters.
icon_color (:obj:`int`, optional): Color of the topic icon in RGB format. Currently,
must be one of 7322096 (0x6FB9F0), 16766590 (0xFFD67E), 13338331 (0xCB86DB),
9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F)
icon_custom_emoji_id (:obj:`str`, optional): New unique identifier of the custom emoji
shown as the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
to get all allowed custom emoji identifiers.
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.ForumTopic`
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"name": name,
}
if icon_color is not None:
data["icon_color"] = icon_color
if icon_custom_emoji_id is not None:
data["icon_custom_emoji_id"] = icon_custom_emoji_id
result = self._post(
"createForumTopic",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
return ForumTopic.de_json(result, self) # type: ignore[return-value, arg-type]
@log
def edit_forum_topic(
self,
chat_id: Union[str, int],
message_thread_id: int,
name: str,
icon_custom_emoji_id: str,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must
be an administrator in the chat for this to work and must have
:attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
unless it is the creator of the topic.
.. seealso:: :meth:`telegram.Message.edit_forum_topic`,
:meth:`telegram.Chat.edit_forum_topic`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
message_thread_id (:obj:`int`): |message_thread_id|
.. versionadded:: 13.15
name (:obj:`str`): New topic name, 1-128 characters.
icon_custom_emoji_id (:obj:`str`): New unique identifier of the custom emoji shown as
the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers` to get all
allowed custom emoji identifiers.
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:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
"name": name,
"icon_custom_emoji_id": icon_custom_emoji_id,
}
return self._post( # type: ignore[return-value]
"editForumTopic",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
@log
def close_forum_topic(
self,
chat_id: Union[str, int],
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to close an open topic in a forum supergroup chat. The bot must
be an administrator in the chat for this to work and must have
:attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
unless it is the creator of the topic.
.. seealso:: :meth:`telegram.Message.close_forum_topic`,
:meth:`telegram.Chat.close_forum_topic`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
message_thread_id (:obj:`int`): |message_thread_id|
.. versionadded:: 13.15
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:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
}
return self._post( # type: ignore[return-value]
"closeForumTopic",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
@log
def reopen_forum_topic(
self,
chat_id: Union[str, int],
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to reopen a closed topic in a forum supergroup chat. The bot must
be an administrator in the chat for this to work and must have
:meth:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
unless it is the creator of the topic.
.. seealso:: :meth:`telegram.Message.reopen_forum_topic`,
:meth:`telegram.Chat.reopen_forum_topic`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
message_thread_id (:obj:`int`): |message_thread_id|
.. versionadded:: 13.15
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:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
}
return self._post( # type: ignore[return-value]
"reopenForumTopic",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
@log
def delete_forum_topic(
self,
chat_id: Union[str, int],
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to delete a forum topic along with all its messages in a forum supergroup
chat. The bot must be an administrator in the chat for this to work and must have
:meth:`~telegram.ChatAdministratorRights.can_delete_messages` administrator rights.
.. seealso:: :meth:`telegram.Message.delete_forum_topic`,
:meth:`telegram.Chat.delete_forum_topic`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
message_thread_id (:obj:`int`): |message_thread_id|
.. versionadded:: 13.15
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:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
}
return self._post( # type: ignore[return-value]
"deleteForumTopic",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
@log
def unpin_all_forum_topic_messages(
self,
chat_id: Union[str, int],
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to clear the list of pinned messages in a forum topic. The bot must
be an administrator in the chat for this to work and must have
:meth:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights
in the supergroup.
.. seealso:: :meth:`telegram.Message.unpin_all_forum_topic_messages`,
:meth:`telegram.Chat.unpin_all_forum_topic_messages`,
.. versionadded:: 13.15
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
message_thread_id (:obj:`int`): |message_thread_id|
.. versionadded:: 13.15
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:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
}
return self._post( # type: ignore[return-value]
"unpinAllForumTopicMessages",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {'id': self.id, 'username': self.username, 'first_name': self.first_name}
@ -6292,3 +6735,17 @@ class Bot(TelegramObject):
"""Alias for :meth:`set_my_default_administrator_rights`"""
createInvoiceLink = create_invoice_link
"""Alias for :meth:`create_invoice_link`"""
getForumTopicIconStickers = get_forum_topic_icon_stickers
"""Alias for :meth:`get_forum_topic_icon_stickers`"""
createForumTopic = create_forum_topic
"""Alias for :meth:`create_forum_topic`"""
editForumTopic = edit_forum_topic
"""Alias for :meth:`edit_forum_topic`"""
closeForumTopic = close_forum_topic
"""Alias for :meth:`close_forum_topic`"""
reopenForumTopic = reopen_forum_topic
"""Alias for :meth:`reopen_forum_topic`"""
deleteForumTopic = delete_forum_topic
"""Alias for :meth:`delete_forum_topic`"""
unpinAllForumTopicMessages = unpin_all_forum_topic_messages
"""Alias for :meth:`unpin_all_forum_topic_messages`"""

View file

@ -621,6 +621,7 @@ class CallbackQuery(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -650,6 +651,7 @@ class CallbackQuery(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
MAX_ANSWER_TEXT_LENGTH: ClassVar[int] = constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH

View file

@ -35,6 +35,7 @@ if TYPE_CHECKING:
Bot,
ChatMember,
ChatInviteLink,
ForumTopic,
Message,
MessageId,
ReplyMarkup,
@ -131,6 +132,21 @@ class Chat(TelegramObject):
in the private chat. Returned only in :meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.14
is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
(has topics_ enabled).
.. versionadded:: 13.15
active_usernames (List[:obj:`str`], optional): If set, the list of all `active chat
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
#collectible-usernames>`_; for private chats, supergroups and channels. Returned
only in :meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.15
emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji
status of the other party in a private chat. Returned only in
:meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.15
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
Attributes:
@ -190,6 +206,23 @@ class Chat(TelegramObject):
in the private chat. Returned only in :meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.14
is_forum (:obj:`bool`): Optional. :obj:`True`, if the supergroup chat is a forum
(has topics_ enabled).
.. versionadded:: 13.15
active_usernames (List[:obj:`str`]): Optional. If set, the list of all `active chat
usernames <https://telegram.org/blog/topics-in-groups-collectible-usernames\
#collectible-usernames>`_; for private chats, supergroups and channels. Returned
only in :meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.15
emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji
status of the other party in a private chat. Returned only in
:meth:`telegram.Bot.get_chat`.
.. versionadded:: 13.15
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
"""
__slots__ = (
@ -218,6 +251,9 @@ class Chat(TelegramObject):
'join_to_send_messages',
'join_by_request',
'has_restricted_voice_and_video_messages',
'is_forum',
'active_usernames',
'emoji_status_custom_emoji_id',
'_id_attrs',
)
@ -261,6 +297,9 @@ class Chat(TelegramObject):
join_to_send_messages: bool = None,
join_by_request: bool = None,
has_restricted_voice_and_video_messages: bool = None,
is_forum: bool = None,
active_usernames: List[str] = None,
emoji_status_custom_emoji_id: str = None,
**_kwargs: Any,
):
# Required
@ -292,6 +331,9 @@ class Chat(TelegramObject):
self.join_to_send_messages = join_to_send_messages
self.join_by_request = join_by_request
self.has_restricted_voice_and_video_messages = has_restricted_voice_and_video_messages
self.is_forum = is_forum
self.active_usernames = active_usernames
self.emoji_status_custom_emoji_id = emoji_status_custom_emoji_id
self.bot = bot
self._id_attrs = (self.id,)
@ -629,6 +671,7 @@ class Chat(TelegramObject):
can_manage_chat: bool = None,
can_manage_voice_chats: bool = None,
can_manage_video_chats: bool = None,
can_manage_topics: bool = None,
) -> bool:
"""Shortcut for::
@ -663,6 +706,7 @@ class Chat(TelegramObject):
can_manage_chat=can_manage_chat,
can_manage_voice_chats=can_manage_voice_chats,
can_manage_video_chats=can_manage_video_chats,
can_manage_topics=can_manage_topics,
)
def restrict_member(
@ -836,6 +880,7 @@ class Chat(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -860,6 +905,7 @@ class Chat(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_media_group(
@ -873,6 +919,7 @@ class Chat(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> List['Message']:
"""Shortcut for::
@ -893,6 +940,7 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_chat_action(
@ -935,6 +983,7 @@ class Chat(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -960,6 +1009,7 @@ class Chat(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_contact(
@ -976,6 +1026,7 @@ class Chat(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1001,6 +1052,7 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_audio(
@ -1021,6 +1073,7 @@ class Chat(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1050,6 +1103,7 @@ class Chat(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_document(
@ -1068,6 +1122,7 @@ class Chat(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1095,6 +1150,7 @@ class Chat(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
caption_entities=caption_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_dice(
@ -1107,6 +1163,7 @@ class Chat(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1128,6 +1185,7 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_game(
@ -1140,6 +1198,7 @@ class Chat(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1161,6 +1220,7 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_invoice(
@ -1193,6 +1253,7 @@ class Chat(TelegramObject):
max_tip_amount: int = None,
suggested_tip_amounts: List[int] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1242,6 +1303,7 @@ class Chat(TelegramObject):
max_tip_amount=max_tip_amount,
suggested_tip_amounts=suggested_tip_amounts,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_location(
@ -1260,6 +1322,7 @@ class Chat(TelegramObject):
proximity_alert_radius: int = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1287,6 +1350,7 @@ class Chat(TelegramObject):
proximity_alert_radius=proximity_alert_radius,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_animation(
@ -1307,6 +1371,7 @@ class Chat(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1336,6 +1401,7 @@ class Chat(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_sticker(
@ -1348,6 +1414,7 @@ class Chat(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1369,6 +1436,7 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_venue(
@ -1389,6 +1457,7 @@ class Chat(TelegramObject):
google_place_type: str = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1418,6 +1487,7 @@ class Chat(TelegramObject):
google_place_type=google_place_type,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_video(
@ -1439,6 +1509,7 @@ class Chat(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1469,6 +1540,7 @@ class Chat(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_video_note(
@ -1485,6 +1557,7 @@ class Chat(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1510,6 +1583,7 @@ class Chat(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_voice(
@ -1527,6 +1601,7 @@ class Chat(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1553,6 +1628,7 @@ class Chat(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_poll(
@ -1577,6 +1653,7 @@ class Chat(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1609,6 +1686,7 @@ class Chat(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
explanation_entities=explanation_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_copy(
@ -1625,6 +1703,7 @@ class Chat(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -1650,6 +1729,7 @@ class Chat(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def copy_message(
@ -1666,6 +1746,7 @@ class Chat(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -1691,6 +1772,7 @@ class Chat(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def export_invite_link(
@ -1887,6 +1969,165 @@ class Chat(TelegramObject):
api_kwargs=api_kwargs,
)
def create_forum_topic(
self,
name: str,
icon_color: int = None,
icon_custom_emoji_id: str = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> "ForumTopic":
"""Shortcut for::
bot.create_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.create_forum_topic`.
.. versionadded:: 13.15
Returns:
:class:`telegram.ForumTopic`
"""
return self.bot.create_forum_topic(
chat_id=self.id,
name=name,
icon_color=icon_color,
icon_custom_emoji_id=icon_custom_emoji_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def edit_forum_topic(
self,
message_thread_id: int,
name: str,
icon_custom_emoji_id: str,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.edit_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.edit_forum_topic(
chat_id=self.id,
message_thread_id=message_thread_id,
name=name,
icon_custom_emoji_id=icon_custom_emoji_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def close_forum_topic(
self,
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.close_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.close_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.close_forum_topic(
chat_id=self.id,
message_thread_id=message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def reopen_forum_topic(
self,
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.reopen_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.reopen_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.reopen_forum_topic(
chat_id=self.id,
message_thread_id=message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def delete_forum_topic(
self,
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.delete_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.delete_forum_topic(
chat_id=self.id,
message_thread_id=message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def unpin_all_forum_topic_messages(
self,
message_thread_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.unpin_all_forum_topic_messages(chat_id=update.effective_chat.id,
*args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.unpin_all_forum_topic_messages`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.unpin_all_forum_topic_messages(
chat_id=self.id,
message_thread_id=message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def get_menu_button(
self,
timeout: ODVInput[float] = DEFAULT_NONE,

View file

@ -62,6 +62,10 @@ class ChatAdministratorRights(TelegramObject):
messages of other users.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
messages; groups and supergroups only.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 13.15
Attributes:
is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
@ -89,6 +93,10 @@ class ChatAdministratorRights(TelegramObject):
messages of other users.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
messages; groups and supergroups only.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 13.15
"""
__slots__ = (
@ -103,6 +111,7 @@ class ChatAdministratorRights(TelegramObject):
'can_post_messages',
'can_edit_messages',
'can_pin_messages',
'can_manage_topics',
'_id_attrs',
)
@ -119,6 +128,7 @@ class ChatAdministratorRights(TelegramObject):
can_post_messages: bool = None,
can_edit_messages: bool = None,
can_pin_messages: bool = None,
can_manage_topics: bool = None,
**_kwargs: Any,
) -> None:
# Required
@ -134,6 +144,7 @@ class ChatAdministratorRights(TelegramObject):
self.can_post_messages = can_post_messages
self.can_edit_messages = can_edit_messages
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self._id_attrs = (
self.is_anonymous,
@ -156,7 +167,7 @@ class ChatAdministratorRights(TelegramObject):
:obj:`True`. This is e.g. useful when changing the bot's default administrator rights with
:meth:`telegram.Bot.set_my_default_administrator_rights`.
"""
return cls(True, True, True, True, True, True, True, True, True, True, True)
return cls(True, True, True, True, True, True, True, True, True, True, True, True)
@classmethod
def no_rights(cls) -> 'ChatAdministratorRights':
@ -164,4 +175,6 @@ class ChatAdministratorRights(TelegramObject):
This method returns the :class:`ChatAdministratorRights` object with all attributes set to
:obj:`False`.
"""
return cls(False, False, False, False, False, False, False, False, False, False, False)
return cls(
False, False, False, False, False, False, False, False, False, False, False, False
)

View file

@ -288,6 +288,7 @@ class ChatMember(TelegramObject):
'can_manage_voice_chats',
'can_manage_video_chats',
'until_date',
'can_manage_topics',
'_id_attrs',
)
@ -329,6 +330,7 @@ class ChatMember(TelegramObject):
can_manage_chat: bool = None,
can_manage_voice_chats: bool = None,
can_manage_video_chats: bool = None,
can_manage_topics: bool = None,
**_kwargs: Any,
):
# check before required to not waste resources if the error is raised
@ -371,6 +373,7 @@ class ChatMember(TelegramObject):
)
self.can_manage_voice_chats = temp
self.can_manage_video_chats = temp
self.can_manage_topics = can_manage_topics
self._id_attrs = (self.user, self.status)
@ -494,6 +497,10 @@ class ChatMemberAdministrator(ChatMember):
new users to the chat.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only.
.. versionadded:: 13.15
Attributes:
status (:obj:`str`): The member's status in the chat,
@ -536,6 +543,10 @@ class ChatMemberAdministrator(ChatMember):
new users to the chat.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to pin messages; groups and supergroups only.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create, rename, close, and reopen forum topics; supergroups only
.. versionadded:: 13.15
"""
__slots__ = ()
@ -557,6 +568,7 @@ class ChatMemberAdministrator(ChatMember):
can_invite_users: bool = None,
can_pin_messages: bool = None,
can_manage_video_chats: bool = None,
can_manage_topics: bool = None,
**_kwargs: Any,
):
super().__init__(
@ -576,6 +588,7 @@ class ChatMemberAdministrator(ChatMember):
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages,
can_manage_video_chats=can_manage_video_chats,
can_manage_topics=can_manage_topics,
)
@ -631,6 +644,10 @@ class ChatMemberRestricted(ChatMember):
allowed to add web page previews to their messages.
until_date (:class:`datetime.datetime`, optional): Date when restrictions
will be lifted for this user.
can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
forum topics.
.. versionadded:: 13.15
Attributes:
status (:obj:`str`): The member's status in the chat,
@ -656,6 +673,10 @@ class ChatMemberRestricted(ChatMember):
allowed to add web page previews to their messages.
until_date (:class:`datetime.datetime`): Optional. Date when restrictions
will be lifted for this user.
can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
forum topics.
.. versionadded:: 13.15
"""
@ -674,6 +695,7 @@ class ChatMemberRestricted(ChatMember):
can_send_other_messages: bool = None,
can_add_web_page_previews: bool = None,
until_date: datetime.datetime = None,
can_manage_topics: bool = None,
**_kwargs: Any,
):
super().__init__(
@ -689,6 +711,7 @@ class ChatMemberRestricted(ChatMember):
can_send_other_messages=can_send_other_messages,
can_add_web_page_previews=can_add_web_page_previews,
until_date=until_date,
can_manage_topics=can_manage_topics,
)

View file

@ -34,7 +34,7 @@ class ChatPermissions(TelegramObject):
Note:
Though not stated explicitly in the official docs, Telegram changes not only the
permissions that are set, but also sets all the others to :obj:`False`. However, since not
documented, this behaviour may change unbeknown to PTB.
documented, this behavior may change unbeknown to PTB.
Args:
can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text
@ -55,6 +55,11 @@ class ChatPermissions(TelegramObject):
users to the chat.
can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
messages. Ignored in public supergroups.
can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
to create forum topics. If omitted defaults to the value of
:attr:`can_pin_messages`.
.. versionadded:: 13.15
Attributes:
can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
@ -75,6 +80,11 @@ class ChatPermissions(TelegramObject):
new users to the chat.
can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
messages. Ignored in public supergroups.
can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
to create forum topics. If omitted defaults to the value of
:attr:`can_pin_messages`.
.. versionadded:: 13.15
"""
@ -88,6 +98,7 @@ class ChatPermissions(TelegramObject):
'can_change_info',
'can_pin_messages',
'can_add_web_page_previews',
'can_manage_topics',
)
def __init__(
@ -100,6 +111,7 @@ class ChatPermissions(TelegramObject):
can_change_info: bool = None,
can_invite_users: bool = None,
can_pin_messages: bool = None,
can_manage_topics: bool = None,
**_kwargs: Any,
):
# Required
@ -111,6 +123,7 @@ class ChatPermissions(TelegramObject):
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self._id_attrs = (
self.can_send_messages,

View file

@ -21,7 +21,7 @@ The following constants were extracted from the
`Telegram Bots API <https://core.telegram.org/bots/api>`_.
Attributes:
BOT_API_VERSION (:obj:`str`): `6.2`. Telegram Bot API version supported by this
BOT_API_VERSION (:obj:`str`): `6.3`. Telegram Bot API version supported by this
version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``.
.. versionadded:: 13.4
@ -263,7 +263,7 @@ Attributes:
"""
from typing import List
BOT_API_VERSION: str = '6.2'
BOT_API_VERSION: str = '6.3'
MAX_MESSAGE_LENGTH: int = 4096
MAX_CAPTION_LENGTH: int = 1024
ANONYMOUS_ADMIN_ID: int = 1087968824

View file

@ -196,6 +196,7 @@ class ExtBot(telegram.bot.Bot):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> Union[bool, Message]:
# We override this method to call self._replace_keyboard and self._insert_callback_data.
# This covers most methods that have a reply_markup
@ -209,6 +210,7 @@ class ExtBot(telegram.bot.Bot):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
if isinstance(result, Message):
self._insert_callback_data(result)
@ -304,6 +306,7 @@ class ExtBot(telegram.bot.Bot):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> MessageId:
# We override this method to call self._replace_keyboard
return super().copy_message(
@ -320,6 +323,7 @@ class ExtBot(telegram.bot.Bot):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def get_chat(

View file

@ -1264,6 +1264,36 @@ officedocument.wordprocessingml.document")``.
web_app_data = _WebAppData()
"""Messages that contain :attr:`telegram.Message.web_app_data`."""
class _ForumTopicCreated(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.forum_topic_created'
def filter(self, message: Message) -> bool:
return bool(message.forum_topic_created)
forum_topic_created = _ForumTopicCreated()
"""Messages that contain :attr:`telegram.Message.forum_topic_created`."""
class _ForumTopicClosed(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.forum_topic_closed'
def filter(self, message: Message) -> bool:
return bool(message.forum_topic_closed)
forum_topic_closed = _ForumTopicClosed()
"""Messages that contain :attr:`telegram.Message.forum_topic_closed`."""
class _ForumTopicReopened(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.forum_topic_reopened'
def filter(self, message: Message) -> bool:
return bool(message.forum_topic_reopened)
forum_topic_reopened = _ForumTopicReopened()
"""Messages that contain :attr:`telegram.Message.forum_topic_reopened`."""
name = 'Filters.status_update'
def filter(self, message: Update) -> bool:
@ -1288,6 +1318,9 @@ officedocument.wordprocessingml.document")``.
or self.video_chat_ended(message)
or self.video_chat_participants_invited(message)
or self.web_app_data(message)
or self.forum_topic_created(message)
or self.forum_topic_closed(message)
or self.forum_topic_reopened(message)
)
status_update = _StatusUpdate()
@ -1361,6 +1394,22 @@ officedocument.wordprocessingml.document")``.
:attr:`telegram.Message.video_chat_participants_invited`.
.. versionadded:: 13.12
web_app_data: Messages that contain
:attr:`telegram.Message.web_app_data`.
.. versionadded:: 13.12
forum_topic_created: Messages that contain
:attr:`telegram.Message.forum_topic_created`.
.. versionadded:: 13.15
forum_topic_closed: Messages that contain
:attr:`telegram.Message.forum_topic_closed`.
.. versionadded:: 13.15
forum_topic_reopened: Messages that contain
:attr:`telegram.Message.forum_topic_reopened`.
.. versionadded:: 13.15
"""
@ -2212,6 +2261,19 @@ officedocument.wordprocessingml.document")``.
.. versionadded:: 13.9
"""
class _IsTopicMessage(MessageFilter):
__slots__ = ()
name = 'Filters.is_topic_message'
def filter(self, message: Message) -> bool:
return bool(message.is_topic_message)
is_topic_message = _IsTopicMessage()
"""Messages that contain :attr:`telegram.Message.is_topic_message`.
.. versionadded:: 13.15
"""
class _HasProtectedContent(MessageFilter):
__slots__ = ()
name = 'Filters.has_protected_content'

134
telegram/forumtopic.py Normal file
View file

@ -0,0 +1,134 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# 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 forum topics."""
from typing import Any
from telegram import TelegramObject
class ForumTopic(TelegramObject):
"""
This object represents a forum topic.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`message_thread_id`, :attr:`name` and :attr:`icon_color`
are equal.
.. versionadded:: 13.15
Args:
message_thread_id (:obj:`int`): Unique identifier of the forum topic
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
as the topic icon.
Attributes:
message_thread_id (:obj:`int`): Unique identifier of the forum topic
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
as the topic icon.
"""
__slots__ = ("message_thread_id", "name", "icon_color", "icon_custom_emoji_id")
def __init__(
self,
message_thread_id: int,
name: str,
icon_color: int,
icon_custom_emoji_id: str = None,
**_kwargs: Any,
):
self.message_thread_id = message_thread_id
self.name = name
self.icon_color = icon_color
self.icon_custom_emoji_id = icon_custom_emoji_id
self._id_attrs = (self.message_thread_id, self.name, self.icon_color)
class ForumTopicCreated(TelegramObject):
"""
This object represents the content of a service message about a new forum topic created in
the chat.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`name` and :attr:`icon_color` are equal.
.. versionadded:: 13.15
Args:
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
as the topic icon.
Attributes:
name (:obj:`str`): Name of the topic
icon_color (:obj:`int`): Color of the topic icon in RGB format
icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
as the topic icon.
"""
__slots__ = ("name", "icon_color", "icon_custom_emoji_id", "_id_attrs")
def __init__(
self,
name: str,
icon_color: int,
icon_custom_emoji_id: str = None,
**_kwargs: Any,
):
self.name = name
self.icon_color = icon_color
self.icon_custom_emoji_id = icon_custom_emoji_id
self._id_attrs = (self.name, self.icon_color)
class ForumTopicClosed(TelegramObject):
"""
This object represents a service message about a forum topic closed in the chat.
Currently holds no information.
.. versionadded:: 13.15
"""
__slots__ = ()
def __init__(self, **_kwargs: Any): # skipcq: PTC-W0049
pass
class ForumTopicReopened(TelegramObject):
"""
This object represents a service message about a forum topic reopened in the chat.
Currently holds no information.
.. versionadded:: 13.15
"""
__slots__ = ()
def __init__(self, **_kwargs: Any): # skipcq: PTC-W0049
pass

View file

@ -60,6 +60,7 @@ from telegram import (
WebAppData,
VideoChatScheduled,
)
from telegram.forumtopic import ForumTopicClosed, ForumTopicCreated, ForumTopicReopened
from telegram.utils.helpers import (
escape_markdown,
from_timestamp,
@ -263,6 +264,26 @@ class Message(TelegramObject):
.. versionadded:: 13.12
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message. ``login_url`` buttons are represented as ordinary url buttons.
is_topic_message (:obj:`bool`, optional): :obj:`True`, if the message is sent to a forum
topic.
.. versionadded:: 13.15
message_thread_id (:obj:`int`, optional): Unique identifier of a message thread to which
the message belongs; for supergroups only.
.. versionadded:: 13.15
forum_topic_created (:class:`telegram.ForumTopicCreated`, optional): Service message:
forum topic created
.. versionadded:: 13.15
forum_topic_closed (:class:`telegram.ForumTopicClosed`, optional): Service message:
forum topic closed
.. versionadded:: 13.15
forum_topic_reopened (:class:`telegram.ForumTopicReopened`, optional): Service message:
forum topic reopened
.. versionadded:: 13.15
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
@ -405,6 +426,26 @@ class Message(TelegramObject):
.. versionadded:: 13.12
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message.
is_topic_message (:obj:`bool`): Optional. :obj:`True`, if the message is sent to a forum
topic.
.. versionadded:: 13.15
message_thread_id (:obj:`int`): Optional. Unique identifier of a message thread to which
the message belongs; for supergroups only.
.. versionadded:: 13.15
forum_topic_created (:class:`telegram.ForumTopicCreated`): Optional. Service message:
forum topic created
.. versionadded:: 13.15
forum_topic_closed (:class:`telegram.ForumTopicClosed`): Optional. Service message:
forum topic closed
.. versionadded:: 13.15
forum_topic_reopened (:class:`telegram.ForumTopicReopened`): Optional. Service message:
forum topic reopened
.. versionadded:: 13.15
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
.. |custom_emoji_formatting_note| replace:: Custom emoji entities will currently be ignored
@ -478,6 +519,11 @@ class Message(TelegramObject):
'is_automatic_forward',
'has_protected_content',
'web_app_data',
'is_topic_message',
'message_thread_id',
'forum_topic_created',
'forum_topic_closed',
'forum_topic_reopened',
'_id_attrs',
)
@ -587,6 +633,11 @@ class Message(TelegramObject):
video_chat_ended: VideoChatEnded = None,
video_chat_participants_invited: VideoChatParticipantsInvited = None,
web_app_data: WebAppData = None,
is_topic_message: bool = None,
message_thread_id: int = None,
forum_topic_created: ForumTopicCreated = None,
forum_topic_closed: ForumTopicClosed = None,
forum_topic_reopened: ForumTopicReopened = None,
**_kwargs: Any,
):
if (
@ -690,7 +741,11 @@ class Message(TelegramObject):
self.voice_chat_participants_invited = temp3
self.video_chat_participants_invited = temp3
self.web_app_data = web_app_data
self.is_topic_message = is_topic_message
self.message_thread_id = message_thread_id
self.forum_topic_created = forum_topic_created
self.forum_topic_closed = forum_topic_closed
self.forum_topic_reopened = forum_topic_reopened
self.bot = bot
self._effective_attachment = DEFAULT_NONE
@ -781,6 +836,13 @@ class Message(TelegramObject):
data.get('video_chat_participants_invited'), bot
)
data['web_app_data'] = WebAppData.de_json(data.get('web_app_data'), bot)
data["forum_topic_closed"] = ForumTopicClosed.de_json(data.get("forum_topic_closed"), bot)
data["forum_topic_created"] = ForumTopicCreated.de_json(
data.get("forum_topic_created"), bot
)
data["forum_topic_reopened"] = ForumTopicReopened.de_json(
data.get("forum_topic_reopened"), bot
)
return cls(bot=bot, **data)
@ -893,6 +955,7 @@ class Message(TelegramObject):
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -924,6 +987,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_markdown(
@ -939,6 +1003,7 @@ class Message(TelegramObject):
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -980,6 +1045,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_markdown_v2(
@ -995,6 +1061,7 @@ class Message(TelegramObject):
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1032,6 +1099,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_html(
@ -1047,6 +1115,7 @@ class Message(TelegramObject):
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1084,6 +1153,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_media_group(
@ -1098,6 +1168,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> List['Message']:
"""Shortcut for::
@ -1127,6 +1198,7 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_photo(
@ -1144,6 +1216,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1176,6 +1249,7 @@ class Message(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_audio(
@ -1197,6 +1271,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1233,6 +1308,7 @@ class Message(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_document(
@ -1252,6 +1328,7 @@ class Message(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1286,6 +1363,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
caption_entities=caption_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_animation(
@ -1307,6 +1385,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1343,6 +1422,7 @@ class Message(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_sticker(
@ -1356,6 +1436,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1384,6 +1465,7 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_video(
@ -1406,6 +1488,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1443,6 +1526,7 @@ class Message(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_video_note(
@ -1460,6 +1544,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1492,6 +1577,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_voice(
@ -1510,6 +1596,7 @@ class Message(TelegramObject):
filename: str = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1543,6 +1630,7 @@ class Message(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_location(
@ -1562,6 +1650,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1596,6 +1685,7 @@ class Message(TelegramObject):
proximity_alert_radius=proximity_alert_radius,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_venue(
@ -1617,6 +1707,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1653,6 +1744,7 @@ class Message(TelegramObject):
google_place_type=google_place_type,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_contact(
@ -1670,6 +1762,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1702,6 +1795,7 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_poll(
@ -1726,6 +1820,7 @@ class Message(TelegramObject):
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1765,6 +1860,7 @@ class Message(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
explanation_entities=explanation_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_dice(
@ -1778,6 +1874,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1806,6 +1903,7 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_chat_action(
@ -1844,6 +1942,7 @@ class Message(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1874,6 +1973,7 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_invoice(
@ -1907,6 +2007,7 @@ class Message(TelegramObject):
max_tip_amount: int = None,
suggested_tip_amounts: List[int] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1965,6 +2066,7 @@ class Message(TelegramObject):
max_tip_amount=max_tip_amount,
suggested_tip_amounts=suggested_tip_amounts,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def forward(
@ -1974,6 +2076,7 @@ class Message(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -2005,6 +2108,7 @@ class Message(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def copy(
@ -2020,6 +2124,7 @@ class Message(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -2049,6 +2154,7 @@ class Message(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def reply_copy(
@ -2066,6 +2172,7 @@ class Message(TelegramObject):
api_kwargs: JSONDict = None,
quote: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -2104,6 +2211,7 @@ class Message(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def edit_text(
@ -2517,6 +2625,145 @@ class Message(TelegramObject):
api_kwargs=api_kwargs,
)
def edit_forum_topic(
self,
name: str,
icon_custom_emoji_id: str,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.edit_forum_topic(
chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.edit_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.edit_forum_topic(
chat_id=self.chat_id,
message_thread_id=self.message_thread_id,
name=name,
icon_custom_emoji_id=icon_custom_emoji_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def close_forum_topic(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.close_forum_topic(
chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.close_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.close_forum_topic(
chat_id=self.chat_id,
message_thread_id=self.message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def reopen_forum_topic(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.reopen_forum_topic(
chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.reopen_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.reopen_forum_topic(
chat_id=self.chat_id,
message_thread_id=self.message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def delete_forum_topic(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.delete_forum_topic(
chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.delete_forum_topic`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.delete_forum_topic(
chat_id=self.chat_id,
message_thread_id=self.message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def unpin_all_forum_topic_messages(
self,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Shortcut for::
bot.unpin_all_forum_topic_messages(
chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
**kwargs
)
For the documentation of the arguments, please see
:meth:`telegram.Bot.unpin_all_forum_topic_messages`.
.. versionadded:: 13.15
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return self.bot.unpin_all_forum_topic_messages(
chat_id=self.chat_id,
message_thread_id=self.message_thread_id,
timeout=timeout,
api_kwargs=api_kwargs,
)
def parse_entity(self, entity: MessageEntity) -> str:
"""Returns the text from a given :class:`telegram.MessageEntity`.

View file

@ -360,6 +360,7 @@ class User(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -384,6 +385,7 @@ class User(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
entities=entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_photo(
@ -400,6 +402,7 @@ class User(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -425,6 +428,7 @@ class User(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_media_group(
@ -438,6 +442,7 @@ class User(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> List['Message']:
"""Shortcut for::
@ -458,6 +463,7 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_audio(
@ -478,6 +484,7 @@ class User(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -507,6 +514,7 @@ class User(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_chat_action(
@ -549,6 +557,7 @@ class User(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -574,6 +583,7 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_dice(
@ -586,6 +596,7 @@ class User(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -607,6 +618,7 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_document(
@ -625,6 +637,7 @@ class User(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -652,6 +665,7 @@ class User(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
caption_entities=caption_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_game(
@ -664,6 +678,7 @@ class User(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -685,6 +700,7 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_invoice(
@ -717,6 +733,7 @@ class User(TelegramObject):
max_tip_amount: int = None,
suggested_tip_amounts: List[int] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -766,6 +783,7 @@ class User(TelegramObject):
max_tip_amount=max_tip_amount,
suggested_tip_amounts=suggested_tip_amounts,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_location(
@ -784,6 +802,7 @@ class User(TelegramObject):
proximity_alert_radius: int = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -811,6 +830,7 @@ class User(TelegramObject):
proximity_alert_radius=proximity_alert_radius,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_animation(
@ -831,6 +851,7 @@ class User(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -860,6 +881,7 @@ class User(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_sticker(
@ -872,6 +894,7 @@ class User(TelegramObject):
api_kwargs: JSONDict = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -893,6 +916,7 @@ class User(TelegramObject):
api_kwargs=api_kwargs,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_video(
@ -914,6 +938,7 @@ class User(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -944,6 +969,7 @@ class User(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_venue(
@ -964,6 +990,7 @@ class User(TelegramObject):
google_place_type: str = None,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -993,6 +1020,7 @@ class User(TelegramObject):
google_place_type=google_place_type,
allow_sending_without_reply=allow_sending_without_reply,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_video_note(
@ -1009,6 +1037,7 @@ class User(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1034,6 +1063,7 @@ class User(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_voice(
@ -1051,6 +1081,7 @@ class User(TelegramObject):
caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
filename: str = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1077,6 +1108,7 @@ class User(TelegramObject):
caption_entities=caption_entities,
filename=filename,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_poll(
@ -1101,6 +1133,7 @@ class User(TelegramObject):
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'Message':
"""Shortcut for::
@ -1133,6 +1166,7 @@ class User(TelegramObject):
allow_sending_without_reply=allow_sending_without_reply,
explanation_entities=explanation_entities,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def send_copy(
@ -1149,6 +1183,7 @@ class User(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -1174,6 +1209,7 @@ class User(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def copy_message(
@ -1190,6 +1226,7 @@ class User(TelegramObject):
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
protect_content: bool = None,
message_thread_id: int = None,
) -> 'MessageId':
"""Shortcut for::
@ -1215,6 +1252,7 @@ class User(TelegramObject):
timeout=timeout,
api_kwargs=api_kwargs,
protect_content=protect_content,
message_thread_id=message_thread_id,
)
def approve_join_request(

View file

@ -29,15 +29,16 @@ from telegram.error import RetryAfter, TimedOut
# These bots are only able to talk in our test chats, so they are quite useless for other
# purposes than testing.
FALLBACKS = (
'W3sidG9rZW4iOiAiNTc5Njk0NzE0OkFBRnBLOHc2emtrVXJENHhTZVl3RjNNTzhlLTRHcm1jeTdjIiwgInBheW1lbnRfc'
'HJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpRME5qWmxOekk1WWpKaSIsICJjaGF0X2lkIjogIjY3NTY2Nj'
'IyNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTMxMDkxMTEzNSIsICJjaGFubmVsX2lkIjogIkBweXRob250ZWxlZ3J'
'hbWJvdHRlc3RzIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBmYWxsYmFjayAxIiwgImJvdF91c2VybmFtZSI6ICJAcHRi'
'X2ZhbGxiYWNrXzFfYm90In0sIHsidG9rZW4iOiAiNTU4MTk0MDY2OkFBRndEUElGbHpHVWxDYVdIdFRPRVg0UkZyWDh1O'
'URNcWZvIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6WWpFd09EUXdNVEZtTkRjeSIsIC'
'JjaGF0X2lkIjogIjY3NTY2NjIyNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTIyMTIxNjgzMCIsICJjaGFubmVsX2l'
'kIjogIkBweXRob250ZWxlZ3JhbWJvdHRlc3RzIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBmYWxsYmFjayAyIiwgImJv'
'dF91c2VybmFtZSI6ICJAcHRiX2ZhbGxiYWNrXzJfYm90In1d'
"W3sidG9rZW4iOiAiNTc5Njk0NzE0OkFBRnBLOHc2emtrVXJENHhTZVl3RjNNTzhlLTRHcm1jeTdjIiwgInBheW1lbnRfc"
"HJvdmlkZXJfdG9rZW4iOiAiMjg0Njg1MDYzOlRFU1Q6TmpRME5qWmxOekk1WWpKaSIsICJjaGF0X2lkIjogIjY3NTY2Nj"
"IyNCIsICJzdXBlcl9ncm91cF9pZCI6ICItMTAwMTMxMDkxMTEzNSIsICJmb3J1bV9ncm91cF9pZCI6ICItMTAwMTYxOTE"
"1OTQwNCIsICJjaGFubmVsX2lkIjogIkBweXRob250ZWxlZ3JhbWJvdHRlc3RzIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0"
"cyBmYWxsYmFjayAxIiwgImJvdF91c2VybmFtZSI6ICJAcHRiX2ZhbGxiYWNrXzFfYm90In0sIHsidG9rZW4iOiAiNTU4M"
"Tk0MDY2OkFBRndEUElGbHpHVWxDYVdIdFRPRVg0UkZyWDh1OURNcWZvIiwgInBheW1lbnRfcHJvdmlkZXJfdG9rZW4iOi"
"AiMjg0Njg1MDYzOlRFU1Q6WWpFd09EUXdNVEZtTkRjeSIsICJjaGF0X2lkIjogIjY3NTY2NjIyNCIsICJzdXBlcl9ncm9"
"1cF9pZCI6ICItMTAwMTIyMTIxNjgzMCIsICJmb3J1bV9ncm91cF9pZCI6ICItMTAwMTYxOTE1OTQwNCIsICJjaGFubmVs"
"X2lkIjogIkBweXRob250ZWxlZ3JhbWJvdHRlc3RzIiwgImJvdF9uYW1lIjogIlBUQiB0ZXN0cyBmYWxsYmFjayAyIiwgI"
"mJvdF91c2VybmFtZSI6ICJAcHRiX2ZhbGxiYWNrXzJfYm90In1d "
)
GITHUB_ACTION = os.getenv('GITHUB_ACTION', None)

View file

@ -138,6 +138,11 @@ def super_group_id(bot_info):
return bot_info['super_group_id']
@pytest.fixture(scope="session")
def forum_group_id(bot_info):
return int(bot_info["forum_group_id"])
@pytest.fixture(scope='session')
def channel_id(bot_info):
return bot_info['channel_id']

View file

@ -1851,6 +1851,7 @@ class TestBot:
can_promote_members=True,
can_manage_chat=True,
can_manage_voice_chats=True,
can_manage_topics=True,
)
with pytest.raises(
@ -1892,6 +1893,7 @@ class TestBot:
and data.get('can_promote_members') == 9
and data.get('can_manage_chat') == 10
and data.get('can_manage_video_chats') == 11
and data.get("can_manage_topics") == 12
)
monkeypatch.setattr(bot, '_post', make_assertion)
@ -1909,6 +1911,7 @@ class TestBot:
can_promote_members=9,
can_manage_chat=10,
can_manage_voice_chats=11,
can_manage_topics=12,
)
# Test that video_chats also works
@ -2172,6 +2175,9 @@ class TestBot:
# set_sticker_position_in_set, delete_sticker_from_set and get_custom_emoji_stickers
# are tested in the test_sticker module.
# get_forum_topic_icon_stickers, edit_forum_topic, etc...
# are tested in the test_forum module.
def test_timeout_propagation_explicit(self, monkeypatch, bot, chat_id):
from telegram.vendor.ptb_urllib3.urllib3.util.timeout import Timeout
@ -2307,6 +2313,7 @@ class TestBot:
assert my_admin_rights_ch.can_promote_members is my_rights.can_promote_members
assert my_admin_rights_ch.can_restrict_members is my_rights.can_restrict_members
assert my_admin_rights_ch.can_pin_messages is None # Not returned for channels
assert my_admin_rights_ch.can_manage_topics is None # Not returned for channels
def test_get_set_chat_menu_button(self, bot, chat_id):
# Test our chat menu button is commands-
@ -2440,6 +2447,7 @@ class TestBot:
assert data["disable_notification"] is True
assert data["caption_entities"] == [MessageEntity(MessageEntity.BOLD, 0, 4)]
assert data['protect_content'] is True
assert data["message_thread_id"] == 1
return data
monkeypatch.setattr(bot.request, 'post', post)
@ -2454,6 +2462,7 @@ class TestBot:
reply_markup=keyboard.to_json() if json_keyboard else keyboard,
disable_notification=True,
protect_content=True,
message_thread_id=1,
)
@flaky(3, 1)

View file

@ -46,6 +46,9 @@ def chat(bot):
join_to_send_messages=True,
join_by_request=True,
has_restricted_voice_and_video_messages=True,
is_forum=True,
active_usernames=TestChat.active_usernames,
emoji_status_custom_emoji_id=TestChat.emoji_status_custom_emoji_id,
)
@ -72,6 +75,9 @@ class TestChat:
join_to_send_messages = True
join_by_request = True
has_restricted_voice_and_video_messages = True
is_forum = True
active_usernames = ["These", "Are", "Usernames!"]
emoji_status_custom_emoji_id = "VeryUniqueCustomEmojiID"
def test_slot_behaviour(self, chat, recwarn, mro_slots):
for attr in chat.__slots__:
@ -103,6 +109,9 @@ class TestChat:
'has_restricted_voice_and_video_messages': (
self.has_restricted_voice_and_video_messages
),
"is_forum": self.is_forum,
"active_usernames": self.active_usernames,
"emoji_status_custom_emoji_id": self.emoji_status_custom_emoji_id,
}
chat = Chat.de_json(json_dict, bot)
@ -128,6 +137,9 @@ class TestChat:
chat.has_restricted_voice_and_video_messages
== self.has_restricted_voice_and_video_messages
)
assert chat.is_forum == self.is_forum
assert chat.active_usernames == self.active_usernames
assert chat.emoji_status_custom_emoji_id == self.emoji_status_custom_emoji_id
def test_to_dict(self, chat):
chat_dict = chat.to_dict()
@ -152,6 +164,9 @@ class TestChat:
chat_dict["has_restricted_voice_and_video_messages"]
== chat.has_restricted_voice_and_video_messages
)
assert chat_dict["is_forum"] == chat.is_forum
assert chat_dict["active_usernames"] == chat.active_usernames
assert chat_dict["emoji_status_custom_emoji_id"] == chat.emoji_status_custom_emoji_id
def test_link(self, chat):
assert chat.link == f'https://t.me/{chat.username}'
@ -795,6 +810,128 @@ class TestChat:
monkeypatch.setattr(chat.bot, 'decline_chat_join_request', make_assertion)
assert chat.decline_join_request(user_id=42)
def test_create_forum_topic(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == chat.id
and kwargs["name"] == "New Name"
and kwargs["icon_color"] == 0x6FB9F0
and kwargs["icon_custom_emoji_id"] == "12345"
)
assert check_shortcut_signature(
Chat.create_forum_topic, Bot.create_forum_topic, ["chat_id"], []
)
assert check_shortcut_call(
chat.create_forum_topic,
chat.bot,
"create_forum_topic",
shortcut_kwargs=["chat_id"],
)
assert check_defaults_handling(chat.create_forum_topic, chat.bot)
monkeypatch.setattr(chat.bot, "create_forum_topic", make_assertion)
assert chat.create_forum_topic(
name="New Name", icon_color=0x6FB9F0, icon_custom_emoji_id="12345"
)
def test_edit_forum_topic(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == chat.id
and kwargs["message_thread_id"] == 42
and kwargs["name"] == "New Name"
and kwargs["icon_custom_emoji_id"] == "12345"
)
assert check_shortcut_signature(
Chat.edit_forum_topic, Bot.edit_forum_topic, ["chat_id"], []
)
assert check_shortcut_call(
chat.edit_forum_topic, chat.bot, "edit_forum_topic", shortcut_kwargs=["chat_id"]
)
assert check_defaults_handling(chat.edit_forum_topic, chat.bot)
monkeypatch.setattr(chat.bot, "edit_forum_topic", make_assertion)
assert chat.edit_forum_topic(
message_thread_id=42, name="New Name", icon_custom_emoji_id="12345"
)
def test_close_forum_topic(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["message_thread_id"] == 42
assert check_shortcut_signature(
Chat.close_forum_topic, Bot.close_forum_topic, ["chat_id"], []
)
assert check_shortcut_call(
chat.close_forum_topic,
chat.bot,
"close_forum_topic",
shortcut_kwargs=["chat_id"],
)
assert check_defaults_handling(chat.close_forum_topic, chat.bot)
monkeypatch.setattr(chat.bot, "close_forum_topic", make_assertion)
assert chat.close_forum_topic(message_thread_id=42)
def test_reopen_forum_topic(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["message_thread_id"] == 42
assert check_shortcut_signature(
Chat.reopen_forum_topic, Bot.reopen_forum_topic, ["chat_id"], []
)
assert check_shortcut_call(
chat.reopen_forum_topic,
chat.bot,
"reopen_forum_topic",
shortcut_kwargs=["chat_id"],
)
assert check_defaults_handling(chat.reopen_forum_topic, chat.bot)
monkeypatch.setattr(chat.bot, "reopen_forum_topic", make_assertion)
assert chat.reopen_forum_topic(message_thread_id=42)
def test_delete_forum_topic(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["message_thread_id"] == 42
assert check_shortcut_signature(
Chat.delete_forum_topic, Bot.delete_forum_topic, ["chat_id"], []
)
assert check_shortcut_call(
chat.delete_forum_topic,
chat.bot,
"delete_forum_topic",
shortcut_kwargs=["chat_id"],
)
assert check_defaults_handling(chat.delete_forum_topic, chat.bot)
monkeypatch.setattr(chat.bot, "delete_forum_topic", make_assertion)
assert chat.delete_forum_topic(message_thread_id=42)
def test_unpin_all_forum_topic_messages(self, monkeypatch, chat):
def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["message_thread_id"] == 42
assert check_shortcut_signature(
Chat.unpin_all_forum_topic_messages,
Bot.unpin_all_forum_topic_messages,
["chat_id"],
[],
)
assert check_shortcut_call(
chat.unpin_all_forum_topic_messages,
chat.bot,
"unpin_all_forum_topic_messages",
shortcut_kwargs=["chat_id"],
)
assert check_defaults_handling(chat.unpin_all_forum_topic_messages, chat.bot)
monkeypatch.setattr(chat.bot, "unpin_all_forum_topic_messages", make_assertion)
assert chat.unpin_all_forum_topic_messages(message_thread_id=42)
def test_equality(self):
a = Chat(self.id_, self.title, self.type_)
b = Chat(self.id_, self.title, self.type_)

View file

@ -34,6 +34,7 @@ def chat_admin_rights():
can_edit_messages=True,
can_manage_chat=True,
can_manage_video_chats=True,
can_manage_topics=True,
is_anonymous=True,
)
@ -57,6 +58,7 @@ class TestChatAdministratorRights:
'can_edit_messages': True,
'can_manage_chat': True,
'can_manage_video_chats': True,
"can_manage_topics": True,
'is_anonymous': True,
}
chat_administrator_rights_de = ChatAdministratorRights.de_json(json_dict, bot)
@ -79,13 +81,14 @@ class TestChatAdministratorRights:
assert admin_rights_dict['can_manage_chat'] == car.can_manage_chat
assert admin_rights_dict['is_anonymous'] == car.is_anonymous
assert admin_rights_dict['can_manage_video_chats'] == car.can_manage_video_chats
assert admin_rights_dict["can_manage_topics"] == car.can_manage_topics
def test_equality(self):
a = ChatAdministratorRights(True, False, False, False, False, False, False, False)
b = ChatAdministratorRights(True, False, False, False, False, False, False, False)
c = ChatAdministratorRights(False, False, False, False, False, False, False, False)
d = ChatAdministratorRights(True, True, False, False, False, False, False, False)
e = ChatAdministratorRights(True, True, False, False, False, False, False, False)
a = ChatAdministratorRights(True, False, False, False, False, False, False, False, False)
b = ChatAdministratorRights(True, False, False, False, False, False, False, False, False)
c = ChatAdministratorRights(False, False, False, False, False, False, False, False, False)
d = ChatAdministratorRights(True, True, False, False, False, False, False, False, False)
e = ChatAdministratorRights(True, True, False, False, False, False, False, False, False)
assert a == b
assert hash(a) == hash(b)
@ -101,7 +104,7 @@ class TestChatAdministratorRights:
assert hash(d) == hash(e)
def test_all_rights(self):
f = ChatAdministratorRights(True, True, True, True, True, True, True, True)
f = ChatAdministratorRights(True, True, True, True, True, True, True, True, True)
t = ChatAdministratorRights.all_rights()
# if the dirs are the same, the attributes will all be there
assert dir(f) == dir(t)
@ -116,7 +119,7 @@ class TestChatAdministratorRights:
assert f != t
def test_no_rights(self):
f = ChatAdministratorRights(False, False, False, False, False, False, False, False)
f = ChatAdministratorRights(False, False, False, False, False, False, False, False, False)
t = ChatAdministratorRights.no_rights()
# if the dirs are the same, the attributes will all be there
assert dir(f) == dir(t)

View file

@ -120,6 +120,7 @@ class TestChatMember:
'can_add_web_page_previews': False,
'can_manage_chat': True,
'can_manage_voice_chats': True,
'can_manage_topics': True,
}
chat_member_type = ChatMember.de_json(json_dict, bot)
@ -221,6 +222,7 @@ class TestChatMember:
'can_add_web_page_previews': False,
'can_manage_chat': True,
'can_manage_video_chats': True,
'can_manage_topics': True,
}
assert type(cls.de_json(json_dict, bot)) is cls

View file

@ -969,6 +969,21 @@ class TestFilters:
assert Filters.status_update.web_app_data(update)
update.message.web_app_data = None
update.message.forum_topic_created = "topic"
assert Filters.status_update(update)
assert Filters.status_update.forum_topic_created(update)
update.message.forum_topic_created = None
update.message.forum_topic_closed = "topic"
assert Filters.status_update(update)
assert Filters.status_update.forum_topic_closed(update)
update.message.forum_topic_closed = None
update.message.forum_topic_reopened = "topic"
assert Filters.status_update(update)
assert Filters.status_update.forum_topic_reopened(update)
update.message.forum_topic_reopened = None
def test_filters_forwarded(self, update):
assert not Filters.forwarded(update)
update.message.forward_date = datetime.datetime.utcnow()
@ -1762,6 +1777,11 @@ class TestFilters:
update.message.is_automatic_forward = True
assert Filters.is_automatic_forward(update)
def test_filters_is_topic_message(self, update):
assert not Filters.is_topic_message(update)
update.message.is_topic_message = True
assert Filters.is_topic_message(update)
def test_filters_has_protected_content(self, update):
assert not Filters.has_protected_content(update)
update.message.has_protected_content = True

331
tests/test_forum.py Normal file
View file

@ -0,0 +1,331 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# 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 ForumTopic, ForumTopicClosed, ForumTopicCreated, ForumTopicReopened, Sticker
TEST_MSG_TEXT = "Topics are forever"
TEST_TOPIC_ICON_COLOR = 0x6FB9F0
TEST_TOPIC_NAME = "Sad bot true: real stories"
@pytest.fixture(scope="module")
def emoji_id(bot):
emoji_sticker_list = bot.get_forum_topic_icon_stickers()
first_sticker = emoji_sticker_list[0]
return first_sticker.custom_emoji_id
@pytest.fixture
def forum_topic_object(forum_group_id, emoji_id):
return ForumTopic(
message_thread_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
icon_custom_emoji_id=emoji_id,
)
@pytest.fixture
def real_topic(bot, emoji_id, forum_group_id):
result = bot.create_forum_topic(
chat_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
icon_custom_emoji_id=emoji_id,
)
yield result
result = bot.delete_forum_topic(
chat_id=forum_group_id, message_thread_id=result.message_thread_id
)
assert result is True, "Topic was not deleted"
class TestForumTopic:
def test_slot_behaviour(self, mro_slots, forum_topic_object):
for attr in forum_topic_object.__slots__:
assert getattr(forum_topic_object, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(forum_topic_object)) == len(
set(mro_slots(forum_topic_object))
), "duplicate slot"
def test_expected_values(self, emoji_id, forum_group_id, forum_topic_object):
assert forum_topic_object.message_thread_id == forum_group_id
assert forum_topic_object.icon_color == TEST_TOPIC_ICON_COLOR
assert forum_topic_object.name == TEST_TOPIC_NAME
assert forum_topic_object.icon_custom_emoji_id == emoji_id
def test_de_json(self, bot, emoji_id, forum_group_id):
assert ForumTopic.de_json(None, bot=bot) is None
json_dict = {
"message_thread_id": forum_group_id,
"name": TEST_TOPIC_NAME,
"icon_color": TEST_TOPIC_ICON_COLOR,
"icon_custom_emoji_id": emoji_id,
}
topic = ForumTopic.de_json(json_dict, bot)
assert topic.message_thread_id == forum_group_id
assert topic.icon_color == TEST_TOPIC_ICON_COLOR
assert topic.name == TEST_TOPIC_NAME
assert topic.icon_custom_emoji_id == emoji_id
def test_to_dict(self, emoji_id, forum_group_id, forum_topic_object):
topic_dict = forum_topic_object.to_dict()
assert isinstance(topic_dict, dict)
assert topic_dict["message_thread_id"] == forum_group_id
assert topic_dict["name"] == TEST_TOPIC_NAME
assert topic_dict["icon_color"] == TEST_TOPIC_ICON_COLOR
assert topic_dict["icon_custom_emoji_id"] == emoji_id
def test_equality(self, emoji_id, forum_group_id):
a = ForumTopic(
message_thread_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
)
b = ForumTopic(
message_thread_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
icon_custom_emoji_id=emoji_id,
)
c = ForumTopic(
message_thread_id=forum_group_id,
name=f"{TEST_TOPIC_NAME}!",
icon_color=TEST_TOPIC_ICON_COLOR,
)
d = ForumTopic(
message_thread_id=forum_group_id + 1,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
)
e = ForumTopic(
message_thread_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=0xFFD67E,
)
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)
@pytest.mark.flaky(3, 1)
def test_create_forum_topic(self, real_topic):
result = real_topic
assert isinstance(result, ForumTopic)
assert result.name == TEST_TOPIC_NAME
assert result.message_thread_id
assert isinstance(result.icon_color, int)
assert isinstance(result.icon_custom_emoji_id, str)
def test_create_forum_topic_with_only_required_args(self, bot, forum_group_id):
result = bot.create_forum_topic(chat_id=forum_group_id, name=TEST_TOPIC_NAME)
assert isinstance(result, ForumTopic)
assert result.name == TEST_TOPIC_NAME
assert result.message_thread_id
assert isinstance(result.icon_color, int) # color is still there though it was not passed
assert result.icon_custom_emoji_id is None
result = bot.delete_forum_topic(
chat_id=forum_group_id, message_thread_id=result.message_thread_id
)
assert result is True, "Failed to delete forum topic"
@pytest.mark.flaky(3, 1)
def test_get_forum_topic_icon_stickers(self, bot):
emoji_sticker_list = bot.get_forum_topic_icon_stickers()
first_sticker = emoji_sticker_list[0]
assert first_sticker.emoji == "📰"
assert first_sticker.height == 512
assert first_sticker.width == 512
assert first_sticker.is_animated
assert not first_sticker.is_video
assert first_sticker.set_name == "Topics"
assert first_sticker.type == Sticker.CUSTOM_EMOJI
assert first_sticker.thumb.width == 128
assert first_sticker.thumb.height == 128
# The following data of first item returned has changed in the past already,
# so check sizes loosely and ID's only by length of string
assert first_sticker.thumb.file_size in range(2000, 7000)
assert first_sticker.file_size in range(20000, 70000)
assert len(first_sticker.custom_emoji_id) == 19
assert len(first_sticker.thumb.file_unique_id) == 16
assert len(first_sticker.file_unique_id) == 15
def test_edit_forum_topic(self, emoji_id, forum_group_id, bot, real_topic):
result = bot.edit_forum_topic(
chat_id=forum_group_id,
message_thread_id=real_topic.message_thread_id,
name=f"{TEST_TOPIC_NAME}_EDITED",
icon_custom_emoji_id=emoji_id,
)
assert result is True, "Failed to edit forum topic"
# no way of checking the edited name, just the boolean result
@pytest.mark.flaky(3, 1)
def test_send_message_to_topic(self, bot, forum_group_id, real_topic):
message_thread_id = real_topic.message_thread_id
message = bot.send_message(
chat_id=forum_group_id, text=TEST_MSG_TEXT, message_thread_id=message_thread_id
)
assert message.text == TEST_MSG_TEXT
assert message.is_topic_message is True
assert message.message_thread_id == message_thread_id
def test_close_and_reopen_forum_topic(self, bot, forum_group_id, real_topic):
message_thread_id = real_topic.message_thread_id
result = bot.close_forum_topic(
chat_id=forum_group_id,
message_thread_id=message_thread_id,
)
assert result is True, "Failed to close forum topic"
# bot will still be able to send a message to a closed topic, so can't test anything like
# the inability to post to the topic
result = bot.reopen_forum_topic(
chat_id=forum_group_id,
message_thread_id=message_thread_id,
)
assert result is True, "Failed to reopen forum topic"
@pytest.mark.xfail(reason="Can fail due to race conditions in GH actions CI")
def test_unpin_all_forum_topic_messages(self, bot, forum_group_id, real_topic):
message_thread_id = real_topic.message_thread_id
msgs = [
(
bot.send_message(
chat_id=forum_group_id, text=TEST_MSG_TEXT, message_thread_id=message_thread_id
)
).pin()
for _ in range(2)
]
assert all(msgs) 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 = bot.unpin_all_forum_topic_messages(
chat_id=forum_group_id, message_thread_id=message_thread_id
)
assert result is True, "Failed to unpin all the messages in forum topic"
@pytest.fixture
def topic_created():
return ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=TEST_TOPIC_ICON_COLOR)
class TestForumTopicCreated:
def test_slot_behaviour(self, topic_created, mro_slots):
for attr in topic_created.__slots__:
assert getattr(topic_created, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(topic_created)) == len(
set(mro_slots(topic_created))
), "duplicate slot"
def test_expected_values(self, topic_created):
assert topic_created.icon_color == TEST_TOPIC_ICON_COLOR
assert topic_created.name == TEST_TOPIC_NAME
def test_de_json(self, bot):
assert ForumTopicCreated.de_json(None, bot=bot) is None
json_dict = {"icon_color": TEST_TOPIC_ICON_COLOR, "name": TEST_TOPIC_NAME}
action = ForumTopicCreated.de_json(json_dict, bot)
assert action.icon_color == TEST_TOPIC_ICON_COLOR
assert action.name == TEST_TOPIC_NAME
def test_to_dict(self, topic_created):
action_dict = topic_created.to_dict()
assert isinstance(action_dict, dict)
assert action_dict["name"] == TEST_TOPIC_NAME
assert action_dict["icon_color"] == TEST_TOPIC_ICON_COLOR
def test_equality(self, emoji_id):
a = ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=TEST_TOPIC_ICON_COLOR)
b = ForumTopicCreated(
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
icon_custom_emoji_id=emoji_id,
)
c = ForumTopicCreated(name=f"{TEST_TOPIC_NAME}!", icon_color=TEST_TOPIC_ICON_COLOR)
d = ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=0xFFD67E)
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 TestForumTopicClosed:
def test_slot_behaviour(self, mro_slots):
action = ForumTopicClosed()
for attr in action.__slots__:
assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
def test_de_json(self):
action = ForumTopicClosed.de_json({}, None)
assert isinstance(action, ForumTopicClosed)
def test_to_dict(self):
action = ForumTopicClosed()
action_dict = action.to_dict()
assert action_dict == {}
class TestForumTopicReopened:
def test_slot_behaviour(self, mro_slots):
action = ForumTopicReopened()
for attr in action.__slots__:
assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
def test_de_json(self):
action = ForumTopicReopened.de_json({}, None)
assert isinstance(action, ForumTopicReopened)
def test_to_dict(self):
action = ForumTopicReopened()
action_dict = action.to_dict()
assert action_dict == {}

View file

@ -43,6 +43,9 @@ from .test_audio import audio, audio_file # noqa: F401
# noinspection PyUnresolvedReferences
from .test_document import document, document_file # noqa: F401
# noinspection PyUnresolvedReferences
from .test_forum import emoji_id, real_topic # noqa: F401
# noinspection PyUnresolvedReferences
from .test_photo import _photo, photo_file, photo, thumb # noqa: F401
@ -458,6 +461,19 @@ class TestSendMediaGroup:
mes.caption_entities == [MessageEntity(MessageEntity.BOLD, 0, 5)] for mes in messages
)
def test_send_media_group_with_message_thread_id(
self, bot, real_topic, forum_group_id, media_group # noqa: F811
):
messages = bot.send_media_group(
forum_group_id,
media_group,
message_thread_id=real_topic.message_thread_id,
)
assert isinstance(messages, list)
assert len(messages) == 3
assert all(isinstance(mes, Message) for mes in messages)
assert all(i.message_thread_id == real_topic.message_thread_id for i in messages)
@flaky(3, 1)
def test_send_media_group_all_args(self, bot, chat_id, media_group):
m1 = bot.send_message(chat_id, text="test")

View file

@ -196,6 +196,7 @@ def message(bot):
)
},
{'web_app_data': WebAppData('some_data', 'some_button_text')},
{"message_thread_id": 123},
],
ids=[
'forwarded_user',
@ -252,6 +253,7 @@ def message(bot):
'is_automatic_forward',
'has_protected_content',
'web_app_data',
'message_thread_id',
],
)
def message_params(bot, request):
@ -1634,6 +1636,122 @@ class TestMessage:
finally:
message.bot.defaults = None
def test_edit_forum_topic(self, monkeypatch, message):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == message.chat_id
and kwargs["message_thread_id"] == message.message_thread_id
and kwargs["name"] == "New Name"
and kwargs["icon_custom_emoji_id"] == "12345"
)
assert check_shortcut_signature(
Message.edit_forum_topic, Bot.edit_forum_topic, ["chat_id", "message_thread_id"], []
)
assert check_shortcut_call(
message.edit_forum_topic,
message.bot,
"edit_forum_topic",
shortcut_kwargs=["chat_id", "message_thread_id"],
)
assert check_defaults_handling(message.edit_forum_topic, message.bot)
monkeypatch.setattr(message.bot, "edit_forum_topic", make_assertion)
assert message.edit_forum_topic(name="New Name", icon_custom_emoji_id="12345")
def test_close_forum_topic(self, monkeypatch, message):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == message.chat_id
and kwargs["message_thread_id"] == message.message_thread_id
)
assert check_shortcut_signature(
Message.close_forum_topic, Bot.close_forum_topic, ["chat_id", "message_thread_id"], []
)
assert check_shortcut_call(
message.close_forum_topic,
message.bot,
"close_forum_topic",
shortcut_kwargs=["chat_id", "message_thread_id"],
)
assert check_defaults_handling(message.close_forum_topic, message.bot)
monkeypatch.setattr(message.bot, "close_forum_topic", make_assertion)
assert message.close_forum_topic()
def test_reopen_forum_topic(self, monkeypatch, message):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == message.chat_id
and kwargs["message_thread_id"] == message.message_thread_id
)
assert check_shortcut_signature(
Message.reopen_forum_topic,
Bot.reopen_forum_topic,
["chat_id", "message_thread_id"],
[],
)
assert check_shortcut_call(
message.reopen_forum_topic,
message.bot,
"reopen_forum_topic",
shortcut_kwargs=["chat_id", "message_thread_id"],
)
assert check_defaults_handling(message.reopen_forum_topic, message.bot)
monkeypatch.setattr(message.bot, "reopen_forum_topic", make_assertion)
assert message.reopen_forum_topic()
def test_delete_forum_topic(self, monkeypatch, message):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == message.chat_id
and kwargs["message_thread_id"] == message.message_thread_id
)
assert check_shortcut_signature(
Message.delete_forum_topic,
Bot.delete_forum_topic,
["chat_id", "message_thread_id"],
[],
)
assert check_shortcut_call(
message.delete_forum_topic,
message.bot,
"delete_forum_topic",
shortcut_kwargs=["chat_id", "message_thread_id"],
)
assert check_defaults_handling(message.delete_forum_topic, message.bot)
monkeypatch.setattr(message.bot, "delete_forum_topic", make_assertion)
assert message.delete_forum_topic()
def test_unpin_all_forum_topic_messages(self, monkeypatch, message):
def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == message.chat_id
and kwargs["message_thread_id"] == message.message_thread_id
)
assert check_shortcut_signature(
Message.unpin_all_forum_topic_messages,
Bot.unpin_all_forum_topic_messages,
["chat_id", "message_thread_id"],
[],
)
assert check_shortcut_call(
message.unpin_all_forum_topic_messages,
message.bot,
"unpin_all_forum_topic_messages",
shortcut_kwargs=["chat_id", "message_thread_id"],
)
assert check_defaults_handling(message.unpin_all_forum_topic_messages, message.bot)
monkeypatch.setattr(message.bot, "unpin_all_forum_topic_messages", make_assertion)
assert message.unpin_all_forum_topic_messages()
def test_equality(self):
id_ = 1
a = Message(

View file

@ -174,6 +174,7 @@ def check_object(h4):
'is_anonymous',
'is_member',
'until_date',
'can_manage_topics',
}
if name == 'BotCommandScope':
ignored |= {'type'} # attributes common to all subclasses