mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-13 18:30:40 +01:00
This commit is contained in:
parent
151123745e
commit
ef1685c436
32 changed files with 1479 additions and 45 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.11-blue?logo=telegram
|
.. image:: https://img.shields.io/badge/Bot%20API-8.0-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
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ After installing_ the library, be sure to check out the section on `working with
|
||||||
Telegram API support
|
Telegram API support
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
All types and methods of the Telegram Bot API **7.11** are natively supported by this library.
|
All types and methods of the Telegram Bot API **8.0** are natively supported by this library.
|
||||||
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
|
In addition, Bot API functionality not yet natively included can still be used as described `in our wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Bot-API-Forward-Compatibility>`_.
|
||||||
|
|
||||||
Notable Features
|
Notable Features
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
- Used for sending documents
|
- Used for sending documents
|
||||||
* - :meth:`~telegram.Bot.send_game`
|
* - :meth:`~telegram.Bot.send_game`
|
||||||
- Used for sending a game
|
- Used for sending a game
|
||||||
|
* - :meth:`~telegram.Bot.send_gift`
|
||||||
|
- Used for sending a gift
|
||||||
* - :meth:`~telegram.Bot.send_invoice`
|
* - :meth:`~telegram.Bot.send_invoice`
|
||||||
- Used for sending an invoice
|
- Used for sending an invoice
|
||||||
* - :meth:`~telegram.Bot.send_location`
|
* - :meth:`~telegram.Bot.send_location`
|
||||||
|
@ -151,6 +153,8 @@
|
||||||
- Used for setting a chat title
|
- Used for setting a chat title
|
||||||
* - :meth:`~telegram.Bot.set_chat_description`
|
* - :meth:`~telegram.Bot.set_chat_description`
|
||||||
- Used for setting the description of a chat
|
- Used for setting the description of a chat
|
||||||
|
* - :meth:`~telegram.Bot.set_user_emoji_status`
|
||||||
|
- Used for setting the users status emoji
|
||||||
* - :meth:`~telegram.Bot.pin_chat_message`
|
* - :meth:`~telegram.Bot.pin_chat_message`
|
||||||
- Used for pinning a message
|
- Used for pinning a message
|
||||||
* - :meth:`~telegram.Bot.unpin_chat_message`
|
* - :meth:`~telegram.Bot.unpin_chat_message`
|
||||||
|
@ -355,7 +359,7 @@
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Miscellaneous</summary>
|
<summary>Payments and Stars</summary>
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
:align: left
|
:align: left
|
||||||
|
@ -363,18 +367,39 @@
|
||||||
|
|
||||||
* - :meth:`~telegram.Bot.create_invoice_link`
|
* - :meth:`~telegram.Bot.create_invoice_link`
|
||||||
- Used to generate an HTTP link for an invoice
|
- Used to generate an HTTP link for an invoice
|
||||||
|
* - :meth:`~telegram.Bot.edit_user_star_subscription`
|
||||||
|
- Used for editing a user's star subscription
|
||||||
|
* - :meth:`~telegram.Bot.get_star_transactions`
|
||||||
|
- Used for obtaining the bot's Telegram Stars transactions
|
||||||
|
* - :meth:`~telegram.Bot.refund_star_payment`
|
||||||
|
- Used for refunding a payment in Telegram Stars
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Miscellaneous</summary>
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:align: left
|
||||||
|
:widths: 1 4
|
||||||
|
|
||||||
* - :meth:`~telegram.Bot.close`
|
* - :meth:`~telegram.Bot.close`
|
||||||
- Used for closing server instance when switching to another local server
|
- Used for closing server instance when switching to another local server
|
||||||
* - :meth:`~telegram.Bot.log_out`
|
* - :meth:`~telegram.Bot.log_out`
|
||||||
- Used for logging out from cloud Bot API server
|
- Used for logging out from cloud Bot API server
|
||||||
* - :meth:`~telegram.Bot.get_file`
|
* - :meth:`~telegram.Bot.get_file`
|
||||||
- Used for getting basic info about a file
|
- Used for getting basic info about a file
|
||||||
|
* - :meth:`~telegram.Bot.get_available_gifts`
|
||||||
|
- Used for getting information about gifts available for sending
|
||||||
* - :meth:`~telegram.Bot.get_me`
|
* - :meth:`~telegram.Bot.get_me`
|
||||||
- Used for getting basic information about the bot
|
- Used for getting basic information about the bot
|
||||||
* - :meth:`~telegram.Bot.get_star_transactions`
|
* - :meth:`~telegram.Bot.save_prepared_inline_message`
|
||||||
- Used for obtaining the bot's Telegram Stars transactions
|
- Used for storing a message to be sent by a user of a Mini App
|
||||||
* - :meth:`~telegram.Bot.refund_star_payment`
|
|
||||||
- Used for refunding a payment in Telegram Stars
|
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,6 @@ Available Types
|
||||||
telegram.inputpaidmediaphoto
|
telegram.inputpaidmediaphoto
|
||||||
telegram.inputpaidmediavideo
|
telegram.inputpaidmediavideo
|
||||||
telegram.inputpolloption
|
telegram.inputpolloption
|
||||||
telegram.inputsticker
|
|
||||||
telegram.keyboardbutton
|
telegram.keyboardbutton
|
||||||
telegram.keyboardbuttonpolltype
|
telegram.keyboardbuttonpolltype
|
||||||
telegram.keyboardbuttonrequestchat
|
telegram.keyboardbuttonrequestchat
|
||||||
|
|
6
docs/source/telegram.gift.rst
Normal file
6
docs/source/telegram.gift.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Gift
|
||||||
|
====
|
||||||
|
|
||||||
|
.. autoclass:: telegram.Gift
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.gifts.rst
Normal file
6
docs/source/telegram.gifts.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Gifts
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. autoclass:: telegram.Gifts
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
|
@ -42,3 +42,4 @@ To enable this option, send the ``/setinline`` command to `@BotFather <https://t
|
||||||
telegram.inputvenuemessagecontent
|
telegram.inputvenuemessagecontent
|
||||||
telegram.inputcontactmessagecontent
|
telegram.inputcontactmessagecontent
|
||||||
telegram.inputinvoicemessagecontent
|
telegram.inputinvoicemessagecontent
|
||||||
|
telegram.preparedinlinemessage
|
||||||
|
|
6
docs/source/telegram.preparedinlinemessage.rst
Normal file
6
docs/source/telegram.preparedinlinemessage.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
PreparedInlineMessage
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.PreparedInlineMessage
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
|
@ -6,6 +6,9 @@ The following methods and objects allow your bot to handle stickers and sticker
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:titlesonly:
|
:titlesonly:
|
||||||
|
|
||||||
|
telegram.gift
|
||||||
|
telegram.gifts
|
||||||
|
telegram.inputsticker
|
||||||
telegram.maskposition
|
telegram.maskposition
|
||||||
telegram.sticker
|
telegram.sticker
|
||||||
telegram.stickerset
|
telegram.stickerset
|
||||||
|
|
|
@ -95,3 +95,5 @@
|
||||||
.. |tg_stars| replace:: `Telegram Stars <https://t.me/BotNews/90>`__
|
.. |tg_stars| replace:: `Telegram Stars <https://t.me/BotNews/90>`__
|
||||||
|
|
||||||
.. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits <https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once>`__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance.
|
.. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits <https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once>`__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance.
|
||||||
|
|
||||||
|
.. |tz-naive-dtms| replace:: For timezone naive :obj:`datetime.datetime` objects, the default timezone of the bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
|
|
@ -101,6 +101,8 @@ __all__ = (
|
||||||
"GameHighScore",
|
"GameHighScore",
|
||||||
"GeneralForumTopicHidden",
|
"GeneralForumTopicHidden",
|
||||||
"GeneralForumTopicUnhidden",
|
"GeneralForumTopicUnhidden",
|
||||||
|
"Gift",
|
||||||
|
"Gifts",
|
||||||
"Giveaway",
|
"Giveaway",
|
||||||
"GiveawayCompleted",
|
"GiveawayCompleted",
|
||||||
"GiveawayCreated",
|
"GiveawayCreated",
|
||||||
|
@ -201,6 +203,7 @@ __all__ = (
|
||||||
"PollAnswer",
|
"PollAnswer",
|
||||||
"PollOption",
|
"PollOption",
|
||||||
"PreCheckoutQuery",
|
"PreCheckoutQuery",
|
||||||
|
"PreparedInlineMessage",
|
||||||
"ProximityAlertTriggered",
|
"ProximityAlertTriggered",
|
||||||
"ReactionCount",
|
"ReactionCount",
|
||||||
"ReactionType",
|
"ReactionType",
|
||||||
|
@ -373,6 +376,7 @@ from ._forumtopic import (
|
||||||
from ._games.callbackgame import CallbackGame
|
from ._games.callbackgame import CallbackGame
|
||||||
from ._games.game import Game
|
from ._games.game import Game
|
||||||
from ._games.gamehighscore import GameHighScore
|
from ._games.gamehighscore import GameHighScore
|
||||||
|
from ._gifts import Gift, Gifts
|
||||||
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
|
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
|
||||||
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
|
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||||
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||||
|
@ -405,6 +409,7 @@ from ._inline.inputlocationmessagecontent import InputLocationMessageContent
|
||||||
from ._inline.inputmessagecontent import InputMessageContent
|
from ._inline.inputmessagecontent import InputMessageContent
|
||||||
from ._inline.inputtextmessagecontent import InputTextMessageContent
|
from ._inline.inputtextmessagecontent import InputTextMessageContent
|
||||||
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
|
from ._inline.inputvenuemessagecontent import InputVenueMessageContent
|
||||||
|
from ._inline.preparedinlinemessage import PreparedInlineMessage
|
||||||
from ._keyboardbutton import KeyboardButton
|
from ._keyboardbutton import KeyboardButton
|
||||||
from ._keyboardbuttonpolltype import KeyboardButtonPollType
|
from ._keyboardbuttonpolltype import KeyboardButtonPollType
|
||||||
from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
|
from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
|
||||||
|
|
304
telegram/_bot.py
304
telegram/_bot.py
|
@ -24,7 +24,7 @@ import contextlib
|
||||||
import copy
|
import copy
|
||||||
import pickle
|
import pickle
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
|
@ -75,7 +75,9 @@ from telegram._files.videonote import VideoNote
|
||||||
from telegram._files.voice import Voice
|
from telegram._files.voice import Voice
|
||||||
from telegram._forumtopic import ForumTopic
|
from telegram._forumtopic import ForumTopic
|
||||||
from telegram._games.gamehighscore import GameHighScore
|
from telegram._games.gamehighscore import GameHighScore
|
||||||
|
from telegram._gifts import Gift, Gifts
|
||||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||||
|
from telegram._inline.preparedinlinemessage import PreparedInlineMessage
|
||||||
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
|
||||||
|
@ -3641,6 +3643,65 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
api_kwargs=api_kwargs,
|
api_kwargs=api_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def save_prepared_inline_message(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
result: "InlineQueryResult",
|
||||||
|
allow_user_chats: Optional[bool] = None,
|
||||||
|
allow_bot_chats: Optional[bool] = None,
|
||||||
|
allow_group_chats: Optional[bool] = None,
|
||||||
|
allow_channel_chats: Optional[bool] = 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,
|
||||||
|
) -> PreparedInlineMessage:
|
||||||
|
"""Stores a message that can be sent by a user of a Mini App.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (:obj:`int`): Unique identifier of the target user that can use the prepared
|
||||||
|
message.
|
||||||
|
result (:class:`telegram.InlineQueryResult`): The result to store.
|
||||||
|
allow_user_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
|
||||||
|
to private chats with users
|
||||||
|
allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
|
||||||
|
to private chats with bots
|
||||||
|
allow_group_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
|
||||||
|
to group and supergroup chats
|
||||||
|
allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be
|
||||||
|
sent to channels
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`telegram.PreparedInlineMessage`: On success, the prepared message is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`telegram.error.TelegramError`
|
||||||
|
"""
|
||||||
|
data: JSONDict = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"result": result,
|
||||||
|
"allow_user_chats": allow_user_chats,
|
||||||
|
"allow_bot_chats": allow_bot_chats,
|
||||||
|
"allow_group_chats": allow_group_chats,
|
||||||
|
"allow_channel_chats": allow_channel_chats,
|
||||||
|
}
|
||||||
|
return PreparedInlineMessage.de_json( # type: ignore[return-value]
|
||||||
|
await self._post(
|
||||||
|
"savePreparedInlineMessage",
|
||||||
|
data,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=api_kwargs,
|
||||||
|
),
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
|
||||||
async def get_user_profile_photos(
|
async def get_user_profile_photos(
|
||||||
self,
|
self,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
|
@ -3779,9 +3840,7 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
be unbanned, unix time. If user is banned for more than 366 days or less than 30
|
be unbanned, unix time. If user is banned for more than 366 days or less than 30
|
||||||
seconds from the current time they are considered to be banned forever. Applied
|
seconds from the current time they are considered to be banned forever. Applied
|
||||||
for supergroups and channels only.
|
for supergroups and channels only.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from
|
revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from
|
||||||
the chat for the user that is being removed. If :obj:`False`, the user will be able
|
the chat for the user that is being removed. If :obj:`False`, the user will be able
|
||||||
to see messages in the group that were sent before the user was removed.
|
to see messages in the group that were sent before the user was removed.
|
||||||
|
@ -5415,9 +5474,7 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
will be lifted for the user, unix time. If user is restricted for more than 366
|
will be lifted for the user, unix time. If user is restricted for more than 366
|
||||||
days or less than 30 seconds from the current time, they are considered to be
|
days or less than 30 seconds from the current time, they are considered to be
|
||||||
restricted forever.
|
restricted forever.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
permissions (:class:`telegram.ChatPermissions`): An object for new user
|
permissions (:class:`telegram.ChatPermissions`): An object for new user
|
||||||
permissions.
|
permissions.
|
||||||
use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat
|
use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat
|
||||||
|
@ -5761,9 +5818,7 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
|
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
|
||||||
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
||||||
expire. Integer input will be interpreted as Unix timestamp.
|
expire. Integer input will be interpreted as Unix timestamp.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
||||||
the chat simultaneously after joining the chat via this invite link;
|
the chat simultaneously after joining the chat via this invite link;
|
||||||
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
||||||
|
@ -5840,9 +5895,7 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
Now also accepts :class:`telegram.ChatInviteLink` instances.
|
Now also accepts :class:`telegram.ChatInviteLink` instances.
|
||||||
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
|
||||||
expire.
|
expire.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
member_limit (:obj:`int`, optional): Maximum number of users that can be members of
|
||||||
the chat simultaneously after joining the chat via this invite link;
|
the chat simultaneously after joining the chat via this invite link;
|
||||||
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
:tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
|
||||||
|
@ -6176,6 +6229,56 @@ class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
|
||||||
api_kwargs=api_kwargs,
|
api_kwargs=api_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def set_user_emoji_status(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
emoji_status_custom_emoji_id: Optional[str] = None,
|
||||||
|
emoji_status_expiration_date: Optional[Union[int, datetime]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
"""Changes the emoji status for a given user that previously allowed the bot to manage
|
||||||
|
their emoji status via the Mini App method
|
||||||
|
`requestEmojiStatusAccess <https://core.telegram.org/bots/webapps#initializing-mini-apps>`_
|
||||||
|
.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (:obj:`int`): Unique identifier of the target user
|
||||||
|
emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of the
|
||||||
|
emoji status to set. Pass an empty string to remove the status.
|
||||||
|
emoji_status_expiration_date (Union[:obj:`int`, :obj:`datetime.datetime`], optional):
|
||||||
|
Expiration date of the emoji status, if any, as unix timestamp or
|
||||||
|
:class:`datetime.datetime` object.
|
||||||
|
|tz-naive-dtms|
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: On success, :obj:`True` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`telegram.error.TelegramError`
|
||||||
|
|
||||||
|
"""
|
||||||
|
data: JSONDict = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"emoji_status_custom_emoji_id": emoji_status_custom_emoji_id,
|
||||||
|
"emoji_status_expiration_date": emoji_status_expiration_date,
|
||||||
|
}
|
||||||
|
return await self._post(
|
||||||
|
"setUserEmojiStatus",
|
||||||
|
data,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=api_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
async def pin_chat_message(
|
async def pin_chat_message(
|
||||||
self,
|
self,
|
||||||
chat_id: Union[str, int],
|
chat_id: Union[str, int],
|
||||||
|
@ -7127,9 +7230,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
:tg-const:`telegram.Poll.MIN_OPEN_PERIOD` and no more than
|
:tg-const:`telegram.Poll.MIN_OPEN_PERIOD` and no more than
|
||||||
:tg-const:`telegram.Poll.MAX_OPEN_PERIOD` seconds in the future.
|
:tg-const:`telegram.Poll.MAX_OPEN_PERIOD` seconds in the future.
|
||||||
Can't be used together with :paramref:`open_period`.
|
Can't be used together with :paramref:`open_period`.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be
|
is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be
|
||||||
immediately closed. This can be useful for poll preview.
|
immediately closed. This can be useful for poll preview.
|
||||||
disable_notification (:obj:`bool`, optional): |disable_notification|
|
disable_notification (:obj:`bool`, optional): |disable_notification|
|
||||||
|
@ -8024,6 +8125,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
send_phone_number_to_provider: Optional[bool] = None,
|
send_phone_number_to_provider: Optional[bool] = None,
|
||||||
send_email_to_provider: Optional[bool] = None,
|
send_email_to_provider: Optional[bool] = None,
|
||||||
is_flexible: Optional[bool] = None,
|
is_flexible: Optional[bool] = None,
|
||||||
|
subscription_period: Optional[Union[int, timedelta]] = None,
|
||||||
|
business_connection_id: Optional[str] = None,
|
||||||
*,
|
*,
|
||||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
@ -8036,6 +8139,10 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
.. versionadded:: 20.0
|
.. versionadded:: 20.0
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||||
|
For payments in |tg_stars| only.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
|
title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
|
||||||
:tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
|
:tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
|
||||||
description (:obj:`str`): Product description.
|
description (:obj:`str`): Product description.
|
||||||
|
@ -8062,6 +8169,15 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
|
|
||||||
.. versionchanged:: 20.0
|
.. versionchanged:: 20.0
|
||||||
|sequenceargs|
|
|sequenceargs|
|
||||||
|
subscription_period (:obj:`int` | :class:`datetime.timedelta`, optional): The time the
|
||||||
|
subscription will be active for before the next payment, either as number of
|
||||||
|
seconds or as :class:`datetime.timedelta` object. The currency must be set to
|
||||||
|
``“XTR”`` (Telegram Stars) if the parameter is used. Currently, it must always be
|
||||||
|
:tg-const:`telegram.constants.InvoiceLimit.SUBSCRIPTION_PERIOD` if specified. Any
|
||||||
|
number of subscriptions can be active for a given bot at the same time, including
|
||||||
|
multiple concurrent subscriptions from the same user.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
|
max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
|
||||||
*smallest units* of the currency (integer, **not** float/double). For example, for
|
*smallest units* of the currency (integer, **not** float/double). For example, for
|
||||||
a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the ``exp``
|
a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the ``exp``
|
||||||
|
@ -8127,6 +8243,12 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
"is_flexible": is_flexible,
|
"is_flexible": is_flexible,
|
||||||
"send_phone_number_to_provider": send_phone_number_to_provider,
|
"send_phone_number_to_provider": send_phone_number_to_provider,
|
||||||
"send_email_to_provider": send_email_to_provider,
|
"send_email_to_provider": send_email_to_provider,
|
||||||
|
"subscription_period": (
|
||||||
|
subscription_period.total_seconds()
|
||||||
|
if isinstance(subscription_period, timedelta)
|
||||||
|
else subscription_period
|
||||||
|
),
|
||||||
|
"business_connection_id": business_connection_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
return await self._post(
|
return await self._post(
|
||||||
|
@ -9254,6 +9376,53 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
bot=self,
|
bot=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def edit_user_star_subscription(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
telegram_payment_charge_id: str,
|
||||||
|
is_canceled: bool,
|
||||||
|
*,
|
||||||
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> bool:
|
||||||
|
"""Allows the bot to cancel or re-enable extension of a subscription paid in Telegram
|
||||||
|
Stars.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (:obj:`int`): Identifier of the user whose subscription will be edited.
|
||||||
|
telegram_payment_charge_id (:obj:`str`): Telegram payment identifier for the
|
||||||
|
subscription.
|
||||||
|
is_canceled (:obj:`bool`): Pass :obj:`True` to cancel extension of the user
|
||||||
|
subscription; the subscription must be active up to the end of the current
|
||||||
|
subscription period. Pass :obj:`False` to allow the user to re-enable a
|
||||||
|
subscription that was previously canceled by the bot.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: On success, :obj:`True` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`telegram.error.TelegramError`
|
||||||
|
"""
|
||||||
|
data: JSONDict = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"telegram_payment_charge_id": telegram_payment_charge_id,
|
||||||
|
"is_canceled": is_canceled,
|
||||||
|
}
|
||||||
|
return await self._post(
|
||||||
|
"editUserStartSubscription",
|
||||||
|
data,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=api_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
async def send_paid_media(
|
async def send_paid_media(
|
||||||
self,
|
self,
|
||||||
chat_id: Union[str, int],
|
chat_id: Union[str, int],
|
||||||
|
@ -9475,6 +9644,99 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
|
|
||||||
return ChatInviteLink.de_json(result, self) # type: ignore[return-value]
|
return ChatInviteLink.de_json(result, self) # type: ignore[return-value]
|
||||||
|
|
||||||
|
async def get_available_gifts(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
) -> Gifts:
|
||||||
|
"""Returns the list of gifts that can be sent by the bot to users.
|
||||||
|
Requires no parameters.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`telegram.Gifts`
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`telegram.error.TelegramError`
|
||||||
|
"""
|
||||||
|
return Gifts.de_json( # type: ignore[return-value]
|
||||||
|
await self._post(
|
||||||
|
"getAvailableGifts",
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=api_kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def send_gift(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
gift_id: Union[str, Gift],
|
||||||
|
text: Optional[str] = None,
|
||||||
|
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
text_entities: Optional[Sequence["MessageEntity"]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
"""Sends a gift to the given user.
|
||||||
|
The gift can't be converted to Telegram Stars by the user
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (:obj:`int`): Unique identifier of the target user that will receive the gift
|
||||||
|
gift_id (:obj:`str` | :class:`~telegram.Gift`): Identifier of the gift or a
|
||||||
|
:class:`~telegram.Gift` object
|
||||||
|
text (:obj:`str`, optional): Text that will be shown along with the gift;
|
||||||
|
0- :tg-const:`telegram.constants.GiftLimit.MAX_TEXT_LENGTH` characters
|
||||||
|
text_parse_mode (:obj:`str`, optional): Mode for parsing entities.
|
||||||
|
See :class:`telegram.constants.ParseMode` and
|
||||||
|
`formatting options <https://core.telegram.org/bots/api#formatting-options>`__ for
|
||||||
|
more details. Entities other than :attr:`~MessageEntity.BOLD`,
|
||||||
|
:attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
|
||||||
|
:attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
|
||||||
|
:attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
|
||||||
|
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): A list of special
|
||||||
|
entities that appear in the gift text. It can be specified instead of
|
||||||
|
:paramref:`text_parse_mode`. Entities other than :attr:`~MessageEntity.BOLD`,
|
||||||
|
:attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
|
||||||
|
:attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
|
||||||
|
:attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: On success, :obj:`True` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`telegram.error.TelegramError`
|
||||||
|
"""
|
||||||
|
data: JSONDict = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"gift_id": gift_id.id if isinstance(gift_id, Gift) else gift_id,
|
||||||
|
"text": text,
|
||||||
|
"text_parse_mode": text_parse_mode,
|
||||||
|
"text_entities": text_entities,
|
||||||
|
}
|
||||||
|
return await self._post(
|
||||||
|
"sendGift",
|
||||||
|
data,
|
||||||
|
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}
|
||||||
|
@ -9531,6 +9793,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
"""Alias for :meth:`send_chat_action`"""
|
"""Alias for :meth:`send_chat_action`"""
|
||||||
answerInlineQuery = answer_inline_query
|
answerInlineQuery = answer_inline_query
|
||||||
"""Alias for :meth:`answer_inline_query`"""
|
"""Alias for :meth:`answer_inline_query`"""
|
||||||
|
savePreparedInlineMessage = save_prepared_inline_message
|
||||||
|
"""Alias for :meth:`save_prepared_inline_message`"""
|
||||||
getUserProfilePhotos = get_user_profile_photos
|
getUserProfilePhotos = get_user_profile_photos
|
||||||
"""Alias for :meth:`get_user_profile_photos`"""
|
"""Alias for :meth:`get_user_profile_photos`"""
|
||||||
getFile = get_file
|
getFile = get_file
|
||||||
|
@ -9615,6 +9879,8 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
||||||
"""Alias for :meth:`set_chat_title`"""
|
"""Alias for :meth:`set_chat_title`"""
|
||||||
setChatDescription = set_chat_description
|
setChatDescription = set_chat_description
|
||||||
"""Alias for :meth:`set_chat_description`"""
|
"""Alias for :meth:`set_chat_description`"""
|
||||||
|
setUserEmojiStatus = set_user_emoji_status
|
||||||
|
"""Alias for :meth:`set_user_emoji_status`"""
|
||||||
pinChatMessage = pin_chat_message
|
pinChatMessage = pin_chat_message
|
||||||
"""Alias for :meth:`pin_chat_message`"""
|
"""Alias for :meth:`pin_chat_message`"""
|
||||||
unpinChatMessage = unpin_chat_message
|
unpinChatMessage = unpin_chat_message
|
||||||
|
@ -9729,9 +9995,15 @@ 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`"""
|
||||||
|
editUserStarSubscription = edit_user_star_subscription
|
||||||
|
"""Alias for :meth:`edit_user_star_subscription`"""
|
||||||
sendPaidMedia = send_paid_media
|
sendPaidMedia = send_paid_media
|
||||||
"""Alias for :meth:`send_paid_media`"""
|
"""Alias for :meth:`send_paid_media`"""
|
||||||
createChatSubscriptionInviteLink = create_chat_subscription_invite_link
|
createChatSubscriptionInviteLink = create_chat_subscription_invite_link
|
||||||
"""Alias for :meth:`create_chat_subscription_invite_link`"""
|
"""Alias for :meth:`create_chat_subscription_invite_link`"""
|
||||||
editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
|
editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
|
||||||
"""Alias for :meth:`edit_chat_subscription_invite_link`"""
|
"""Alias for :meth:`edit_chat_subscription_invite_link`"""
|
||||||
|
getAvailableGifts = get_available_gifts
|
||||||
|
"""Alias for :meth:`get_available_gifts`"""
|
||||||
|
sendGift = send_gift
|
||||||
|
"""Alias for :meth:`send_gift`"""
|
||||||
|
|
|
@ -44,6 +44,7 @@ if TYPE_CHECKING:
|
||||||
ChatMember,
|
ChatMember,
|
||||||
Contact,
|
Contact,
|
||||||
Document,
|
Document,
|
||||||
|
Gift,
|
||||||
InlineKeyboardMarkup,
|
InlineKeyboardMarkup,
|
||||||
InputMediaAudio,
|
InputMediaAudio,
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
|
@ -3436,6 +3437,46 @@ class _ChatBase(TelegramObject):
|
||||||
allow_paid_broadcast=allow_paid_broadcast,
|
allow_paid_broadcast=allow_paid_broadcast,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def send_gift(
|
||||||
|
self,
|
||||||
|
gift_id: Union[str, "Gift"],
|
||||||
|
text: Optional[str] = None,
|
||||||
|
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
text_entities: Optional[Sequence["MessageEntity"]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
"""Shortcut for::
|
||||||
|
|
||||||
|
await bot.send_gift(user_id=update.effective_chat.id, *args, **kwargs )
|
||||||
|
|
||||||
|
For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`.
|
||||||
|
|
||||||
|
Caution:
|
||||||
|
Can only work, if the chat is a private chat, see :attr:`type`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: On success, :obj:`True` is returned.
|
||||||
|
"""
|
||||||
|
return await self.get_bot().send_gift(
|
||||||
|
user_id=self.id,
|
||||||
|
gift_id=gift_id,
|
||||||
|
text=text,
|
||||||
|
text_parse_mode=text_parse_mode,
|
||||||
|
text_entities=text_entities,
|
||||||
|
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.
|
||||||
|
|
136
telegram/_gifts.py
Normal file
136
telegram/_gifts.py
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
#
|
||||||
|
# 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 classes related to gifs sent by bots."""
|
||||||
|
from collections.abc import Sequence
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from telegram._files.sticker import Sticker
|
||||||
|
from telegram._telegramobject import TelegramObject
|
||||||
|
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||||
|
from telegram._utils.types import JSONDict
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from telegram import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class Gift(TelegramObject):
|
||||||
|
"""This object represents a gift that can be sent by the bot.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal if their :attr:`id` is equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (:obj:`str`): Unique identifier of the gift
|
||||||
|
sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
|
||||||
|
star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
|
||||||
|
total_count (:obj:`int`, optional): The total number of the gifts of this type that can be
|
||||||
|
sent; for limited gifts only
|
||||||
|
remaining_count (:obj:`int`, optional): The number of remaining gifts of this type that can
|
||||||
|
be sent; for limited gifts only
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id (:obj:`str`): Unique identifier of the gift
|
||||||
|
sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
|
||||||
|
star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
|
||||||
|
total_count (:obj:`int`): Optional. The total number of the gifts of this type that can be
|
||||||
|
sent; for limited gifts only
|
||||||
|
remaining_count (:obj:`int`): Optional. The number of remaining gifts of this type that can
|
||||||
|
be sent; for limited gifts only
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("id", "remaining_count", "star_count", "sticker", "total_count")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
id: str,
|
||||||
|
sticker: Sticker,
|
||||||
|
star_count: int,
|
||||||
|
total_count: Optional[int] = None,
|
||||||
|
remaining_count: Optional[int] = None,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.id: str = id
|
||||||
|
self.sticker: Sticker = sticker
|
||||||
|
self.star_count: int = star_count
|
||||||
|
self.total_count: Optional[int] = total_count
|
||||||
|
self.remaining_count: Optional[int] = remaining_count
|
||||||
|
|
||||||
|
self._id_attrs = (self.id,)
|
||||||
|
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gift"]:
|
||||||
|
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||||
|
return cls(**data)
|
||||||
|
|
||||||
|
|
||||||
|
class Gifts(TelegramObject):
|
||||||
|
"""This object represent a list of gifts.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal if their :attr:`gifts` are equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gifts (Sequence[:class:`Gift`]): The sequence of gifts
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
gifts (tuple[:class:`Gift`]): The sequence of gifts
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("gifts",)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
gifts: Sequence[Gift],
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.gifts: tuple[Gift, ...] = parse_sequence_arg(gifts)
|
||||||
|
|
||||||
|
self._id_attrs = (self.gifts,)
|
||||||
|
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gifts"]:
|
||||||
|
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data["gifts"] = Gift.de_list(data.get("gifts"), bot)
|
||||||
|
return cls(**data)
|
83
telegram/_inline/preparedinlinemessage.py
Normal file
83
telegram/_inline/preparedinlinemessage.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#!/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 an object that represents a Telegram Prepared inline Message."""
|
||||||
|
import datetime as dtm
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from telegram._telegramobject import TelegramObject
|
||||||
|
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||||
|
from telegram._utils.types import JSONDict
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from telegram import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class PreparedInlineMessage(TelegramObject):
|
||||||
|
"""Describes an inline message to be sent by a user of a Mini App.
|
||||||
|
|
||||||
|
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||||
|
considered equal, if their :attr:`id` is equal.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (:obj:`str`): Unique identifier of the prepared message
|
||||||
|
expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message.
|
||||||
|
Expired prepared messages can no longer be used.
|
||||||
|
|datetime_localization|
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id (:obj:`str`): Unique identifier of the prepared message
|
||||||
|
expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message.
|
||||||
|
Expired prepared messages can no longer be used.
|
||||||
|
|datetime_localization|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("expiration_date", "id")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
id: str, # pylint: disable=redefined-builtin
|
||||||
|
expiration_date: dtm.datetime,
|
||||||
|
*,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
):
|
||||||
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
|
self.id: str = id
|
||||||
|
self.expiration_date: dtm.datetime = expiration_date
|
||||||
|
|
||||||
|
self._id_attrs = (self.id,)
|
||||||
|
|
||||||
|
self._freeze()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(
|
||||||
|
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||||
|
) -> Optional["PreparedInlineMessage"]:
|
||||||
|
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||||
|
data = cls._parse_data(data)
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Get the local timezone from the bot if it has defaults
|
||||||
|
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||||
|
data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo)
|
||||||
|
|
||||||
|
return super().de_json(data=data, bot=bot)
|
|
@ -19,11 +19,12 @@
|
||||||
# pylint: disable=redefined-builtin
|
# pylint: disable=redefined-builtin
|
||||||
"""This module contains the classes for Telegram Stars transactions."""
|
"""This module contains the classes for Telegram Stars transactions."""
|
||||||
|
|
||||||
|
import datetime as dtm
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from datetime import datetime
|
|
||||||
from typing import TYPE_CHECKING, Final, Optional
|
from typing import TYPE_CHECKING, Final, Optional
|
||||||
|
|
||||||
from telegram import constants
|
from telegram import constants
|
||||||
|
from telegram._gifts import Gift
|
||||||
from telegram._paidmedia import PaidMedia
|
from telegram._paidmedia import PaidMedia
|
||||||
from telegram._telegramobject import TelegramObject
|
from telegram._telegramobject import TelegramObject
|
||||||
from telegram._user import User
|
from telegram._user import User
|
||||||
|
@ -144,7 +145,7 @@ class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
date: datetime,
|
date: dtm.datetime,
|
||||||
url: str,
|
url: str,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
@ -152,7 +153,7 @@ class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState):
|
||||||
super().__init__(type=RevenueWithdrawalState.SUCCEEDED, api_kwargs=api_kwargs)
|
super().__init__(type=RevenueWithdrawalState.SUCCEEDED, api_kwargs=api_kwargs)
|
||||||
|
|
||||||
with self._unfrozen():
|
with self._unfrozen():
|
||||||
self.date: datetime = date
|
self.date: dtm.datetime = date
|
||||||
self.url: str = url
|
self.url: str = url
|
||||||
self._id_attrs = (
|
self._id_attrs = (
|
||||||
self.type,
|
self.type,
|
||||||
|
@ -328,30 +329,51 @@ 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.
|
invoice_payload (:obj:`str`, optional): Bot-specified invoice payload.
|
||||||
|
subscription_period (:class:`datetime.timedelta`, optional): The duration of the paid
|
||||||
|
subscription
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
paid_media (Sequence[:class:`telegram.PaidMedia`], optional): Information about the paid
|
paid_media (Sequence[:class:`telegram.PaidMedia`], optional): Information about the paid
|
||||||
media bought by the user.
|
media bought by the user.
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
.. versionadded:: 21.5
|
||||||
paid_media_payload (:obj:`str`, optional): Optional. Bot-specified paid media payload.
|
paid_media_payload (:obj:`str`, optional): Bot-specified paid media payload.
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
.. versionadded:: 21.6
|
||||||
|
gift (:class:`telegram.Gift`, optional): The gift sent to the user by the bot
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
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.
|
invoice_payload (:obj:`str`): Optional. Bot-specified invoice payload.
|
||||||
|
subscription_period (:class:`datetime.timedelta`): Optional. The duration of the paid
|
||||||
|
subscription
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
paid_media (tuple[:class:`telegram.PaidMedia`]): Optional. Information about the paid
|
paid_media (tuple[:class:`telegram.PaidMedia`]): Optional. Information about the paid
|
||||||
media bought by the user.
|
media bought by the user.
|
||||||
|
|
||||||
.. versionadded:: 21.5
|
.. versionadded:: 21.5
|
||||||
paid_media_payload (:obj:`str`): Optional. Optional. Bot-specified paid media payload.
|
paid_media_payload (:obj:`str`): Optional. Bot-specified paid media payload.
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
.. versionadded:: 21.6
|
||||||
|
gift (:class:`telegram.Gift`): Optional. The gift sent to the user by the bot
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ("invoice_payload", "paid_media", "paid_media_payload", "user")
|
__slots__ = (
|
||||||
|
"gift",
|
||||||
|
"invoice_payload",
|
||||||
|
"paid_media",
|
||||||
|
"paid_media_payload",
|
||||||
|
"subscription_period",
|
||||||
|
"user",
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -359,6 +381,8 @@ class TransactionPartnerUser(TransactionPartner):
|
||||||
invoice_payload: Optional[str] = None,
|
invoice_payload: Optional[str] = None,
|
||||||
paid_media: Optional[Sequence[PaidMedia]] = None,
|
paid_media: Optional[Sequence[PaidMedia]] = None,
|
||||||
paid_media_payload: Optional[str] = None,
|
paid_media_payload: Optional[str] = None,
|
||||||
|
subscription_period: Optional[dtm.timedelta] = None,
|
||||||
|
gift: Optional[Gift] = None,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -369,6 +393,9 @@ class TransactionPartnerUser(TransactionPartner):
|
||||||
self.invoice_payload: Optional[str] = invoice_payload
|
self.invoice_payload: Optional[str] = invoice_payload
|
||||||
self.paid_media: Optional[tuple[PaidMedia, ...]] = parse_sequence_arg(paid_media)
|
self.paid_media: Optional[tuple[PaidMedia, ...]] = parse_sequence_arg(paid_media)
|
||||||
self.paid_media_payload: Optional[str] = paid_media_payload
|
self.paid_media_payload: Optional[str] = paid_media_payload
|
||||||
|
self.subscription_period: Optional[dtm.timedelta] = subscription_period
|
||||||
|
self.gift: Optional[Gift] = gift
|
||||||
|
|
||||||
self._id_attrs = (
|
self._id_attrs = (
|
||||||
self.type,
|
self.type,
|
||||||
self.user,
|
self.user,
|
||||||
|
@ -386,6 +413,12 @@ class TransactionPartnerUser(TransactionPartner):
|
||||||
|
|
||||||
data["user"] = User.de_json(data.get("user"), bot)
|
data["user"] = User.de_json(data.get("user"), bot)
|
||||||
data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot)
|
data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot)
|
||||||
|
data["subscription_period"] = (
|
||||||
|
dtm.timedelta(seconds=sp)
|
||||||
|
if (sp := data.get("subscription_period")) is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
data["gift"] = Gift.de_json(data.get("gift"), bot)
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
return super().de_json(data=data, bot=bot) # type: ignore[return-value]
|
||||||
|
|
||||||
|
@ -496,7 +529,7 @@ class StarTransaction(TelegramObject):
|
||||||
self,
|
self,
|
||||||
id: str,
|
id: str,
|
||||||
amount: int,
|
amount: int,
|
||||||
date: datetime,
|
date: dtm.datetime,
|
||||||
source: Optional[TransactionPartner] = None,
|
source: Optional[TransactionPartner] = None,
|
||||||
receiver: Optional[TransactionPartner] = None,
|
receiver: Optional[TransactionPartner] = None,
|
||||||
*,
|
*,
|
||||||
|
@ -505,7 +538,7 @@ class StarTransaction(TelegramObject):
|
||||||
super().__init__(api_kwargs=api_kwargs)
|
super().__init__(api_kwargs=api_kwargs)
|
||||||
self.id: str = id
|
self.id: str = id
|
||||||
self.amount: int = amount
|
self.amount: int = amount
|
||||||
self.date: datetime = date
|
self.date: dtm.datetime = date
|
||||||
self.source: Optional[TransactionPartner] = source
|
self.source: Optional[TransactionPartner] = source
|
||||||
self.receiver: Optional[TransactionPartner] = receiver
|
self.receiver: Optional[TransactionPartner] = receiver
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
"""This module contains an object that represents a Telegram SuccessfulPayment."""
|
"""This module contains an object that represents a Telegram SuccessfulPayment."""
|
||||||
|
|
||||||
|
import datetime as dtm
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from telegram._payment.orderinfo import OrderInfo
|
from telegram._payment.orderinfo import OrderInfo
|
||||||
from telegram._telegramobject import TelegramObject
|
from telegram._telegramobject import TelegramObject
|
||||||
|
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||||
from telegram._utils.types import JSONDict
|
from telegram._utils.types import JSONDict
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -45,6 +47,17 @@ class SuccessfulPayment(TelegramObject):
|
||||||
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.
|
||||||
|
subscription_expiration_date (:class:`datetime.datetime`, optional): Expiration date of the
|
||||||
|
subscription; for recurring payments only.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
is_recurring (:obj:`bool`, optional): True, if the payment is for a subscription.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
is_first_recurring (:obj:`bool`, optional): True, if the payment is the first payment of a
|
||||||
|
subscription.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
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.
|
||||||
|
@ -61,6 +74,17 @@ class SuccessfulPayment(TelegramObject):
|
||||||
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.
|
||||||
|
subscription_expiration_date (:class:`datetime.datetime`): Optional. Expiration
|
||||||
|
date of the subscription; for recurring payments only.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
is_recurring (:obj:`bool`): Optional. True, if the payment is for a subscription.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
is_first_recurring (:obj:`bool`): Optional. True, if the payment is the first payment of a
|
||||||
|
subscription.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
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.
|
||||||
|
@ -72,9 +96,12 @@ class SuccessfulPayment(TelegramObject):
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"currency",
|
"currency",
|
||||||
"invoice_payload",
|
"invoice_payload",
|
||||||
|
"is_first_recurring",
|
||||||
|
"is_recurring",
|
||||||
"order_info",
|
"order_info",
|
||||||
"provider_payment_charge_id",
|
"provider_payment_charge_id",
|
||||||
"shipping_option_id",
|
"shipping_option_id",
|
||||||
|
"subscription_expiration_date",
|
||||||
"telegram_payment_charge_id",
|
"telegram_payment_charge_id",
|
||||||
"total_amount",
|
"total_amount",
|
||||||
)
|
)
|
||||||
|
@ -88,6 +115,9 @@ class SuccessfulPayment(TelegramObject):
|
||||||
provider_payment_charge_id: str,
|
provider_payment_charge_id: str,
|
||||||
shipping_option_id: Optional[str] = None,
|
shipping_option_id: Optional[str] = None,
|
||||||
order_info: Optional[OrderInfo] = None,
|
order_info: Optional[OrderInfo] = None,
|
||||||
|
subscription_expiration_date: Optional[dtm.datetime] = None,
|
||||||
|
is_recurring: Optional[bool] = None,
|
||||||
|
is_first_recurring: Optional[bool] = None,
|
||||||
*,
|
*,
|
||||||
api_kwargs: Optional[JSONDict] = None,
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
):
|
):
|
||||||
|
@ -99,6 +129,9 @@ class SuccessfulPayment(TelegramObject):
|
||||||
self.order_info: Optional[OrderInfo] = order_info
|
self.order_info: Optional[OrderInfo] = order_info
|
||||||
self.telegram_payment_charge_id: str = telegram_payment_charge_id
|
self.telegram_payment_charge_id: str = telegram_payment_charge_id
|
||||||
self.provider_payment_charge_id: str = provider_payment_charge_id
|
self.provider_payment_charge_id: str = provider_payment_charge_id
|
||||||
|
self.subscription_expiration_date: Optional[dtm.datetime] = subscription_expiration_date
|
||||||
|
self.is_recurring: Optional[bool] = is_recurring
|
||||||
|
self.is_first_recurring: Optional[bool] = is_first_recurring
|
||||||
|
|
||||||
self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)
|
self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id)
|
||||||
|
|
||||||
|
@ -116,4 +149,11 @@ class SuccessfulPayment(TelegramObject):
|
||||||
|
|
||||||
data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot)
|
data["order_info"] = OrderInfo.de_json(data.get("order_info"), bot)
|
||||||
|
|
||||||
|
# Get the local timezone from the bot if it has defaults
|
||||||
|
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||||
|
|
||||||
|
data["subscription_expiration_date"] = from_timestamp(
|
||||||
|
data.get("subscription_expiration_date"), tzinfo=loc_tzinfo
|
||||||
|
)
|
||||||
|
|
||||||
return super().de_json(data=data, bot=bot)
|
return super().de_json(data=data, bot=bot)
|
||||||
|
|
|
@ -636,6 +636,8 @@ class TelegramObject:
|
||||||
|
|
||||||
elif isinstance(value, datetime.datetime):
|
elif isinstance(value, datetime.datetime):
|
||||||
out[key] = to_timestamp(value)
|
out[key] = to_timestamp(value)
|
||||||
|
elif isinstance(value, datetime.timedelta):
|
||||||
|
out[key] = value.total_seconds()
|
||||||
|
|
||||||
for key in pop_keys:
|
for key in pop_keys:
|
||||||
out.pop(key)
|
out.pop(key)
|
||||||
|
|
|
@ -36,6 +36,7 @@ if TYPE_CHECKING:
|
||||||
Audio,
|
Audio,
|
||||||
Contact,
|
Contact,
|
||||||
Document,
|
Document,
|
||||||
|
Gift,
|
||||||
InlineKeyboardMarkup,
|
InlineKeyboardMarkup,
|
||||||
InputMediaAudio,
|
InputMediaAudio,
|
||||||
InputMediaDocument,
|
InputMediaDocument,
|
||||||
|
@ -1646,6 +1647,43 @@ class User(TelegramObject):
|
||||||
allow_paid_broadcast=allow_paid_broadcast,
|
allow_paid_broadcast=allow_paid_broadcast,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def send_gift(
|
||||||
|
self,
|
||||||
|
gift_id: Union[str, "Gift"],
|
||||||
|
text: Optional[str] = None,
|
||||||
|
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
text_entities: Optional[Sequence["MessageEntity"]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
"""Shortcut for::
|
||||||
|
|
||||||
|
await bot.send_gift( user_id=update.effective_user.id, *args, **kwargs )
|
||||||
|
|
||||||
|
For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: On success, :obj:`True` is returned.
|
||||||
|
"""
|
||||||
|
return await self.get_bot().send_gift(
|
||||||
|
user_id=self.id,
|
||||||
|
gift_id=gift_id,
|
||||||
|
text=text,
|
||||||
|
text_parse_mode=text_parse_mode,
|
||||||
|
text_entities=text_entities,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=api_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
async def send_copy(
|
async def send_copy(
|
||||||
self,
|
self,
|
||||||
from_chat_id: Union[str, int],
|
from_chat_id: Union[str, int],
|
||||||
|
|
|
@ -64,6 +64,7 @@ __all__ = [
|
||||||
"FloodLimit",
|
"FloodLimit",
|
||||||
"ForumIconColor",
|
"ForumIconColor",
|
||||||
"ForumTopicLimit",
|
"ForumTopicLimit",
|
||||||
|
"GiftLimit",
|
||||||
"GiveawayLimit",
|
"GiveawayLimit",
|
||||||
"InlineKeyboardButtonLimit",
|
"InlineKeyboardButtonLimit",
|
||||||
"InlineKeyboardMarkupLimit",
|
"InlineKeyboardMarkupLimit",
|
||||||
|
@ -152,7 +153,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=11)
|
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=8, minor=0)
|
||||||
#: :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__`.
|
||||||
|
@ -1224,6 +1225,21 @@ class ForumIconColor(IntEnum):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class GiftLimit(IntEnum):
|
||||||
|
"""This enum contains limitations for :meth:`~telegram.Bot.send_gift`.
|
||||||
|
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
MAX_TEXT_LENGTH = 255
|
||||||
|
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||||
|
:paramref:`~telegram.Bot.send_gift.text` parameter of :meth:`~telegram.Bot.send_gift`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class GiveawayLimit(IntEnum):
|
class GiveawayLimit(IntEnum):
|
||||||
"""This enum contains limitations for :class:`telegram.Giveaway` and related classes.
|
"""This enum contains limitations for :class:`telegram.Giveaway` and related classes.
|
||||||
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.
|
||||||
|
@ -2902,6 +2918,13 @@ class InvoiceLimit(IntEnum):
|
||||||
|
|
||||||
.. versionadded:: 21.6
|
.. versionadded:: 21.6
|
||||||
"""
|
"""
|
||||||
|
SUBSCRIPTION_PERIOD = datetime.timedelta(days=30).total_seconds()
|
||||||
|
""":obj:`int`: The period of time for which the subscription is active before
|
||||||
|
the next payment, passed as :paramref:`~telegram.Bot.create_invoice_link.subscription_period`
|
||||||
|
parameter of :meth:`telegram.Bot.create_invoice_link`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class UserProfilePhotosLimit(IntEnum):
|
class UserProfilePhotosLimit(IntEnum):
|
||||||
|
|
|
@ -437,9 +437,7 @@ class CallbackDataCache:
|
||||||
Args:
|
Args:
|
||||||
time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp
|
time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp
|
||||||
or a :obj:`datetime.datetime` to clear only entries which are older.
|
or a :obj:`datetime.datetime` to clear only entries which are older.
|
||||||
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
|
|tz-naive-dtms|
|
||||||
bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is
|
|
||||||
used.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.__clear(self._keyboard_data, time_cutoff=time_cutoff)
|
self.__clear(self._keyboard_data, time_cutoff=time_cutoff)
|
||||||
|
|
|
@ -188,6 +188,7 @@ class Defaults:
|
||||||
"explanation_parse_mode",
|
"explanation_parse_mode",
|
||||||
"link_preview_options",
|
"link_preview_options",
|
||||||
"parse_mode",
|
"parse_mode",
|
||||||
|
"text_parse_mode",
|
||||||
"protect_content",
|
"protect_content",
|
||||||
"question_parse_mode",
|
"question_parse_mode",
|
||||||
):
|
):
|
||||||
|
@ -271,7 +272,8 @@ class Defaults:
|
||||||
@property
|
@property
|
||||||
def text_parse_mode(self) -> Optional[str]:
|
def text_parse_mode(self) -> Optional[str]:
|
||||||
""":obj:`str`: Optional. Alias for :attr:`parse_mode`, used for
|
""":obj:`str`: Optional. Alias for :attr:`parse_mode`, used for
|
||||||
the corresponding parameter of :class:`telegram.InputPollOption`.
|
the corresponding parameter of :class:`telegram.InputPollOption` and
|
||||||
|
:meth:`telegram.Bot.send_gift`.
|
||||||
|
|
||||||
.. versionadded:: 21.2
|
.. versionadded:: 21.2
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"""This module contains an object that represents a Telegram Bot with convenience extensions."""
|
"""This module contains an object that represents a Telegram Bot with convenience extensions."""
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
|
@ -57,6 +57,8 @@ from telegram import (
|
||||||
File,
|
File,
|
||||||
ForumTopic,
|
ForumTopic,
|
||||||
GameHighScore,
|
GameHighScore,
|
||||||
|
Gift,
|
||||||
|
Gifts,
|
||||||
InlineKeyboardMarkup,
|
InlineKeyboardMarkup,
|
||||||
InlineQueryResultsButton,
|
InlineQueryResultsButton,
|
||||||
InputMedia,
|
InputMedia,
|
||||||
|
@ -69,6 +71,7 @@ from telegram import (
|
||||||
MessageId,
|
MessageId,
|
||||||
PhotoSize,
|
PhotoSize,
|
||||||
Poll,
|
Poll,
|
||||||
|
PreparedInlineMessage,
|
||||||
ReactionType,
|
ReactionType,
|
||||||
ReplyParameters,
|
ReplyParameters,
|
||||||
SentWebAppMessage,
|
SentWebAppMessage,
|
||||||
|
@ -979,6 +982,36 @@ 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 save_prepared_inline_message(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
result: "InlineQueryResult",
|
||||||
|
allow_user_chats: Optional[bool] = None,
|
||||||
|
allow_bot_chats: Optional[bool] = None,
|
||||||
|
allow_group_chats: Optional[bool] = None,
|
||||||
|
allow_channel_chats: Optional[bool] = 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,
|
||||||
|
) -> PreparedInlineMessage:
|
||||||
|
return await super().save_prepared_inline_message(
|
||||||
|
user_id=user_id,
|
||||||
|
result=result,
|
||||||
|
allow_user_chats=allow_user_chats,
|
||||||
|
allow_bot_chats=allow_bot_chats,
|
||||||
|
allow_group_chats=allow_group_chats,
|
||||||
|
allow_channel_chats=allow_channel_chats,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
|
)
|
||||||
|
|
||||||
async def answer_pre_checkout_query(
|
async def answer_pre_checkout_query(
|
||||||
self,
|
self,
|
||||||
pre_checkout_query_id: str,
|
pre_checkout_query_id: str,
|
||||||
|
@ -1171,6 +1204,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
send_phone_number_to_provider: Optional[bool] = None,
|
send_phone_number_to_provider: Optional[bool] = None,
|
||||||
send_email_to_provider: Optional[bool] = None,
|
send_email_to_provider: Optional[bool] = None,
|
||||||
is_flexible: Optional[bool] = None,
|
is_flexible: Optional[bool] = None,
|
||||||
|
subscription_period: Optional[Union[int, timedelta]] = None,
|
||||||
|
business_connection_id: Optional[str] = None,
|
||||||
*,
|
*,
|
||||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
@ -1204,6 +1239,8 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
write_timeout=write_timeout,
|
write_timeout=write_timeout,
|
||||||
connect_timeout=connect_timeout,
|
connect_timeout=connect_timeout,
|
||||||
pool_timeout=pool_timeout,
|
pool_timeout=pool_timeout,
|
||||||
|
subscription_period=subscription_period,
|
||||||
|
business_connection_id=business_connection_id,
|
||||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3385,6 +3422,30 @@ 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 set_user_emoji_status(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
emoji_status_custom_emoji_id: Optional[str] = None,
|
||||||
|
emoji_status_expiration_date: Optional[Union[int, datetime]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
return await super().set_user_emoji_status(
|
||||||
|
user_id=user_id,
|
||||||
|
emoji_status_custom_emoji_id=emoji_status_custom_emoji_id,
|
||||||
|
emoji_status_expiration_date=emoji_status_expiration_date,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
|
)
|
||||||
|
|
||||||
async def set_chat_menu_button(
|
async def set_chat_menu_button(
|
||||||
self,
|
self,
|
||||||
chat_id: Optional[int] = None,
|
chat_id: Optional[int] = None,
|
||||||
|
@ -4255,6 +4316,30 @@ 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 edit_user_star_subscription(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
telegram_payment_charge_id: str,
|
||||||
|
is_canceled: bool,
|
||||||
|
*,
|
||||||
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
rate_limit_args: Optional[RLARGS] = None,
|
||||||
|
) -> bool:
|
||||||
|
return await super().edit_user_star_subscription(
|
||||||
|
user_id=user_id,
|
||||||
|
telegram_payment_charge_id=telegram_payment_charge_id,
|
||||||
|
is_canceled=is_canceled,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
|
)
|
||||||
|
|
||||||
async def send_paid_media(
|
async def send_paid_media(
|
||||||
self,
|
self,
|
||||||
chat_id: Union[str, int],
|
chat_id: Union[str, int],
|
||||||
|
@ -4355,6 +4440,52 @@ 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 get_available_gifts(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||||
|
api_kwargs: Optional[JSONDict] = None,
|
||||||
|
rate_limit_args: Optional[RLARGS] = None,
|
||||||
|
) -> Gifts:
|
||||||
|
return await super().get_available_gifts(
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
write_timeout=write_timeout,
|
||||||
|
connect_timeout=connect_timeout,
|
||||||
|
pool_timeout=pool_timeout,
|
||||||
|
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def send_gift(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
gift_id: Union[str, Gift],
|
||||||
|
text: Optional[str] = None,
|
||||||
|
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
|
||||||
|
text_entities: Optional[Sequence["MessageEntity"]] = 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,
|
||||||
|
) -> bool:
|
||||||
|
return await super().send_gift(
|
||||||
|
user_id=user_id,
|
||||||
|
gift_id=gift_id,
|
||||||
|
text=text,
|
||||||
|
text_parse_mode=text_parse_mode,
|
||||||
|
text_entities=text_entities,
|
||||||
|
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
|
||||||
|
@ -4379,6 +4510,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
sendGame = send_game
|
sendGame = send_game
|
||||||
sendChatAction = send_chat_action
|
sendChatAction = send_chat_action
|
||||||
answerInlineQuery = answer_inline_query
|
answerInlineQuery = answer_inline_query
|
||||||
|
savePreparedInlineMessage = save_prepared_inline_message
|
||||||
getUserProfilePhotos = get_user_profile_photos
|
getUserProfilePhotos = get_user_profile_photos
|
||||||
getFile = get_file
|
getFile = get_file
|
||||||
banChatMember = ban_chat_member
|
banChatMember = ban_chat_member
|
||||||
|
@ -4421,6 +4553,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
||||||
deleteChatPhoto = delete_chat_photo
|
deleteChatPhoto = delete_chat_photo
|
||||||
setChatTitle = set_chat_title
|
setChatTitle = set_chat_title
|
||||||
setChatDescription = set_chat_description
|
setChatDescription = set_chat_description
|
||||||
|
setUserEmojiStatus = set_user_emoji_status
|
||||||
pinChatMessage = pin_chat_message
|
pinChatMessage = pin_chat_message
|
||||||
unpinChatMessage = unpin_chat_message
|
unpinChatMessage = unpin_chat_message
|
||||||
unpinAllChatMessages = unpin_all_chat_messages
|
unpinAllChatMessages = unpin_all_chat_messages
|
||||||
|
@ -4478,6 +4611,9 @@ 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
|
||||||
|
editUserStarSubscription = edit_user_star_subscription
|
||||||
createChatSubscriptionInviteLink = create_chat_subscription_invite_link
|
createChatSubscriptionInviteLink = create_chat_subscription_invite_link
|
||||||
editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
|
editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
|
||||||
sendPaidMedia = send_paid_media
|
sendPaidMedia = send_paid_media
|
||||||
|
getAvailableGifts = get_available_gifts
|
||||||
|
sendGift = send_gift
|
||||||
|
|
108
tests/_inline/test_preparedinlinemessage.py
Normal file
108
tests/_inline/test_preparedinlinemessage.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#!/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/].
|
||||||
|
import datetime as dtm
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from telegram import Location, PreparedInlineMessage
|
||||||
|
from telegram._utils.datetime import UTC, to_timestamp
|
||||||
|
from tests.auxil.slots import mro_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def prepared_inline_message():
|
||||||
|
return PreparedInlineMessage(
|
||||||
|
PreparedInlineMessageTestBase.id,
|
||||||
|
PreparedInlineMessageTestBase.expiration_date,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PreparedInlineMessageTestBase:
|
||||||
|
id = "some_uid"
|
||||||
|
expiration_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPreparedInlineMessageWithoutRequest(PreparedInlineMessageTestBase):
|
||||||
|
def test_slot_behaviour(self, prepared_inline_message):
|
||||||
|
inst = prepared_inline_message
|
||||||
|
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, prepared_inline_message):
|
||||||
|
assert prepared_inline_message.id == self.id
|
||||||
|
assert prepared_inline_message.expiration_date == self.expiration_date
|
||||||
|
|
||||||
|
def test_de_json(self, prepared_inline_message):
|
||||||
|
json_dict = {
|
||||||
|
"id": self.id,
|
||||||
|
"expiration_date": to_timestamp(self.expiration_date),
|
||||||
|
}
|
||||||
|
new_prepared_inline_message = PreparedInlineMessage.de_json(json_dict, None)
|
||||||
|
|
||||||
|
assert isinstance(new_prepared_inline_message, PreparedInlineMessage)
|
||||||
|
assert new_prepared_inline_message.id == prepared_inline_message.id
|
||||||
|
assert (
|
||||||
|
new_prepared_inline_message.expiration_date == prepared_inline_message.expiration_date
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
|
||||||
|
json_dict = {
|
||||||
|
"id": "some_uid",
|
||||||
|
"expiration_date": to_timestamp(self.expiration_date),
|
||||||
|
}
|
||||||
|
pim = PreparedInlineMessage.de_json(json_dict, offline_bot)
|
||||||
|
pim_raw = PreparedInlineMessage.de_json(json_dict, raw_bot)
|
||||||
|
pim_tz = PreparedInlineMessage.de_json(json_dict, tz_bot)
|
||||||
|
|
||||||
|
# comparing utcoffset because comparing tzinfo objects is not reliable
|
||||||
|
offset = pim_tz.expiration_date.utcoffset()
|
||||||
|
offset_tz = tz_bot.defaults.tzinfo.utcoffset(pim_tz.expiration_date.replace(tzinfo=None))
|
||||||
|
|
||||||
|
assert pim.expiration_date.tzinfo == UTC
|
||||||
|
assert pim_raw.expiration_date.tzinfo == UTC
|
||||||
|
assert offset_tz == offset
|
||||||
|
|
||||||
|
def test_to_dict(self, prepared_inline_message):
|
||||||
|
prepared_inline_message_dict = prepared_inline_message.to_dict()
|
||||||
|
|
||||||
|
assert isinstance(prepared_inline_message_dict, dict)
|
||||||
|
assert prepared_inline_message_dict["id"] == prepared_inline_message.id
|
||||||
|
assert prepared_inline_message_dict["expiration_date"] == to_timestamp(
|
||||||
|
self.expiration_date
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_equality(self, prepared_inline_message):
|
||||||
|
a = prepared_inline_message
|
||||||
|
b = PreparedInlineMessage(self.id, self.expiration_date)
|
||||||
|
c = PreparedInlineMessage(self.id, self.expiration_date + dtm.timedelta(seconds=1))
|
||||||
|
d = PreparedInlineMessage("other_uid", self.expiration_date)
|
||||||
|
e = Location(123, 456)
|
||||||
|
|
||||||
|
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)
|
|
@ -17,6 +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/].
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime as dtm
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -122,10 +123,14 @@ class TestInvoiceWithoutRequest(InvoiceTestBase):
|
||||||
protect_content=True,
|
protect_content=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def test_send_all_args_create_invoice_link(self, offline_bot, monkeypatch):
|
@pytest.mark.parametrize("subscription_period", [42, dtm.timedelta(seconds=42)])
|
||||||
|
async def test_send_all_args_create_invoice_link(
|
||||||
|
self, offline_bot, monkeypatch, subscription_period
|
||||||
|
):
|
||||||
async def make_assertion(*args, **_):
|
async def make_assertion(*args, **_):
|
||||||
kwargs = args[1]
|
kwargs = args[1]
|
||||||
return all(kwargs[i] == i for i in kwargs)
|
sp = kwargs.pop("subscription_period") == 42
|
||||||
|
return all(kwargs[i] == i for i in kwargs) and sp
|
||||||
|
|
||||||
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
monkeypatch.setattr(offline_bot, "_post", make_assertion)
|
||||||
assert await offline_bot.create_invoice_link(
|
assert await offline_bot.create_invoice_link(
|
||||||
|
@ -149,6 +154,8 @@ class TestInvoiceWithoutRequest(InvoiceTestBase):
|
||||||
send_phone_number_to_provider="send_phone_number_to_provider",
|
send_phone_number_to_provider="send_phone_number_to_provider",
|
||||||
send_email_to_provider="send_email_to_provider",
|
send_email_to_provider="send_email_to_provider",
|
||||||
is_flexible="is_flexible",
|
is_flexible="is_flexible",
|
||||||
|
business_connection_id="business_connection_id",
|
||||||
|
subscription_period=subscription_period,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def test_send_object_as_provider_data(
|
async def test_send_object_as_provider_data(
|
||||||
|
|
|
@ -16,9 +16,12 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
|
import datetime as dtm
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from telegram import OrderInfo, SuccessfulPayment
|
from telegram import OrderInfo, SuccessfulPayment
|
||||||
|
from telegram._utils.datetime import UTC, to_timestamp
|
||||||
from tests.auxil.slots import mro_slots
|
from tests.auxil.slots import mro_slots
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +35,9 @@ def successful_payment():
|
||||||
SuccessfulPaymentTestBase.provider_payment_charge_id,
|
SuccessfulPaymentTestBase.provider_payment_charge_id,
|
||||||
shipping_option_id=SuccessfulPaymentTestBase.shipping_option_id,
|
shipping_option_id=SuccessfulPaymentTestBase.shipping_option_id,
|
||||||
order_info=SuccessfulPaymentTestBase.order_info,
|
order_info=SuccessfulPaymentTestBase.order_info,
|
||||||
|
subscription_expiration_date=SuccessfulPaymentTestBase.subscription_expiration_date,
|
||||||
|
is_recurring=SuccessfulPaymentTestBase.is_recurring,
|
||||||
|
is_first_recurring=SuccessfulPaymentTestBase.is_first_recurring,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +49,9 @@ class SuccessfulPaymentTestBase:
|
||||||
order_info = OrderInfo()
|
order_info = OrderInfo()
|
||||||
telegram_payment_charge_id = "telegram_payment_charge_id"
|
telegram_payment_charge_id = "telegram_payment_charge_id"
|
||||||
provider_payment_charge_id = "provider_payment_charge_id"
|
provider_payment_charge_id = "provider_payment_charge_id"
|
||||||
|
subscription_expiration_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
|
||||||
|
is_recurring = True
|
||||||
|
is_first_recurring = True
|
||||||
|
|
||||||
|
|
||||||
class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
|
class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
|
||||||
|
@ -61,6 +70,9 @@ class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
|
||||||
"order_info": self.order_info.to_dict(),
|
"order_info": self.order_info.to_dict(),
|
||||||
"telegram_payment_charge_id": self.telegram_payment_charge_id,
|
"telegram_payment_charge_id": self.telegram_payment_charge_id,
|
||||||
"provider_payment_charge_id": self.provider_payment_charge_id,
|
"provider_payment_charge_id": self.provider_payment_charge_id,
|
||||||
|
"subscription_expiration_date": to_timestamp(self.subscription_expiration_date),
|
||||||
|
"is_recurring": self.is_recurring,
|
||||||
|
"is_first_recurring": self.is_first_recurring,
|
||||||
}
|
}
|
||||||
successful_payment = SuccessfulPayment.de_json(json_dict, offline_bot)
|
successful_payment = SuccessfulPayment.de_json(json_dict, offline_bot)
|
||||||
assert successful_payment.api_kwargs == {}
|
assert successful_payment.api_kwargs == {}
|
||||||
|
@ -72,6 +84,32 @@ class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
|
||||||
assert successful_payment.order_info == self.order_info
|
assert successful_payment.order_info == self.order_info
|
||||||
assert successful_payment.telegram_payment_charge_id == self.telegram_payment_charge_id
|
assert successful_payment.telegram_payment_charge_id == self.telegram_payment_charge_id
|
||||||
assert successful_payment.provider_payment_charge_id == self.provider_payment_charge_id
|
assert successful_payment.provider_payment_charge_id == self.provider_payment_charge_id
|
||||||
|
assert successful_payment.subscription_expiration_date == self.subscription_expiration_date
|
||||||
|
assert successful_payment.is_recurring == self.is_recurring
|
||||||
|
assert successful_payment.is_first_recurring == self.is_first_recurring
|
||||||
|
|
||||||
|
def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
|
||||||
|
json_dict = {
|
||||||
|
"invoice_payload": self.invoice_payload,
|
||||||
|
"currency": self.currency,
|
||||||
|
"total_amount": self.total_amount,
|
||||||
|
"telegram_payment_charge_id": self.telegram_payment_charge_id,
|
||||||
|
"provider_payment_charge_id": self.provider_payment_charge_id,
|
||||||
|
"subscription_expiration_date": to_timestamp(self.subscription_expiration_date),
|
||||||
|
}
|
||||||
|
successful_payment = SuccessfulPayment.de_json(json_dict, offline_bot)
|
||||||
|
successful_payment_raw = SuccessfulPayment.de_json(json_dict, raw_bot)
|
||||||
|
successful_payment_tz = SuccessfulPayment.de_json(json_dict, tz_bot)
|
||||||
|
|
||||||
|
# comparing utcoffsets because comparing timezones is unpredicatable
|
||||||
|
date_offset = successful_payment_tz.subscription_expiration_date.utcoffset()
|
||||||
|
tz_bot_offset = tz_bot.defaults.tzinfo.utcoffset(
|
||||||
|
successful_payment_tz.subscription_expiration_date.replace(tzinfo=None)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert successful_payment_raw.subscription_expiration_date.tzinfo == UTC
|
||||||
|
assert successful_payment.subscription_expiration_date.tzinfo == UTC
|
||||||
|
assert date_offset == tz_bot_offset
|
||||||
|
|
||||||
def test_to_dict(self, successful_payment):
|
def test_to_dict(self, successful_payment):
|
||||||
successful_payment_dict = successful_payment.to_dict()
|
successful_payment_dict = successful_payment.to_dict()
|
||||||
|
@ -92,6 +130,13 @@ class TestSuccessfulPaymentWithoutRequest(SuccessfulPaymentTestBase):
|
||||||
successful_payment_dict["provider_payment_charge_id"]
|
successful_payment_dict["provider_payment_charge_id"]
|
||||||
== successful_payment.provider_payment_charge_id
|
== successful_payment.provider_payment_charge_id
|
||||||
)
|
)
|
||||||
|
assert successful_payment_dict["subscription_expiration_date"] == to_timestamp(
|
||||||
|
successful_payment.subscription_expiration_date
|
||||||
|
)
|
||||||
|
assert successful_payment_dict["is_recurring"] == successful_payment.is_recurring
|
||||||
|
assert (
|
||||||
|
successful_payment_dict["is_first_recurring"] == successful_payment.is_first_recurring
|
||||||
|
)
|
||||||
|
|
||||||
def test_equality(self):
|
def test_equality(self):
|
||||||
a = SuccessfulPayment(
|
a = SuccessfulPayment(
|
||||||
|
|
|
@ -67,6 +67,7 @@ from telegram import (
|
||||||
MessageEntity,
|
MessageEntity,
|
||||||
Poll,
|
Poll,
|
||||||
PollOption,
|
PollOption,
|
||||||
|
PreparedInlineMessage,
|
||||||
ReactionTypeCustomEmoji,
|
ReactionTypeCustomEmoji,
|
||||||
ReactionTypeEmoji,
|
ReactionTypeEmoji,
|
||||||
ReplyParameters,
|
ReplyParameters,
|
||||||
|
@ -2321,6 +2322,22 @@ class TestBotWithoutRequest:
|
||||||
obj = await offline_bot.get_star_transactions(offset=3)
|
obj = await offline_bot.get_star_transactions(offset=3)
|
||||||
assert isinstance(obj, StarTransactions)
|
assert isinstance(obj, StarTransactions)
|
||||||
|
|
||||||
|
async def test_edit_user_star_subscription(self, offline_bot, monkeypatch):
|
||||||
|
"""Can't properly test, so we only check that the correct values are passed"""
|
||||||
|
|
||||||
|
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||||
|
return (
|
||||||
|
request_data.parameters.get("user_id") == 42
|
||||||
|
and request_data.parameters.get("telegram_payment_charge_id")
|
||||||
|
== "telegram_payment_charge_id"
|
||||||
|
and request_data.parameters.get("is_canceled") is False
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||||
|
assert await offline_bot.edit_user_star_subscription(
|
||||||
|
42, "telegram_payment_charge_id", False
|
||||||
|
)
|
||||||
|
|
||||||
async def test_create_chat_subscription_invite_link(
|
async def test_create_chat_subscription_invite_link(
|
||||||
self,
|
self,
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
|
@ -2336,6 +2353,39 @@ class TestBotWithoutRequest:
|
||||||
|
|
||||||
await offline_bot.create_chat_subscription_invite_link(1234, 2592000, 6)
|
await offline_bot.create_chat_subscription_invite_link(1234, 2592000, 6)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"expiration_date", [dtm.datetime(2024, 1, 1), 1704067200], ids=["datetime", "timestamp"]
|
||||||
|
)
|
||||||
|
async def test_set_user_emoji_status_basic(self, offline_bot, monkeypatch, expiration_date):
|
||||||
|
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||||
|
assert request_data.parameters.get("user_id") == 4242
|
||||||
|
assert (
|
||||||
|
request_data.parameters.get("emoji_status_custom_emoji_id")
|
||||||
|
== "emoji_status_custom_emoji_id"
|
||||||
|
)
|
||||||
|
assert request_data.parameters.get("emoji_status_expiration_date") == 1704067200
|
||||||
|
|
||||||
|
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||||
|
await offline_bot.set_user_emoji_status(
|
||||||
|
4242, "emoji_status_custom_emoji_id", expiration_date
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_set_user_emoji_status_default_timezone(self, tz_bot, monkeypatch):
|
||||||
|
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||||
|
assert request_data.parameters.get("user_id") == 4242
|
||||||
|
assert (
|
||||||
|
request_data.parameters.get("emoji_status_custom_emoji_id")
|
||||||
|
== "emoji_status_custom_emoji_id"
|
||||||
|
)
|
||||||
|
assert request_data.parameters.get("emoji_status_expiration_date") == to_timestamp(
|
||||||
|
dtm.datetime(2024, 1, 1), tzinfo=tz_bot.defaults.tzinfo
|
||||||
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(tz_bot.request, "post", make_assertion)
|
||||||
|
await tz_bot.set_user_emoji_status(
|
||||||
|
4242, "emoji_status_custom_emoji_id", dtm.datetime(2024, 1, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBotWithRequest:
|
class TestBotWithRequest:
|
||||||
"""
|
"""
|
||||||
|
@ -2345,6 +2395,9 @@ class TestBotWithRequest:
|
||||||
is tested in `test_callbackdatacache`
|
is tested in `test_callbackdatacache`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# get_available_gifts, send_gift are tested in `test_gift`.
|
||||||
|
# No need to duplicate here.
|
||||||
|
|
||||||
async def test_invalid_token_server_response(self):
|
async def test_invalid_token_server_response(self):
|
||||||
with pytest.raises(InvalidToken, match="The token `12` was rejected by the server."):
|
with pytest.raises(InvalidToken, match="The token `12` was rejected by the server."):
|
||||||
async with ExtBot(token="12"):
|
async with ExtBot(token="12"):
|
||||||
|
@ -2841,6 +2894,15 @@ class TestBotWithRequest:
|
||||||
1234, results=inline_results, next_offset=42, current_offset=51
|
1234, results=inline_results, next_offset=42, current_offset=51
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_save_prepared_inline_message(self, bot, chat_id):
|
||||||
|
# We can't really check that the result is stored correctly, we just ensur ethat we get
|
||||||
|
# a proper return value
|
||||||
|
result = InlineQueryResultArticle(
|
||||||
|
id="some_id", title="title", input_message_content=InputTextMessageContent("text")
|
||||||
|
)
|
||||||
|
out = await bot.save_prepared_inline_message(chat_id, result, True, False, True, False)
|
||||||
|
assert isinstance(out, PreparedInlineMessage)
|
||||||
|
|
||||||
async def test_get_user_profile_photos(self, bot, chat_id):
|
async def test_get_user_profile_photos(self, bot, chat_id):
|
||||||
user_profile_photos = await bot.get_user_profile_photos(chat_id)
|
user_profile_photos = await bot.get_user_profile_photos(chat_id)
|
||||||
assert user_profile_photos.photos[0][0].file_size == 5403
|
assert user_profile_photos.photos[0][0].file_size == 5403
|
||||||
|
|
|
@ -1311,6 +1311,28 @@ class TestChatWithoutRequest(ChatTestBase):
|
||||||
media="media", star_count=42, caption="stars", payload="payload"
|
media="media", star_count=42, caption="stars", payload="payload"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_instance_method_send_gift(self, monkeypatch, chat):
|
||||||
|
async def make_assertion(*_, **kwargs):
|
||||||
|
return (
|
||||||
|
kwargs["user_id"] == chat.id
|
||||||
|
and kwargs["gift_id"] == "gift_id"
|
||||||
|
and kwargs["text"] == "text"
|
||||||
|
and kwargs["text_parse_mode"] == "text_parse_mode"
|
||||||
|
and kwargs["text_entities"] == "text_entities"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert check_shortcut_signature(Chat.send_gift, Bot.send_gift, ["user_id"], [])
|
||||||
|
assert await check_shortcut_call(chat.send_gift, chat.get_bot(), "send_gift")
|
||||||
|
assert await check_defaults_handling(chat.send_gift, chat.get_bot())
|
||||||
|
|
||||||
|
monkeypatch.setattr(chat.get_bot(), "send_gift", make_assertion)
|
||||||
|
assert await chat.send_gift(
|
||||||
|
gift_id="gift_id",
|
||||||
|
text="text",
|
||||||
|
text_parse_mode="text_parse_mode",
|
||||||
|
text_entities="text_entities",
|
||||||
|
)
|
||||||
|
|
||||||
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"):
|
||||||
|
|
267
tests/test_gifts.py
Normal file
267
tests/test_gifts.py
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
#!/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 collections.abc import Sequence
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from telegram import BotCommand, Gift, Gifts, MessageEntity, Sticker
|
||||||
|
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||||
|
from telegram.request import RequestData
|
||||||
|
from tests.auxil.slots import mro_slots
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gift(request):
|
||||||
|
return Gift(
|
||||||
|
id=GiftTestBase.id,
|
||||||
|
sticker=GiftTestBase.sticker,
|
||||||
|
star_count=GiftTestBase.star_count,
|
||||||
|
total_count=GiftTestBase.total_count,
|
||||||
|
remaining_count=GiftTestBase.remaining_count,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GiftTestBase:
|
||||||
|
id = "some_id"
|
||||||
|
sticker = Sticker(
|
||||||
|
file_id="file_id",
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
width=512,
|
||||||
|
height=512,
|
||||||
|
is_animated=False,
|
||||||
|
is_video=False,
|
||||||
|
type="regular",
|
||||||
|
)
|
||||||
|
star_count = 5
|
||||||
|
total_count = 10
|
||||||
|
remaining_count = 5
|
||||||
|
|
||||||
|
|
||||||
|
class TestGiftWithoutRequest(GiftTestBase):
|
||||||
|
def test_slot_behaviour(self, gift):
|
||||||
|
for attr in gift.__slots__:
|
||||||
|
assert getattr(gift, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(gift)) == len(set(mro_slots(gift))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_de_json(self, offline_bot, gift):
|
||||||
|
json_dict = {
|
||||||
|
"id": self.id,
|
||||||
|
"sticker": self.sticker.to_dict(),
|
||||||
|
"star_count": self.star_count,
|
||||||
|
"total_count": self.total_count,
|
||||||
|
"remaining_count": self.remaining_count,
|
||||||
|
}
|
||||||
|
gift = Gift.de_json(json_dict, offline_bot)
|
||||||
|
assert gift.api_kwargs == {}
|
||||||
|
|
||||||
|
assert gift.id == self.id
|
||||||
|
assert gift.sticker == self.sticker
|
||||||
|
assert gift.star_count == self.star_count
|
||||||
|
assert gift.total_count == self.total_count
|
||||||
|
assert gift.remaining_count == self.remaining_count
|
||||||
|
|
||||||
|
assert Gift.de_json(None, offline_bot) is None
|
||||||
|
|
||||||
|
def test_to_dict(self, gift):
|
||||||
|
gift_dict = gift.to_dict()
|
||||||
|
|
||||||
|
assert isinstance(gift_dict, dict)
|
||||||
|
assert gift_dict["id"] == self.id
|
||||||
|
assert gift_dict["sticker"] == self.sticker.to_dict()
|
||||||
|
assert gift_dict["star_count"] == self.star_count
|
||||||
|
assert gift_dict["total_count"] == self.total_count
|
||||||
|
assert gift_dict["remaining_count"] == self.remaining_count
|
||||||
|
|
||||||
|
def test_equality(self, gift):
|
||||||
|
a = gift
|
||||||
|
b = Gift(self.id, self.sticker, self.star_count, self.total_count, self.remaining_count)
|
||||||
|
c = Gift(
|
||||||
|
"other_uid", self.sticker, self.star_count, self.total_count, self.remaining_count
|
||||||
|
)
|
||||||
|
d = BotCommand("start", "description")
|
||||||
|
|
||||||
|
assert a == b
|
||||||
|
assert hash(a) == hash(b)
|
||||||
|
|
||||||
|
assert a != c
|
||||||
|
assert hash(a) != hash(c)
|
||||||
|
|
||||||
|
assert a != d
|
||||||
|
assert hash(a) != hash(d)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"gift",
|
||||||
|
[
|
||||||
|
"gift_id",
|
||||||
|
Gift(
|
||||||
|
"gift_id",
|
||||||
|
Sticker("file_id", "file_unique_id", 512, 512, False, False, "regular"),
|
||||||
|
5,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=["string", "Gift"],
|
||||||
|
)
|
||||||
|
async def test_send_gift(self, offline_bot, gift, monkeypatch):
|
||||||
|
# We can't send actual gifts, so we just check that the correct parameters are passed
|
||||||
|
text_entities = [
|
||||||
|
MessageEntity(MessageEntity.TEXT_LINK, 0, 4, "url"),
|
||||||
|
MessageEntity(MessageEntity.BOLD, 5, 9),
|
||||||
|
]
|
||||||
|
|
||||||
|
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||||
|
user_id = request_data.parameters["user_id"] == "user_id"
|
||||||
|
gift_id = request_data.parameters["gift_id"] == "gift_id"
|
||||||
|
text = request_data.parameters["text"] == "text"
|
||||||
|
text_parse_mode = request_data.parameters["text_parse_mode"] == "text_parse_mode"
|
||||||
|
tes = request_data.parameters["text_entities"] == [
|
||||||
|
me.to_dict() for me in text_entities
|
||||||
|
]
|
||||||
|
return user_id and gift_id and text and text_parse_mode and tes
|
||||||
|
|
||||||
|
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
|
||||||
|
assert await offline_bot.send_gift(
|
||||||
|
"user_id", gift, "text", text_parse_mode="text_parse_mode", text_entities=text_entities
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("passed_value", "expected_value"),
|
||||||
|
[(DEFAULT_NONE, "Markdown"), ("HTML", "HTML"), (None, None)],
|
||||||
|
)
|
||||||
|
async def test_send_gift_default_parse_mode(
|
||||||
|
self, default_bot, monkeypatch, passed_value, expected_value
|
||||||
|
):
|
||||||
|
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||||
|
return request_data.parameters.get("text_parse_mode") == expected_value
|
||||||
|
|
||||||
|
monkeypatch.setattr(default_bot.request, "post", make_assertion)
|
||||||
|
kwargs = {
|
||||||
|
"user_id": "user_id",
|
||||||
|
"gift_id": "gift_id",
|
||||||
|
}
|
||||||
|
if passed_value is not DEFAULT_NONE:
|
||||||
|
kwargs["text_parse_mode"] = passed_value
|
||||||
|
|
||||||
|
assert await default_bot.send_gift(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gifts(request):
|
||||||
|
return Gifts(gifts=GiftsTestBase.gifts)
|
||||||
|
|
||||||
|
|
||||||
|
class GiftsTestBase:
|
||||||
|
gifts: Sequence[Gift] = [
|
||||||
|
Gift(
|
||||||
|
id="id1",
|
||||||
|
sticker=Sticker(
|
||||||
|
file_id="file_id",
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
width=512,
|
||||||
|
height=512,
|
||||||
|
is_animated=False,
|
||||||
|
is_video=False,
|
||||||
|
type="regular",
|
||||||
|
),
|
||||||
|
star_count=5,
|
||||||
|
total_count=5,
|
||||||
|
remaining_count=5,
|
||||||
|
),
|
||||||
|
Gift(
|
||||||
|
id="id2",
|
||||||
|
sticker=Sticker(
|
||||||
|
file_id="file_id",
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
width=512,
|
||||||
|
height=512,
|
||||||
|
is_animated=False,
|
||||||
|
is_video=False,
|
||||||
|
type="regular",
|
||||||
|
),
|
||||||
|
star_count=6,
|
||||||
|
total_count=6,
|
||||||
|
remaining_count=6,
|
||||||
|
),
|
||||||
|
Gift(
|
||||||
|
id="id3",
|
||||||
|
sticker=Sticker(
|
||||||
|
file_id="file_id",
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
width=512,
|
||||||
|
height=512,
|
||||||
|
is_animated=False,
|
||||||
|
is_video=False,
|
||||||
|
type="regular",
|
||||||
|
),
|
||||||
|
star_count=7,
|
||||||
|
total_count=7,
|
||||||
|
remaining_count=7,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TestGiftsWithoutRequest(GiftsTestBase):
|
||||||
|
def test_slot_behaviour(self, gifts):
|
||||||
|
for attr in gifts.__slots__:
|
||||||
|
assert getattr(gifts, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||||
|
assert len(mro_slots(gifts)) == len(set(mro_slots(gifts))), "duplicate slot"
|
||||||
|
|
||||||
|
def test_de_json(self, offline_bot, gifts):
|
||||||
|
json_dict = {"gifts": [gift.to_dict() for gift in self.gifts]}
|
||||||
|
gifts = Gifts.de_json(json_dict, offline_bot)
|
||||||
|
assert gifts.api_kwargs == {}
|
||||||
|
|
||||||
|
assert gifts.gifts == tuple(self.gifts)
|
||||||
|
for de_json_gift, original_gift in zip(gifts.gifts, self.gifts):
|
||||||
|
assert de_json_gift.id == original_gift.id
|
||||||
|
assert de_json_gift.sticker == original_gift.sticker
|
||||||
|
assert de_json_gift.star_count == original_gift.star_count
|
||||||
|
assert de_json_gift.total_count == original_gift.total_count
|
||||||
|
assert de_json_gift.remaining_count == original_gift.remaining_count
|
||||||
|
|
||||||
|
assert Gifts.de_json(None, offline_bot) is None
|
||||||
|
|
||||||
|
def test_to_dict(self, gifts):
|
||||||
|
gifts_dict = gifts.to_dict()
|
||||||
|
|
||||||
|
assert isinstance(gifts_dict, dict)
|
||||||
|
assert gifts_dict["gifts"] == [gift.to_dict() for gift in self.gifts]
|
||||||
|
|
||||||
|
def test_equality(self, gifts):
|
||||||
|
a = gifts
|
||||||
|
b = Gifts(self.gifts)
|
||||||
|
c = Gifts(self.gifts[:2])
|
||||||
|
d = BotCommand("start", "description")
|
||||||
|
|
||||||
|
assert a == b
|
||||||
|
assert hash(a) == hash(b)
|
||||||
|
|
||||||
|
assert a != c
|
||||||
|
assert hash(a) != hash(c)
|
||||||
|
|
||||||
|
assert a != d
|
||||||
|
assert hash(a) != hash(d)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGiftsWithRequest(GiftTestBase):
|
||||||
|
async def test_get_available_gifts(self, bot, chat_id):
|
||||||
|
# We don't control the available gifts, so we can not make any better assertions
|
||||||
|
assert isinstance(await bot.get_available_gifts(), Gifts)
|
|
@ -24,7 +24,7 @@ import inspect
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ DATETIME_REGEX = re.compile(
|
||||||
""",
|
""",
|
||||||
re.VERBOSE,
|
re.VERBOSE,
|
||||||
)
|
)
|
||||||
|
TIMEDELTA_REGEX = re.compile(r"\w+_period$") # Parameter names ending with "_period"
|
||||||
|
|
||||||
log = logging.debug
|
log = logging.debug
|
||||||
|
|
||||||
|
@ -191,7 +192,18 @@ def check_param_type(
|
||||||
# If it's a class, we only accept datetime as the parameter
|
# If it's a class, we only accept datetime as the parameter
|
||||||
mapped_type = datetime if is_class else mapped_type | datetime
|
mapped_type = datetime if is_class else mapped_type | datetime
|
||||||
|
|
||||||
# 4) COMPLEX TYPES:
|
# 4) HANDLING TIMEDELTA:
|
||||||
|
elif re.search(TIMEDELTA_REGEX, ptb_param.name) and obj.__name__ in (
|
||||||
|
"TransactionPartnerUser",
|
||||||
|
"create_invoice_link",
|
||||||
|
):
|
||||||
|
# Currently we only support timedelta for `subscription_period` in `TransactionPartnerUser`
|
||||||
|
# and `create_invoice_link`.
|
||||||
|
# See https://github.com/python-telegram-bot/python-telegram-bot/issues/4575
|
||||||
|
log("Checking that `%s` is a timedelta!\n", ptb_param.name)
|
||||||
|
mapped_type = timedelta if is_class else mapped_type | timedelta
|
||||||
|
|
||||||
|
# 5) COMPLEX TYPES:
|
||||||
# Some types are too complicated, so we replace our annotation with a simpler type:
|
# Some types are too complicated, so we replace our annotation with a simpler type:
|
||||||
elif any(ptb_param.name in key for key in PTCE.COMPLEX_TYPES):
|
elif any(ptb_param.name in key for key in PTCE.COMPLEX_TYPES):
|
||||||
log("Converting `%s` to a simpler type!\n", ptb_param.name)
|
log("Converting `%s` to a simpler type!\n", ptb_param.name)
|
||||||
|
@ -199,7 +211,7 @@ def check_param_type(
|
||||||
if ptb_param.name == param_name and is_class is is_expected_class:
|
if ptb_param.name == param_name and is_class is is_expected_class:
|
||||||
ptb_annotation = wrap_with_none(tg_parameter, exception_type, obj)
|
ptb_annotation = wrap_with_none(tg_parameter, exception_type, obj)
|
||||||
|
|
||||||
# 5) HANDLING DEFAULTS PARAMETERS:
|
# 6) HANDLING DEFAULTS PARAMETERS:
|
||||||
# Classes whose parameters are all ODVInput should be converted and checked.
|
# Classes whose parameters are all ODVInput should be converted and checked.
|
||||||
elif obj.__name__ in PTCE.IGNORED_DEFAULTS_CLASSES:
|
elif obj.__name__ in PTCE.IGNORED_DEFAULTS_CLASSES:
|
||||||
log("Checking that `%s`'s param is ODVInput:\n", obj.__name__)
|
log("Checking that `%s`'s param is ODVInput:\n", obj.__name__)
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
"""This module contains exceptions to our API compared to the official API."""
|
"""This module contains exceptions to our API compared to the official API."""
|
||||||
|
|
||||||
|
from telegram import Animation, Audio, Document, Gift, PhotoSize, Sticker, Video, VideoNote, Voice
|
||||||
from telegram import Animation, Audio, Document, PhotoSize, Sticker, Video, VideoNote, Voice
|
|
||||||
from tests.test_official.helpers import _get_params_base
|
from tests.test_official.helpers import _get_params_base
|
||||||
|
|
||||||
IGNORED_OBJECTS = ("ResponseParameters",)
|
IGNORED_OBJECTS = ("ResponseParameters",)
|
||||||
|
@ -45,6 +44,7 @@ class ParamTypeCheckingExceptions:
|
||||||
"animation": Animation,
|
"animation": Animation,
|
||||||
"voice": Voice,
|
"voice": Voice,
|
||||||
"sticker": Sticker,
|
"sticker": Sticker,
|
||||||
|
"gift_id": Gift,
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Look into merging this with COMPLEX_TYPES
|
# TODO: Look into merging this with COMPLEX_TYPES
|
||||||
|
|
|
@ -24,6 +24,7 @@ import pytest
|
||||||
|
|
||||||
from telegram import (
|
from telegram import (
|
||||||
Dice,
|
Dice,
|
||||||
|
Gift,
|
||||||
PaidMediaPhoto,
|
PaidMediaPhoto,
|
||||||
PhotoSize,
|
PhotoSize,
|
||||||
RevenueWithdrawalState,
|
RevenueWithdrawalState,
|
||||||
|
@ -32,6 +33,7 @@ from telegram import (
|
||||||
RevenueWithdrawalStateSucceeded,
|
RevenueWithdrawalStateSucceeded,
|
||||||
StarTransaction,
|
StarTransaction,
|
||||||
StarTransactions,
|
StarTransactions,
|
||||||
|
Sticker,
|
||||||
TransactionPartner,
|
TransactionPartner,
|
||||||
TransactionPartnerFragment,
|
TransactionPartnerFragment,
|
||||||
TransactionPartnerOther,
|
TransactionPartnerOther,
|
||||||
|
@ -76,6 +78,22 @@ def transaction_partner_user():
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
paid_media_payload="payload",
|
paid_media_payload="payload",
|
||||||
|
subscription_period=datetime.timedelta(days=1),
|
||||||
|
gift=Gift(
|
||||||
|
id="some_id",
|
||||||
|
sticker=Sticker(
|
||||||
|
file_id="file_id",
|
||||||
|
file_unique_id="file_unique_id",
|
||||||
|
width=512,
|
||||||
|
height=512,
|
||||||
|
is_animated=False,
|
||||||
|
is_video=False,
|
||||||
|
type="regular",
|
||||||
|
),
|
||||||
|
star_count=5,
|
||||||
|
total_count=10,
|
||||||
|
remaining_count=5,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -515,6 +533,20 @@ class TestTransactionPartnerWithoutRequest(TransactionPartnerTestBase):
|
||||||
assert hash(c) != hash(f)
|
assert hash(c) != hash(f)
|
||||||
|
|
||||||
|
|
||||||
|
class TestTransactionPartnerUserWithoutRequest(TransactionPartnerTestBase):
|
||||||
|
def test_de_json_required(self, offline_bot):
|
||||||
|
json_dict = {
|
||||||
|
"user": transaction_partner_user().user.to_dict(),
|
||||||
|
}
|
||||||
|
tp = TransactionPartnerUser.de_json(json_dict, offline_bot)
|
||||||
|
assert tp.api_kwargs == {}
|
||||||
|
assert tp.user == transaction_partner_user().user
|
||||||
|
|
||||||
|
# This test is here mainly to check that the below cases work
|
||||||
|
assert tp.subscription_period is None
|
||||||
|
assert tp.gift is None
|
||||||
|
|
||||||
|
|
||||||
class RevenueWithdrawalStateTestBase:
|
class RevenueWithdrawalStateTestBase:
|
||||||
date = datetime.datetime(2024, 1, 1, 0, 0, 0, 0, tzinfo=UTC)
|
date = datetime.datetime(2024, 1, 1, 0, 0, 0, 0, tzinfo=UTC)
|
||||||
url = "url"
|
url = "url"
|
||||||
|
|
|
@ -720,3 +720,25 @@ class TestUserWithoutRequest(UserTestBase):
|
||||||
|
|
||||||
monkeypatch.setattr(user.get_bot(), "refund_star_payment", make_assertion)
|
monkeypatch.setattr(user.get_bot(), "refund_star_payment", make_assertion)
|
||||||
assert await user.refund_star_payment(telegram_payment_charge_id=42)
|
assert await user.refund_star_payment(telegram_payment_charge_id=42)
|
||||||
|
|
||||||
|
async def test_instance_method_send_gift(self, monkeypatch, user):
|
||||||
|
async def make_assertion(*_, **kwargs):
|
||||||
|
return (
|
||||||
|
kwargs["user_id"] == user.id
|
||||||
|
and kwargs["gift_id"] == "gift_id"
|
||||||
|
and kwargs["text"] == "text"
|
||||||
|
and kwargs["text_parse_mode"] == "text_parse_mode"
|
||||||
|
and kwargs["text_entities"] == "text_entities"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert check_shortcut_signature(user.send_gift, Bot.send_gift, ["user_id"], [])
|
||||||
|
assert await check_shortcut_call(user.send_gift, user.get_bot(), "send_gift")
|
||||||
|
assert await check_defaults_handling(user.send_gift, user.get_bot())
|
||||||
|
|
||||||
|
monkeypatch.setattr(user.get_bot(), "send_gift", make_assertion)
|
||||||
|
assert await user.send_gift(
|
||||||
|
gift_id="gift_id",
|
||||||
|
text="text",
|
||||||
|
text_parse_mode="text_parse_mode",
|
||||||
|
text_entities="text_entities",
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue