mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-10-23 17:36:26 +02:00
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
This commit is contained in:
parent
98bed6f01a
commit
dba7866aab
47 changed files with 1470 additions and 120 deletions
|
@ -11,7 +11,7 @@
|
||||||
:target: https://pypi.org/project/python-telegram-bot/
|
:target: https://pypi.org/project/python-telegram-bot/
|
||||||
:alt: Supported Python versions
|
:alt: Supported Python versions
|
||||||
|
|
||||||
.. image:: https://img.shields.io/badge/Bot%20API-7.5-blue?logo=telegram
|
.. image:: https://img.shields.io/badge/Bot%20API-7.6-blue?logo=telegram
|
||||||
:target: https://core.telegram.org/bots/api-changelog
|
:target: https://core.telegram.org/bots/api-changelog
|
||||||
:alt: Supported Bot API version
|
:alt: Supported Bot API version
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ make the development of bots easy and straightforward. These classes are contain
|
||||||
Telegram API support
|
Telegram API support
|
||||||
====================
|
====================
|
||||||
|
|
||||||
All types and methods of the Telegram Bot API **7.5** are supported.
|
All types and methods of the Telegram Bot API **7.6** are supported.
|
||||||
|
|
||||||
Installing
|
Installing
|
||||||
==========
|
==========
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
- Used for sending media grouped together
|
- Used for sending media grouped together
|
||||||
* - :meth:`~telegram.Bot.send_message`
|
* - :meth:`~telegram.Bot.send_message`
|
||||||
- Used for sending text messages
|
- Used for sending text messages
|
||||||
|
* - :meth:`~telegram.Bot.send_paid_media`
|
||||||
|
- Used for sending paid media to channels
|
||||||
* - :meth:`~telegram.Bot.send_photo`
|
* - :meth:`~telegram.Bot.send_photo`
|
||||||
- Used for sending photos
|
- Used for sending photos
|
||||||
* - :meth:`~telegram.Bot.send_poll`
|
* - :meth:`~telegram.Bot.send_poll`
|
||||||
|
|
|
@ -88,6 +88,9 @@ Available Types
|
||||||
telegram.inputmediadocument
|
telegram.inputmediadocument
|
||||||
telegram.inputmediaphoto
|
telegram.inputmediaphoto
|
||||||
telegram.inputmediavideo
|
telegram.inputmediavideo
|
||||||
|
telegram.inputpaidmedia
|
||||||
|
telegram.inputpaidmediaphoto
|
||||||
|
telegram.inputpaidmediavideo
|
||||||
telegram.inputpolloption
|
telegram.inputpolloption
|
||||||
telegram.inputsticker
|
telegram.inputsticker
|
||||||
telegram.keyboardbutton
|
telegram.keyboardbutton
|
||||||
|
@ -113,6 +116,11 @@ Available Types
|
||||||
telegram.messageoriginuser
|
telegram.messageoriginuser
|
||||||
telegram.messagereactioncountupdated
|
telegram.messagereactioncountupdated
|
||||||
telegram.messagereactionupdated
|
telegram.messagereactionupdated
|
||||||
|
telegram.paidmedia
|
||||||
|
telegram.paidmediainfo
|
||||||
|
telegram.paidmediaphoto
|
||||||
|
telegram.paidmediapreview
|
||||||
|
telegram.paidmediavideo
|
||||||
telegram.photosize
|
telegram.photosize
|
||||||
telegram.poll
|
telegram.poll
|
||||||
telegram.pollanswer
|
telegram.pollanswer
|
||||||
|
@ -125,22 +133,12 @@ Available Types
|
||||||
telegram.replykeyboardmarkup
|
telegram.replykeyboardmarkup
|
||||||
telegram.replykeyboardremove
|
telegram.replykeyboardremove
|
||||||
telegram.replyparameters
|
telegram.replyparameters
|
||||||
telegram.revenuewithdrawalstate
|
|
||||||
telegram.revenuewithdrawalstatefailed
|
|
||||||
telegram.revenuewithdrawalstatepending
|
|
||||||
telegram.revenuewithdrawalstatesucceeded
|
|
||||||
telegram.sentwebappmessage
|
telegram.sentwebappmessage
|
||||||
telegram.shareduser
|
telegram.shareduser
|
||||||
telegram.startransaction
|
|
||||||
telegram.startransactions
|
|
||||||
telegram.story
|
telegram.story
|
||||||
telegram.switchinlinequerychosenchat
|
telegram.switchinlinequerychosenchat
|
||||||
telegram.telegramobject
|
telegram.telegramobject
|
||||||
telegram.textquote
|
telegram.textquote
|
||||||
telegram.transactionpartner
|
|
||||||
telegram.transactionpartnerfragment
|
|
||||||
telegram.transactionpartnerother
|
|
||||||
telegram.transactionpartneruser
|
|
||||||
telegram.update
|
telegram.update
|
||||||
telegram.user
|
telegram.user
|
||||||
telegram.userchatboosts
|
telegram.userchatboosts
|
||||||
|
|
6
docs/source/telegram.inputpaidmedia.rst
Normal file
6
docs/source/telegram.inputpaidmedia.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
InputPaidMedia
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputPaidMedia
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.inputpaidmediaphoto.rst
Normal file
6
docs/source/telegram.inputpaidmediaphoto.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
InputPaidMediaPhoto
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputPaidMediaPhoto
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.inputpaidmediavideo.rst
Normal file
6
docs/source/telegram.inputpaidmediavideo.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
InputPaidMediaVideo
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputPaidMediaVideo
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.paidmedia.rst
Normal file
6
docs/source/telegram.paidmedia.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PaidMedia
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PaidMedia
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.paidmediainfo.rst
Normal file
6
docs/source/telegram.paidmediainfo.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PaidMediaInfo
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PaidMediaInfo
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.paidmediaphoto.rst
Normal file
6
docs/source/telegram.paidmediaphoto.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PaidMediaPhoto
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PaidMediaPhoto
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.paidmediapreview.rst
Normal file
6
docs/source/telegram.paidmediapreview.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PaidMediaPreview
|
||||||
|
================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PaidMediaPreview
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.paidmediavideo.rst
Normal file
6
docs/source/telegram.paidmediavideo.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PaidMediaVideo
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PaidMediaVideo
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
|
@ -8,7 +8,18 @@ Payments
|
||||||
telegram.labeledprice
|
telegram.labeledprice
|
||||||
telegram.orderinfo
|
telegram.orderinfo
|
||||||
telegram.precheckoutquery
|
telegram.precheckoutquery
|
||||||
|
telegram.revenuewithdrawalstate
|
||||||
|
telegram.revenuewithdrawalstatefailed
|
||||||
|
telegram.revenuewithdrawalstatepending
|
||||||
|
telegram.revenuewithdrawalstatesucceeded
|
||||||
telegram.shippingaddress
|
telegram.shippingaddress
|
||||||
telegram.shippingoption
|
telegram.shippingoption
|
||||||
telegram.shippingquery
|
telegram.shippingquery
|
||||||
|
telegram.startransaction
|
||||||
|
telegram.startransactions
|
||||||
telegram.successfulpayment
|
telegram.successfulpayment
|
||||||
|
telegram.transactionpartner
|
||||||
|
telegram.transactionpartnerfragment
|
||||||
|
telegram.transactionpartnerother
|
||||||
|
telegram.transactionpartnertelegramads
|
||||||
|
telegram.transactionpartneruser
|
||||||
|
|
7
docs/source/telegram.transactionpartnertelegramads.rst
Normal file
7
docs/source/telegram.transactionpartnertelegramads.rst
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
TransactionPartnerTelegramAds
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.TransactionPartnerTelegramAds
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
:inherited-members: TelegramObject
|
|
@ -142,6 +142,9 @@ __all__ = (
|
||||||
"InputMediaPhoto",
|
"InputMediaPhoto",
|
||||||
"InputMediaVideo",
|
"InputMediaVideo",
|
||||||
"InputMessageContent",
|
"InputMessageContent",
|
||||||
|
"InputPaidMedia",
|
||||||
|
"InputPaidMediaPhoto",
|
||||||
|
"InputPaidMediaVideo",
|
||||||
"InputPollOption",
|
"InputPollOption",
|
||||||
"InputSticker",
|
"InputSticker",
|
||||||
"InputTextMessageContent",
|
"InputTextMessageContent",
|
||||||
|
@ -173,6 +176,11 @@ __all__ = (
|
||||||
"MessageReactionCountUpdated",
|
"MessageReactionCountUpdated",
|
||||||
"MessageReactionUpdated",
|
"MessageReactionUpdated",
|
||||||
"OrderInfo",
|
"OrderInfo",
|
||||||
|
"PaidMedia",
|
||||||
|
"PaidMediaInfo",
|
||||||
|
"PaidMediaPhoto",
|
||||||
|
"PaidMediaPreview",
|
||||||
|
"PaidMediaVideo",
|
||||||
"PassportData",
|
"PassportData",
|
||||||
"PassportElementError",
|
"PassportElementError",
|
||||||
"PassportElementErrorDataField",
|
"PassportElementErrorDataField",
|
||||||
|
@ -223,6 +231,7 @@ __all__ = (
|
||||||
"TransactionPartner",
|
"TransactionPartner",
|
||||||
"TransactionPartnerFragment",
|
"TransactionPartnerFragment",
|
||||||
"TransactionPartnerOther",
|
"TransactionPartnerOther",
|
||||||
|
"TransactionPartnerTelegramAds",
|
||||||
"TransactionPartnerUser",
|
"TransactionPartnerUser",
|
||||||
"Update",
|
"Update",
|
||||||
"User",
|
"User",
|
||||||
|
@ -333,6 +342,9 @@ from ._files.inputmedia import (
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
InputMediaPhoto,
|
InputMediaPhoto,
|
||||||
InputMediaVideo,
|
InputMediaVideo,
|
||||||
|
InputPaidMedia,
|
||||||
|
InputPaidMediaPhoto,
|
||||||
|
InputPaidMediaVideo,
|
||||||
)
|
)
|
||||||
from ._files.inputsticker import InputSticker
|
from ._files.inputsticker import InputSticker
|
||||||
from ._files.location import Location
|
from ._files.location import Location
|
||||||
|
@ -405,6 +417,7 @@ from ._messageorigin import (
|
||||||
MessageOriginUser,
|
MessageOriginUser,
|
||||||
)
|
)
|
||||||
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
|
||||||
|
from ._paidmedia import PaidMedia, PaidMediaInfo, PaidMediaPhoto, PaidMediaPreview, PaidMediaVideo
|
||||||
from ._passport.credentials import (
|
from ._passport.credentials import (
|
||||||
Credentials,
|
Credentials,
|
||||||
DataCredentials,
|
DataCredentials,
|
||||||
|
@ -436,16 +449,7 @@ from ._payment.precheckoutquery import PreCheckoutQuery
|
||||||
from ._payment.shippingaddress import ShippingAddress
|
from ._payment.shippingaddress import ShippingAddress
|
||||||
from ._payment.shippingoption import ShippingOption
|
from ._payment.shippingoption import ShippingOption
|
||||||
from ._payment.shippingquery import ShippingQuery
|
from ._payment.shippingquery import ShippingQuery
|
||||||
from ._payment.successfulpayment import SuccessfulPayment
|
from ._payment.stars import (
|
||||||
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
|
|
||||||
from ._proximityalerttriggered import ProximityAlertTriggered
|
|
||||||
from ._reaction import ReactionCount, ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
|
||||||
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
|
|
||||||
from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
|
||||||
from ._replykeyboardremove import ReplyKeyboardRemove
|
|
||||||
from ._sentwebappmessage import SentWebAppMessage
|
|
||||||
from ._shared import ChatShared, SharedUser, UsersShared
|
|
||||||
from ._stars import (
|
|
||||||
RevenueWithdrawalState,
|
RevenueWithdrawalState,
|
||||||
RevenueWithdrawalStateFailed,
|
RevenueWithdrawalStateFailed,
|
||||||
RevenueWithdrawalStatePending,
|
RevenueWithdrawalStatePending,
|
||||||
|
@ -455,8 +459,18 @@ from ._stars import (
|
||||||
TransactionPartner,
|
TransactionPartner,
|
||||||
TransactionPartnerFragment,
|
TransactionPartnerFragment,
|
||||||
TransactionPartnerOther,
|
TransactionPartnerOther,
|
||||||
|
TransactionPartnerTelegramAds,
|
||||||
TransactionPartnerUser,
|
TransactionPartnerUser,
|
||||||
)
|
)
|
||||||
|
from ._payment.successfulpayment import SuccessfulPayment
|
||||||
|
from ._poll import InputPollOption, Poll, PollAnswer, PollOption
|
||||||
|
from ._proximityalerttriggered import ProximityAlertTriggered
|
||||||
|
from ._reaction import ReactionCount, ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
||||||
|
from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
|
||||||
|
from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
||||||
|
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||||
|
from ._sentwebappmessage import SentWebAppMessage
|
||||||
|
from ._shared import ChatShared, SharedUser, UsersShared
|
||||||
from ._story import Story
|
from ._story import Story
|
||||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||||
from ._telegramobject import TelegramObject
|
from ._telegramobject import TelegramObject
|
||||||
|
|
115
telegram/_bot.py
115
telegram/_bot.py
|
@ -70,7 +70,7 @@ from telegram._files.chatphoto import ChatPhoto
|
||||||
from telegram._files.contact import Contact
|
from telegram._files.contact import Contact
|
||||||
from telegram._files.document import Document
|
from telegram._files.document import Document
|
||||||
from telegram._files.file import File
|
from telegram._files.file import File
|
||||||
from telegram._files.inputmedia import InputMedia
|
from telegram._files.inputmedia import InputMedia, InputPaidMedia
|
||||||
from telegram._files.location import Location
|
from telegram._files.location import Location
|
||||||
from telegram._files.photosize import PhotoSize
|
from telegram._files.photosize import PhotoSize
|
||||||
from telegram._files.sticker import MaskPosition, Sticker, StickerSet
|
from telegram._files.sticker import MaskPosition, Sticker, StickerSet
|
||||||
|
@ -84,11 +84,11 @@ from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||||
from telegram._menubutton import MenuButton
|
from telegram._menubutton import MenuButton
|
||||||
from telegram._message import Message
|
from telegram._message import Message
|
||||||
from telegram._messageid import MessageId
|
from telegram._messageid import MessageId
|
||||||
|
from telegram._payment.stars import StarTransactions
|
||||||
from telegram._poll import InputPollOption, Poll
|
from telegram._poll import InputPollOption, Poll
|
||||||
from telegram._reaction import ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
from telegram._reaction import ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
|
||||||
from telegram._reply import ReplyParameters
|
from telegram._reply import ReplyParameters
|
||||||
from telegram._sentwebappmessage import SentWebAppMessage
|
from telegram._sentwebappmessage import SentWebAppMessage
|
||||||
from telegram._stars import StarTransactions
|
|
||||||
from telegram._telegramobject import TelegramObject
|
from telegram._telegramobject import TelegramObject
|
||||||
from telegram._update import Update
|
from telegram._update import Update
|
||||||
from telegram._user import User
|
from telegram._user import User
|
||||||
|
@ -578,13 +578,16 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||||
with new._unfrozen():
|
with new._unfrozen():
|
||||||
new.parse_mode = DefaultValue.get_value(new.parse_mode)
|
new.parse_mode = DefaultValue.get_value(new.parse_mode)
|
||||||
data[key] = new
|
data[key] = new
|
||||||
elif key == "media" and isinstance(val, Sequence):
|
elif (
|
||||||
|
key == "media"
|
||||||
|
and isinstance(val, Sequence)
|
||||||
|
and not isinstance(val[0], InputPaidMedia)
|
||||||
|
):
|
||||||
# Copy objects as not to edit them in-place
|
# Copy objects as not to edit them in-place
|
||||||
copy_list = [copy.copy(media) for media in val]
|
copy_list = [copy.copy(media) for media in val]
|
||||||
for media in copy_list:
|
for media in copy_list:
|
||||||
with media._unfrozen():
|
with media._unfrozen():
|
||||||
media.parse_mode = DefaultValue.get_value(media.parse_mode)
|
media.parse_mode = DefaultValue.get_value(media.parse_mode)
|
||||||
|
|
||||||
data[key] = copy_list
|
data[key] = copy_list
|
||||||
# 2)
|
# 2)
|
||||||
else:
|
else:
|
||||||
|
@ -7654,7 +7657,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
) -> MessageId:
|
) -> MessageId:
|
||||||
"""Use this method to copy messages of any kind. Service messages and invoice messages
|
"""Use this method to copy messages of any kind. Service messages, paid media messages,
|
||||||
|
giveaway messages, giveaway winners messages, and invoice messages
|
||||||
can't be copied. The method is analogous to the method :meth:`forward_message`, but the
|
can't be copied. The method is analogous to the method :meth:`forward_message`, but the
|
||||||
copied message doesn't have a link to the original message.
|
copied message doesn't have a link to the original message.
|
||||||
|
|
||||||
|
@ -7780,11 +7784,12 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
) -> Tuple["MessageId", ...]:
|
) -> Tuple["MessageId", ...]:
|
||||||
"""
|
"""
|
||||||
Use this method to copy messages of any kind. If some of the specified messages can't be
|
Use this method to copy messages of any kind. If some of the specified messages can't be
|
||||||
found or copied, they are skipped. Service messages, giveaway messages, giveaway winners
|
found or copied, they are skipped. Service messages, paid media messages, giveaway
|
||||||
messages, and invoice messages can't be copied. A quiz poll can be copied only if the value
|
messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can
|
||||||
of the field correct_option_id is known to the bot. The method is analogous to the method
|
be copied only if the value
|
||||||
:meth:`forward_messages`, but the copied messages don't have a link to the original
|
of the field :attr:`telegram.Poll.correct_option_id` is known to the bot. The method is
|
||||||
message. Album grouping is kept for copied messages.
|
analogous to the method :meth:`forward_messages`, but the copied messages don't have a
|
||||||
|
link to the original message. Album grouping is kept for copied messages.
|
||||||
|
|
||||||
.. versionadded:: 20.8
|
.. versionadded:: 20.8
|
||||||
|
|
||||||
|
@ -9163,6 +9168,94 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
bot=self,
|
bot=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def send_paid_media(
|
||||||
|
self,
|
||||||
|
chat_id: Union[str, int],
|
||||||
|
star_count: int,
|
||||||
|
media: Sequence["InputPaidMedia"],
|
||||||
|
caption: Optional[str] = None,
|
||||||
|
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||||
|
show_caption_above_media: Optional[bool] = None,
|
||||||
|
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_parameters: Optional["ReplyParameters"] = None,
|
||||||
|
reply_markup: Optional[ReplyMarkup] = None,
|
||||||
|
*,
|
||||||
|
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_to_message_id: Optional[int] = 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: Optional[JSONDict] = None,
|
||||||
|
) -> Message:
|
||||||
|
"""Use this method to send paid media to channel chats.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
|
||||||
|
star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access
|
||||||
|
to the media.
|
||||||
|
media (Sequence[:class:`telegram.InputPaidMedia`]): A list describing the media to be
|
||||||
|
sent; up to :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items.
|
||||||
|
caption (:obj:`str`, optional): Caption of the media to be sent,
|
||||||
|
0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
||||||
|
parse_mode (:obj:`str`, optional): |parse_mode|
|
||||||
|
caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
|
||||||
|
|caption_entities|
|
||||||
|
show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
|
||||||
|
disable_notification (:obj:`bool`, optional): |disable_notification|
|
||||||
|
protect_content (:obj:`bool`, optional): |protect_content|
|
||||||
|
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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,
|
||||||
|
"star_count": star_count,
|
||||||
|
"media": media,
|
||||||
|
"show_caption_above_media": show_caption_above_media,
|
||||||
|
}
|
||||||
|
|
||||||
|
return await self._send_message(
|
||||||
|
"sendPaidMedia",
|
||||||
|
data,
|
||||||
|
caption=caption,
|
||||||
|
parse_mode=parse_mode,
|
||||||
|
caption_entities=caption_entities,
|
||||||
|
disable_notification=disable_notification,
|
||||||
|
protect_content=protect_content,
|
||||||
|
reply_parameters=reply_parameters,
|
||||||
|
reply_markup=reply_markup,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
|
def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
|
||||||
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
||||||
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
||||||
|
@ -9417,3 +9510,5 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
"""Alias for :meth:`refund_star_payment`"""
|
"""Alias for :meth:`refund_star_payment`"""
|
||||||
getStarTransactions = get_star_transactions
|
getStarTransactions = get_star_transactions
|
||||||
"""Alias for :meth:`get_star_transactions`"""
|
"""Alias for :meth:`get_star_transactions`"""
|
||||||
|
sendPaidMedia = send_paid_media
|
||||||
|
"""Alias for :meth:`send_paid_media`"""
|
||||||
|
|
|
@ -48,6 +48,7 @@ if TYPE_CHECKING:
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
InputMediaPhoto,
|
InputMediaPhoto,
|
||||||
InputMediaVideo,
|
InputMediaVideo,
|
||||||
|
InputPaidMedia,
|
||||||
InputPollOption,
|
InputPollOption,
|
||||||
LabeledPrice,
|
LabeledPrice,
|
||||||
LinkPreviewOptions,
|
LinkPreviewOptions,
|
||||||
|
@ -3257,6 +3258,60 @@ class _ChatBase(TelegramObject):
|
||||||
api_kwargs=api_kwargs,
|
api_kwargs=api_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def send_paid_media(
|
||||||
|
self,
|
||||||
|
star_count: int,
|
||||||
|
media: Sequence["InputPaidMedia"],
|
||||||
|
caption: Optional[str] = None,
|
||||||
|
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||||
|
show_caption_above_media: Optional[bool] = None,
|
||||||
|
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_parameters: Optional["ReplyParameters"] = None,
|
||||||
|
reply_markup: Optional[ReplyMarkup] = None,
|
||||||
|
*,
|
||||||
|
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_to_message_id: Optional[int] = 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: Optional[JSONDict] = None,
|
||||||
|
) -> "Message":
|
||||||
|
"""Shortcut for::
|
||||||
|
|
||||||
|
await bot.send_paid_media(chat_id=update.effective_chat.id, *args, **kwargs)
|
||||||
|
|
||||||
|
For the documentation of the arguments, please see
|
||||||
|
:meth:`telegram.Bot.send_paid_media`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`telegram.Message`: On success, instance representing the message posted.
|
||||||
|
"""
|
||||||
|
return await self.get_bot().send_paid_media(
|
||||||
|
chat_id=self.id,
|
||||||
|
star_count=star_count,
|
||||||
|
media=media,
|
||||||
|
caption=caption,
|
||||||
|
parse_mode=parse_mode,
|
||||||
|
caption_entities=caption_entities,
|
||||||
|
show_caption_above_media=show_caption_above_media,
|
||||||
|
disable_notification=disable_notification,
|
||||||
|
protect_content=protect_content,
|
||||||
|
reply_parameters=reply_parameters,
|
||||||
|
reply_markup=reply_markup,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Chat(_ChatBase):
|
class Chat(_ChatBase):
|
||||||
"""This object represents a chat.
|
"""This object represents a chat.
|
||||||
|
|
|
@ -195,6 +195,10 @@ class ChatFullInfo(_ChatBase):
|
||||||
chats.
|
chats.
|
||||||
location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which
|
location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which
|
||||||
the supergroup is connected.
|
the supergroup is connected.
|
||||||
|
can_send_paid_media (:obj:`bool`, optional): :obj:`True`, if paid media messages can be
|
||||||
|
sent or forwarded to the channel chat. The field is available only for channel chats.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
id (:obj:`int`): Unique identifier for this chat.
|
id (:obj:`int`): Unique identifier for this chat.
|
||||||
|
@ -345,6 +349,10 @@ class ChatFullInfo(_ChatBase):
|
||||||
chats.
|
chats.
|
||||||
location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which
|
location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which
|
||||||
the supergroup is connected.
|
the supergroup is connected.
|
||||||
|
can_send_paid_media (:obj:`bool`): Optional. :obj:`True`, if paid media messages can be
|
||||||
|
sent or forwarded to the channel chat. The field is available only for channel chats.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
.. _accent colors: https://core.telegram.org/bots/api#accent-colors
|
.. _accent colors: https://core.telegram.org/bots/api#accent-colors
|
||||||
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
|
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
|
||||||
|
@ -360,6 +368,7 @@ class ChatFullInfo(_ChatBase):
|
||||||
"business_intro",
|
"business_intro",
|
||||||
"business_location",
|
"business_location",
|
||||||
"business_opening_hours",
|
"business_opening_hours",
|
||||||
|
"can_send_paid_media",
|
||||||
"can_set_sticker_set",
|
"can_set_sticker_set",
|
||||||
"custom_emoji_sticker_set_name",
|
"custom_emoji_sticker_set_name",
|
||||||
"description",
|
"description",
|
||||||
|
@ -434,6 +443,7 @@ class ChatFullInfo(_ChatBase):
|
||||||
custom_emoji_sticker_set_name: Optional[str] = None,
|
custom_emoji_sticker_set_name: Optional[str] = None,
|
||||||
linked_chat_id: Optional[int] = None,
|
linked_chat_id: Optional[int] = None,
|
||||||
location: Optional[ChatLocation] = None,
|
location: Optional[ChatLocation] = None,
|
||||||
|
can_send_paid_media: Optional[bool] = None,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
):
|
):
|
||||||
|
@ -496,6 +506,7 @@ class ChatFullInfo(_ChatBase):
|
||||||
self.business_intro: Optional[BusinessIntro] = business_intro
|
self.business_intro: Optional[BusinessIntro] = business_intro
|
||||||
self.business_location: Optional[BusinessLocation] = business_location
|
self.business_location: Optional[BusinessLocation] = business_location
|
||||||
self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
|
self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
|
||||||
|
self.can_send_paid_media: Optional[bool] = can_send_paid_media
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(
|
def de_json(
|
||||||
|
|
|
@ -44,7 +44,7 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
file_size (:obj:`int`, optional): File size.
|
file_size (:obj:`int`, optional): File size.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by sender.
|
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by the sender.
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
.. versionadded:: 20.2
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class _BaseThumbedMedium(_BaseMedium):
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
file_size (:obj:`int`): Optional. File size.
|
file_size (:obj:`int`): Optional. File size.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by sender.
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by the sender.
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
.. versionadded:: 20.2
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,11 @@ class Animation(_BaseThumbedMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
width (:obj:`int`): Video width as defined by sender.
|
width (:obj:`int`): Video width as defined by the sender.
|
||||||
height (:obj:`int`): Video height as defined by sender.
|
height (:obj:`int`): Video height as defined by the sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_name (:obj:`str`, optional): Original animation filename as defined by sender.
|
file_name (:obj:`str`, optional): Original animation filename as defined by the sender.
|
||||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by
|
thumbnail (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by
|
||||||
sender.
|
sender.
|
||||||
|
@ -56,11 +56,11 @@ class Animation(_BaseThumbedMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
width (:obj:`int`): Video width as defined by sender.
|
width (:obj:`int`): Video width as defined by the sender.
|
||||||
height (:obj:`int`): Video height as defined by sender.
|
height (:obj:`int`): Video height as defined by the sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_name (:obj:`str`): Optional. Original animation filename as defined by sender.
|
file_name (:obj:`str`): Optional. Original animation filename as defined by the sender.
|
||||||
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
|
mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by
|
||||||
sender.
|
sender.
|
||||||
|
|
|
@ -39,12 +39,12 @@ class Audio(_BaseThumbedMedium):
|
||||||
or reuse the file.
|
or reuse the file.
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
||||||
the same over time and for different bots. Can't be used to download or reuse the file.
|
the same over time and for different bots. Can't be used to download or reuse the file.
|
||||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
|
||||||
performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
|
performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by
|
||||||
tags.
|
audio tags.
|
||||||
title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags.
|
title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags.
|
||||||
file_name (:obj:`str`, optional): Original filename as defined by sender.
|
file_name (:obj:`str`, optional): Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
|
thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
|
||||||
which the music file belongs.
|
which the music file belongs.
|
||||||
|
@ -56,12 +56,12 @@ class Audio(_BaseThumbedMedium):
|
||||||
or reuse the file.
|
or reuse the file.
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
||||||
the same over time and for different bots. Can't be used to download or reuse the file.
|
the same over time and for different bots. Can't be used to download or reuse the file.
|
||||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
|
||||||
performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
|
performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by
|
||||||
tags.
|
audio tags.
|
||||||
title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags.
|
title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags.
|
||||||
file_name (:obj:`str`): Optional. Original filename as defined by sender.
|
file_name (:obj:`str`): Optional. Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
|
mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
|
||||||
which the music file belongs.
|
which the music file belongs.
|
||||||
|
|
|
@ -39,10 +39,11 @@ class Document(_BaseThumbedMedium):
|
||||||
or reuse the file.
|
or reuse the file.
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
||||||
the same over time and for different bots. Can't be used to download or reuse the file.
|
the same over time and for different bots. Can't be used to download or reuse the file.
|
||||||
file_name (:obj:`str`, optional): Original filename as defined by sender.
|
file_name (:obj:`str`, optional): Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by sender.
|
thumbnail (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by the
|
||||||
|
sender.
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
.. versionadded:: 20.2
|
||||||
|
|
||||||
|
@ -51,10 +52,11 @@ class Document(_BaseThumbedMedium):
|
||||||
or reuse the file.
|
or reuse the file.
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
|
||||||
the same over time and for different bots. Can't be used to download or reuse the file.
|
the same over time and for different bots. Can't be used to download or reuse the file.
|
||||||
file_name (:obj:`str`): Optional. Original filename as defined by sender.
|
file_name (:obj:`str`): Optional. Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
|
mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by sender.
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by the
|
||||||
|
sender.
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
.. versionadded:: 20.2
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
"""Base class for Telegram InputMedia Objects."""
|
"""Base class for Telegram InputMedia Objects."""
|
||||||
from typing import Optional, Sequence, Tuple, Union
|
from typing import Final, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
from telegram import constants
|
from telegram import constants
|
||||||
from telegram._files.animation import Animation
|
from telegram._files.animation import Animation
|
||||||
|
@ -115,13 +115,162 @@ class InputMedia(TelegramObject):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InputPaidMedia(TelegramObject):
|
||||||
|
"""
|
||||||
|
Base class for Telegram InputPaidMedia Objects. Currently, it can be one of:
|
||||||
|
|
||||||
|
* :class:`telegram.InputMediaPhoto`
|
||||||
|
* :class:`telegram.InputMediaVideo`
|
||||||
|
|
||||||
|
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (:obj:`str`): Type of media that the instance represents.
|
||||||
|
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
|
||||||
|
:class:`telegram.PhotoSize` | :class:`telegram.Video`): File to send. |fileinputnopath|
|
||||||
|
Lastly you can pass an existing telegram media object of the corresponding type
|
||||||
|
to send.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the input media.
|
||||||
|
media (:obj:`str` | :class:`telegram.InputFile`): Media to send.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PHOTO: Final[str] = constants.InputPaidMediaType.PHOTO
|
||||||
|
""":const:`telegram.constants.InputPaidMediaType.PHOTO`"""
|
||||||
|
VIDEO: Final[str] = constants.InputPaidMediaType.VIDEO
|
||||||
|
""":const:`telegram.constants.InputPaidMediaType.VIDEO`"""
|
||||||
|
|
||||||
|
__slots__ = ("media", "type")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
type: str, # pylint: disable=redefined-builtin
|
||||||
|
media: Union[str, InputFile, PhotoSize, Video],
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.type: str = enum.get_member(constants.InputPaidMediaType, type, type)
|
||||||
|
self.media: Union[str, InputFile, PhotoSize, Video] = media
|
||||||
|
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
|
||||||
|
class InputPaidMediaPhoto(InputPaidMedia):
|
||||||
|
"""The paid media to send is a photo.
|
||||||
|
|
||||||
|
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
|
||||||
|
:class:`telegram.PhotoSize`): File to send. |fileinputnopath|
|
||||||
|
Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the media, always
|
||||||
|
:tg-const:`telegram.constants.InputPaidMediaType.PHOTO`.
|
||||||
|
media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
media: Union[FileInput, PhotoSize],
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
media = parse_file_input(media, PhotoSize, attach=True, local_mode=True)
|
||||||
|
super().__init__(type=InputPaidMedia.PHOTO, media=media, api_kwargs=api_kwargs)
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
|
||||||
|
class InputPaidMediaVideo(InputPaidMedia):
|
||||||
|
"""
|
||||||
|
The paid media to send is a video.
|
||||||
|
|
||||||
|
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Note:
|
||||||
|
* When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the
|
||||||
|
width, height and duration from that video, unless otherwise specified with the optional
|
||||||
|
arguments.
|
||||||
|
* :paramref:`thumbnail` will be ignored for small video files, for which Telegram can
|
||||||
|
easily generate thumbnails. However, this behaviour is undocumented and might be
|
||||||
|
changed by Telegram.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
media (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
|
||||||
|
:class:`telegram.Video`): File to send. |fileinputnopath|
|
||||||
|
Lastly you can pass an existing :class:`telegram.Video` object to send.
|
||||||
|
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||||
|
optional): |thumbdocstringnopath|
|
||||||
|
width (:obj:`int`, optional): Video width.
|
||||||
|
height (:obj:`int`, optional): Video height.
|
||||||
|
duration (:obj:`int`, optional): Video duration in seconds.
|
||||||
|
supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
|
||||||
|
suitable for streaming.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the media, always
|
||||||
|
:tg-const:`telegram.constants.InputPaidMediaType.VIDEO`.
|
||||||
|
media (:obj:`str` | :class:`telegram.InputFile`): Video to send.
|
||||||
|
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||||
|
width (:obj:`int`): Optional. Video width.
|
||||||
|
height (:obj:`int`): Optional. Video height.
|
||||||
|
duration (:obj:`int`): Optional. Video duration in seconds.
|
||||||
|
supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is
|
||||||
|
suitable for streaming.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("duration", "height", "supports_streaming", "thumbnail", "width")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
media: Union[FileInput, Video],
|
||||||
|
thumbnail: Optional[FileInput] = None,
|
||||||
|
width: Optional[int] = None,
|
||||||
|
height: Optional[int] = None,
|
||||||
|
duration: Optional[int] = None,
|
||||||
|
supports_streaming: Optional[bool] = None,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
if isinstance(media, Video):
|
||||||
|
width = width if width is not None else media.width
|
||||||
|
height = height if height is not None else media.height
|
||||||
|
duration = duration if duration is not None else media.duration
|
||||||
|
media = media.file_id
|
||||||
|
else:
|
||||||
|
# We use local_mode=True because we don't have access to the actual setting and want
|
||||||
|
# things to work in local mode.
|
||||||
|
media = parse_file_input(media, attach=True, local_mode=True)
|
||||||
|
|
||||||
|
super().__init__(type=InputPaidMedia.VIDEO, media=media, api_kwargs=api_kwargs)
|
||||||
|
with self._unfrozen():
|
||||||
|
self.thumbnail: Optional[Union[str, InputFile]] = InputMedia._parse_thumbnail_input(
|
||||||
|
thumbnail
|
||||||
|
)
|
||||||
|
self.width: Optional[int] = width
|
||||||
|
self.height: Optional[int] = height
|
||||||
|
self.duration: Optional[int] = duration
|
||||||
|
self.supports_streaming: Optional[bool] = supports_streaming
|
||||||
|
|
||||||
|
|
||||||
class InputMediaAnimation(InputMedia):
|
class InputMediaAnimation(InputMedia):
|
||||||
"""Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
|
"""Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
When using a :class:`telegram.Animation` for the :attr:`media` attribute, it will take the
|
When using a :class:`telegram.Animation` for the :attr:`media` attribute, it will take the
|
||||||
width, height and duration from that video, unless otherwise specified with the optional
|
width, height and duration from that animation, unless otherwise specified with the
|
||||||
arguments.
|
optional arguments.
|
||||||
|
|
||||||
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||||
|
|
||||||
|
@ -510,10 +659,10 @@ class InputMediaAudio(InputMedia):
|
||||||
.. versionchanged:: 20.0
|
.. versionchanged:: 20.0
|
||||||
|sequenceclassargs|
|
|sequenceclassargs|
|
||||||
|
|
||||||
duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender.
|
duration (:obj:`int`, optional): Duration of the audio in seconds as defined by the sender.
|
||||||
performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio
|
performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by
|
||||||
tags.
|
audio tags.
|
||||||
title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags.
|
title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags.
|
||||||
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
|
||||||
optional): |thumbdocstringnopath|
|
optional): |thumbdocstringnopath|
|
||||||
|
|
||||||
|
@ -533,9 +682,9 @@ class InputMediaAudio(InputMedia):
|
||||||
* |tupleclassattrs|
|
* |tupleclassattrs|
|
||||||
* |alwaystuple|
|
* |alwaystuple|
|
||||||
duration (:obj:`int`): Optional. Duration of the audio in seconds.
|
duration (:obj:`int`): Optional. Duration of the audio in seconds.
|
||||||
performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio
|
performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by
|
||||||
tags.
|
audio tags.
|
||||||
title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags.
|
title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags.
|
||||||
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
|
||||||
|
|
||||||
.. versionadded:: 20.2
|
.. versionadded:: 20.2
|
||||||
|
|
|
@ -32,8 +32,8 @@ class Location(TelegramObject):
|
||||||
considered equal, if their :attr:`longitude` and :attr:`latitude` are equal.
|
considered equal, if their :attr:`longitude` and :attr:`latitude` are equal.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
longitude (:obj:`float`): Longitude as defined by sender.
|
longitude (:obj:`float`): Longitude as defined by the sender.
|
||||||
latitude (:obj:`float`): Latitude as defined by sender.
|
latitude (:obj:`float`): Latitude as defined by the sender.
|
||||||
horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
|
horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
|
||||||
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
|
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
|
||||||
live_period (:obj:`int`, optional): Time relative to the message sending date, during which
|
live_period (:obj:`int`, optional): Time relative to the message sending date, during which
|
||||||
|
@ -45,8 +45,8 @@ class Location(TelegramObject):
|
||||||
approaching another chat member, in meters. For sent live locations only.
|
approaching another chat member, in meters. For sent live locations only.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
longitude (:obj:`float`): Longitude as defined by sender.
|
longitude (:obj:`float`): Longitude as defined by the sender.
|
||||||
latitude (:obj:`float`): Latitude as defined by sender.
|
latitude (:obj:`float`): Latitude as defined by the sender.
|
||||||
horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
|
horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
|
||||||
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
|
measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
|
||||||
live_period (:obj:`int`): Optional. Time relative to the message sending date, during which
|
live_period (:obj:`int`): Optional. Time relative to the message sending date, during which
|
||||||
|
|
|
@ -39,11 +39,11 @@ class Video(_BaseThumbedMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
width (:obj:`int`): Video width as defined by sender.
|
width (:obj:`int`): Video width as defined by the sender.
|
||||||
height (:obj:`int`): Video height as defined by sender.
|
height (:obj:`int`): Video height as defined by the sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_name (:obj:`str`, optional): Original filename as defined by sender.
|
file_name (:obj:`str`, optional): Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`, optional): MIME type of a file as defined by sender.
|
mime_type (:obj:`str`, optional): MIME type of a file as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ class Video(_BaseThumbedMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
width (:obj:`int`): Video width as defined by sender.
|
width (:obj:`int`): Video width as defined by the sender.
|
||||||
height (:obj:`int`): Video height as defined by sender.
|
height (:obj:`int`): Video height as defined by the sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_name (:obj:`str`): Optional. Original filename as defined by sender.
|
file_name (:obj:`str`): Optional. Original filename as defined by the sender.
|
||||||
mime_type (:obj:`str`): Optional. MIME type of a file as defined by sender.
|
mime_type (:obj:`str`): Optional. MIME type of a file as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class VideoNote(_BaseThumbedMedium):
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
length (:obj:`int`): Video width and height (diameter of the video message) as defined
|
length (:obj:`int`): Video width and height (diameter of the video message) as defined
|
||||||
by sender.
|
by sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class VideoNote(_BaseThumbedMedium):
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
length (:obj:`int`): Video width and height (diameter of the video message) as defined
|
length (:obj:`int`): Video width and height (diameter of the video message) as defined
|
||||||
by sender.
|
by sender.
|
||||||
duration (:obj:`int`): Duration of the video in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ class Voice(_BaseMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
|
||||||
mime_type (:obj:`str`, optional): MIME type of the file as defined by sender.
|
mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`, optional): File size in bytes.
|
file_size (:obj:`int`, optional): File size in bytes.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
@ -45,8 +45,8 @@ class Voice(_BaseMedium):
|
||||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||||
is supposed to be the same over time and for different bots.
|
is supposed to be the same over time and for different bots.
|
||||||
Can't be used to download or reuse the file.
|
Can't be used to download or reuse the file.
|
||||||
duration (:obj:`int`): Duration of the audio in seconds as defined by sender.
|
duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
|
||||||
mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender.
|
mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
|
||||||
file_size (:obj:`int`): Optional. File size in bytes.
|
file_size (:obj:`int`): Optional. File size in bytes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -145,7 +145,10 @@ class MenuButtonWebApp(MenuButton):
|
||||||
web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
|
web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
|
||||||
when the user presses the button. The Web App will be able to send an arbitrary
|
when the user presses the button. The Web App will be able to send an arbitrary
|
||||||
message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
|
message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
|
||||||
of :class:`~telegram.Bot`.
|
of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can
|
||||||
|
be specified in the object instead of the Web App's URL, in which case the Web App
|
||||||
|
will be opened as if the user pressed the link.
|
||||||
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.WEB_APP`.
|
type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.WEB_APP`.
|
||||||
|
@ -153,7 +156,9 @@ class MenuButtonWebApp(MenuButton):
|
||||||
web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
|
web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
|
||||||
when the user presses the button. The Web App will be able to send an arbitrary
|
when the user presses the button. The Web App will be able to send an arbitrary
|
||||||
message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
|
message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
|
||||||
of :class:`~telegram.Bot`.
|
of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can
|
||||||
|
be specified in the object instead of the Web App's URL, in which case the Web App
|
||||||
|
will be opened as if the user pressed the link.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ("text", "web_app")
|
__slots__ = ("text", "web_app")
|
||||||
|
|
|
@ -52,6 +52,7 @@ from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||||
from telegram._linkpreviewoptions import LinkPreviewOptions
|
from telegram._linkpreviewoptions import LinkPreviewOptions
|
||||||
from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
|
from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
|
||||||
from telegram._messageentity import MessageEntity
|
from telegram._messageentity import MessageEntity
|
||||||
|
from telegram._paidmedia import PaidMediaInfo
|
||||||
from telegram._passport.passportdata import PassportData
|
from telegram._passport.passportdata import PassportData
|
||||||
from telegram._payment.invoice import Invoice
|
from telegram._payment.invoice import Invoice
|
||||||
from telegram._payment.successfulpayment import SuccessfulPayment
|
from telegram._payment.successfulpayment import SuccessfulPayment
|
||||||
|
@ -380,7 +381,8 @@ class Message(MaybeInaccessibleMessage):
|
||||||
.. versionchanged:: 20.0
|
.. versionchanged:: 20.0
|
||||||
|sequenceclassargs|
|
|sequenceclassargs|
|
||||||
|
|
||||||
caption (:obj:`str`, optional): Caption for the animation, audio, document, photo, video
|
caption (:obj:`str`, optional): Caption for the animation, audio, document, paid media,
|
||||||
|
photo, video
|
||||||
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
||||||
contact (:class:`telegram.Contact`, optional): Message is a shared contact, information
|
contact (:class:`telegram.Contact`, optional): Message is a shared contact, information
|
||||||
about the contact.
|
about the contact.
|
||||||
|
@ -571,6 +573,10 @@ class Message(MaybeInaccessibleMessage):
|
||||||
background set.
|
background set.
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
.. versionadded:: 21.2
|
||||||
|
paid_media (:obj:`telegram.PaidMediaInfo`, optional): Message contains paid media;
|
||||||
|
information about the paid media.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
message_id (:obj:`int`): Unique message identifier inside this chat.
|
message_id (:obj:`int`): Unique message identifier inside this chat.
|
||||||
|
@ -692,7 +698,8 @@ class Message(MaybeInaccessibleMessage):
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
.. versionchanged:: 20.0
|
||||||
|tupleclassattrs|
|
|tupleclassattrs|
|
||||||
caption (:obj:`str`): Optional. Caption for the animation, audio, document, photo, video
|
caption (:obj:`str`): Optional. Caption for the animation, audio, document, paid media,
|
||||||
|
photo, video
|
||||||
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
|
||||||
contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information
|
contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information
|
||||||
about the contact.
|
about the contact.
|
||||||
|
@ -884,6 +891,10 @@ class Message(MaybeInaccessibleMessage):
|
||||||
background set
|
background set
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
.. versionadded:: 21.2
|
||||||
|
paid_media (:obj:`telegram.PaidMediaInfo`): Optional. Message contains paid media;
|
||||||
|
information about the paid media.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
|
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
|
||||||
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
|
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
|
||||||
|
@ -950,6 +961,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
"new_chat_members",
|
"new_chat_members",
|
||||||
"new_chat_photo",
|
"new_chat_photo",
|
||||||
"new_chat_title",
|
"new_chat_title",
|
||||||
|
"paid_media",
|
||||||
"passport_data",
|
"passport_data",
|
||||||
"photo",
|
"photo",
|
||||||
"pinned_message",
|
"pinned_message",
|
||||||
|
@ -1067,6 +1079,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
chat_background_set: Optional[ChatBackground] = None,
|
chat_background_set: Optional[ChatBackground] = None,
|
||||||
effect_id: Optional[str] = None,
|
effect_id: Optional[str] = None,
|
||||||
show_caption_above_media: Optional[bool] = None,
|
show_caption_above_media: Optional[bool] = None,
|
||||||
|
paid_media: Optional[PaidMediaInfo] = None,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
):
|
):
|
||||||
|
@ -1168,6 +1181,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
self.chat_background_set: Optional[ChatBackground] = chat_background_set
|
self.chat_background_set: Optional[ChatBackground] = chat_background_set
|
||||||
self.effect_id: Optional[str] = effect_id
|
self.effect_id: Optional[str] = effect_id
|
||||||
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
self.show_caption_above_media: Optional[bool] = show_caption_above_media
|
||||||
|
self.paid_media: Optional[PaidMediaInfo] = paid_media
|
||||||
|
|
||||||
self._effective_attachment = DEFAULT_NONE
|
self._effective_attachment = DEFAULT_NONE
|
||||||
|
|
||||||
|
@ -1283,6 +1297,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot)
|
data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot)
|
||||||
data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot)
|
data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot)
|
||||||
data["chat_background_set"] = ChatBackground.de_json(data.get("chat_background_set"), bot)
|
data["chat_background_set"] = ChatBackground.de_json(data.get("chat_background_set"), bot)
|
||||||
|
data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot)
|
||||||
|
|
||||||
# Unfortunately, this needs to be here due to cyclic imports
|
# Unfortunately, this needs to be here due to cyclic imports
|
||||||
from telegram._giveaway import ( # pylint: disable=import-outside-toplevel
|
from telegram._giveaway import ( # pylint: disable=import-outside-toplevel
|
||||||
|
@ -1346,6 +1361,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
Location,
|
Location,
|
||||||
PassportData,
|
PassportData,
|
||||||
Sequence[PhotoSize],
|
Sequence[PhotoSize],
|
||||||
|
PaidMediaInfo,
|
||||||
Poll,
|
Poll,
|
||||||
Sticker,
|
Sticker,
|
||||||
Story,
|
Story,
|
||||||
|
@ -1369,6 +1385,7 @@ class Message(MaybeInaccessibleMessage):
|
||||||
* :class:`telegram.Location`
|
* :class:`telegram.Location`
|
||||||
* :class:`telegram.PassportData`
|
* :class:`telegram.PassportData`
|
||||||
* List[:class:`telegram.PhotoSize`]
|
* List[:class:`telegram.PhotoSize`]
|
||||||
|
* :class:`telegram.PaidMediaInfo`
|
||||||
* :class:`telegram.Poll`
|
* :class:`telegram.Poll`
|
||||||
* :class:`telegram.Sticker`
|
* :class:`telegram.Sticker`
|
||||||
* :class:`telegram.Story`
|
* :class:`telegram.Story`
|
||||||
|
@ -1386,6 +1403,9 @@ class Message(MaybeInaccessibleMessage):
|
||||||
:attr:`dice`, :attr:`passport_data` and :attr:`poll` are now also considered to be an
|
:attr:`dice`, :attr:`passport_data` and :attr:`poll` are now also considered to be an
|
||||||
attachment.
|
attachment.
|
||||||
|
|
||||||
|
.. versionchanged:: NEXT.VERSION
|
||||||
|
:attr:`paid_media` is now also considered to be an attachment.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(self._effective_attachment, DefaultValue):
|
if not isinstance(self._effective_attachment, DefaultValue):
|
||||||
return self._effective_attachment
|
return self._effective_attachment
|
||||||
|
|
290
telegram/_paidmedia.py
Normal file
290
telegram/_paidmedia.py
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# A library that provides a Python interface to the Telegram Bot API
|
||||||
|
# Copyright (C) 2015-2024
|
||||||
|
# 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 that represent paid media in Telegram."""
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Dict, Final, Optional, Sequence, Tuple, Type
|
||||||
|
|
||||||
|
from telegram import constants
|
||||||
|
from telegram._files.photosize import PhotoSize
|
||||||
|
from telegram._files.video import Video
|
||||||
|
from telegram._telegramobject import TelegramObject
|
||||||
|
from telegram._utils import enum
|
||||||
|
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||||
|
from telegram._utils.types import JSONDict
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from telegram import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMedia(TelegramObject):
|
||||||
|
"""Describes the paid media added to a message. Currently, it can be one of:
|
||||||
|
|
||||||
|
* :class:`telegram.PaidMediaPreview`
|
||||||
|
* :class:`telegram.PaidMediaPhoto`
|
||||||
|
* :class:`telegram.PaidMediaVideo`
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`type` is equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (:obj:`str`): Type of the paid media.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the paid media.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("type",)
|
||||||
|
|
||||||
|
PREVIEW: Final[str] = constants.PaidMediaType.PREVIEW
|
||||||
|
""":const:`telegram.constants.PaidMediaType.PREVIEW`"""
|
||||||
|
PHOTO: Final[str] = constants.PaidMediaType.PHOTO
|
||||||
|
""":const:`telegram.constants.PaidMediaType.PHOTO`"""
|
||||||
|
VIDEO: Final[str] = constants.PaidMediaType.VIDEO
|
||||||
|
""":const:`telegram.constants.PaidMediaType.VIDEO`"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
type: str, # pylint: disable=redefined-builtin
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.type: str = enum.get_member(constants.PaidMediaType, type, type)
|
||||||
|
|
||||||
|
self._id_attrs = (self.type,)
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(
|
||||||
|
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||||
|
) -> Optional["PaidMedia"]:
|
||||||
|
"""Converts JSON data to the appropriate :class:`PaidMedia` object, i.e. takes
|
||||||
|
care of selecting the correct subclass.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (Dict[:obj:`str`, ...]): The JSON data.
|
||||||
|
bot (:class:`telegram.Bot`, optional): The bot associated with this object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The Telegram object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not data and cls is PaidMedia:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_class_mapping: Dict[str, Type[PaidMedia]] = {
|
||||||
|
cls.PREVIEW: PaidMediaPreview,
|
||||||
|
cls.PHOTO: PaidMediaPhoto,
|
||||||
|
cls.VIDEO: PaidMediaVideo,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cls is PaidMedia and data.get("type") in _class_mapping:
|
||||||
|
return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
|
||||||
|
|
||||||
|
return super().de_json(data=data, bot=bot)
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMediaPreview(PaidMedia):
|
||||||
|
"""The paid media isn't available before the payment.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`width`, :attr:`height`, and :attr:`duration`
|
||||||
|
are equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`.
|
||||||
|
width (:obj:`int`, optional): Media width as defined by the sender.
|
||||||
|
height (:obj:`int`, optional): Media height as defined by the sender.
|
||||||
|
duration (:obj:`int`, optional): Duration of the media in seconds as defined by the sender.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`.
|
||||||
|
width (:obj:`int`): Optional. Media width as defined by the sender.
|
||||||
|
height (:obj:`int`): Optional. Media height as defined by the sender.
|
||||||
|
duration (:obj:`int`): Optional. Duration of the media in seconds as defined by the sender.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("duration", "height", "width")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
width: Optional[int] = None,
|
||||||
|
height: Optional[int] = None,
|
||||||
|
duration: Optional[int] = None,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(type=PaidMedia.PREVIEW, api_kwargs=api_kwargs)
|
||||||
|
|
||||||
|
with self._unfrozen():
|
||||||
|
self.width: Optional[int] = width
|
||||||
|
self.height: Optional[int] = height
|
||||||
|
self.duration: Optional[int] = duration
|
||||||
|
|
||||||
|
self._id_attrs = (self.type, self.width, self.height, self.duration)
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMediaPhoto(PaidMedia):
|
||||||
|
"""
|
||||||
|
The paid media is a photo.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`photo` are equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`.
|
||||||
|
photo (Sequence[:class:`telegram.PhotoSize`]): The photo.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`.
|
||||||
|
photo (Tuple[:class:`telegram.PhotoSize`]): The photo.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("photo",)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
photo: Sequence["PhotoSize"],
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(type=PaidMedia.PHOTO, api_kwargs=api_kwargs)
|
||||||
|
|
||||||
|
with self._unfrozen():
|
||||||
|
self.photo: Tuple[PhotoSize, ...] = parse_sequence_arg(photo)
|
||||||
|
|
||||||
|
self._id_attrs = (self.type, self.photo)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(
|
||||||
|
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||||
|
) -> Optional["PaidMediaPhoto"]:
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data["photo"] = PhotoSize.de_list(data.get("photo"), bot=bot)
|
||||||
|
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMediaVideo(PaidMedia):
|
||||||
|
"""
|
||||||
|
The paid media is a video.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`video` are equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`.
|
||||||
|
video (:class:`telegram.Video`): The video.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`.
|
||||||
|
video (:class:`telegram.Video`): The video.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("video",)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
video: Video,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(type=PaidMedia.VIDEO, api_kwargs=api_kwargs)
|
||||||
|
|
||||||
|
with self._unfrozen():
|
||||||
|
self.video: Video = video
|
||||||
|
|
||||||
|
self._id_attrs = (self.type, self.video)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(
|
||||||
|
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||||
|
) -> Optional["PaidMediaVideo"]:
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data["video"] = Video.de_json(data.get("video"), bot=bot)
|
||||||
|
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMediaInfo(TelegramObject):
|
||||||
|
"""
|
||||||
|
Describes the paid media added to a message.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`star_count` and :attr:`paid_media` are equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to
|
||||||
|
the media.
|
||||||
|
paid_media (Sequence[:class:`telegram.PaidMedia`]): Information about the paid media.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to
|
||||||
|
the media.
|
||||||
|
paid_media (Tuple[:class:`telegram.PaidMedia`]): Information about the paid media.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("paid_media", "star_count")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
star_count: int,
|
||||||
|
paid_media: Sequence[PaidMedia],
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.star_count: int = star_count
|
||||||
|
self.paid_media: Tuple[PaidMedia, ...] = parse_sequence_arg(paid_media)
|
||||||
|
|
||||||
|
self._id_attrs = (self.star_count, self.paid_media)
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(
|
||||||
|
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||||
|
) -> Optional["PaidMediaInfo"]:
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot)
|
||||||
|
return super().de_json(data=data, bot=bot)
|
|
@ -50,7 +50,7 @@ class PreCheckoutQuery(TelegramObject):
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
||||||
it shows the number of digits past the decimal point for each currency
|
it shows the number of digits past the decimal point for each currency
|
||||||
(2 for the majority of currencies).
|
(2 for the majority of currencies).
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
||||||
user.
|
user.
|
||||||
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
||||||
|
@ -66,7 +66,7 @@ class PreCheckoutQuery(TelegramObject):
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
||||||
it shows the number of digits past the decimal point for each currency
|
it shows the number of digits past the decimal point for each currency
|
||||||
(2 for the majority of currencies).
|
(2 for the majority of currencies).
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
||||||
user.
|
user.
|
||||||
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
||||||
|
|
|
@ -43,13 +43,13 @@ class ShippingQuery(TelegramObject):
|
||||||
Args:
|
Args:
|
||||||
id (:obj:`str`): Unique query identifier.
|
id (:obj:`str`): Unique query identifier.
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
from_user (:class:`telegram.User`): User who sent the query.
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
id (:obj:`str`): Unique query identifier.
|
id (:obj:`str`): Unique query identifier.
|
||||||
from_user (:class:`telegram.User`): User who sent the query.
|
from_user (:class:`telegram.User`): User who sent the query.
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -183,8 +183,9 @@ class TransactionPartner(TelegramObject):
|
||||||
"""This object describes the source of a transaction, or its recipient for outgoing
|
"""This object describes the source of a transaction, or its recipient for outgoing
|
||||||
transactions. Currently, it can be one of:
|
transactions. Currently, it can be one of:
|
||||||
|
|
||||||
* :class:`TransactionPartnerFragment`
|
|
||||||
* :class:`TransactionPartnerUser`
|
* :class:`TransactionPartnerUser`
|
||||||
|
* :class:`TransactionPartnerFragment`
|
||||||
|
* :class:`TransactionPartnerTelegramAds`
|
||||||
* :class:`TransactionPartnerOther`
|
* :class:`TransactionPartnerOther`
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
@ -207,6 +208,8 @@ class TransactionPartner(TelegramObject):
|
||||||
""":const:`telegram.constants.TransactionPartnerType.USER`"""
|
""":const:`telegram.constants.TransactionPartnerType.USER`"""
|
||||||
OTHER: Final[str] = constants.TransactionPartnerType.OTHER
|
OTHER: Final[str] = constants.TransactionPartnerType.OTHER
|
||||||
""":const:`telegram.constants.TransactionPartnerType.OTHER`"""
|
""":const:`telegram.constants.TransactionPartnerType.OTHER`"""
|
||||||
|
TELEGRAM_ADS: Final[str] = constants.TransactionPartnerType.TELEGRAM_ADS
|
||||||
|
""":const:`telegram.constants.TransactionPartnerType.TELEGRAM_ADS`"""
|
||||||
|
|
||||||
def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
@ -242,6 +245,7 @@ class TransactionPartner(TelegramObject):
|
||||||
cls.FRAGMENT: TransactionPartnerFragment,
|
cls.FRAGMENT: TransactionPartnerFragment,
|
||||||
cls.USER: TransactionPartnerUser,
|
cls.USER: TransactionPartnerUser,
|
||||||
cls.OTHER: TransactionPartnerOther,
|
cls.OTHER: TransactionPartnerOther,
|
||||||
|
cls.TELEGRAM_ADS: TransactionPartnerTelegramAds,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cls is TransactionPartner and data.get("type") in _class_mapping:
|
if cls is TransactionPartner and data.get("type") in _class_mapping:
|
||||||
|
@ -305,20 +309,29 @@ class TransactionPartnerUser(TransactionPartner):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user (:class:`telegram.User`): Information about the user.
|
user (:class:`telegram.User`): Information about the user.
|
||||||
|
invoice_payload (:obj:`str`, optional): Bot-specified invoice payload.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
type (:obj:`str`): The type of the transaction partner,
|
type (:obj:`str`): The type of the transaction partner,
|
||||||
always :tg-const:`telegram.TransactionPartner.USER`.
|
always :tg-const:`telegram.TransactionPartner.USER`.
|
||||||
user (:class:`telegram.User`): Information about the user.
|
user (:class:`telegram.User`): Information about the user.
|
||||||
|
invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ("user",)
|
__slots__ = ("invoice_payload", "user")
|
||||||
|
|
||||||
def __init__(self, user: "User", *, api_kwargs: Optional[JSONDict] = None) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
user: "User",
|
||||||
|
invoice_payload: Optional[str] = None,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs)
|
super().__init__(type=TransactionPartner.USER, api_kwargs=api_kwargs)
|
||||||
|
|
||||||
with self._unfrozen():
|
with self._unfrozen():
|
||||||
self.user: User = user
|
self.user: User = user
|
||||||
|
self.invoice_payload: Optional[str] = invoice_payload
|
||||||
self._id_attrs = (
|
self._id_attrs = (
|
||||||
self.type,
|
self.type,
|
||||||
self.user,
|
self.user,
|
||||||
|
@ -355,6 +368,23 @@ class TransactionPartnerOther(TransactionPartner):
|
||||||
self._freeze()
|
self._freeze()
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionPartnerTelegramAds(TransactionPartner):
|
||||||
|
"""Describes a withdrawal transaction to the Telegram Ads platform.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type (:obj:`str`): The type of the transaction partner,
|
||||||
|
always :tg-const:`telegram.TransactionPartner.TELEGRAM_ADS`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
|
||||||
|
super().__init__(type=TransactionPartner.TELEGRAM_ADS, api_kwargs=api_kwargs)
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
|
||||||
class StarTransaction(TelegramObject):
|
class StarTransaction(TelegramObject):
|
||||||
"""Describes a Telegram Star transaction.
|
"""Describes a Telegram Star transaction.
|
||||||
|
|
|
@ -44,7 +44,7 @@ class SuccessfulPayment(TelegramObject):
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
||||||
it shows the number of digits past the decimal point for each currency
|
it shows the number of digits past the decimal point for each currency
|
||||||
(2 for the majority of currencies).
|
(2 for the majority of currencies).
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the
|
||||||
user.
|
user.
|
||||||
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user.
|
||||||
|
@ -60,7 +60,7 @@ class SuccessfulPayment(TelegramObject):
|
||||||
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_,
|
||||||
it shows the number of digits past the decimal point for each currency
|
it shows the number of digits past the decimal point for each currency
|
||||||
(2 for the majority of currencies).
|
(2 for the majority of currencies).
|
||||||
invoice_payload (:obj:`str`): Bot specified invoice payload.
|
invoice_payload (:obj:`str`): Bot-specified invoice payload.
|
||||||
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the
|
||||||
user.
|
user.
|
||||||
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user.
|
||||||
|
|
|
@ -38,7 +38,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class InputPollOption(TelegramObject):
|
class InputPollOption(TelegramObject):
|
||||||
"""
|
"""
|
||||||
This object contains information about one answer option in a poll to send.
|
This object contains information about one answer option in a poll to be sent.
|
||||||
|
|
||||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
considered equal, if their :attr:`text` is equal.
|
considered equal, if their :attr:`text` is equal.
|
||||||
|
|
|
@ -37,6 +37,7 @@ from telegram._giveaway import Giveaway, GiveawayWinners
|
||||||
from telegram._linkpreviewoptions import LinkPreviewOptions
|
from telegram._linkpreviewoptions import LinkPreviewOptions
|
||||||
from telegram._messageentity import MessageEntity
|
from telegram._messageentity import MessageEntity
|
||||||
from telegram._messageorigin import MessageOrigin
|
from telegram._messageorigin import MessageOrigin
|
||||||
|
from telegram._paidmedia import PaidMediaInfo
|
||||||
from telegram._payment.invoice import Invoice
|
from telegram._payment.invoice import Invoice
|
||||||
from telegram._poll import Poll
|
from telegram._poll import Poll
|
||||||
from telegram._story import Story
|
from telegram._story import Story
|
||||||
|
@ -101,6 +102,10 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
poll (:class:`telegram.Poll`, optional): Message is a native poll, information about the
|
poll (:class:`telegram.Poll`, optional): Message is a native poll, information about the
|
||||||
poll.
|
poll.
|
||||||
venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue.
|
venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue.
|
||||||
|
paid_media (:class:`telegram.PaidMedia`, optional): Message contains paid media;
|
||||||
|
information about the paid media.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
|
origin (:class:`telegram.MessageOrigin`): Origin of the message replied to by the given
|
||||||
|
@ -144,6 +149,10 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
poll (:class:`telegram.Poll`): Optional. Message is a native poll, information about the
|
poll (:class:`telegram.Poll`): Optional. Message is a native poll, information about the
|
||||||
poll.
|
poll.
|
||||||
venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the venue.
|
venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the venue.
|
||||||
|
paid_media (:class:`telegram.PaidMedia`): Optional. Message contains paid media;
|
||||||
|
information about the paid media.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
|
@ -162,6 +171,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
"location",
|
"location",
|
||||||
"message_id",
|
"message_id",
|
||||||
"origin",
|
"origin",
|
||||||
|
"paid_media",
|
||||||
"photo",
|
"photo",
|
||||||
"poll",
|
"poll",
|
||||||
"sticker",
|
"sticker",
|
||||||
|
@ -197,6 +207,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
location: Optional[Location] = None,
|
location: Optional[Location] = None,
|
||||||
poll: Optional[Poll] = None,
|
poll: Optional[Poll] = None,
|
||||||
venue: Optional[Venue] = None,
|
venue: Optional[Venue] = None,
|
||||||
|
paid_media: Optional[PaidMediaInfo] = None,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
):
|
):
|
||||||
|
@ -225,6 +236,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
self.location: Optional[Location] = location
|
self.location: Optional[Location] = location
|
||||||
self.poll: Optional[Poll] = poll
|
self.poll: Optional[Poll] = poll
|
||||||
self.venue: Optional[Venue] = venue
|
self.venue: Optional[Venue] = venue
|
||||||
|
self.paid_media: Optional[PaidMediaInfo] = paid_media
|
||||||
|
|
||||||
self._id_attrs = (self.origin,)
|
self._id_attrs = (self.origin,)
|
||||||
|
|
||||||
|
@ -263,6 +275,7 @@ class ExternalReplyInfo(TelegramObject):
|
||||||
data["location"] = Location.de_json(data.get("location"), bot)
|
data["location"] = Location.de_json(data.get("location"), bot)
|
||||||
data["poll"] = Poll.de_json(data.get("poll"), bot)
|
data["poll"] = Poll.de_json(data.get("poll"), bot)
|
||||||
data["venue"] = Venue.de_json(data.get("venue"), bot)
|
data["venue"] = Venue.de_json(data.get("venue"), bot)
|
||||||
|
data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot)
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
return super().de_json(data=data, bot=bot)
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ __all__ = [
|
||||||
"InlineQueryResultType",
|
"InlineQueryResultType",
|
||||||
"InlineQueryResultsButtonLimit",
|
"InlineQueryResultsButtonLimit",
|
||||||
"InputMediaType",
|
"InputMediaType",
|
||||||
|
"InputPaidMediaType",
|
||||||
"InvoiceLimit",
|
"InvoiceLimit",
|
||||||
"KeyboardButtonRequestUsersLimit",
|
"KeyboardButtonRequestUsersLimit",
|
||||||
"LocationLimit",
|
"LocationLimit",
|
||||||
|
@ -82,6 +83,7 @@ __all__ = [
|
||||||
"MessageLimit",
|
"MessageLimit",
|
||||||
"MessageOriginType",
|
"MessageOriginType",
|
||||||
"MessageType",
|
"MessageType",
|
||||||
|
"PaidMediaType",
|
||||||
"ParseMode",
|
"ParseMode",
|
||||||
"PollLimit",
|
"PollLimit",
|
||||||
"PollType",
|
"PollType",
|
||||||
|
@ -149,7 +151,7 @@ class _AccentColor(NamedTuple):
|
||||||
#: :data:`telegram.__bot_api_version_info__`.
|
#: :data:`telegram.__bot_api_version_info__`.
|
||||||
#:
|
#:
|
||||||
#: .. versionadded:: 20.0
|
#: .. versionadded:: 20.0
|
||||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=5)
|
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=6)
|
||||||
#: :obj:`str`: Telegram Bot API
|
#: :obj:`str`: Telegram Bot API
|
||||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||||
#: :data:`telegram.__bot_api_version__`.
|
#: :data:`telegram.__bot_api_version__`.
|
||||||
|
@ -1259,6 +1261,21 @@ class InputMediaType(StringEnum):
|
||||||
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
|
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
|
||||||
|
|
||||||
|
|
||||||
|
class InputPaidMediaType(StringEnum):
|
||||||
|
"""This enum contains the available types of :class:`telegram.InputPaidMedia`. The enum
|
||||||
|
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
PHOTO = "photo"
|
||||||
|
""":obj:`str`: Type of :class:`telegram.InputMediaPhoto`."""
|
||||||
|
VIDEO = "video"
|
||||||
|
""":obj:`str`: Type of :class:`telegram.InputMediaVideo`."""
|
||||||
|
|
||||||
|
|
||||||
class InlineQueryLimit(IntEnum):
|
class InlineQueryLimit(IntEnum):
|
||||||
"""This enum contains limitations for :class:`telegram.InlineQuery`/
|
"""This enum contains limitations for :class:`telegram.InlineQuery`/
|
||||||
:meth:`telegram.Bot.answer_inline_query`. The enum members of this enumeration are instances
|
:meth:`telegram.Bot.answer_inline_query`. The enum members of this enumeration are instances
|
||||||
|
@ -1602,6 +1619,11 @@ class MessageAttachmentType(StringEnum):
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.invoice`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.invoice`."""
|
||||||
LOCATION = "location"
|
LOCATION = "location"
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.location`."""
|
||||||
|
PAID_MEDIA = "paid_media"
|
||||||
|
""":obj:`str`: Messages with :attr:`telegram.Message.paid_media`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
PASSPORT_DATA = "passport_data"
|
PASSPORT_DATA = "passport_data"
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.passport_data`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.passport_data`."""
|
||||||
PHOTO = "photo"
|
PHOTO = "photo"
|
||||||
|
@ -1883,6 +1905,11 @@ class MessageType(StringEnum):
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.new_chat_title`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.new_chat_title`."""
|
||||||
NEW_CHAT_PHOTO = "new_chat_photo"
|
NEW_CHAT_PHOTO = "new_chat_photo"
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.new_chat_photo`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.new_chat_photo`."""
|
||||||
|
PAID_MEDIA = "paid_media"
|
||||||
|
""":obj:`str`: Messages with :attr:`telegram.Message.paid_media`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
PASSPORT_DATA = "passport_data"
|
PASSPORT_DATA = "passport_data"
|
||||||
""":obj:`str`: Messages with :attr:`telegram.Message.passport_data`."""
|
""":obj:`str`: Messages with :attr:`telegram.Message.passport_data`."""
|
||||||
PHOTO = "photo"
|
PHOTO = "photo"
|
||||||
|
@ -1951,6 +1978,24 @@ class MessageType(StringEnum):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PaidMediaType(StringEnum):
|
||||||
|
"""
|
||||||
|
This enum contains the available types of :class:`telegram.PaidMedia`. The enum
|
||||||
|
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
PREVIEW = "preview"
|
||||||
|
""":obj:`str`: The type of :class:`telegram.PaidMediaPreview`."""
|
||||||
|
VIDEO = "video"
|
||||||
|
""":obj:`str`: The type of :class:`telegram.PaidMediaVideo`."""
|
||||||
|
PHOTO = "photo"
|
||||||
|
""":obj:`str`: The type of :class:`telegram.PaidMediaPhoto`."""
|
||||||
|
|
||||||
|
|
||||||
class PollingLimit(IntEnum):
|
class PollingLimit(IntEnum):
|
||||||
"""This enum contains limitations for :paramref:`telegram.Bot.get_updates.limit`.
|
"""This enum contains limitations for :paramref:`telegram.Bot.get_updates.limit`.
|
||||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||||
|
@ -2490,6 +2535,8 @@ class TransactionPartnerType(StringEnum):
|
||||||
""":obj:`str`: Transaction with a user."""
|
""":obj:`str`: Transaction with a user."""
|
||||||
OTHER = "other"
|
OTHER = "other"
|
||||||
""":obj:`str`: Transaction with unknown source or recipient."""
|
""":obj:`str`: Transaction with unknown source or recipient."""
|
||||||
|
TELEGRAM_ADS = "telegram_ads"
|
||||||
|
""":obj:`str`: Transaction with Telegram Ads."""
|
||||||
|
|
||||||
|
|
||||||
class ParseMode(StringEnum):
|
class ParseMode(StringEnum):
|
||||||
|
|
|
@ -107,6 +107,7 @@ if TYPE_CHECKING:
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
InputMediaPhoto,
|
InputMediaPhoto,
|
||||||
InputMediaVideo,
|
InputMediaVideo,
|
||||||
|
InputPaidMedia,
|
||||||
InputSticker,
|
InputSticker,
|
||||||
LabeledPrice,
|
LabeledPrice,
|
||||||
MessageEntity,
|
MessageEntity,
|
||||||
|
@ -4216,6 +4217,50 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def send_paid_media(
|
||||||
|
self,
|
||||||
|
chat_id: Union[str, int],
|
||||||
|
star_count: int,
|
||||||
|
media: Sequence["InputPaidMedia"],
|
||||||
|
caption: Optional[str] = None,
|
||||||
|
parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||||
|
show_caption_above_media: Optional[bool] = None,
|
||||||
|
disable_notification: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_parameters: Optional["ReplyParameters"] = None,
|
||||||
|
reply_markup: Optional[ReplyMarkup] = None,
|
||||||
|
*,
|
||||||
|
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||||
|
reply_to_message_id: Optional[int] = 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: Optional[JSONDict] = None,
|
||||||
|
rate_limit_args: Optional[RLARGS] = None,
|
||||||
|
) -> Message:
|
||||||
|
return await super().send_paid_media(
|
||||||
|
chat_id=chat_id,
|
||||||
|
star_count=star_count,
|
||||||
|
media=media,
|
||||||
|
caption=caption,
|
||||||
|
parse_mode=parse_mode,
|
||||||
|
caption_entities=caption_entities,
|
||||||
|
show_caption_above_media=show_caption_above_media,
|
||||||
|
disable_notification=disable_notification,
|
||||||
|
protect_content=protect_content,
|
||||||
|
reply_parameters=reply_parameters,
|
||||||
|
reply_markup=reply_markup,
|
||||||
|
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=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
|
)
|
||||||
|
|
||||||
# updated camelCase aliases
|
# updated camelCase aliases
|
||||||
getMe = get_me
|
getMe = get_me
|
||||||
sendMessage = send_message
|
sendMessage = send_message
|
||||||
|
@ -4339,3 +4384,4 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
replaceStickerInSet = replace_sticker_in_set
|
replaceStickerInSet = replace_sticker_in_set
|
||||||
refundStarPayment = refund_star_payment
|
refundStarPayment = refund_star_payment
|
||||||
getStarTransactions = get_star_transactions
|
getStarTransactions = get_star_transactions
|
||||||
|
sendPaidMedia = send_paid_media
|
||||||
|
|
|
@ -23,7 +23,7 @@ from datetime import datetime
|
||||||
from typing import List, Optional, Sequence, Tuple, final
|
from typing import List, Optional, Sequence, Tuple, final
|
||||||
|
|
||||||
from telegram._files.inputfile import InputFile
|
from telegram._files.inputfile import InputFile
|
||||||
from telegram._files.inputmedia import InputMedia
|
from telegram._files.inputmedia import InputMedia, InputPaidMedia
|
||||||
from telegram._files.inputsticker import InputSticker
|
from telegram._files.inputsticker import InputSticker
|
||||||
from telegram._telegramobject import TelegramObject
|
from telegram._telegramobject import TelegramObject
|
||||||
from telegram._utils.datetime import to_timestamp
|
from telegram._utils.datetime import to_timestamp
|
||||||
|
@ -117,7 +117,7 @@ class RequestParameter:
|
||||||
return value.attach_uri, [value]
|
return value.attach_uri, [value]
|
||||||
return None, [value]
|
return None, [value]
|
||||||
|
|
||||||
if isinstance(value, InputMedia) and isinstance(value.media, InputFile):
|
if isinstance(value, (InputMedia, InputPaidMedia)) and isinstance(value.media, InputFile):
|
||||||
# We call to_dict and change the returned dict instead of overriding
|
# We call to_dict and change the returned dict instead of overriding
|
||||||
# value.media in case the same value is reused for another request
|
# value.media in case the same value is reused for another request
|
||||||
data = value.to_dict()
|
data = value.to_dict()
|
||||||
|
|
|
@ -31,6 +31,8 @@ from telegram import (
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
InputMediaPhoto,
|
InputMediaPhoto,
|
||||||
InputMediaVideo,
|
InputMediaVideo,
|
||||||
|
InputPaidMediaPhoto,
|
||||||
|
InputPaidMediaVideo,
|
||||||
Message,
|
Message,
|
||||||
MessageEntity,
|
MessageEntity,
|
||||||
ReplyParameters,
|
ReplyParameters,
|
||||||
|
@ -134,6 +136,25 @@ def input_media_document(class_thumb_file):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def input_paid_media_photo():
|
||||||
|
return InputPaidMediaPhoto(
|
||||||
|
media=TestInputMediaPhotoBase.media,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def input_paid_media_video(class_thumb_file):
|
||||||
|
return InputPaidMediaVideo(
|
||||||
|
media=TestInputMediaVideoBase.media,
|
||||||
|
thumbnail=class_thumb_file,
|
||||||
|
width=TestInputMediaVideoBase.width,
|
||||||
|
height=TestInputMediaVideoBase.height,
|
||||||
|
duration=TestInputMediaVideoBase.duration,
|
||||||
|
supports_streaming=TestInputMediaVideoBase.supports_streaming,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestInputMediaVideoBase:
|
class TestInputMediaVideoBase:
|
||||||
type_ = "video"
|
type_ = "video"
|
||||||
media = "NOTAREALFILEID"
|
media = "NOTAREALFILEID"
|
||||||
|
@ -514,6 +535,91 @@ class TestInputMediaDocumentWithoutRequest(TestInputMediaDocumentBase):
|
||||||
assert input_media_document.thumbnail == data_file("telegram.jpg").as_uri()
|
assert input_media_document.thumbnail == data_file("telegram.jpg").as_uri()
|
||||||
|
|
||||||
|
|
||||||
|
class TestInputPaidMediaPhotoWithoutRequest(TestInputMediaPhotoBase):
|
||||||
|
def test_slot_behaviour(self, input_paid_media_photo):
|
||||||
|
inst = input_paid_media_photo
|
||||||
|
for attr in inst.__slots__:
|
||||||
|
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_expected_values(self, input_paid_media_photo):
|
||||||
|
assert input_paid_media_photo.type == self.type_
|
||||||
|
assert input_paid_media_photo.media == self.media
|
||||||
|
|
||||||
|
def test_to_dict(self, input_paid_media_photo):
|
||||||
|
input_paid_media_photo_dict = input_paid_media_photo.to_dict()
|
||||||
|
assert input_paid_media_photo_dict["type"] == input_paid_media_photo.type
|
||||||
|
assert input_paid_media_photo_dict["media"] == input_paid_media_photo.media
|
||||||
|
|
||||||
|
def test_with_photo(self, photo): # noqa: F811
|
||||||
|
# fixture found in test_photo
|
||||||
|
input_paid_media_photo = InputPaidMediaPhoto(photo)
|
||||||
|
assert input_paid_media_photo.type == self.type_
|
||||||
|
assert input_paid_media_photo.media == photo.file_id
|
||||||
|
|
||||||
|
def test_with_photo_file(self, photo_file): # noqa: F811
|
||||||
|
# fixture found in test_photo
|
||||||
|
input_paid_media_photo = InputPaidMediaPhoto(photo_file)
|
||||||
|
assert input_paid_media_photo.type == self.type_
|
||||||
|
assert isinstance(input_paid_media_photo.media, InputFile)
|
||||||
|
|
||||||
|
def test_with_local_files(self):
|
||||||
|
input_paid_media_photo = InputPaidMediaPhoto(data_file("telegram.jpg"))
|
||||||
|
assert input_paid_media_photo.media == data_file("telegram.jpg").as_uri()
|
||||||
|
|
||||||
|
|
||||||
|
class TestInputPaidMediaVideoWithoutRequest(TestInputMediaVideoBase):
|
||||||
|
def test_slot_behaviour(self, input_paid_media_video):
|
||||||
|
inst = input_paid_media_video
|
||||||
|
for attr in inst.__slots__:
|
||||||
|
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_expected_values(self, input_paid_media_video):
|
||||||
|
assert input_paid_media_video.type == self.type_
|
||||||
|
assert input_paid_media_video.media == self.media
|
||||||
|
assert input_paid_media_video.width == self.width
|
||||||
|
assert input_paid_media_video.height == self.height
|
||||||
|
assert input_paid_media_video.duration == self.duration
|
||||||
|
assert input_paid_media_video.supports_streaming == self.supports_streaming
|
||||||
|
assert isinstance(input_paid_media_video.thumbnail, InputFile)
|
||||||
|
|
||||||
|
def test_to_dict(self, input_paid_media_video):
|
||||||
|
input_paid_media_video_dict = input_paid_media_video.to_dict()
|
||||||
|
assert input_paid_media_video_dict["type"] == input_paid_media_video.type
|
||||||
|
assert input_paid_media_video_dict["media"] == input_paid_media_video.media
|
||||||
|
assert input_paid_media_video_dict["width"] == input_paid_media_video.width
|
||||||
|
assert input_paid_media_video_dict["height"] == input_paid_media_video.height
|
||||||
|
assert input_paid_media_video_dict["duration"] == input_paid_media_video.duration
|
||||||
|
assert (
|
||||||
|
input_paid_media_video_dict["supports_streaming"]
|
||||||
|
== input_paid_media_video.supports_streaming
|
||||||
|
)
|
||||||
|
assert input_paid_media_video_dict["thumbnail"] == input_paid_media_video.thumbnail
|
||||||
|
|
||||||
|
def test_with_video(self, video): # noqa: F811
|
||||||
|
# fixture found in test_video
|
||||||
|
input_paid_media_video = InputPaidMediaVideo(video)
|
||||||
|
assert input_paid_media_video.type == self.type_
|
||||||
|
assert input_paid_media_video.media == video.file_id
|
||||||
|
assert input_paid_media_video.width == video.width
|
||||||
|
assert input_paid_media_video.height == video.height
|
||||||
|
assert input_paid_media_video.duration == video.duration
|
||||||
|
|
||||||
|
def test_with_video_file(self, video_file): # noqa: F811
|
||||||
|
# fixture found in test_video
|
||||||
|
input_paid_media_video = InputPaidMediaVideo(video_file)
|
||||||
|
assert input_paid_media_video.type == self.type_
|
||||||
|
assert isinstance(input_paid_media_video.media, InputFile)
|
||||||
|
|
||||||
|
def test_with_local_files(self):
|
||||||
|
input_paid_media_video = InputPaidMediaVideo(
|
||||||
|
data_file("telegram.mp4"), thumbnail=data_file("telegram.jpg")
|
||||||
|
)
|
||||||
|
assert input_paid_media_video.media == data_file("telegram.mp4").as_uri()
|
||||||
|
assert input_paid_media_video.thumbnail == data_file("telegram.jpg").as_uri()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def media_group(photo, thumb): # noqa: F811
|
def media_group(photo, thumb): # noqa: F811
|
||||||
return [
|
return [
|
||||||
|
@ -1044,3 +1150,20 @@ class TestSendMediaGroupWithRequest:
|
||||||
assert message.caption_entities == ()
|
assert message.caption_entities == ()
|
||||||
# make sure that the media was not modified
|
# make sure that the media was not modified
|
||||||
assert media.parse_mode == copied_media.parse_mode
|
assert media.parse_mode == copied_media.parse_mode
|
||||||
|
|
||||||
|
async def test_send_paid_media(self, bot, channel_id, photo_file, video_file): # noqa: F811
|
||||||
|
msg = await bot.send_paid_media(
|
||||||
|
chat_id=channel_id,
|
||||||
|
star_count=20,
|
||||||
|
media=[
|
||||||
|
InputPaidMediaPhoto(media=photo_file),
|
||||||
|
InputPaidMediaVideo(media=video_file),
|
||||||
|
],
|
||||||
|
caption="bye onlyfans",
|
||||||
|
show_caption_above_media=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert isinstance(msg, Message)
|
||||||
|
assert msg.caption == "bye onlyfans"
|
||||||
|
assert msg.show_caption_above_media
|
||||||
|
assert msg.paid_media.star_count == 20
|
||||||
|
|
|
@ -1244,6 +1244,22 @@ class TestChatWithoutRequest(TestChatBase):
|
||||||
123, [ReactionTypeEmoji(ReactionEmoji.THUMBS_DOWN)], True
|
123, [ReactionTypeEmoji(ReactionEmoji.THUMBS_DOWN)], True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_instance_method_send_paid_media(self, monkeypatch, chat):
|
||||||
|
async def make_assertion(*_, **kwargs):
|
||||||
|
return (
|
||||||
|
kwargs["chat_id"] == chat.id
|
||||||
|
and kwargs["media"] == "media"
|
||||||
|
and kwargs["star_count"] == 42
|
||||||
|
and kwargs["caption"] == "stars"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert check_shortcut_signature(Chat.send_paid_media, Bot.send_paid_media, ["chat_id"], [])
|
||||||
|
assert await check_shortcut_call(chat.send_paid_media, chat.get_bot(), "send_paid_media")
|
||||||
|
assert await check_defaults_handling(chat.send_paid_media, chat.get_bot())
|
||||||
|
|
||||||
|
monkeypatch.setattr(chat.get_bot(), "send_paid_media", make_assertion)
|
||||||
|
assert await chat.send_paid_media(media="media", star_count=42, caption="stars")
|
||||||
|
|
||||||
def test_mention_html(self):
|
def test_mention_html(self):
|
||||||
chat = Chat(id=1, type="foo")
|
chat = Chat(id=1, type="foo")
|
||||||
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
|
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
|
||||||
|
|
|
@ -55,13 +55,15 @@ def chat_full_info(bot):
|
||||||
bio=TestChatFullInfoBase.bio,
|
bio=TestChatFullInfoBase.bio,
|
||||||
linked_chat_id=TestChatFullInfoBase.linked_chat_id,
|
linked_chat_id=TestChatFullInfoBase.linked_chat_id,
|
||||||
location=TestChatFullInfoBase.location,
|
location=TestChatFullInfoBase.location,
|
||||||
has_private_forwards=True,
|
has_private_forwards=TestChatFullInfoBase.has_private_forwards,
|
||||||
has_protected_content=True,
|
has_protected_content=TestChatFullInfoBase.has_protected_content,
|
||||||
has_visible_history=True,
|
has_visible_history=TestChatFullInfoBase.has_visible_history,
|
||||||
join_to_send_messages=True,
|
join_to_send_messages=TestChatFullInfoBase.join_to_send_messages,
|
||||||
join_by_request=True,
|
join_by_request=TestChatFullInfoBase.join_by_request,
|
||||||
has_restricted_voice_and_video_messages=True,
|
has_restricted_voice_and_video_messages=(
|
||||||
is_forum=True,
|
TestChatFullInfoBase.has_restricted_voice_and_video_messages
|
||||||
|
),
|
||||||
|
is_forum=TestChatFullInfoBase.is_forum,
|
||||||
active_usernames=TestChatFullInfoBase.active_usernames,
|
active_usernames=TestChatFullInfoBase.active_usernames,
|
||||||
emoji_status_custom_emoji_id=TestChatFullInfoBase.emoji_status_custom_emoji_id,
|
emoji_status_custom_emoji_id=TestChatFullInfoBase.emoji_status_custom_emoji_id,
|
||||||
emoji_status_expiration_date=TestChatFullInfoBase.emoji_status_expiration_date,
|
emoji_status_expiration_date=TestChatFullInfoBase.emoji_status_expiration_date,
|
||||||
|
@ -76,10 +78,11 @@ def chat_full_info(bot):
|
||||||
business_intro=TestChatFullInfoBase.business_intro,
|
business_intro=TestChatFullInfoBase.business_intro,
|
||||||
business_location=TestChatFullInfoBase.business_location,
|
business_location=TestChatFullInfoBase.business_location,
|
||||||
business_opening_hours=TestChatFullInfoBase.business_opening_hours,
|
business_opening_hours=TestChatFullInfoBase.business_opening_hours,
|
||||||
birthdate=Birthdate(1, 1),
|
birthdate=TestChatFullInfoBase.birthdate,
|
||||||
personal_chat=TestChatFullInfoBase.personal_chat,
|
personal_chat=TestChatFullInfoBase.personal_chat,
|
||||||
first_name="first_name",
|
first_name=TestChatFullInfoBase.first_name,
|
||||||
last_name="last_name",
|
last_name=TestChatFullInfoBase.last_name,
|
||||||
|
can_send_paid_media=TestChatFullInfoBase.can_send_paid_media,
|
||||||
)
|
)
|
||||||
chat.set_bot(bot)
|
chat.set_bot(bot)
|
||||||
chat._unfreeze()
|
chat._unfreeze()
|
||||||
|
@ -136,6 +139,7 @@ class TestChatFullInfoBase:
|
||||||
personal_chat = Chat(3, "private", "private")
|
personal_chat = Chat(3, "private", "private")
|
||||||
first_name = "first_name"
|
first_name = "first_name"
|
||||||
last_name = "last_name"
|
last_name = "last_name"
|
||||||
|
can_send_paid_media = True
|
||||||
|
|
||||||
|
|
||||||
class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
||||||
|
@ -188,6 +192,7 @@ class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
||||||
"personal_chat": self.personal_chat.to_dict(),
|
"personal_chat": self.personal_chat.to_dict(),
|
||||||
"first_name": self.first_name,
|
"first_name": self.first_name,
|
||||||
"last_name": self.last_name,
|
"last_name": self.last_name,
|
||||||
|
"can_send_paid_media": self.can_send_paid_media,
|
||||||
}
|
}
|
||||||
cfi = ChatFullInfo.de_json(json_dict, bot)
|
cfi = ChatFullInfo.de_json(json_dict, bot)
|
||||||
assert cfi.id == self.id_
|
assert cfi.id == self.id_
|
||||||
|
@ -232,6 +237,7 @@ class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
||||||
assert cfi.first_name == self.first_name
|
assert cfi.first_name == self.first_name
|
||||||
assert cfi.last_name == self.last_name
|
assert cfi.last_name == self.last_name
|
||||||
assert cfi.max_reaction_count == self.max_reaction_count
|
assert cfi.max_reaction_count == self.max_reaction_count
|
||||||
|
assert cfi.can_send_paid_media == self.can_send_paid_media
|
||||||
|
|
||||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||||
json_dict = {
|
json_dict = {
|
||||||
|
@ -305,6 +311,7 @@ class TestChatFullInfoWithoutRequest(TestChatFullInfoBase):
|
||||||
assert cfi_dict["personal_chat"] == cfi.personal_chat.to_dict()
|
assert cfi_dict["personal_chat"] == cfi.personal_chat.to_dict()
|
||||||
assert cfi_dict["first_name"] == cfi.first_name
|
assert cfi_dict["first_name"] == cfi.first_name
|
||||||
assert cfi_dict["last_name"] == cfi.last_name
|
assert cfi_dict["last_name"] == cfi.last_name
|
||||||
|
assert cfi_dict["can_send_paid_media"] == cfi.can_send_paid_media
|
||||||
|
|
||||||
assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count
|
assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,8 @@ class TestConstantsWithoutRequest:
|
||||||
name = to_snake_case(match.group(1))
|
name = to_snake_case(match.group(1))
|
||||||
if name == "photo_size":
|
if name == "photo_size":
|
||||||
name = "photo"
|
name = "photo"
|
||||||
|
if name == "paid_media_info":
|
||||||
|
name = "paid_media"
|
||||||
try:
|
try:
|
||||||
constants.MessageAttachmentType(name)
|
constants.MessageAttachmentType(name)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -46,6 +46,8 @@ from telegram import (
|
||||||
MessageAutoDeleteTimerChanged,
|
MessageAutoDeleteTimerChanged,
|
||||||
MessageEntity,
|
MessageEntity,
|
||||||
MessageOriginChat,
|
MessageOriginChat,
|
||||||
|
PaidMediaInfo,
|
||||||
|
PaidMediaPreview,
|
||||||
PassportData,
|
PassportData,
|
||||||
PhotoSize,
|
PhotoSize,
|
||||||
Poll,
|
Poll,
|
||||||
|
@ -275,6 +277,7 @@ def message(bot):
|
||||||
{"chat_background_set": ChatBackground(type=BackgroundTypeChatTheme("ice"))},
|
{"chat_background_set": ChatBackground(type=BackgroundTypeChatTheme("ice"))},
|
||||||
{"effect_id": "123456789"},
|
{"effect_id": "123456789"},
|
||||||
{"show_caption_above_media": True},
|
{"show_caption_above_media": True},
|
||||||
|
{"paid_media": PaidMediaInfo(5, [PaidMediaPreview(10, 10, 10)])},
|
||||||
],
|
],
|
||||||
ids=[
|
ids=[
|
||||||
"reply",
|
"reply",
|
||||||
|
@ -346,6 +349,7 @@ def message(bot):
|
||||||
"chat_background_set",
|
"chat_background_set",
|
||||||
"effect_id",
|
"effect_id",
|
||||||
"show_caption_above_media",
|
"show_caption_above_media",
|
||||||
|
"paid_media",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def message_params(bot, request):
|
def message_params(bot, request):
|
||||||
|
@ -1221,6 +1225,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
||||||
"game",
|
"game",
|
||||||
"invoice",
|
"invoice",
|
||||||
"location",
|
"location",
|
||||||
|
"paid_media",
|
||||||
"passport_data",
|
"passport_data",
|
||||||
"photo",
|
"photo",
|
||||||
"poll",
|
"poll",
|
||||||
|
|
|
@ -127,6 +127,8 @@ PTB_EXTRA_PARAMS = {
|
||||||
"InputTextMessageContent": {"disable_web_page_preview"}, # convenience arg, here for bw compat
|
"InputTextMessageContent": {"disable_web_page_preview"}, # convenience arg, here for bw compat
|
||||||
"RevenueWithdrawalState": {"type"}, # attributes common to all subclasses
|
"RevenueWithdrawalState": {"type"}, # attributes common to all subclasses
|
||||||
"TransactionPartner": {"type"}, # attributes common to all subclasses
|
"TransactionPartner": {"type"}, # attributes common to all subclasses
|
||||||
|
"PaidMedia": {"type"}, # attributes common to all subclasses
|
||||||
|
"InputPaidMedia": {"type", "media"}, # attributes common to all subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,6 +155,8 @@ PTB_IGNORED_PARAMS = {
|
||||||
r"BackgroundFill\w+": {"type"},
|
r"BackgroundFill\w+": {"type"},
|
||||||
r"RevenueWithdrawalState\w+": {"type"},
|
r"RevenueWithdrawalState\w+": {"type"},
|
||||||
r"TransactionPartner\w+": {"type"},
|
r"TransactionPartner\w+": {"type"},
|
||||||
|
r"PaidMedia\w+": {"type"},
|
||||||
|
r"InputPaidMedia\w+": {"type"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
325
tests/test_paidmedia.py
Normal file
325
tests/test_paidmedia.py
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# A library that provides a Python interface to the Telegram Bot API
|
||||||
|
# Copyright (C) 2015-2024
|
||||||
|
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from telegram import (
|
||||||
|
Dice,
|
||||||
|
PaidMedia,
|
||||||
|
PaidMediaInfo,
|
||||||
|
PaidMediaPhoto,
|
||||||
|
PaidMediaPreview,
|
||||||
|
PaidMediaVideo,
|
||||||
|
PhotoSize,
|
||||||
|
Video,
|
||||||
|
)
|
||||||
|
from telegram.constants import PaidMediaType
|
||||||
|
from tests.auxil.slots import mro_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(
|
||||||
|
scope="module",
|
||||||
|
params=[
|
||||||
|
PaidMedia.PREVIEW,
|
||||||
|
PaidMedia.PHOTO,
|
||||||
|
PaidMedia.VIDEO,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def pm_scope_type(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(
|
||||||
|
scope="module",
|
||||||
|
params=[
|
||||||
|
PaidMediaPreview,
|
||||||
|
PaidMediaPhoto,
|
||||||
|
PaidMediaVideo,
|
||||||
|
],
|
||||||
|
ids=[
|
||||||
|
PaidMedia.PREVIEW,
|
||||||
|
PaidMedia.PHOTO,
|
||||||
|
PaidMedia.VIDEO,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def pm_scope_class(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(
|
||||||
|
scope="module",
|
||||||
|
params=[
|
||||||
|
(
|
||||||
|
PaidMediaPreview,
|
||||||
|
PaidMedia.PREVIEW,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PaidMediaPhoto,
|
||||||
|
PaidMedia.PHOTO,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
PaidMediaVideo,
|
||||||
|
PaidMedia.VIDEO,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=[
|
||||||
|
PaidMedia.PREVIEW,
|
||||||
|
PaidMedia.PHOTO,
|
||||||
|
PaidMedia.VIDEO,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def pm_scope_class_and_type(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def paid_media(pm_scope_class_and_type):
|
||||||
|
# We use de_json here so that we don't have to worry about which class gets which arguments
|
||||||
|
return pm_scope_class_and_type[0].de_json(
|
||||||
|
{
|
||||||
|
"type": pm_scope_class_and_type[1],
|
||||||
|
"width": TestPaidMediaBase.width,
|
||||||
|
"height": TestPaidMediaBase.height,
|
||||||
|
"duration": TestPaidMediaBase.duration,
|
||||||
|
"video": TestPaidMediaBase.video.to_dict(),
|
||||||
|
"photo": [p.to_dict() for p in TestPaidMediaBase.photo],
|
||||||
|
},
|
||||||
|
bot=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def paid_media_video():
|
||||||
|
return PaidMediaVideo(video=TestPaidMediaBase.video)
|
||||||
|
|
||||||
|
|
||||||
|
def paid_media_photo():
|
||||||
|
return PaidMediaPhoto(photo=TestPaidMediaBase.photo)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def paid_media_info():
|
||||||
|
return PaidMediaInfo(
|
||||||
|
star_count=TestPaidMediaInfoBase.star_count,
|
||||||
|
paid_media=[paid_media_video(), paid_media_photo()],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaidMediaBase:
|
||||||
|
width = 640
|
||||||
|
height = 480
|
||||||
|
duration = 60
|
||||||
|
video = Video(
|
||||||
|
file_id="video_file_id",
|
||||||
|
width=640,
|
||||||
|
height=480,
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
duration=60,
|
||||||
|
)
|
||||||
|
photo = (
|
||||||
|
PhotoSize(
|
||||||
|
file_id="photo_file_id",
|
||||||
|
width=640,
|
||||||
|
height=480,
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaidMediaWithoutRequest(TestPaidMediaBase):
|
||||||
|
def test_slot_behaviour(self, paid_media):
|
||||||
|
inst = paid_media
|
||||||
|
for attr in inst.__slots__:
|
||||||
|
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_de_json(self, bot, pm_scope_class_and_type):
|
||||||
|
cls = pm_scope_class_and_type[0]
|
||||||
|
type_ = pm_scope_class_and_type[1]
|
||||||
|
|
||||||
|
json_dict = {
|
||||||
|
"type": type_,
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height,
|
||||||
|
"duration": self.duration,
|
||||||
|
"video": self.video.to_dict(),
|
||||||
|
"photo": [p.to_dict() for p in self.photo],
|
||||||
|
}
|
||||||
|
pm = PaidMedia.de_json(json_dict, bot)
|
||||||
|
assert set(pm.api_kwargs.keys()) == {
|
||||||
|
"width",
|
||||||
|
"height",
|
||||||
|
"duration",
|
||||||
|
"video",
|
||||||
|
"photo",
|
||||||
|
} - set(cls.__slots__)
|
||||||
|
|
||||||
|
assert isinstance(pm, PaidMedia)
|
||||||
|
assert type(pm) is cls
|
||||||
|
assert pm.type == type_
|
||||||
|
if "width" in cls.__slots__:
|
||||||
|
assert pm.width == self.width
|
||||||
|
assert pm.height == self.height
|
||||||
|
assert pm.duration == self.duration
|
||||||
|
if "video" in cls.__slots__:
|
||||||
|
assert pm.video == self.video
|
||||||
|
if "photo" in cls.__slots__:
|
||||||
|
assert pm.photo == self.photo
|
||||||
|
|
||||||
|
assert cls.de_json(None, bot) is None
|
||||||
|
assert PaidMedia.de_json({}, bot) is None
|
||||||
|
|
||||||
|
def test_de_json_invalid_type(self, bot):
|
||||||
|
json_dict = {
|
||||||
|
"type": "invalid",
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height,
|
||||||
|
"duration": self.duration,
|
||||||
|
"video": self.video.to_dict(),
|
||||||
|
"photo": [p.to_dict() for p in self.photo],
|
||||||
|
}
|
||||||
|
pm = PaidMedia.de_json(json_dict, bot)
|
||||||
|
assert pm.api_kwargs == {
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height,
|
||||||
|
"duration": self.duration,
|
||||||
|
"video": self.video.to_dict(),
|
||||||
|
"photo": [p.to_dict() for p in self.photo],
|
||||||
|
}
|
||||||
|
|
||||||
|
assert type(pm) is PaidMedia
|
||||||
|
assert pm.type == "invalid"
|
||||||
|
|
||||||
|
def test_de_json_subclass(self, pm_scope_class, bot):
|
||||||
|
"""This makes sure that e.g. PaidMediaPreivew(data) never returns a
|
||||||
|
TransactionPartnerPhoto instance."""
|
||||||
|
json_dict = {
|
||||||
|
"type": "invalid",
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height,
|
||||||
|
"duration": self.duration,
|
||||||
|
"video": self.video.to_dict(),
|
||||||
|
"photo": [p.to_dict() for p in self.photo],
|
||||||
|
}
|
||||||
|
assert type(pm_scope_class.de_json(json_dict, bot)) is pm_scope_class
|
||||||
|
|
||||||
|
def test_to_dict(self, paid_media):
|
||||||
|
pm_dict = paid_media.to_dict()
|
||||||
|
|
||||||
|
assert isinstance(pm_dict, dict)
|
||||||
|
assert pm_dict["type"] == paid_media.type
|
||||||
|
if hasattr(paid_media_info, "width"):
|
||||||
|
assert pm_dict["width"] == paid_media.width
|
||||||
|
assert pm_dict["height"] == paid_media.height
|
||||||
|
assert pm_dict["duration"] == paid_media.duration
|
||||||
|
if hasattr(paid_media_info, "video"):
|
||||||
|
assert pm_dict["video"] == paid_media.video.to_dict()
|
||||||
|
if hasattr(paid_media_info, "photo"):
|
||||||
|
assert pm_dict["photo"] == [p.to_dict() for p in paid_media.photo]
|
||||||
|
|
||||||
|
def test_type_enum_conversion(self):
|
||||||
|
assert type(PaidMedia("video").type) is PaidMediaType
|
||||||
|
assert PaidMedia("unknown").type == "unknown"
|
||||||
|
|
||||||
|
def test_equality(self, paid_media, bot):
|
||||||
|
a = PaidMedia("base_type")
|
||||||
|
b = PaidMedia("base_type")
|
||||||
|
c = paid_media
|
||||||
|
d = deepcopy(paid_media)
|
||||||
|
e = Dice(4, "emoji")
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert c == d
|
||||||
|
assert hash(c) == hash(d)
|
||||||
|
|
||||||
|
assert c != e
|
||||||
|
assert hash(c) != hash(e)
|
||||||
|
|
||||||
|
if hasattr(c, "video"):
|
||||||
|
json_dict = c.to_dict()
|
||||||
|
json_dict["video"] = Video("different", "d2", 1, 1, 1).to_dict()
|
||||||
|
f = c.__class__.de_json(json_dict, bot)
|
||||||
|
|
||||||
|
assert c != f
|
||||||
|
assert hash(c) != hash(f)
|
||||||
|
|
||||||
|
if hasattr(c, "photo"):
|
||||||
|
json_dict = c.to_dict()
|
||||||
|
json_dict["photo"] = [PhotoSize("different", "d2", 1, 1, 1).to_dict()]
|
||||||
|
f = c.__class__.de_json(json_dict, bot)
|
||||||
|
|
||||||
|
assert c != f
|
||||||
|
assert hash(c) != hash(f)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaidMediaInfoBase:
|
||||||
|
star_count = 200
|
||||||
|
paid_media = [paid_media_video(), paid_media_photo()]
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaidMediaInfoWithoutRequest(TestPaidMediaInfoBase):
|
||||||
|
def test_slot_behaviour(self, paid_media_info):
|
||||||
|
inst = paid_media_info
|
||||||
|
for attr in inst.__slots__:
|
||||||
|
assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_de_json(self, bot):
|
||||||
|
json_dict = {
|
||||||
|
"star_count": self.star_count,
|
||||||
|
"paid_media": [t.to_dict() for t in self.paid_media],
|
||||||
|
}
|
||||||
|
pmi = PaidMediaInfo.de_json(json_dict, bot)
|
||||||
|
pmi_none = PaidMediaInfo.de_json(None, bot)
|
||||||
|
assert pmi.paid_media == tuple(self.paid_media)
|
||||||
|
assert pmi.star_count == self.star_count
|
||||||
|
assert pmi_none is None
|
||||||
|
|
||||||
|
def test_to_dict(self, paid_media_info):
|
||||||
|
assert paid_media_info.to_dict() == {
|
||||||
|
"star_count": self.star_count,
|
||||||
|
"paid_media": [t.to_dict() for t in self.paid_media],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_equality(self):
|
||||||
|
pmi1 = PaidMediaInfo(
|
||||||
|
star_count=self.star_count, paid_media=[paid_media_video(), paid_media_photo()]
|
||||||
|
)
|
||||||
|
pmi2 = PaidMediaInfo(
|
||||||
|
star_count=self.star_count, paid_media=[paid_media_video(), paid_media_photo()]
|
||||||
|
)
|
||||||
|
pmi3 = PaidMediaInfo(star_count=100, paid_media=[paid_media_photo()])
|
||||||
|
|
||||||
|
assert pmi1 == pmi2
|
||||||
|
assert hash(pmi1) == hash(pmi2)
|
||||||
|
|
||||||
|
assert pmi1 != pmi3
|
||||||
|
assert hash(pmi1) != hash(pmi3)
|
|
@ -29,6 +29,8 @@ from telegram import (
|
||||||
LinkPreviewOptions,
|
LinkPreviewOptions,
|
||||||
MessageEntity,
|
MessageEntity,
|
||||||
MessageOriginUser,
|
MessageOriginUser,
|
||||||
|
PaidMediaInfo,
|
||||||
|
PaidMediaPreview,
|
||||||
ReplyParameters,
|
ReplyParameters,
|
||||||
TextQuote,
|
TextQuote,
|
||||||
User,
|
User,
|
||||||
|
@ -44,6 +46,7 @@ def external_reply_info():
|
||||||
message_id=TestExternalReplyInfoBase.message_id,
|
message_id=TestExternalReplyInfoBase.message_id,
|
||||||
link_preview_options=TestExternalReplyInfoBase.link_preview_options,
|
link_preview_options=TestExternalReplyInfoBase.link_preview_options,
|
||||||
giveaway=TestExternalReplyInfoBase.giveaway,
|
giveaway=TestExternalReplyInfoBase.giveaway,
|
||||||
|
paid_media=TestExternalReplyInfoBase.paid_media,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,6 +62,7 @@ class TestExternalReplyInfoBase:
|
||||||
dtm.datetime.now(dtm.timezone.utc).replace(microsecond=0),
|
dtm.datetime.now(dtm.timezone.utc).replace(microsecond=0),
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
paid_media = PaidMediaInfo(5, [PaidMediaPreview(10, 10, 10)])
|
||||||
|
|
||||||
|
|
||||||
class TestExternalReplyInfoWithoutRequest(TestExternalReplyInfoBase):
|
class TestExternalReplyInfoWithoutRequest(TestExternalReplyInfoBase):
|
||||||
|
@ -76,6 +80,7 @@ class TestExternalReplyInfoWithoutRequest(TestExternalReplyInfoBase):
|
||||||
"message_id": self.message_id,
|
"message_id": self.message_id,
|
||||||
"link_preview_options": self.link_preview_options.to_dict(),
|
"link_preview_options": self.link_preview_options.to_dict(),
|
||||||
"giveaway": self.giveaway.to_dict(),
|
"giveaway": self.giveaway.to_dict(),
|
||||||
|
"paid_media": self.paid_media.to_dict(),
|
||||||
}
|
}
|
||||||
|
|
||||||
external_reply_info = ExternalReplyInfo.de_json(json_dict, bot)
|
external_reply_info = ExternalReplyInfo.de_json(json_dict, bot)
|
||||||
|
@ -86,6 +91,7 @@ class TestExternalReplyInfoWithoutRequest(TestExternalReplyInfoBase):
|
||||||
assert external_reply_info.message_id == self.message_id
|
assert external_reply_info.message_id == self.message_id
|
||||||
assert external_reply_info.link_preview_options == self.link_preview_options
|
assert external_reply_info.link_preview_options == self.link_preview_options
|
||||||
assert external_reply_info.giveaway == self.giveaway
|
assert external_reply_info.giveaway == self.giveaway
|
||||||
|
assert external_reply_info.paid_media == self.paid_media
|
||||||
|
|
||||||
assert ExternalReplyInfo.de_json(None, bot) is None
|
assert ExternalReplyInfo.de_json(None, bot) is None
|
||||||
|
|
||||||
|
@ -98,6 +104,7 @@ class TestExternalReplyInfoWithoutRequest(TestExternalReplyInfoBase):
|
||||||
assert ext_reply_info_dict["message_id"] == self.message_id
|
assert ext_reply_info_dict["message_id"] == self.message_id
|
||||||
assert ext_reply_info_dict["link_preview_options"] == self.link_preview_options.to_dict()
|
assert ext_reply_info_dict["link_preview_options"] == self.link_preview_options.to_dict()
|
||||||
assert ext_reply_info_dict["giveaway"] == self.giveaway.to_dict()
|
assert ext_reply_info_dict["giveaway"] == self.giveaway.to_dict()
|
||||||
|
assert ext_reply_info_dict["paid_media"] == self.paid_media.to_dict()
|
||||||
|
|
||||||
def test_equality(self, external_reply_info):
|
def test_equality(self, external_reply_info):
|
||||||
a = external_reply_info
|
a = external_reply_info
|
||||||
|
|
|
@ -33,6 +33,7 @@ from telegram import (
|
||||||
TransactionPartner,
|
TransactionPartner,
|
||||||
TransactionPartnerFragment,
|
TransactionPartnerFragment,
|
||||||
TransactionPartnerOther,
|
TransactionPartnerOther,
|
||||||
|
TransactionPartnerTelegramAds,
|
||||||
TransactionPartnerUser,
|
TransactionPartnerUser,
|
||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
|
@ -101,6 +102,7 @@ def star_transactions():
|
||||||
TransactionPartner.FRAGMENT,
|
TransactionPartner.FRAGMENT,
|
||||||
TransactionPartner.OTHER,
|
TransactionPartner.OTHER,
|
||||||
TransactionPartner.USER,
|
TransactionPartner.USER,
|
||||||
|
TransactionPartner.TELEGRAM_ADS,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def tp_scope_type(request):
|
def tp_scope_type(request):
|
||||||
|
@ -113,11 +115,13 @@ def tp_scope_type(request):
|
||||||
TransactionPartnerFragment,
|
TransactionPartnerFragment,
|
||||||
TransactionPartnerOther,
|
TransactionPartnerOther,
|
||||||
TransactionPartnerUser,
|
TransactionPartnerUser,
|
||||||
|
TransactionPartnerTelegramAds,
|
||||||
],
|
],
|
||||||
ids=[
|
ids=[
|
||||||
TransactionPartner.FRAGMENT,
|
TransactionPartner.FRAGMENT,
|
||||||
TransactionPartner.OTHER,
|
TransactionPartner.OTHER,
|
||||||
TransactionPartner.USER,
|
TransactionPartner.USER,
|
||||||
|
TransactionPartner.TELEGRAM_ADS,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def tp_scope_class(request):
|
def tp_scope_class(request):
|
||||||
|
@ -130,11 +134,13 @@ def tp_scope_class(request):
|
||||||
(TransactionPartnerFragment, TransactionPartner.FRAGMENT),
|
(TransactionPartnerFragment, TransactionPartner.FRAGMENT),
|
||||||
(TransactionPartnerOther, TransactionPartner.OTHER),
|
(TransactionPartnerOther, TransactionPartner.OTHER),
|
||||||
(TransactionPartnerUser, TransactionPartner.USER),
|
(TransactionPartnerUser, TransactionPartner.USER),
|
||||||
|
(TransactionPartnerTelegramAds, TransactionPartner.TELEGRAM_ADS),
|
||||||
],
|
],
|
||||||
ids=[
|
ids=[
|
||||||
TransactionPartner.FRAGMENT,
|
TransactionPartner.FRAGMENT,
|
||||||
TransactionPartner.OTHER,
|
TransactionPartner.OTHER,
|
||||||
TransactionPartner.USER,
|
TransactionPartner.USER,
|
||||||
|
TransactionPartner.TELEGRAM_ADS,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def tp_scope_class_and_type(request):
|
def tp_scope_class_and_type(request):
|
||||||
|
@ -147,6 +153,7 @@ def transaction_partner(tp_scope_class_and_type):
|
||||||
return tp_scope_class_and_type[0].de_json(
|
return tp_scope_class_and_type[0].de_json(
|
||||||
{
|
{
|
||||||
"type": tp_scope_class_and_type[1],
|
"type": tp_scope_class_and_type[1],
|
||||||
|
"invoice_payload": TestTransactionPartnerBase.invoice_payload,
|
||||||
"withdrawal_state": TestTransactionPartnerBase.withdrawal_state.to_dict(),
|
"withdrawal_state": TestTransactionPartnerBase.withdrawal_state.to_dict(),
|
||||||
"user": TestTransactionPartnerBase.user.to_dict(),
|
"user": TestTransactionPartnerBase.user.to_dict(),
|
||||||
},
|
},
|
||||||
|
@ -244,6 +251,7 @@ class TestStarTransactionWithoutRequest(TestStarTransactionBase):
|
||||||
}
|
}
|
||||||
st = StarTransaction.de_json(json_dict, bot)
|
st = StarTransaction.de_json(json_dict, bot)
|
||||||
st_none = StarTransaction.de_json(None, bot)
|
st_none = StarTransaction.de_json(None, bot)
|
||||||
|
assert st.api_kwargs == {}
|
||||||
assert st.id == self.id
|
assert st.id == self.id
|
||||||
assert st.amount == self.amount
|
assert st.amount == self.amount
|
||||||
assert st.date == from_timestamp(self.date)
|
assert st.date == from_timestamp(self.date)
|
||||||
|
@ -329,6 +337,7 @@ class TestStarTransactionsWithoutRequest(TestStarTransactionsBase):
|
||||||
}
|
}
|
||||||
st = StarTransactions.de_json(json_dict, bot)
|
st = StarTransactions.de_json(json_dict, bot)
|
||||||
st_none = StarTransactions.de_json(None, bot)
|
st_none = StarTransactions.de_json(None, bot)
|
||||||
|
assert st.api_kwargs == {}
|
||||||
assert st.transactions == tuple(self.transactions)
|
assert st.transactions == tuple(self.transactions)
|
||||||
assert st_none is None
|
assert st_none is None
|
||||||
|
|
||||||
|
@ -359,6 +368,7 @@ class TestStarTransactionsWithoutRequest(TestStarTransactionsBase):
|
||||||
class TestTransactionPartnerBase:
|
class TestTransactionPartnerBase:
|
||||||
withdrawal_state = withdrawal_state_succeeded()
|
withdrawal_state = withdrawal_state_succeeded()
|
||||||
user = transaction_partner_user().user
|
user = transaction_partner_user().user
|
||||||
|
invoice_payload = "payload"
|
||||||
|
|
||||||
|
|
||||||
class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
|
@ -374,11 +384,14 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
|
|
||||||
json_dict = {
|
json_dict = {
|
||||||
"type": type_,
|
"type": type_,
|
||||||
|
"invoice_payload": self.invoice_payload,
|
||||||
"withdrawal_state": self.withdrawal_state.to_dict(),
|
"withdrawal_state": self.withdrawal_state.to_dict(),
|
||||||
"user": self.user.to_dict(),
|
"user": self.user.to_dict(),
|
||||||
}
|
}
|
||||||
tp = TransactionPartner.de_json(json_dict, bot)
|
tp = TransactionPartner.de_json(json_dict, bot)
|
||||||
assert set(tp.api_kwargs.keys()) == {"user", "withdrawal_state"} - set(cls.__slots__)
|
assert set(tp.api_kwargs.keys()) == {"user", "withdrawal_state", "invoice_payload"} - set(
|
||||||
|
cls.__slots__
|
||||||
|
)
|
||||||
|
|
||||||
assert isinstance(tp, TransactionPartner)
|
assert isinstance(tp, TransactionPartner)
|
||||||
assert type(tp) is cls
|
assert type(tp) is cls
|
||||||
|
@ -387,6 +400,7 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
assert tp.withdrawal_state == self.withdrawal_state
|
assert tp.withdrawal_state == self.withdrawal_state
|
||||||
if "user" in cls.__slots__:
|
if "user" in cls.__slots__:
|
||||||
assert tp.user == self.user
|
assert tp.user == self.user
|
||||||
|
assert tp.invoice_payload == self.invoice_payload
|
||||||
|
|
||||||
assert cls.de_json(None, bot) is None
|
assert cls.de_json(None, bot) is None
|
||||||
assert TransactionPartner.de_json({}, bot) is None
|
assert TransactionPartner.de_json({}, bot) is None
|
||||||
|
@ -394,6 +408,7 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
def test_de_json_invalid_type(self, bot):
|
def test_de_json_invalid_type(self, bot):
|
||||||
json_dict = {
|
json_dict = {
|
||||||
"type": "invalid",
|
"type": "invalid",
|
||||||
|
"invoice_payload": self.invoice_payload,
|
||||||
"withdrawal_state": self.withdrawal_state.to_dict(),
|
"withdrawal_state": self.withdrawal_state.to_dict(),
|
||||||
"user": self.user.to_dict(),
|
"user": self.user.to_dict(),
|
||||||
}
|
}
|
||||||
|
@ -401,6 +416,7 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
assert tp.api_kwargs == {
|
assert tp.api_kwargs == {
|
||||||
"withdrawal_state": self.withdrawal_state.to_dict(),
|
"withdrawal_state": self.withdrawal_state.to_dict(),
|
||||||
"user": self.user.to_dict(),
|
"user": self.user.to_dict(),
|
||||||
|
"invoice_payload": self.invoice_payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert type(tp) is TransactionPartner
|
assert type(tp) is TransactionPartner
|
||||||
|
@ -411,6 +427,7 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
TransactionPartnerFragment instance."""
|
TransactionPartnerFragment instance."""
|
||||||
json_dict = {
|
json_dict = {
|
||||||
"type": "invalid",
|
"type": "invalid",
|
||||||
|
"invoice_payload": self.invoice_payload,
|
||||||
"withdrawal_state": self.withdrawal_state.to_dict(),
|
"withdrawal_state": self.withdrawal_state.to_dict(),
|
||||||
"user": self.user.to_dict(),
|
"user": self.user.to_dict(),
|
||||||
}
|
}
|
||||||
|
@ -423,6 +440,7 @@ class TestTransactionPartnerWithoutRequest(TestTransactionPartnerBase):
|
||||||
assert tp_dict["type"] == transaction_partner.type
|
assert tp_dict["type"] == transaction_partner.type
|
||||||
if hasattr(transaction_partner, "user"):
|
if hasattr(transaction_partner, "user"):
|
||||||
assert tp_dict["user"] == transaction_partner.user.to_dict()
|
assert tp_dict["user"] == transaction_partner.user.to_dict()
|
||||||
|
assert tp_dict["invoice_payload"] == transaction_partner.invoice_payload
|
||||||
if hasattr(transaction_partner, "withdrawal_state"):
|
if hasattr(transaction_partner, "withdrawal_state"):
|
||||||
assert tp_dict["withdrawal_state"] == transaction_partner.withdrawal_state.to_dict()
|
assert tp_dict["withdrawal_state"] == transaction_partner.withdrawal_state.to_dict()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue