Full Support for Bot API 8.2 (#4633)

Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com>
This commit is contained in:
Poolitzer 2025-01-03 11:39:35 +01:00 committed by GitHub
parent a781a4fddb
commit f2dc0175cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 643 additions and 9 deletions

View file

@ -11,7 +11,7 @@
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions
.. image:: https://img.shields.io/badge/Bot%20API-8.1-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-8.2-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
: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
~~~~~~~~~~~~~~~~~~~~
All types and methods of the Telegram Bot API **8.1** are natively supported by this library.
All types and methods of the Telegram Bot API **8.2** 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>`_.
Notable Features

View file

@ -183,6 +183,29 @@
</details>
<br>
.. raw:: html
<details>
<summary>Verification on behalf of an organization</summary>
.. list-table::
:align: left
:widths: 1 4
* - :meth:`~telegram.Bot.verify_chat`
- Used for verifying a chat
* - :meth:`~telegram.Bot.verify_user`
- Used for verifying a user
* - :meth:`~telegram.Bot.remove_chat_verification`
- Used for removing the verification from a chat
* - :meth:`~telegram.Bot.remove_user_verification`
- Used for removing the verification from a user
.. raw:: html
</details>
<br>
.. raw:: html
<details>

View file

@ -9721,6 +9721,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
pay_for_upgrade: Optional[bool] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@ -9752,6 +9753,10 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
:attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
:attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
:attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
pay_for_upgrade (:obj:`bool`, optional): Pass :obj:`True` to pay for the gift upgrade
from the bot's balance, thereby making the upgrade free for the receiver.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
@ -9765,6 +9770,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
"text": text,
"text_parse_mode": text_parse_mode,
"text_entities": text_entities,
"pay_for_upgrade": pay_for_upgrade,
}
return await self._post(
"sendGift",
@ -9776,6 +9782,168 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
api_kwargs=api_kwargs,
)
async def verify_chat(
self,
chat_id: Union[int, str],
custom_description: Optional[str] = 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:
"""Verifies a chat on behalf of the organization which is represented by the bot.
.. versionadded:: NEXT.VERSION
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
custom_description (:obj:`str`, optional): Custom description for the verification;
0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be
empty if the organization isn't allowed to provide a custom verification
description.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
"custom_description": custom_description,
}
return await self._post(
"verifyChat",
data,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def verify_user(
self,
user_id: int,
custom_description: Optional[str] = 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:
"""Verifies a user on behalf of the organization which is represented by the bot.
.. versionadded:: NEXT.VERSION
Args:
user_id (:obj:`int`): Unique identifier of the target user.
custom_description (:obj:`str`, optional): Custom description for the verification;
0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be
empty if the organization isn't allowed to provide a custom verification
description.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"user_id": user_id,
"custom_description": custom_description,
}
return await self._post(
"verifyUser",
data,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def remove_chat_verification(
self,
chat_id: Union[int, str],
*,
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:
"""Removes verification from a chat that is currently verified on behalf of the
organization represented by the bot.
.. versionadded:: NEXT.VERSION
Args:
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"chat_id": chat_id,
}
return await self._post(
"removeChatVerification",
data,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def remove_user_verification(
self,
user_id: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Removes verification from a user who is currently verified on behalf of the
organization represented by the bot.
.. versionadded:: NEXT.VERSION
Args:
user_id (:obj:`int`): Unique identifier of the target user.
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"user_id": user_id,
}
return await self._post(
"removeUserVerification",
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
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
@ -10046,3 +10214,11 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
"""Alias for :meth:`get_available_gifts`"""
sendGift = send_gift
"""Alias for :meth:`send_gift`"""
verifyChat = verify_chat
"""Alias for :meth:`verify_chat`"""
verifyUser = verify_user
"""Alias for :meth:`verify_user`"""
removeChatVerification = remove_chat_verification
"""Alias for :meth:`remove_chat_verification`"""
removeUserVerification = remove_user_verification
"""Alias for :meth:`remove_user_verification`"""

View file

@ -3443,6 +3443,7 @@ class _ChatBase(TelegramObject):
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
pay_for_upgrade: Optional[bool] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@ -3470,6 +3471,69 @@ class _ChatBase(TelegramObject):
text=text,
text_parse_mode=text_parse_mode,
text_entities=text_entities,
pay_for_upgrade=pay_for_upgrade,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def verify(
self,
custom_description: Optional[str] = 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.verify_chat(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.verify_chat`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().verify_chat(
chat_id=self.id,
custom_description=custom_description,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def remove_verification(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Shortcut for::
await bot.remove_chat_verification(chat_id=update.effective_chat.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.remove_chat_verification`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().remove_chat_verification(
chat_id=self.id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,

View file

@ -46,6 +46,10 @@ class Gift(TelegramObject):
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
upgrade_star_count (:obj:`int`, optional): The number of Telegram Stars that must be paid
to upgrade the gift to a unique one
.. versionadded:: NEXT.VERSION
Attributes:
id (:obj:`str`): Unique identifier of the gift
@ -55,10 +59,21 @@ class Gift(TelegramObject):
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
upgrade_star_count (:obj:`int`): Optional. The number of Telegram Stars that must be paid
to upgrade the gift to a unique one
.. versionadded:: NEXT.VERSION
"""
__slots__ = ("id", "remaining_count", "star_count", "sticker", "total_count")
__slots__ = (
"id",
"remaining_count",
"star_count",
"sticker",
"total_count",
"upgrade_star_count",
)
def __init__(
self,
@ -67,6 +82,7 @@ class Gift(TelegramObject):
star_count: int,
total_count: Optional[int] = None,
remaining_count: Optional[int] = None,
upgrade_star_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
@ -76,6 +92,7 @@ class Gift(TelegramObject):
self.star_count: int = star_count
self.total_count: Optional[int] = total_count
self.remaining_count: Optional[int] = remaining_count
self.upgrade_star_count: Optional[int] = upgrade_star_count
self._id_attrs = (self.id,)

View file

@ -23,7 +23,9 @@ from typing import TYPE_CHECKING, Optional
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
from telegram._inline.inlinequeryresult import InlineQueryResult
from telegram._utils.types import JSONDict
from telegram._utils.warnings import warn
from telegram.constants import InlineQueryResultType
from telegram.warnings import PTBDeprecationWarning
if TYPE_CHECKING:
from telegram import InputMessageContent
@ -50,6 +52,10 @@ class InlineQueryResultArticle(InlineQueryResult):
url (:obj:`str`, optional): URL of the result.
hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown
in the message.
.. deprecated:: NEXT.VERSION
This attribute will be removed in future PTB versions. Pass an empty string as URL
instead.
description (:obj:`str`, optional): Short description of the result.
thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
@ -74,6 +80,10 @@ class InlineQueryResultArticle(InlineQueryResult):
url (:obj:`str`): Optional. URL of the result.
hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown
in the message.
.. deprecated:: NEXT.VERSION
This attribute will be removed in future PTB versions. Pass an empty string as URL
instead.
description (:obj:`str`): Optional. Short description of the result.
thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
@ -123,6 +133,15 @@ class InlineQueryResultArticle(InlineQueryResult):
# Optional
self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
self.url: Optional[str] = url
if hide_url is not None:
warn(
PTBDeprecationWarning(
"NEXT.VERSION",
"The argument `hide_url` will be removed in future PTB"
"versions. Pass an empty string as URL instead.",
),
stacklevel=2,
)
self.hide_url: Optional[bool] = hide_url
self.description: Optional[str] = description
self.thumbnail_url: Optional[str] = thumbnail_url

View file

@ -1653,6 +1653,7 @@ class User(TelegramObject):
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
pay_for_upgrade: Optional[bool] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@ -1677,6 +1678,7 @@ class User(TelegramObject):
text=text,
text_parse_mode=text_parse_mode,
text_entities=text_entities,
pay_for_upgrade=pay_for_upgrade,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
@ -2270,3 +2272,65 @@ class User(TelegramObject):
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def verify(
self,
custom_description: Optional[str] = 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.verify_user(user_id=update.effective_user.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.verify_user`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().verify_user(
user_id=self.id,
custom_description=custom_description,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
async def remove_verification(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Shortcut for::
await bot.remove_user_verification(user_id=update.effective_user.id, *args, **kwargs)
For the documentation of the arguments, please see
:meth:`telegram.Bot.remove_user_verification`.
.. versionadded:: NEXT.VERSION
Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().remove_user_verification(
user_id=self.id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

View file

@ -104,6 +104,7 @@ __all__ = [
"TransactionPartnerType",
"UpdateType",
"UserProfilePhotosLimit",
"VerifyLimit",
"WebhookLimit",
]
@ -154,7 +155,7 @@ class _AccentColor(NamedTuple):
#: :data:`telegram.__bot_api_version_info__`.
#:
#: .. versionadded:: 20.0
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=8, minor=1)
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=8, minor=2)
#: :obj:`str`: Telegram Bot API
#: version supported by this version of `python-telegram-bot`. Also available as
#: :data:`telegram.__bot_api_version__`.
@ -3229,3 +3230,20 @@ class ReactionEmoji(StringEnum):
""":obj:`str`: Woman Shrugging"""
POUTING_FACE = "😡"
""":obj:`str`: Pouting face"""
class VerifyLimit(IntEnum):
"""This enum contains limitations for :meth:`~telegram.Bot.verify_chat` and
:meth:`~telegram.Bot.verify_user`.
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
.. versionadded:: NEXT.VERSION
"""
__slots__ = ()
MAX_TEXT_LENGTH = 70
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
:paramref:`~telegram.Bot.verify_chat.custom_description` or
:paramref:`~telegram.Bot.verify_user.custom_description` parameter.
"""

View file

@ -4465,6 +4465,7 @@ class ExtBot(Bot, Generic[RLARGS]):
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
pay_for_upgrade: Optional[bool] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
@ -4479,6 +4480,91 @@ class ExtBot(Bot, Generic[RLARGS]):
text=text,
text_parse_mode=text_parse_mode,
text_entities=text_entities,
pay_for_upgrade=pay_for_upgrade,
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 verify_chat(
self,
chat_id: Union[int, str],
custom_description: Optional[str] = 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().verify_chat(
chat_id=chat_id,
custom_description=custom_description,
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 verify_user(
self,
user_id: int,
custom_description: Optional[str] = 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().verify_user(
user_id=user_id,
custom_description=custom_description,
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 remove_chat_verification(
self,
chat_id: Union[int, str],
*,
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().remove_chat_verification(
chat_id=chat_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
)
async def remove_user_verification(
self,
user_id: int,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
rate_limit_args: Optional[RLARGS] = None,
) -> bool:
return await super().remove_user_verification(
user_id=user_id,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
@ -4617,3 +4703,7 @@ class ExtBot(Bot, Generic[RLARGS]):
sendPaidMedia = send_paid_media
getAvailableGifts = get_available_gifts
sendGift = send_gift
verifyChat = verify_chat
verifyUser = verify_user
removeChatVerification = remove_chat_verification
removeUserVerification = remove_user_verification

View file

@ -28,6 +28,7 @@ from telegram import (
InputTextMessageContent,
)
from telegram.constants import InlineQueryResultType
from telegram.warnings import PTBDeprecationWarning
from tests.auxil.slots import mro_slots
@ -157,3 +158,31 @@ class TestInlineQueryResultArticleWithoutRequest(InlineQueryResultArticleTestBas
assert a != e
assert hash(a) != hash(e)
def test_deprecation_warning_for_hide_url(self):
with pytest.warns(PTBDeprecationWarning, match="The argument `hide_url`") as record:
InlineQueryResultArticle(
self.id_, self.title, self.input_message_content, hide_url=True
)
assert record[0].filename == __file__, "wrong stacklevel!"
with pytest.warns(PTBDeprecationWarning, match="The argument `hide_url`") as record:
InlineQueryResultArticle(
self.id_, self.title, self.input_message_content, hide_url=False
)
assert record[0].filename == __file__, "wrong stacklevel!"
assert (
InlineQueryResultArticle(
self.id_, self.title, self.input_message_content, hide_url=True
).hide_url
is True
)
assert (
InlineQueryResultArticle(
self.id_, self.title, self.input_message_content, hide_url=False
).hide_url
is False
)

View file

@ -2386,6 +2386,48 @@ class TestBotWithoutRequest:
4242, "emoji_status_custom_emoji_id", dtm.datetime(2024, 1, 1)
)
async def test_verify_user(self, offline_bot, monkeypatch):
"No way to test this without getting verified"
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("user_id") == 1234
assert request_data.parameters.get("custom_description") == "this is so custom"
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.verify_user(1234, "this is so custom")
async def test_verify_chat(self, offline_bot, monkeypatch):
"No way to test this without getting verified"
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("chat_id") == 1234
assert request_data.parameters.get("custom_description") == "this is so custom"
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.verify_chat(1234, "this is so custom")
async def test_unverify_user(self, offline_bot, monkeypatch):
"No way to test this without getting verified"
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("user_id") == 1234
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.remove_user_verification(1234)
async def test_unverify_chat(self, offline_bot, monkeypatch):
"No way to test this without getting verified"
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
assert request_data.parameters.get("chat_id") == 1234
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.remove_chat_verification(1234)
class TestBotWithRequest:
"""

View file

@ -1333,6 +1333,37 @@ class TestChatWithoutRequest(ChatTestBase):
text_entities="text_entities",
)
async def test_instance_method_verify_chat(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == chat.id
and kwargs["custom_description"] == "This is a custom description"
)
assert check_shortcut_signature(Chat.verify, Bot.verify_chat, ["chat_id"], [])
assert await check_shortcut_call(chat.verify, chat.get_bot(), "verify_chat")
assert await check_defaults_handling(chat.verify, chat.get_bot())
monkeypatch.setattr(chat.get_bot(), "verify_chat", make_assertion)
assert await chat.verify(
custom_description="This is a custom description",
)
async def test_instance_method_remove_chat_verification(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id
assert check_shortcut_signature(
Chat.remove_verification, Bot.remove_chat_verification, ["chat_id"], []
)
assert await check_shortcut_call(
chat.remove_verification, chat.get_bot(), "remove_chat_verification"
)
assert await check_defaults_handling(chat.remove_verification, chat.get_bot())
monkeypatch.setattr(chat.get_bot(), "remove_chat_verification", make_assertion)
assert await chat.remove_verification()
def test_mention_html(self):
chat = Chat(id=1, type="foo")
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):

View file

@ -34,6 +34,7 @@ def gift(request):
star_count=GiftTestBase.star_count,
total_count=GiftTestBase.total_count,
remaining_count=GiftTestBase.remaining_count,
upgrade_star_count=GiftTestBase.upgrade_star_count,
)
@ -51,6 +52,7 @@ class GiftTestBase:
star_count = 5
total_count = 10
remaining_count = 5
upgrade_star_count = 10
class TestGiftWithoutRequest(GiftTestBase):
@ -66,6 +68,7 @@ class TestGiftWithoutRequest(GiftTestBase):
"star_count": self.star_count,
"total_count": self.total_count,
"remaining_count": self.remaining_count,
"upgrade_star_count": self.upgrade_star_count,
}
gift = Gift.de_json(json_dict, offline_bot)
assert gift.api_kwargs == {}
@ -75,6 +78,7 @@ class TestGiftWithoutRequest(GiftTestBase):
assert gift.star_count == self.star_count
assert gift.total_count == self.total_count
assert gift.remaining_count == self.remaining_count
assert gift.upgrade_star_count == self.upgrade_star_count
assert Gift.de_json(None, offline_bot) is None
@ -87,12 +91,25 @@ class TestGiftWithoutRequest(GiftTestBase):
assert gift_dict["star_count"] == self.star_count
assert gift_dict["total_count"] == self.total_count
assert gift_dict["remaining_count"] == self.remaining_count
assert gift_dict["upgrade_star_count"] == self.upgrade_star_count
def test_equality(self, gift):
a = gift
b = Gift(self.id, self.sticker, self.star_count, self.total_count, self.remaining_count)
b = Gift(
self.id,
self.sticker,
self.star_count,
self.total_count,
self.remaining_count,
self.upgrade_star_count,
)
c = Gift(
"other_uid", self.sticker, self.star_count, self.total_count, self.remaining_count
"other_uid",
self.sticker,
self.star_count,
self.total_count,
self.remaining_count,
self.upgrade_star_count,
)
d = BotCommand("start", "description")
@ -115,6 +132,7 @@ class TestGiftWithoutRequest(GiftTestBase):
5,
10,
5,
10,
),
],
ids=["string", "Gift"],
@ -134,11 +152,18 @@ class TestGiftWithoutRequest(GiftTestBase):
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
pay_for_upgrade = request_data.parameters["pay_for_upgrade"] is True
return user_id and gift_id and text and text_parse_mode and tes and pay_for_upgrade
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
"user_id",
gift,
"text",
text_parse_mode="text_parse_mode",
text_entities=text_entities,
pay_for_upgrade=True,
)
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
@ -184,6 +209,7 @@ class GiftsTestBase:
star_count=5,
total_count=5,
remaining_count=5,
upgrade_star_count=5,
),
Gift(
id="id2",
@ -199,6 +225,7 @@ class GiftsTestBase:
star_count=6,
total_count=6,
remaining_count=6,
upgrade_star_count=6,
),
Gift(
id="id3",
@ -214,6 +241,7 @@ class GiftsTestBase:
star_count=7,
total_count=7,
remaining_count=7,
upgrade_star_count=7,
),
]
@ -236,6 +264,7 @@ class TestGiftsWithoutRequest(GiftsTestBase):
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 de_json_gift.upgrade_star_count == original_gift.upgrade_star_count
assert Gifts.de_json(None, offline_bot) is None

