Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changes/unreleased/rich-messages.8QxQnWCw9fvLArqxvnwu2c.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
features = "Add support for sending rich messages (`Bot API 10.1 <https://core.telegram.org/bots/api#rich-message-formatting-options>`_) via the new :class:`telegram.InputRichMessage` class and the :meth:`telegram.Bot.send_rich_message` and :meth:`telegram.Bot.send_rich_message_draft` methods."

[[pull_requests]]
uid = "5263"
author_uids = ["Phil9l"]
closes_threads = []
2 changes: 2 additions & 0 deletions docs/source/telegram.at-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ Available Types
telegram.inputprofilephotostatic
telegram.inputpolloption
telegram.inputpolloptionmedia
telegram.inputrichmessage
telegram.inputrichmessagecontent
telegram.inputstorycontent
telegram.inputstorycontentphoto
telegram.inputstorycontentvideo
Expand Down
1 change: 1 addition & 0 deletions docs/source/telegram.inline-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ To enable this option, send the ``/setinline`` command to `@BotFather <https://t
telegram.inlinequeryresultvideo
telegram.inlinequeryresultvoice
telegram.inputmessagecontent
telegram.inputrichmessagecontent
telegram.inputtextmessagecontent
telegram.inputlocationmessagecontent
telegram.inputvenuemessagecontent
Expand Down
6 changes: 6 additions & 0 deletions docs/source/telegram.inputrichmessage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
InputRichMessage
================

.. autoclass:: telegram.InputRichMessage
:members:
:show-inheritance:
5 changes: 5 additions & 0 deletions docs/source/telegram.inputrichmessagecontent.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
InputRichMessageContent
=======================

.. autoclass:: telegram.InputRichMessageContent
:members:
3 changes: 3 additions & 0 deletions src/telegram/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
"InputProfilePhoto",
"InputProfilePhotoAnimated",
"InputProfilePhotoStatic",
"InputRichMessage",
"InputRichMessageContent",
"InputSticker",
"InputStoryContent",
"InputStoryContentPhoto",
Expand Down Expand Up @@ -512,6 +514,7 @@
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
from ._inline.preparedinlinemessage import PreparedInlineMessage
from ._inputchecklist import InputChecklist, InputChecklistTask
from ._inputrichmessage import InputRichMessage, InputRichMessageContent
from ._keyboardbutton import KeyboardButton
from ._keyboardbuttonpolltype import KeyboardButtonPollType
from ._keyboardbuttonrequest import (
Expand Down
137 changes: 137 additions & 0 deletions src/telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
InputMediaVideo,
InputPollMedia,
InputProfilePhoto,
InputRichMessage,
InputSticker,
InputStoryContent,
LabeledPrice,
Expand Down Expand Up @@ -1280,6 +1281,138 @@ async def send_message_draft(
api_kwargs=api_kwargs,
)

async def send_rich_message(
self,
chat_id: int | str,
rich_message: "InputRichMessage",
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
message_thread_id: int | None = None,
reply_parameters: "ReplyParameters | None" = None,
business_connection_id: str | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
direct_messages_topic_id: int | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
*,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int | None = None,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> Message:
"""Use this method to send rich messages. If the message contains a block with a media
element, then the bot must have the right to send the media to the chat.

.. versionadded:: NEXT.VERSION

Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
rich_message (:class:`telegram.InputRichMessage`): The message to be sent.
disable_notification (:obj:`bool`, optional): |disable_notification|
protect_content (:obj:`bool`, optional): |protect_content|
reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
:class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
Additional interface options. An object for an inline keyboard, custom reply
keyboard, instructions to remove reply keyboard or to force a reply from the user.
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
business_connection_id (:obj:`str`, optional): |business_id_str|
message_effect_id (:obj:`str`, optional): |message_effect_id|
allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
direct_messages_topic_id (:obj:`int`, optional): |direct_messages_topic_id|
suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional):
|suggested_post_parameters|

Keyword Args:
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
parameter for.
reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
parameter for.

Returns:
:class:`telegram.Message`: On success, the sent message is returned.

Raises:
:class:`telegram.error.TelegramError`

"""
data: JSONDict = {"chat_id": chat_id, "rich_message": rich_message}

return await self._send_message(
"sendRichMessage",
data,
disable_notification=disable_notification,
protect_content=protect_content,
reply_markup=reply_markup,
message_thread_id=message_thread_id,
reply_parameters=reply_parameters,
business_connection_id=business_connection_id,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
direct_messages_topic_id=direct_messages_topic_id,
suggested_post_parameters=suggested_post_parameters,
allow_sending_without_reply=allow_sending_without_reply,
reply_to_message_id=reply_to_message_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

async def send_rich_message_draft(
self,
chat_id: int,
draft_id: int,
rich_message: "InputRichMessage",
message_thread_id: int | None = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> bool:
"""Use this method to stream a partial rich message to a user while the message is being
generated. Note that the streamed draft is ephemeral and acts as a temporary preview -
once the output is finalized, you must call :meth:`~Bot.send_rich_message` with the
complete message to persist it in the user's chat.

.. versionadded:: NEXT.VERSION

Args:
chat_id (:obj:`int`): Unique identifier for the target private chat.
draft_id (:obj:`int`): Unique identifier of the message draft; must be non-zero.
Changes of drafts with the same identifier are animated.
rich_message (:class:`telegram.InputRichMessage`): The partial message to be streamed.
message_thread_id (:obj:`int`, optional): Unique identifier for the target
message thread.

Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
data: JSONDict = {
"chat_id": chat_id,
"draft_id": draft_id,
"rich_message": rich_message,
}
return await self._send_message(
"sendRichMessageDraft",
data,
message_thread_id=message_thread_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

async def delete_messages(
self,
chat_id: int | str,
Expand Down Expand Up @@ -12176,6 +12309,10 @@ def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
"""Alias for :meth:`send_message`"""
sendMessageDraft = send_message_draft
"""Alias for :meth:`send_message_draft`"""
sendRichMessage = send_rich_message
"""Alias for :meth:`send_rich_message`"""
sendRichMessageDraft = send_rich_message_draft
"""Alias for :meth:`send_rich_message_draft`"""
deleteMessage = delete_message
"""Alias for :meth:`delete_message`"""
deleteMessages = delete_messages
Expand Down
94 changes: 94 additions & 0 deletions src/telegram/_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
InputPaidMedia,
InputPollMedia,
InputPollOption,
InputRichMessage,
LabeledPrice,
LinkPreviewOptions,
LivePhoto,
Expand Down Expand Up @@ -1131,6 +1132,99 @@ async def send_message_draft(
api_kwargs=api_kwargs,
)

async def send_rich_message(
self,
rich_message: "InputRichMessage",
disable_notification: ODVInput[bool] = DEFAULT_NONE,
protect_content: ODVInput[bool] = DEFAULT_NONE,
reply_markup: "ReplyMarkup | None" = None,
message_thread_id: int | None = None,
reply_parameters: "ReplyParameters | None" = None,
business_connection_id: str | None = None,
message_effect_id: str | None = None,
allow_paid_broadcast: bool | None = None,
direct_messages_topic_id: int | None = None,
suggested_post_parameters: "SuggestedPostParameters | None" = None,
*,
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
reply_to_message_id: int | None = None,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> "Message":
"""Shortcut for::

await bot.send_rich_message(update.effective_chat.id, *args, **kwargs)

For the documentation of the arguments, please see :meth:`telegram.Bot.send_rich_message`.

.. versionadded:: NEXT.VERSION

Returns:
:class:`telegram.Message`: On success, instance representing the message posted.

"""
return await self.get_bot().send_rich_message(
chat_id=self.id,
rich_message=rich_message,
disable_notification=disable_notification,
protect_content=protect_content,
reply_markup=reply_markup,
message_thread_id=message_thread_id,
reply_parameters=reply_parameters,
business_connection_id=business_connection_id,
message_effect_id=message_effect_id,
allow_paid_broadcast=allow_paid_broadcast,
direct_messages_topic_id=direct_messages_topic_id,
suggested_post_parameters=suggested_post_parameters,
allow_sending_without_reply=allow_sending_without_reply,
reply_to_message_id=reply_to_message_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

async def send_rich_message_draft(
self,
draft_id: int,
rich_message: "InputRichMessage",
message_thread_id: int | None = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict | None = None,
) -> bool:
"""Shortcut for::

await bot.send_rich_message_draft(update.effective_chat.id, *args, **kwargs)

For the documentation of the arguments, please see
:meth:`telegram.Bot.send_rich_message_draft`.

.. versionadded:: NEXT.VERSION

Returns:
:obj:`bool`: On success, :obj:`True` is returned.

"""
return await self.get_bot().send_rich_message_draft(
chat_id=self.id,
draft_id=draft_id,
rich_message=rich_message,
message_thread_id=message_thread_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

async def delete_message(
self,
message_id: int,
Expand Down
2 changes: 1 addition & 1 deletion src/telegram/_inline/inputmessagecontent.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class InputMessageContent(TelegramObject):
"""Base class for Telegram InputMessageContent Objects.
See: :class:`telegram.InputContactMessageContent`,
:class:`telegram.InputInvoiceMessageContent`,
:class:`telegram.InputInvoiceMessageContent`, :class:`telegram.InputRichMessageContent`,
:class:`telegram.InputLocationMessageContent`, :class:`telegram.InputTextMessageContent` and
:class:`telegram.InputVenueMessageContent` for more details.
Expand Down
Loading
Loading