View file

@ -200,7 +200,8 @@ def ignored_param_requirements(object_name: str) -> set[str]:
# Arguments that are optional arguments for now for backwards compatibility
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {
"send_invoice|create_invoice_link|InputInvoiceMessageContent": {"provider_token"}
"send_invoice|create_invoice_link|InputInvoiceMessageContent": {"provider_token"},
"InlineQueryResultArticle": {"hide_url"},
}

View file

@ -742,3 +742,34 @@ class TestUserWithoutRequest(UserTestBase):
text_parse_mode="text_parse_mode",
text_entities="text_entities",
)
async def test_instance_method_verify_user(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return (
kwargs["user_id"] == user.id
and kwargs["custom_description"] == "This is a custom description"
)
assert check_shortcut_signature(user.verify, Bot.verify_user, ["user_id"], [])
assert await check_shortcut_call(user.verify, user.get_bot(), "verify_user")
assert await check_defaults_handling(user.verify, user.get_bot())
monkeypatch.setattr(user.get_bot(), "verify_user", make_assertion)
assert await user.verify(
custom_description="This is a custom description",
)
async def test_instance_method_remove_user_verification(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return kwargs["user_id"] == user.id
assert check_shortcut_signature(
user.remove_verification, Bot.remove_user_verification, ["user_id"], []
)
assert await check_shortcut_call(
user.remove_verification, user.get_bot(), "remove_user_verification"
)
assert await check_defaults_handling(user.remove_verification, user.get_bot())
monkeypatch.setattr(user.get_bot(), "remove_user_verification", make_assertion)
assert await user.remove_verification()