mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
API 6.7 (#3673)
Co-authored-by: Dmitry Kolomatskiy <58207913+lemontree210@users.noreply.github.com> Co-authored-by: Harshil Mehta <37377066+harshil21@users.noreply.github.com> Co-authored-by: poolitzer <github@poolitzer.eu> Co-authored-by: Aditya <clot27@apx_managed.vanilla>
This commit is contained in:
parent
450dc2115c
commit
8c252c9822
30 changed files with 1236 additions and 91 deletions
|
@ -14,7 +14,7 @@
|
|||
:target: https://pypi.org/project/python-telegram-bot/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.6-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
|||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **6.6** are supported.
|
||||
All types and methods of the Telegram Bot API **6.7** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
:target: https://pypi.org/project/python-telegram-bot-raw/
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.6-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-6.7-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju
|
|||
Telegram API support
|
||||
====================
|
||||
|
||||
All types and methods of the Telegram Bot API **6.6** are supported.
|
||||
All types and methods of the Telegram Bot API **6.7** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
|
|
@ -196,6 +196,10 @@
|
|||
- Used for setting the short description of the bot
|
||||
* - :meth:`~telegram.Bot.get_my_short_description`
|
||||
- Used for obtaining the short description of the bot
|
||||
* - :meth:`~telegram.Bot.set_my_name`
|
||||
- Used for setting the name of the bot
|
||||
* - :meth:`~telegram.Bot.get_my_name`
|
||||
- Used for obtaining the name of the bot
|
||||
|
||||
.. raw:: html
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ Available Types
|
|||
telegram.botcommandscopechatmember
|
||||
telegram.botcommandscopedefault
|
||||
telegram.botdescription
|
||||
telegram.botname
|
||||
telegram.botshortdescription
|
||||
telegram.callbackquery
|
||||
telegram.chat
|
||||
|
@ -78,6 +79,7 @@ Available Types
|
|||
telegram.replykeyboardmarkup
|
||||
telegram.replykeyboardremove
|
||||
telegram.sentwebappmessage
|
||||
telegram.switchinlinequerychosenchat
|
||||
telegram.telegramobject
|
||||
telegram.update
|
||||
telegram.user
|
||||
|
|
6
docs/source/telegram.botname.rst
Normal file
6
docs/source/telegram.botname.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BotName
|
||||
=======
|
||||
|
||||
.. autoclass:: telegram.BotName
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -24,6 +24,7 @@ Inline Mode
|
|||
telegram.inlinequeryresultlocation
|
||||
telegram.inlinequeryresultmpeg4gif
|
||||
telegram.inlinequeryresultphoto
|
||||
telegram.inlinequeryresultsbutton
|
||||
telegram.inlinequeryresultvenue
|
||||
telegram.inlinequeryresultvideo
|
||||
telegram.inlinequeryresultvoice
|
||||
|
|
6
docs/source/telegram.inlinequeryresultsbutton.rst
Normal file
6
docs/source/telegram.inlinequeryresultsbutton.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
InlineQueryResultsButton
|
||||
========================
|
||||
|
||||
.. autoclass:: telegram.InlineQueryResultsButton
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.switchinlinequerychosenchat.rst
Normal file
6
docs/source/telegram.switchinlinequerychosenchat.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
SwitchInlineQueryChosenChat
|
||||
===========================
|
||||
|
||||
.. autoclass:: telegram.SwitchInlineQueryChosenChat
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -38,6 +38,7 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
"BotCommandScopeChatMember",
|
||||
"BotCommandScopeDefault",
|
||||
"BotDescription",
|
||||
"BotName",
|
||||
"BotShortDescription",
|
||||
"CallbackGame",
|
||||
"CallbackQuery",
|
||||
|
@ -102,6 +103,7 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
"InlineQueryResultLocation",
|
||||
"InlineQueryResultMpeg4Gif",
|
||||
"InlineQueryResultPhoto",
|
||||
"InlineQueryResultsButton",
|
||||
"InlineQueryResultVenue",
|
||||
"InlineQueryResultVideo",
|
||||
"InlineQueryResultVoice",
|
||||
|
@ -169,6 +171,7 @@ __all__ = ( # Keep this alphabetically ordered
|
|||
"Sticker",
|
||||
"StickerSet",
|
||||
"SuccessfulPayment",
|
||||
"SwitchInlineQueryChosenChat",
|
||||
"TelegramObject",
|
||||
"Update",
|
||||
"User",
|
||||
|
@ -204,6 +207,7 @@ from ._botcommandscope import (
|
|||
BotCommandScopeDefault,
|
||||
)
|
||||
from ._botdescription import BotDescription, BotShortDescription
|
||||
from ._botname import BotName
|
||||
from ._callbackquery import CallbackQuery
|
||||
from ._chat import Chat
|
||||
from ._chatadministratorrights import ChatAdministratorRights
|
||||
|
@ -280,6 +284,7 @@ from ._inline.inlinequeryresultgif import InlineQueryResultGif
|
|||
from ._inline.inlinequeryresultlocation import InlineQueryResultLocation
|
||||
from ._inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif
|
||||
from ._inline.inlinequeryresultphoto import InlineQueryResultPhoto
|
||||
from ._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from ._inline.inlinequeryresultvenue import InlineQueryResultVenue
|
||||
from ._inline.inlinequeryresultvideo import InlineQueryResultVideo
|
||||
from ._inline.inlinequeryresultvoice import InlineQueryResultVoice
|
||||
|
@ -336,6 +341,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
|||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
from ._sentwebappmessage import SentWebAppMessage
|
||||
from ._shared import ChatShared, UserShared
|
||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from ._telegramobject import TelegramObject
|
||||
from ._update import Update
|
||||
from ._user import User
|
||||
|
|
146
telegram/_bot.py
146
telegram/_bot.py
|
@ -56,6 +56,7 @@ except ImportError:
|
|||
from telegram._botcommand import BotCommand
|
||||
from telegram._botcommandscope import BotCommandScope
|
||||
from telegram._botdescription import BotDescription, BotShortDescription
|
||||
from telegram._botname import BotName
|
||||
from telegram._chat import Chat
|
||||
from telegram._chatadministratorrights import ChatAdministratorRights
|
||||
from telegram._chatinvitelink import ChatInviteLink
|
||||
|
@ -79,6 +80,7 @@ from telegram._files.voice import Voice
|
|||
from telegram._forumtopic import ForumTopic
|
||||
from telegram._games.gamehighscore import GameHighScore
|
||||
from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._menubutton import MenuButton
|
||||
from telegram._message import Message
|
||||
from telegram._messageid import MessageId
|
||||
|
@ -2811,8 +2813,15 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
cache_time: int = None,
|
||||
is_personal: bool = None,
|
||||
next_offset: str = None,
|
||||
# Deprecated params since bot api 6.7
|
||||
# <----
|
||||
switch_pm_text: str = None,
|
||||
switch_pm_parameter: str = None,
|
||||
# --->
|
||||
# New params since bot api 6.7
|
||||
# <----
|
||||
button: InlineQueryResultsButton = None,
|
||||
# --->
|
||||
*,
|
||||
current_offset: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -2825,15 +2834,6 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
Use this method to send answers to an inline query. No more than
|
||||
:tg-const:`telegram.InlineQuery.MAX_RESULTS` results per query are allowed.
|
||||
|
||||
Example:
|
||||
An inline bot that sends YouTube videos can ask the user to connect the bot to their
|
||||
YouTube account to adapt search results accordingly. To do this, it displays a
|
||||
'Connect your YouTube account' button above the results, or even before showing any.
|
||||
The user presses the button, switches to a private chat with the bot and, in doing so,
|
||||
passes a start parameter that instructs the bot to return an OAuth link. Once done, the
|
||||
bot can offer a switch_inline button so that the user can easily return to the chat
|
||||
where they wanted to use the bot's inline capabilities.
|
||||
|
||||
Warning:
|
||||
In most use cases :paramref:`current_offset` should not be passed manually. Instead of
|
||||
calling this method directly, use the shortcut :meth:`telegram.InlineQuery.answer` with
|
||||
|
@ -2842,6 +2842,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
|
||||
.. seealso:: :wiki:`Working with Files and Media <Working-with-Files-and-Media>`
|
||||
|
||||
.. |api6_7_depr| replace:: Since Bot API 6.7, this argument is deprecated in favour of
|
||||
:paramref:`button`.
|
||||
|
||||
Args:
|
||||
inline_query_id (:obj:`str`): Unique identifier for the answered query.
|
||||
results (List[:class:`telegram.InlineQueryResult`] | Callable): A list of results for
|
||||
|
@ -2862,12 +2865,22 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
switch_pm_text (:obj:`str`, optional): If passed, clients will display a button with
|
||||
specified text that switches the user to a private chat with the bot and sends the
|
||||
bot a start message with the parameter :paramref:`switch_pm_parameter`.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|api6_7_depr|
|
||||
switch_pm_parameter (:obj:`str`, optional): Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
:tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
|
||||
:tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
|
||||
only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|api6_7_depr|
|
||||
button (:class:`telegram.InlineQueryResultsButton`, optional): A button to be shown
|
||||
above the inline query results.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
current_offset (:obj:`str`, optional): The :attr:`telegram.InlineQuery.offset` of
|
||||
the inline query to answer. If passed, PTB will automatically take care of
|
||||
|
@ -2881,6 +2894,26 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
if (switch_pm_text or switch_pm_parameter) and button:
|
||||
raise TypeError(
|
||||
"Since Bot API 6.7, the parameter `button is mutually exclusive to the deprecated "
|
||||
"parameters `switch_pm_text` and `switch_pm_parameter`. Please use the new "
|
||||
"parameter `button`."
|
||||
)
|
||||
|
||||
if switch_pm_text and switch_pm_parameter:
|
||||
self._warn(
|
||||
"Since Bot API 6.7, the parameters `switch_pm_text` and `switch_pm_parameter` are "
|
||||
"deprecated in favour of the new parameter `button`. Please use the new parameter "
|
||||
"`button` instead.",
|
||||
category=PTBDeprecationWarning,
|
||||
stacklevel=3,
|
||||
)
|
||||
button = InlineQueryResultsButton(
|
||||
text=switch_pm_text,
|
||||
start_parameter=switch_pm_parameter,
|
||||
)
|
||||
|
||||
effective_results, next_offset = self._effective_inline_results(
|
||||
results=results, next_offset=next_offset, current_offset=current_offset
|
||||
)
|
||||
|
@ -2896,8 +2929,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"next_offset": next_offset,
|
||||
"cache_time": cache_time,
|
||||
"is_personal": is_personal,
|
||||
"switch_pm_text": switch_pm_text,
|
||||
"switch_pm_parameter": switch_pm_parameter,
|
||||
"button": button,
|
||||
}
|
||||
|
||||
return await self._post(
|
||||
|
@ -8138,6 +8170,94 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
bot=self,
|
||||
)
|
||||
|
||||
@_log
|
||||
async def set_my_name(
|
||||
self,
|
||||
name: str = None,
|
||||
language_code: 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: JSONDict = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Use this method to change the bot's name.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
name (:obj:`str`, optional): New bot name;
|
||||
0-:tg-const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`
|
||||
characters. Pass an empty string to remove the dedicated name for the given
|
||||
language.
|
||||
|
||||
Caution:
|
||||
If :paramref:`language_code` is not specified, a :paramref:`name` *must*
|
||||
be specified.
|
||||
language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
|
||||
the name will be applied to all users for whose language there is no
|
||||
dedicated name.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data: JSONDict = {"name": name, "language_code": language_code}
|
||||
|
||||
return await self._post(
|
||||
"setMyName",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
@_log
|
||||
async def get_my_name(
|
||||
self,
|
||||
language_code: 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: JSONDict = None,
|
||||
) -> BotName:
|
||||
"""
|
||||
Use this method to get the current bot name for the given user language.
|
||||
|
||||
Args:
|
||||
language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty
|
||||
string.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.BotName`: On success, the bot name is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
data = {"language_code": language_code}
|
||||
return BotName.de_json( # type: ignore[return-value]
|
||||
await self._post(
|
||||
"getMyName",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
),
|
||||
bot=self,
|
||||
)
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict: # skipcq: PYL-W0613
|
||||
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
||||
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
||||
|
@ -8382,3 +8502,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""Alias for :meth:`set_sticker_keywords`"""
|
||||
setStickerMaskPosition = set_sticker_mask_position
|
||||
"""Alias for :meth:`set_sticker_mask_position`"""
|
||||
setMyName = set_my_name
|
||||
"""Alias for :meth:`set_my_name`"""
|
||||
getMyName = get_my_name
|
||||
"""Alias for :meth:`get_my_name`"""
|
||||
|
|
54
telegram/_botname.py
Normal file
54
telegram/_botname.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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 represent a Telegram bots name."""
|
||||
from typing import ClassVar
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class BotName(TelegramObject):
|
||||
"""This object represents the bot's name.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`name` is equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
name (:obj:`str`): The bot's name.
|
||||
|
||||
Attributes:
|
||||
name (:obj:`str`): The bot's name.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("name",)
|
||||
|
||||
def __init__(self, name: str, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.name = name
|
||||
|
||||
self._id_attrs = (self.name,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
MAX_LENGTH: ClassVar[int] = constants.BotNameLimit.MAX_NAME_LENGTH
|
||||
""":const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`"""
|
|
@ -59,6 +59,10 @@ class ChatMemberUpdated(TelegramObject):
|
|||
new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
|
||||
invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used
|
||||
by the user to join the chat. For joining by invite link events only.
|
||||
via_chat_folder_invite_link (:obj:`bool`, optional): :obj:`True`, if the user joined the
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
chat (:class:`telegram.Chat`): Chat the user belongs to.
|
||||
|
@ -72,6 +76,10 @@ class ChatMemberUpdated(TelegramObject):
|
|||
new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
|
||||
invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used
|
||||
by the user to join the chat. For joining by invite link events only.
|
||||
via_chat_folder_invite_link (:obj:`bool`): Optional. :obj:`True`, if the user joined the
|
||||
chat via a chat folder invite link
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
"""
|
||||
|
||||
|
@ -82,6 +90,7 @@ class ChatMemberUpdated(TelegramObject):
|
|||
"old_chat_member",
|
||||
"new_chat_member",
|
||||
"invite_link",
|
||||
"via_chat_folder_invite_link",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
@ -92,6 +101,7 @@ class ChatMemberUpdated(TelegramObject):
|
|||
old_chat_member: ChatMember,
|
||||
new_chat_member: ChatMember,
|
||||
invite_link: ChatInviteLink = None,
|
||||
via_chat_folder_invite_link: bool = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
|
@ -102,6 +112,7 @@ class ChatMemberUpdated(TelegramObject):
|
|||
self.date: datetime.datetime = date
|
||||
self.old_chat_member: ChatMember = old_chat_member
|
||||
self.new_chat_member: ChatMember = new_chat_member
|
||||
self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link
|
||||
|
||||
# Optionals
|
||||
self.invite_link: Optional[ChatInviteLink] = invite_link
|
||||
|
|
|
@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, ClassVar, Optional, Union
|
|||
from telegram import constants
|
||||
from telegram._games.callbackgame import CallbackGame
|
||||
from telegram._loginurl import LoginUrl
|
||||
from telegram._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._webappinfo import WebAppInfo
|
||||
|
@ -111,6 +112,10 @@ class InlineKeyboardButton(TelegramObject):
|
|||
in inline mode when they are currently in a private chat with it. Especially useful
|
||||
when combined with ``switch_pm*`` actions - in this case the user will be automatically
|
||||
returned to the chat they switched from, skipping the chat selection screen.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
|
@ -122,6 +127,20 @@ class InlineKeyboardButton(TelegramObject):
|
|||
pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. This type of button
|
||||
**must** always be the **first** button in the first row and can only be used in
|
||||
invoice messages.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`, optional):
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Tip:
|
||||
This is similar to :paramref:`switch_inline_query`, but gives more control on
|
||||
which chats can be selected.
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that this field works correctly only if your Telegram
|
||||
client is released after April 20th 2023.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
|
@ -154,6 +173,10 @@ class InlineKeyboardButton(TelegramObject):
|
|||
in inline mode when they are currently in a private chat with it. Especially useful
|
||||
when combined with ``switch_pm*`` actions - in this case the user will be automatically
|
||||
returned to the chat they switched from, skipping the chat selection screen.
|
||||
|
||||
Tip:
|
||||
This is similar to the new parameter :paramref:`switch_inline_query_chosen_chat`,
|
||||
but gives no control over which chats can be selected.
|
||||
switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will
|
||||
insert the bot's username and the specified inline query in the current chat's input
|
||||
field. Can be empty, in which case only the bot's username will be inserted. This
|
||||
|
@ -165,7 +188,20 @@ class InlineKeyboardButton(TelegramObject):
|
|||
pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. This type of button
|
||||
**must** always be the **first** button in the first row and can only be used in
|
||||
invoice messages.
|
||||
switch_inline_query_chosen_chat (:obj:`telegram.SwitchInlineQueryChosenChat`): Optional.
|
||||
If set, pressing the button will prompt the user to select one of their chats of the
|
||||
specified type, open that chat and insert the bot's username and the specified inline
|
||||
query in the input field.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Tip:
|
||||
This is similar to :attr:`switch_inline_query`, but gives more control on
|
||||
which chats can be selected.
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that this field works correctly only if your Telegram
|
||||
client is released after April 20th 2023.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
|
@ -178,6 +214,7 @@ class InlineKeyboardButton(TelegramObject):
|
|||
"text",
|
||||
"login_url",
|
||||
"web_app",
|
||||
"switch_inline_query_chosen_chat",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
|
@ -191,6 +228,7 @@ class InlineKeyboardButton(TelegramObject):
|
|||
pay: bool = None,
|
||||
login_url: LoginUrl = None,
|
||||
web_app: WebAppInfo = None,
|
||||
switch_inline_query_chosen_chat: SwitchInlineQueryChosenChat = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
|
@ -207,6 +245,9 @@ class InlineKeyboardButton(TelegramObject):
|
|||
self.callback_game: Optional[CallbackGame] = callback_game
|
||||
self.pay: Optional[bool] = pay
|
||||
self.web_app: Optional[WebAppInfo] = web_app
|
||||
self.switch_inline_query_chosen_chat: Optional[
|
||||
SwitchInlineQueryChosenChat
|
||||
] = switch_inline_query_chosen_chat
|
||||
self._id_attrs = ()
|
||||
self._set_id_attrs()
|
||||
|
||||
|
@ -236,6 +277,9 @@ class InlineKeyboardButton(TelegramObject):
|
|||
data["login_url"] = LoginUrl.de_json(data.get("login_url"), bot)
|
||||
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
|
||||
data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot)
|
||||
data["switch_inline_query_chosen_chat"] = SwitchInlineQueryChosenChat.de_json(
|
||||
data.get("switch_inline_query_chosen_chat"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Callable, ClassVar, Optional, Sequence, Union
|
|||
|
||||
from telegram import constants
|
||||
from telegram._files.location import Location
|
||||
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
|
@ -146,6 +147,7 @@ class InlineQuery(TelegramObject):
|
|||
next_offset: str = None,
|
||||
switch_pm_text: str = None,
|
||||
switch_pm_parameter: str = None,
|
||||
button: InlineQueryResultsButton = None,
|
||||
*,
|
||||
current_offset: str = None,
|
||||
auto_pagination: bool = False,
|
||||
|
@ -192,6 +194,7 @@ class InlineQuery(TelegramObject):
|
|||
next_offset=next_offset,
|
||||
switch_pm_text=switch_pm_text,
|
||||
switch_pm_parameter=switch_pm_parameter,
|
||||
button=button,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
|
117
telegram/_inline/inlinequeryresultsbutton.py
Normal file
117
telegram/_inline/inlinequeryresultsbutton.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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/].
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains the class that represent a Telegram InlineQueryResultsButton."""
|
||||
|
||||
from typing import TYPE_CHECKING, ClassVar, Optional
|
||||
|
||||
from telegram import constants
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._webappinfo import WebAppInfo
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class InlineQueryResultsButton(TelegramObject):
|
||||
"""This object represents a button to be shown above inline query results. You **must** use
|
||||
exactly one of the optional fields.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`text`, :attr:`web_app` and :attr:`start_parameter` are equal.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
web_app (:class:`telegram.WebAppInfo`, optional): Description of the
|
||||
`Web App <https://core.telegram.org/bots/webapps>`_ that will be launched when the
|
||||
user presses the button. The Web App will be able to switch back to the inline mode
|
||||
using the method
|
||||
`switchInlineQuery <https://core.telegram.org/bots/webapps#initializing-web-apps>`_
|
||||
inside the Web App.
|
||||
start_parameter (:obj:`str`, optional): Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
:tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
|
||||
:tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
|
||||
only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
|
||||
|
||||
Example:
|
||||
An inline bot that sends YouTube videos can ask the user to connect the bot to
|
||||
their YouTube account to adapt search results accordingly. To do this, it displays
|
||||
a 'Connect your YouTube account' button above the results, or even before showing
|
||||
any. The user presses the button, switches to a private chat with the bot and, in
|
||||
doing so, passes a start parameter that instructs the bot to return an OAuth link.
|
||||
Once done, the bot can offer a switch_inline button so that the user can easily
|
||||
return to the chat where they wanted to use the bot's inline capabilities.
|
||||
|
||||
Attributes:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
web_app (:class:`telegram.WebAppInfo`): Optional. Description of the
|
||||
`Web App <https://core.telegram.org/bots/webapps>`_ that will be launched when the
|
||||
user presses the button. The Web App will be able to switch back to the inline mode
|
||||
using the method ``web_app_switch_inline_query`` inside the Web App.
|
||||
start_parameter (:obj:`str`): Optional. Deep-linking parameter for the
|
||||
:guilabel:`/start` message sent to the bot when user presses the switch button.
|
||||
:tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
|
||||
:tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
|
||||
only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("text", "web_app", "start_parameter")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
web_app: WebAppInfo = None,
|
||||
start_parameter: str = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.text: str = text
|
||||
|
||||
# Optional
|
||||
self.web_app: Optional[WebAppInfo] = web_app
|
||||
self.start_parameter: Optional[str] = start_parameter
|
||||
|
||||
self._id_attrs = (self.text, self.web_app, self.start_parameter)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["InlineQueryResultsButton"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
MIN_START_PARAMETER_LENGTH: ClassVar[
|
||||
int
|
||||
] = constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH
|
||||
""":const:`telegram.constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`"""
|
||||
MAX_START_PARAMETER_LENGTH: ClassVar[
|
||||
int
|
||||
] = constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH
|
||||
""":const:`telegram.constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`"""
|
|
@ -59,6 +59,7 @@ from telegram._utils.argumentparsing import parse_sequence_arg
|
|||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._videochat import (
|
||||
VideoChatEnded,
|
||||
VideoChatParticipantsInvited,
|
||||
|
@ -69,6 +70,7 @@ from telegram._webappdata import WebAppData
|
|||
from telegram._writeaccessallowed import WriteAccessAllowed
|
||||
from telegram.constants import MessageAttachmentType, ParseMode
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import (
|
||||
|
@ -578,8 +580,13 @@ class Message(TelegramObject):
|
|||
|
||||
.. versionadded:: 20.1
|
||||
|
||||
.. |custom_emoji_formatting_note| replace:: Custom emoji entities will currently be ignored
|
||||
by this function. Instead, the supplied replacement for the emoji will be used.
|
||||
.. |custom_emoji_formatting_note| replace:: Custom emoji entities will be ignored by this
|
||||
function. Instead, the supplied replacement for the emoji will be used.
|
||||
|
||||
.. |custom_emoji_md1_deprecation| replace:: Since custom emoji entities are not supported by
|
||||
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method will raise a
|
||||
:exc:`ValueError` in future versions instead of falling back to the supplied replacement
|
||||
for the emoji.
|
||||
"""
|
||||
|
||||
# fmt: on
|
||||
|
@ -3317,6 +3324,10 @@ class Message(TelegramObject):
|
|||
insert = f"<s>{escaped_text}</s>"
|
||||
elif entity.type == MessageEntity.SPOILER:
|
||||
insert = f'<span class="tg-spoiler">{escaped_text}</span>'
|
||||
elif entity.type == MessageEntity.CUSTOM_EMOJI:
|
||||
insert = (
|
||||
f'<tg-emoji emoji-id="{entity.custom_emoji_id}">{escaped_text}</tg-emoji>'
|
||||
)
|
||||
else:
|
||||
insert = escaped_text
|
||||
|
||||
|
@ -3355,12 +3366,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message text with the entities formatted as HTML in
|
||||
the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as HTML.
|
||||
|
||||
|
@ -3374,12 +3385,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message text with the entities formatted as HTML.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as HTML.
|
||||
|
||||
|
@ -3394,12 +3405,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
HTML in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as HTML.
|
||||
"""
|
||||
|
@ -3413,12 +3424,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as HTML.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as HTML.
|
||||
"""
|
||||
|
@ -3522,6 +3533,26 @@ class Message(TelegramObject):
|
|||
"Spoiler entities are not supported for Markdown version 1"
|
||||
)
|
||||
insert = f"||{escaped_text}||"
|
||||
elif entity.type == MessageEntity.CUSTOM_EMOJI:
|
||||
if version == 1:
|
||||
# this ensures compatibility to previous PTB versions
|
||||
insert = escaped_text
|
||||
warn(
|
||||
"Custom emoji entities are not supported for Markdown version 1. "
|
||||
"Future version of PTB will raise a ValueError instead of falling "
|
||||
"back to the alternative standard emoji.",
|
||||
stacklevel=3,
|
||||
category=PTBDeprecationWarning,
|
||||
)
|
||||
else:
|
||||
# This should never be needed because ids are numeric but the documentation
|
||||
# specifically mentions it so here we are
|
||||
custom_emoji_id = escape_markdown(
|
||||
entity.custom_emoji_id,
|
||||
version=version,
|
||||
entity_type=MessageEntity.CUSTOM_EMOJI,
|
||||
)
|
||||
insert = f"![{escaped_text}](tg://emoji?id={custom_emoji_id})"
|
||||
else:
|
||||
insert = escaped_text
|
||||
|
||||
|
@ -3570,6 +3601,9 @@ class Message(TelegramObject):
|
|||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
|
@ -3588,12 +3622,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message text with the entities formatted as Markdown
|
||||
in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
"""
|
||||
|
@ -3614,6 +3648,9 @@ class Message(TelegramObject):
|
|||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
|
||||
|
@ -3632,12 +3669,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message text with the entities formatted as Markdown.
|
||||
This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message text with entities formatted as Markdown.
|
||||
"""
|
||||
|
@ -3658,6 +3695,9 @@ class Message(TelegramObject):
|
|||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
|
@ -3676,12 +3716,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown in the same way the original message was formatted.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
"""
|
||||
|
@ -3704,6 +3744,9 @@ class Message(TelegramObject):
|
|||
|
||||
* |custom_emoji_formatting_note|
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
|custom_emoji_md1_deprecation|
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
|
||||
|
@ -3722,12 +3765,12 @@ class Message(TelegramObject):
|
|||
Use this if you want to retrieve the message caption with the caption entities formatted as
|
||||
Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink.
|
||||
|
||||
Note:
|
||||
|custom_emoji_formatting_note|
|
||||
|
||||
.. versionchanged:: 13.10
|
||||
Spoiler entities are now formatted as Markdown V2.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entities are now supported.
|
||||
|
||||
Returns:
|
||||
:obj:`str`: Message caption with caption entities formatted as Markdown.
|
||||
"""
|
||||
|
|
99
telegram/_switchinlinequerychosenchat.py
Normal file
99
telegram/_switchinlinequerychosenchat.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# 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
|
||||
"""This module contains a class that represents a Telegram SwitchInlineQueryChosenChat."""
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class SwitchInlineQueryChosenChat(TelegramObject):
|
||||
"""
|
||||
This object represents an inline button that switches the current user to inline mode in a
|
||||
chosen chat, with an optional default inline query.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`query`, :attr:`allow_user_chats`, :attr:`allow_bot_chats`,
|
||||
:attr:`allow_group_chats`, and :attr:`allow_channel_chats` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Caution:
|
||||
The PTB team has discovered that you must pass at least one of
|
||||
:paramref:`allow_user_chats`, :paramref:`allow_bot_chats`, :paramref:`allow_group_chats`,
|
||||
or :paramref:`allow_channel_chats` to Telegram. Otherwise, an error will be raised.
|
||||
|
||||
Args:
|
||||
query (:obj:`str`, optional): The default inline query to be inserted in the input field.
|
||||
If left empty, only the bot's username will be inserted.
|
||||
allow_user_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with users
|
||||
can be chosen.
|
||||
allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True`, if private chats with bots can
|
||||
be chosen.
|
||||
allow_group_chats (:obj:`bool`, optional): Pass :obj:`True`, if group and supergroup chats
|
||||
can be chosen.
|
||||
allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True`, if channel chats can be
|
||||
chosen.
|
||||
|
||||
Attributes:
|
||||
query (:obj:`str`): Optional. The default inline query to be inserted in the input field.
|
||||
If left empty, only the bot's username will be inserted.
|
||||
allow_user_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with users can be
|
||||
chosen.
|
||||
allow_bot_chats (:obj:`bool`): Optional. :obj:`True`, if private chats with bots can be
|
||||
chosen.
|
||||
allow_group_chats (:obj:`bool`): Optional. :obj:`True`, if group and supergroup chats can
|
||||
be chosen.
|
||||
allow_channel_chats (:obj:`bool`): Optional. :obj:`True`, if channel chats can be chosen.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"query",
|
||||
"allow_user_chats",
|
||||
"allow_bot_chats",
|
||||
"allow_group_chats",
|
||||
"allow_channel_chats",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
query: str = None,
|
||||
allow_user_chats: bool = None,
|
||||
allow_bot_chats: bool = None,
|
||||
allow_group_chats: bool = None,
|
||||
allow_channel_chats: bool = None,
|
||||
*,
|
||||
api_kwargs: JSONDict = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Optional
|
||||
self.query = query
|
||||
self.allow_user_chats = allow_user_chats
|
||||
self.allow_bot_chats = allow_bot_chats
|
||||
self.allow_group_chats = allow_group_chats
|
||||
self.allow_channel_chats = allow_channel_chats
|
||||
|
||||
self._id_attrs = (
|
||||
self.query,
|
||||
self.allow_user_chats,
|
||||
self.allow_bot_chats,
|
||||
self.allow_group_chats,
|
||||
self.allow_channel_chats,
|
||||
)
|
||||
|
||||
self._freeze()
|
|
@ -17,21 +17,35 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains objects related to the write access allowed service message."""
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class WriteAccessAllowed(TelegramObject):
|
||||
"""
|
||||
This object represents a service message about a user allowing a bot added to the attachment
|
||||
menu to write messages. Currently holds no information.
|
||||
This object represents a service message about a user allowing a bot to write messages after
|
||||
adding the bot to the attachment menu or launching a Web App from a link.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
Args:
|
||||
web_app_name (:obj:`str`, optional): Name of the Web App which was launched from a link.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
web_app_name (:obj:`str`): Optional. Name of the Web App which was launched from a link.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
__slots__ = ("web_app_name",)
|
||||
|
||||
def __init__(self, *, api_kwargs: JSONDict = None):
|
||||
def __init__(self, web_app_name: str = None, *, api_kwargs: JSONDict = None):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.web_app_name: Optional[str] = web_app_name
|
||||
|
||||
self._freeze()
|
||||
|
|
|
@ -37,6 +37,7 @@ __all__ = [
|
|||
"BotCommandLimit",
|
||||
"BotCommandScopeType",
|
||||
"BotDescriptionLimit",
|
||||
"BotNameLimit",
|
||||
"CallbackQueryLimit",
|
||||
"ChatAction",
|
||||
"ChatID",
|
||||
|
@ -57,6 +58,7 @@ __all__ = [
|
|||
"InlineKeyboardMarkupLimit",
|
||||
"InlineQueryLimit",
|
||||
"InlineQueryResultLimit",
|
||||
"InlineQueryResultsButtonLimit",
|
||||
"InlineQueryResultType",
|
||||
"InputMediaType",
|
||||
"InvoiceLimit",
|
||||
|
@ -114,7 +116,7 @@ class _BotAPIVersion(NamedTuple):
|
|||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO = _BotAPIVersion(major=6, minor=6)
|
||||
BOT_API_VERSION_INFO = _BotAPIVersion(major=6, minor=7)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
|
@ -209,6 +211,21 @@ class BotDescriptionLimit(IntEnum):
|
|||
"""
|
||||
|
||||
|
||||
class BotNameLimit(IntEnum):
|
||||
"""This enum contains limitations for the methods :meth:`telegram.Bot.set_my_name`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MAX_NAME_LENGTH = 64
|
||||
""":obj:`int`: Maximum length for the parameter :paramref:`~telegram.Bot.set_my_name.name` of
|
||||
:meth:`telegram.Bot.set_my_name`
|
||||
"""
|
||||
|
||||
|
||||
class CallbackQueryLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.CallbackQuery`/
|
||||
:meth:`telegram.Bot.answer_callback_query`. The enum members of this enumeration are instances
|
||||
|
@ -735,11 +752,19 @@ class InlineQueryLimit(IntEnum):
|
|||
MIN_SWITCH_PM_TEXT_LENGTH = 1
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of
|
||||
:meth:`telegram.Bot.answer_inline_query`."""
|
||||
:meth:`telegram.Bot.answer_inline_query`.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`.
|
||||
"""
|
||||
MAX_SWITCH_PM_TEXT_LENGTH = 64
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.Bot.answer_inline_query.switch_pm_parameter` parameter of
|
||||
:meth:`telegram.Bot.answer_inline_query`."""
|
||||
:meth:`telegram.Bot.answer_inline_query`.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Deprecated in favor of :attr:`InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`.
|
||||
"""
|
||||
|
||||
|
||||
class InlineQueryResultLimit(IntEnum):
|
||||
|
@ -763,6 +788,26 @@ class InlineQueryResultLimit(IntEnum):
|
|||
"""
|
||||
|
||||
|
||||
class InlineQueryResultsButtonLimit(IntEnum):
|
||||
"""This enum contains limitations for :class:`telegram.InlineQueryResultsButton`.
|
||||
The enum members of this enumeration are instances of :class:`int` and can be treated as such.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
MIN_START_PARAMETER_LENGTH = InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH
|
||||
""":obj:`int`: Minimum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of
|
||||
:meth:`telegram.InlineQueryResultsButton`."""
|
||||
|
||||
MAX_START_PARAMETER_LENGTH = InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH
|
||||
""":obj:`int`: Maximum number of characters in a :obj:`str` passed as the
|
||||
:paramref:`~telegram.InlineQueryResultsButton.start_parameter` parameter of
|
||||
:meth:`telegram.InlineQueryResultsButton`."""
|
||||
|
||||
|
||||
class InlineQueryResultType(StringEnum):
|
||||
"""This enum contains the available types of :class:`telegram.InlineQueryResult`. The enum
|
||||
members of this enumeration are instances of :class:`str` and can be treated as such.
|
||||
|
|
|
@ -46,6 +46,7 @@ from telegram import (
|
|||
BotCommand,
|
||||
BotCommandScope,
|
||||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
|
@ -60,6 +61,7 @@ from telegram import (
|
|||
ForumTopic,
|
||||
GameHighScore,
|
||||
InlineKeyboardMarkup,
|
||||
InlineQueryResultsButton,
|
||||
InputMedia,
|
||||
InputSticker,
|
||||
Location,
|
||||
|
@ -792,6 +794,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
next_offset: str = None,
|
||||
switch_pm_text: str = None,
|
||||
switch_pm_parameter: str = None,
|
||||
button: InlineQueryResultsButton = None,
|
||||
*,
|
||||
current_offset: str = None,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -814,6 +817,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
button=button,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
|
@ -3581,6 +3585,48 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def set_my_name(
|
||||
self,
|
||||
name: str = None,
|
||||
language_code: 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: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> bool:
|
||||
return await super().set_my_name(
|
||||
name=name,
|
||||
language_code=language_code,
|
||||
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 get_my_name(
|
||||
self,
|
||||
language_code: 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: JSONDict = None,
|
||||
rate_limit_args: RLARGS = None,
|
||||
) -> BotName:
|
||||
return await super().get_my_name(
|
||||
language_code=language_code,
|
||||
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_custom_emoji_sticker_set_thumbnail(
|
||||
self,
|
||||
name: str,
|
||||
|
@ -3823,3 +3869,5 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
setStickerEmojiList = set_sticker_emoji_list
|
||||
setStickerKeywords = set_sticker_keywords
|
||||
setStickerMaskPosition = set_sticker_mask_position
|
||||
setMyName = set_my_name
|
||||
getMyName = get_my_name
|
||||
|
|
|
@ -44,23 +44,27 @@ if TYPE_CHECKING:
|
|||
def escape_markdown(text: str, version: int = 1, entity_type: str = None) -> str:
|
||||
"""Helper function to escape telegram markup symbols.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Custom emoji entity escaping is now supported.
|
||||
|
||||
Args:
|
||||
text (:obj:`str`): The text.
|
||||
version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown.
|
||||
Either ``1`` or ``2``. Defaults to ``1``.
|
||||
entity_type (:obj:`str`, optional): For the entity types
|
||||
:tg-const:`telegram.MessageEntity.PRE`, :tg-const:`telegram.MessageEntity.CODE` and
|
||||
the link part of :tg-const:`telegram.MessageEntity.TEXT_LINK`, only certain characters
|
||||
need to be escaped in :tg-const:`telegram.constants.ParseMode.MARKDOWN_V2`.
|
||||
See the official API documentation for details. Only valid in combination with
|
||||
``version=2``, will be ignored else.
|
||||
the link part of :tg-const:`telegram.MessageEntity.TEXT_LINK` and
|
||||
:tg-const:`telegram.MessageEntity.CUSTOM_EMOJI`, only certain characters need to be
|
||||
escaped in :tg-const:`telegram.constants.ParseMode.MARKDOWN_V2`. See the `official API
|
||||
documentation <https://core.telegram.org/bots/api#formatting-options>`_ for details.
|
||||
Only valid in combination with ``version=2``, will be ignored else.
|
||||
"""
|
||||
if int(version) == 1:
|
||||
escape_chars = r"_*`["
|
||||
elif int(version) == 2:
|
||||
if entity_type in ["pre", "code"]:
|
||||
escape_chars = r"\`"
|
||||
elif entity_type == "text_link":
|
||||
elif entity_type in ["text_link", "custom_emoji"]:
|
||||
escape_chars = r"\)"
|
||||
else:
|
||||
escape_chars = r"\_*[]()~`>#+-=|{}.!"
|
||||
|
|
|
@ -19,7 +19,13 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import CallbackGame, InlineKeyboardButton, LoginUrl, WebAppInfo
|
||||
from telegram import (
|
||||
CallbackGame,
|
||||
InlineKeyboardButton,
|
||||
LoginUrl,
|
||||
SwitchInlineQueryChosenChat,
|
||||
WebAppInfo,
|
||||
)
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
|
@ -35,6 +41,7 @@ def inline_keyboard_button():
|
|||
pay=TestInlineKeyboardButtonBase.pay,
|
||||
login_url=TestInlineKeyboardButtonBase.login_url,
|
||||
web_app=TestInlineKeyboardButtonBase.web_app,
|
||||
switch_inline_query_chosen_chat=TestInlineKeyboardButtonBase.switch_inline_query_chosen_chat, # noqa: E501
|
||||
)
|
||||
|
||||
|
||||
|
@ -48,6 +55,7 @@ class TestInlineKeyboardButtonBase:
|
|||
pay = True
|
||||
login_url = LoginUrl("http://google.com")
|
||||
web_app = WebAppInfo(url="https://example.com")
|
||||
switch_inline_query_chosen_chat = SwitchInlineQueryChosenChat("a_bot", True, False, True, True)
|
||||
|
||||
|
||||
class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
||||
|
@ -70,6 +78,10 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
|||
assert inline_keyboard_button.pay == self.pay
|
||||
assert inline_keyboard_button.login_url == self.login_url
|
||||
assert inline_keyboard_button.web_app == self.web_app
|
||||
assert (
|
||||
inline_keyboard_button.switch_inline_query_chosen_chat
|
||||
== self.switch_inline_query_chosen_chat
|
||||
)
|
||||
|
||||
def test_to_dict(self, inline_keyboard_button):
|
||||
inline_keyboard_button_dict = inline_keyboard_button.to_dict()
|
||||
|
@ -95,6 +107,10 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
|||
inline_keyboard_button_dict["login_url"] == inline_keyboard_button.login_url.to_dict()
|
||||
)
|
||||
assert inline_keyboard_button_dict["web_app"] == inline_keyboard_button.web_app.to_dict()
|
||||
assert (
|
||||
inline_keyboard_button_dict["switch_inline_query_chosen_chat"]
|
||||
== inline_keyboard_button.switch_inline_query_chosen_chat.to_dict()
|
||||
)
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
|
@ -107,6 +123,7 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
|||
"web_app": self.web_app.to_dict(),
|
||||
"login_url": self.login_url.to_dict(),
|
||||
"pay": self.pay,
|
||||
"switch_inline_query_chosen_chat": self.switch_inline_query_chosen_chat.to_dict(),
|
||||
}
|
||||
|
||||
inline_keyboard_button = InlineKeyboardButton.de_json(json_dict, None)
|
||||
|
@ -124,6 +141,10 @@ class TestInlineKeyboardButtonWithoutRequest(TestInlineKeyboardButtonBase):
|
|||
assert inline_keyboard_button.pay == self.pay
|
||||
assert inline_keyboard_button.login_url == self.login_url
|
||||
assert inline_keyboard_button.web_app == self.web_app
|
||||
assert (
|
||||
inline_keyboard_button.switch_inline_query_chosen_chat
|
||||
== self.switch_inline_query_chosen_chat
|
||||
)
|
||||
|
||||
none = InlineKeyboardButton.de_json({}, bot)
|
||||
assert none is None
|
||||
|
|
|
@ -34,6 +34,7 @@ from telegram import (
|
|||
BotCommand,
|
||||
BotCommandScopeChat,
|
||||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
|
@ -44,6 +45,7 @@ from telegram import (
|
|||
InlineKeyboardMarkup,
|
||||
InlineQueryResultArticle,
|
||||
InlineQueryResultDocument,
|
||||
InlineQueryResultsButton,
|
||||
InlineQueryResultVoice,
|
||||
InputFile,
|
||||
InputMessageContent,
|
||||
|
@ -76,7 +78,7 @@ from telegram.error import BadRequest, InvalidToken, NetworkError
|
|||
from telegram.ext import ExtBot, InvalidCallbackData
|
||||
from telegram.helpers import escape_markdown
|
||||
from telegram.request import BaseRequest, HTTPXRequest, RequestData
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
|
||||
from tests.auxil.bot_method_checks import check_defaults_handling
|
||||
from tests.auxil.ci_bots import FALLBACKS
|
||||
from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS
|
||||
|
@ -655,10 +657,11 @@ class TestBotWithoutRequest:
|
|||
)
|
||||
|
||||
# TODO: Needs improvement. We need incoming inline query to test answer.
|
||||
async def test_answer_inline_query(self, monkeypatch, bot, raw_bot):
|
||||
@pytest.mark.parametrize("button_type", ["start", "web_app", "backward_compat"])
|
||||
async def test_answer_inline_query(self, monkeypatch, bot, raw_bot, button_type):
|
||||
# For now just test that our internals pass the correct data
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters == {
|
||||
expected = {
|
||||
"cache_time": 300,
|
||||
"results": [
|
||||
{
|
||||
|
@ -685,12 +688,22 @@ class TestBotWithoutRequest:
|
|||
},
|
||||
],
|
||||
"next_offset": "42",
|
||||
"switch_pm_parameter": "start_pm",
|
||||
"inline_query_id": 1234,
|
||||
"is_personal": True,
|
||||
"switch_pm_text": "switch pm",
|
||||
}
|
||||
|
||||
if button_type in ["start", "backward_compat"]:
|
||||
button_dict = {"text": "button_text", "start_parameter": "start_parameter"}
|
||||
else:
|
||||
button_dict = {
|
||||
"text": "button_text",
|
||||
"web_app": {"url": "https://python-telegram-bot.org"},
|
||||
}
|
||||
|
||||
expected["button"] = button_dict
|
||||
|
||||
return request_data.parameters == expected
|
||||
|
||||
results = [
|
||||
InlineQueryResultArticle("11", "first", InputTextMessageContent("first")),
|
||||
InlineQueryResultArticle("12", "second", InputMessageContentDWPP("second")),
|
||||
|
@ -705,6 +718,17 @@ class TestBotWithoutRequest:
|
|||
),
|
||||
]
|
||||
|
||||
if button_type == "start":
|
||||
button = InlineQueryResultsButton(
|
||||
text="button_text", start_parameter="start_parameter"
|
||||
)
|
||||
elif button_type == "web_app":
|
||||
button = InlineQueryResultsButton(
|
||||
text="button_text", web_app=WebAppInfo("https://python-telegram-bot.org")
|
||||
)
|
||||
else:
|
||||
button = None
|
||||
|
||||
copied_results = copy.copy(results)
|
||||
ext_bot = bot
|
||||
for bot in (ext_bot, raw_bot):
|
||||
|
@ -717,8 +741,11 @@ class TestBotWithoutRequest:
|
|||
cache_time=300,
|
||||
is_personal=True,
|
||||
next_offset="42",
|
||||
switch_pm_text="switch pm",
|
||||
switch_pm_parameter="start_pm",
|
||||
switch_pm_text="button_text" if button_type == "backward_compat" else None,
|
||||
switch_pm_parameter="start_parameter"
|
||||
if button_type == "backward_compat"
|
||||
else None,
|
||||
button=button,
|
||||
)
|
||||
|
||||
# 1)
|
||||
|
@ -739,6 +766,43 @@ class TestBotWithoutRequest:
|
|||
|
||||
monkeypatch.delattr(bot.request, "post")
|
||||
|
||||
@pytest.mark.parametrize("bot_class", ["Bot", "ExtBot"])
|
||||
async def test_answer_inline_query_deprecated_args(
|
||||
self, monkeypatch, recwarn, bot_class, bot, raw_bot
|
||||
):
|
||||
async def mock_post(*args, **kwargs):
|
||||
return True
|
||||
|
||||
bot = raw_bot if bot_class == "Bot" else bot
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", mock_post)
|
||||
|
||||
with pytest.raises(
|
||||
TypeError, match="6.7, the parameter `button is mutually exclusive to the deprecated"
|
||||
):
|
||||
await bot.answer_inline_query(
|
||||
inline_query_id="123",
|
||||
results=[],
|
||||
button=True,
|
||||
switch_pm_text="text",
|
||||
switch_pm_parameter="param",
|
||||
)
|
||||
|
||||
recwarn.clear()
|
||||
assert await bot.answer_inline_query(
|
||||
inline_query_id="123",
|
||||
results=[],
|
||||
switch_pm_text="text",
|
||||
switch_pm_parameter="parameter",
|
||||
)
|
||||
assert len(recwarn) == 1
|
||||
assert recwarn[-1].category is PTBDeprecationWarning
|
||||
assert str(recwarn[-1].message).startswith(
|
||||
"Since Bot API 6.7, the parameters `switch_pm_text` and `switch_pm_parameter` are "
|
||||
"deprecated"
|
||||
)
|
||||
assert recwarn[-1].filename == __file__, "stacklevel is incorrect!"
|
||||
|
||||
async def test_answer_inline_query_no_default_parse_mode(self, monkeypatch, bot):
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters == {
|
||||
|
@ -769,10 +833,8 @@ class TestBotWithoutRequest:
|
|||
},
|
||||
],
|
||||
"next_offset": "42",
|
||||
"switch_pm_parameter": "start_pm",
|
||||
"inline_query_id": 1234,
|
||||
"is_personal": True,
|
||||
"switch_pm_text": "switch pm",
|
||||
}
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
|
@ -797,8 +859,6 @@ class TestBotWithoutRequest:
|
|||
cache_time=300,
|
||||
is_personal=True,
|
||||
next_offset="42",
|
||||
switch_pm_text="switch pm",
|
||||
switch_pm_parameter="start_pm",
|
||||
)
|
||||
# make sure that the results were not edited in-place
|
||||
assert results == copied_results
|
||||
|
@ -862,10 +922,8 @@ class TestBotWithoutRequest:
|
|||
},
|
||||
],
|
||||
"next_offset": "42",
|
||||
"switch_pm_parameter": "start_pm",
|
||||
"inline_query_id": 1234,
|
||||
"is_personal": True,
|
||||
"switch_pm_text": "switch pm",
|
||||
}
|
||||
|
||||
monkeypatch.setattr(default_bot.request, "post", make_assertion)
|
||||
|
@ -890,8 +948,6 @@ class TestBotWithoutRequest:
|
|||
cache_time=300,
|
||||
is_personal=True,
|
||||
next_offset="42",
|
||||
switch_pm_text="switch pm",
|
||||
switch_pm_parameter="start_pm",
|
||||
)
|
||||
# make sure that the results were not edited in-place
|
||||
assert results == copied_results
|
||||
|
@ -1680,6 +1736,80 @@ class TestBotWithoutRequest:
|
|||
assert warning.filename == __file__, "wrong stacklevel!"
|
||||
assert warning.category is PTBUserWarning
|
||||
|
||||
async def test_set_get_my_name(self, bot, monkeypatch):
|
||||
"""We only test that we pass the correct values to TG since this endpoint is heavily
|
||||
rate limited which makes automated tests rather infeasible."""
|
||||
default_name = "default_bot_name"
|
||||
en_name = "en_bot_name"
|
||||
de_name = "de_bot_name"
|
||||
|
||||
# We predefine the responses that we would TG expect to send us
|
||||
set_stack = asyncio.Queue()
|
||||
get_stack = asyncio.Queue()
|
||||
await set_stack.put({"name": default_name})
|
||||
await set_stack.put({"name": en_name, "language_code": "en"})
|
||||
await set_stack.put({"name": de_name, "language_code": "de"})
|
||||
await get_stack.put({"name": default_name, "language_code": None})
|
||||
await get_stack.put({"name": en_name, "language_code": "en"})
|
||||
await get_stack.put({"name": de_name, "language_code": "de"})
|
||||
|
||||
await set_stack.put({"name": default_name})
|
||||
await set_stack.put({"language_code": "en"})
|
||||
await set_stack.put({"language_code": "de"})
|
||||
await get_stack.put({"name": default_name, "language_code": None})
|
||||
await get_stack.put({"name": default_name, "language_code": "en"})
|
||||
await get_stack.put({"name": default_name, "language_code": "de"})
|
||||
|
||||
async def post(url, request_data: RequestData, *args, **kwargs):
|
||||
# The mock-post now just fetches the predefined responses from the queues
|
||||
if "setMyName" in url:
|
||||
expected = await set_stack.get()
|
||||
assert request_data.json_parameters == expected
|
||||
set_stack.task_done()
|
||||
return True
|
||||
|
||||
bot_name = await get_stack.get()
|
||||
if "language_code" in request_data.json_parameters:
|
||||
assert request_data.json_parameters == {"language_code": bot_name["language_code"]}
|
||||
else:
|
||||
assert request_data.json_parameters == {}
|
||||
get_stack.task_done()
|
||||
return bot_name
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", post)
|
||||
|
||||
# Set the names
|
||||
assert all(
|
||||
await asyncio.gather(
|
||||
bot.set_my_name(default_name),
|
||||
bot.set_my_name(en_name, language_code="en"),
|
||||
bot.set_my_name(de_name, language_code="de"),
|
||||
)
|
||||
)
|
||||
|
||||
# Check that they were set correctly
|
||||
assert await asyncio.gather(
|
||||
bot.get_my_name(), bot.get_my_name("en"), bot.get_my_name("de")
|
||||
) == [
|
||||
BotName(default_name),
|
||||
BotName(en_name),
|
||||
BotName(de_name),
|
||||
]
|
||||
|
||||
# Delete the names
|
||||
assert all(
|
||||
await asyncio.gather(
|
||||
bot.set_my_name(default_name),
|
||||
bot.set_my_name(None, language_code="en"),
|
||||
bot.set_my_name(None, language_code="de"),
|
||||
)
|
||||
)
|
||||
|
||||
# Check that they were deleted correctly
|
||||
assert await asyncio.gather(
|
||||
bot.get_my_name(), bot.get_my_name("en"), bot.get_my_name("de")
|
||||
) == 3 * [BotName(default_name)]
|
||||
|
||||
|
||||
class TestBotWithRequest:
|
||||
"""
|
||||
|
|
56
tests/test_botname.py
Normal file
56
tests/test_botname.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import pytest
|
||||
|
||||
from telegram import BotName
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def bot_name(bot):
|
||||
return BotName(TestBotNameBase.name)
|
||||
|
||||
|
||||
class TestBotNameBase:
|
||||
name = "This is a test name"
|
||||
|
||||
|
||||
class TestBotNameWithoutRequest(TestBotNameBase):
|
||||
def test_slot_behaviour(self, bot_name):
|
||||
for attr in bot_name.__slots__:
|
||||
assert getattr(bot_name, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(bot_name)) == len(set(mro_slots(bot_name))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, bot_name):
|
||||
bot_name_dict = bot_name.to_dict()
|
||||
|
||||
assert isinstance(bot_name_dict, dict)
|
||||
assert bot_name_dict["name"] == self.name
|
||||
|
||||
def test_equality(self):
|
||||
a = BotName(self.name)
|
||||
b = BotName(self.name)
|
||||
c = BotName("text.com")
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
|
@ -79,7 +79,7 @@ def invite_link(user):
|
|||
|
||||
@pytest.fixture(scope="module")
|
||||
def chat_member_updated(user, chat, old_chat_member, new_chat_member, invite_link, time):
|
||||
return ChatMemberUpdated(chat, user, time, old_chat_member, new_chat_member, invite_link)
|
||||
return ChatMemberUpdated(chat, user, time, old_chat_member, new_chat_member, invite_link, True)
|
||||
|
||||
|
||||
class TestChatMemberUpdatedBase:
|
||||
|
@ -113,6 +113,7 @@ class TestChatMemberUpdatedWithoutRequest(TestChatMemberUpdatedBase):
|
|||
assert chat_member_updated.old_chat_member == old_chat_member
|
||||
assert chat_member_updated.new_chat_member == new_chat_member
|
||||
assert chat_member_updated.invite_link is None
|
||||
assert chat_member_updated.via_chat_folder_invite_link is None
|
||||
|
||||
def test_de_json_all_args(
|
||||
self, bot, user, time, invite_link, chat, old_chat_member, new_chat_member
|
||||
|
@ -124,6 +125,7 @@ class TestChatMemberUpdatedWithoutRequest(TestChatMemberUpdatedBase):
|
|||
"old_chat_member": old_chat_member.to_dict(),
|
||||
"new_chat_member": new_chat_member.to_dict(),
|
||||
"invite_link": invite_link.to_dict(),
|
||||
"via_chat_folder_invite_link": True,
|
||||
}
|
||||
|
||||
chat_member_updated = ChatMemberUpdated.de_json(json_dict, bot)
|
||||
|
@ -136,6 +138,7 @@ class TestChatMemberUpdatedWithoutRequest(TestChatMemberUpdatedBase):
|
|||
assert chat_member_updated.old_chat_member == old_chat_member
|
||||
assert chat_member_updated.new_chat_member == new_chat_member
|
||||
assert chat_member_updated.invite_link == invite_link
|
||||
assert chat_member_updated.via_chat_folder_invite_link is True
|
||||
|
||||
def test_de_json_localization(
|
||||
self, bot, raw_bot, tz_bot, user, chat, old_chat_member, new_chat_member, time, invite_link
|
||||
|
@ -178,6 +181,10 @@ class TestChatMemberUpdatedWithoutRequest(TestChatMemberUpdatedBase):
|
|||
== chat_member_updated.new_chat_member.to_dict()
|
||||
)
|
||||
assert chat_member_updated_dict["invite_link"] == chat_member_updated.invite_link.to_dict()
|
||||
assert (
|
||||
chat_member_updated_dict["via_chat_folder_invite_link"]
|
||||
== chat_member_updated.via_chat_folder_invite_link
|
||||
)
|
||||
|
||||
def test_equality(self, time, old_chat_member, new_chat_member, invite_link):
|
||||
a = ChatMemberUpdated(
|
||||
|
|
|
@ -32,8 +32,9 @@ class TestHelpers:
|
|||
("_italic_", r"\_italic\_"),
|
||||
("`code`", r"\`code\`"),
|
||||
("[text_link](https://github.com/)", r"\[text\_link](https://github.com/)"),
|
||||
("![👍](tg://emoji?id=1)", r"!\[👍](tg://emoji?id=1)"),
|
||||
],
|
||||
ids=["bold", "italic", "code", "text_link"],
|
||||
ids=["bold", "italic", "code", "text_link", "custom_emoji_id"],
|
||||
)
|
||||
def test_escape_markdown(self, test_str, expected):
|
||||
assert expected == helpers.escape_markdown(test_str)
|
||||
|
@ -68,13 +69,16 @@ class TestHelpers:
|
|||
test_str, version=2, entity_type=MessageEntity.CODE
|
||||
)
|
||||
|
||||
def test_escape_markdown_v2_text_link(self):
|
||||
def test_escape_markdown_v2_links(self):
|
||||
test_str = "https://url.containing/funny)cha)\\ra\\)cter\\s"
|
||||
expected_str = "https://url.containing/funny\\)cha\\)\\\\ra\\\\\\)cter\\\\s"
|
||||
|
||||
assert expected_str == helpers.escape_markdown(
|
||||
test_str, version=2, entity_type=MessageEntity.TEXT_LINK
|
||||
)
|
||||
assert expected_str == helpers.escape_markdown(
|
||||
test_str, version=2, entity_type=MessageEntity.CUSTOM_EMOJI
|
||||
)
|
||||
|
||||
def test_markdown_invalid_version(self):
|
||||
with pytest.raises(ValueError, match="Markdown version must be either"):
|
||||
|
|
83
tests/test_inlinequeryresultsbutton.py
Normal file
83
tests/test_inlinequeryresultsbutton.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-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import pytest
|
||||
|
||||
from telegram import InlineQueryResultsButton, WebAppInfo
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def inline_query_results_button():
|
||||
return InlineQueryResultsButton(
|
||||
text=TestInlineQueryResultsButtonBase.text,
|
||||
start_parameter=TestInlineQueryResultsButtonBase.start_parameter,
|
||||
web_app=TestInlineQueryResultsButtonBase.web_app,
|
||||
)
|
||||
|
||||
|
||||
class TestInlineQueryResultsButtonBase:
|
||||
text = "text"
|
||||
start_parameter = "start_parameter"
|
||||
web_app = WebAppInfo(url="https://python-telegram-bot.org")
|
||||
|
||||
|
||||
class TestInlineQueryResultsButtonWithoutRequest(TestInlineQueryResultsButtonBase):
|
||||
def test_slot_behaviour(self, inline_query_results_button):
|
||||
inst = inline_query_results_button
|
||||
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_to_dict(self, inline_query_results_button):
|
||||
inline_query_results_button_dict = inline_query_results_button.to_dict()
|
||||
assert isinstance(inline_query_results_button_dict, dict)
|
||||
assert inline_query_results_button_dict["text"] == self.text
|
||||
assert inline_query_results_button_dict["start_parameter"] == self.start_parameter
|
||||
assert inline_query_results_button_dict["web_app"] == self.web_app.to_dict()
|
||||
|
||||
def test_de_json(self, bot):
|
||||
assert InlineQueryResultsButton.de_json(None, bot) is None
|
||||
assert InlineQueryResultsButton.de_json({}, bot) is None
|
||||
|
||||
json_dict = {
|
||||
"text": self.text,
|
||||
"start_parameter": self.start_parameter,
|
||||
"web_app": self.web_app.to_dict(),
|
||||
}
|
||||
inline_query_results_button = InlineQueryResultsButton.de_json(json_dict, bot)
|
||||
|
||||
assert inline_query_results_button.text == self.text
|
||||
assert inline_query_results_button.start_parameter == self.start_parameter
|
||||
assert inline_query_results_button.web_app == self.web_app
|
||||
|
||||
def test_equality(self):
|
||||
a = InlineQueryResultsButton(self.text, self.start_parameter, self.web_app)
|
||||
b = InlineQueryResultsButton(self.text, self.start_parameter, self.web_app)
|
||||
c = InlineQueryResultsButton(self.text, "", self.web_app)
|
||||
d = InlineQueryResultsButton(self.text, self.start_parameter, None)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
|
@ -59,6 +59,7 @@ from telegram import (
|
|||
from telegram._utils.datetime import UTC
|
||||
from telegram.constants import ChatAction, ParseMode
|
||||
from telegram.ext import Defaults
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests._passport.test_passport import RAW_PASSPORT_DATA
|
||||
from tests.auxil.bot_method_checks import (
|
||||
check_defaults_handling,
|
||||
|
@ -322,10 +323,11 @@ class TestMessageBase:
|
|||
{"length": 9, "offset": 101, "type": "strikethrough"},
|
||||
{"length": 10, "offset": 129, "type": "pre", "language": "python"},
|
||||
{"length": 7, "offset": 141, "type": "spoiler"},
|
||||
{"length": 2, "offset": 150, "type": "custom_emoji", "custom_emoji_id": "1"},
|
||||
]
|
||||
test_text_v2 = (
|
||||
r"Test for <bold, ita_lic, \`code, links, text-mention and `\pre. "
|
||||
"http://google.com and bold nested in strk>trgh nested in italic. Python pre. Spoiled."
|
||||
"http://google.com and bold nested in strk>trgh nested in italic. Python pre. Spoiled. 👍."
|
||||
)
|
||||
test_message = Message(
|
||||
message_id=1,
|
||||
|
@ -513,7 +515,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
r"<pre>`\pre</pre>. http://google.com "
|
||||
"and <i>bold <b>nested in <s>strk>trgh</s> nested in</b> italic</i>. "
|
||||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>.'
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.'
|
||||
)
|
||||
text_html = self.test_message_v2.text_html
|
||||
assert text_html == test_html_string
|
||||
|
@ -532,7 +535,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
r'<pre>`\pre</pre>. <a href="http://google.com">http://google.com</a> '
|
||||
"and <i>bold <b>nested in <s>strk>trgh</s> nested in</b> italic</i>. "
|
||||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>.'
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.'
|
||||
)
|
||||
text_html = self.test_message_v2.text_html_urled
|
||||
assert text_html == test_html_string
|
||||
|
@ -553,7 +557,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"[links](http://github.com/abc\\\\\\)def), "
|
||||
"[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. "
|
||||
r"http://google\.com and _bold *nested in ~strk\>trgh~ nested in* italic_\. "
|
||||
"```python\nPython pre```\\. ||Spoiled||\\."
|
||||
"```python\nPython pre```\\. ||Spoiled||\\. ![👍](tg://emoji?id=1)\\."
|
||||
)
|
||||
text_markdown = self.test_message_v2.text_markdown_v2
|
||||
assert text_markdown == test_md_string
|
||||
|
@ -603,7 +607,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"[links](http://github.com/abc\\\\\\)def), "
|
||||
"[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. "
|
||||
r"[http://google\.com](http://google.com) and _bold *nested in ~strk\>trgh~ "
|
||||
"nested in* italic_\\. ```python\nPython pre```\\. ||Spoiled||\\."
|
||||
"nested in* italic_\\. ```python\nPython pre```\\. ||Spoiled||\\. "
|
||||
"![👍](tg://emoji?id=1)\\."
|
||||
)
|
||||
text_markdown = self.test_message_v2.text_markdown_v2_urled
|
||||
assert text_markdown == test_md_string
|
||||
|
@ -634,17 +639,72 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"text_html",
|
||||
"text_html_urled",
|
||||
"text_markdown",
|
||||
"text_markdown_urled",
|
||||
],
|
||||
)
|
||||
def test_text_custom_emoji_md_v1(self, type_, recwarn):
|
||||
text = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: 😎"
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
length=2,
|
||||
custom_emoji_id="5472409228461217725",
|
||||
)
|
||||
message = Message(
|
||||
1,
|
||||
from_user=self.from_user,
|
||||
date=self.date,
|
||||
chat=self.chat,
|
||||
text=text,
|
||||
entities=[emoji_entity],
|
||||
)
|
||||
assert expected == getattr(message, type_)
|
||||
|
||||
assert len(recwarn) == 1
|
||||
assert recwarn[0].category is PTBDeprecationWarning
|
||||
assert str(recwarn[0].message).startswith(
|
||||
"Custom emoji entities are not supported for Markdown version 1"
|
||||
)
|
||||
assert recwarn[0].filename == __file__
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"text_markdown_v2",
|
||||
"text_markdown_v2_urled",
|
||||
],
|
||||
)
|
||||
def test_text_custom_emoji(self, type_):
|
||||
def test_text_custom_emoji_md_v2(self, type_):
|
||||
text = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: ![😎](tg://emoji?id=5472409228461217725)"
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
length=2,
|
||||
custom_emoji_id="5472409228461217725",
|
||||
)
|
||||
message = Message(
|
||||
1,
|
||||
from_user=self.from_user,
|
||||
date=self.date,
|
||||
chat=self.chat,
|
||||
text=text,
|
||||
entities=[emoji_entity],
|
||||
)
|
||||
assert expected == message[type_]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"text_html",
|
||||
"text_html_urled",
|
||||
],
|
||||
)
|
||||
def test_text_custom_emoji_html(self, type_):
|
||||
text = "Look a custom emoji: 😎"
|
||||
expected = 'Look a custom emoji: <tg-emoji emoji-id="5472409228461217725">😎</tg-emoji>'
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
|
@ -670,7 +730,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
r"<pre>`\pre</pre>. http://google.com "
|
||||
"and <i>bold <b>nested in <s>strk>trgh</s> nested in</b> italic</i>. "
|
||||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>.'
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.'
|
||||
)
|
||||
caption_html = self.test_message_v2.caption_html
|
||||
assert caption_html == test_html_string
|
||||
|
@ -689,7 +750,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
r'<pre>`\pre</pre>. <a href="http://google.com">http://google.com</a> '
|
||||
"and <i>bold <b>nested in <s>strk>trgh</s> nested in</b> italic</i>. "
|
||||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>.'
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.'
|
||||
)
|
||||
caption_html = self.test_message_v2.caption_html_urled
|
||||
assert caption_html == test_html_string
|
||||
|
@ -710,7 +772,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"[links](http://github.com/abc\\\\\\)def), "
|
||||
"[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. "
|
||||
r"http://google\.com and _bold *nested in ~strk\>trgh~ nested in* italic_\. "
|
||||
"```python\nPython pre```\\. ||Spoiled||\\."
|
||||
"```python\nPython pre```\\. ||Spoiled||\\. ![👍](tg://emoji?id=1)\\."
|
||||
)
|
||||
caption_markdown = self.test_message_v2.caption_markdown_v2
|
||||
assert caption_markdown == test_md_string
|
||||
|
@ -737,7 +799,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"[links](http://github.com/abc\\\\\\)def), "
|
||||
"[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. "
|
||||
r"[http://google\.com](http://google.com) and _bold *nested in ~strk\>trgh~ "
|
||||
"nested in* italic_\\. ```python\nPython pre```\\. ||Spoiled||\\."
|
||||
"nested in* italic_\\. ```python\nPython pre```\\. ||Spoiled||\\. "
|
||||
"![👍](tg://emoji?id=1)\\."
|
||||
)
|
||||
caption_markdown = self.test_message_v2.caption_markdown_v2_urled
|
||||
assert caption_markdown == test_md_string
|
||||
|
@ -773,17 +836,72 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"caption_html",
|
||||
"caption_html_urled",
|
||||
"caption_markdown",
|
||||
"caption_markdown_urled",
|
||||
],
|
||||
)
|
||||
def test_caption_custom_emoji_md_v1(self, type_, recwarn):
|
||||
caption = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: 😎"
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
length=2,
|
||||
custom_emoji_id="5472409228461217725",
|
||||
)
|
||||
message = Message(
|
||||
1,
|
||||
from_user=self.from_user,
|
||||
date=self.date,
|
||||
chat=self.chat,
|
||||
caption=caption,
|
||||
caption_entities=[emoji_entity],
|
||||
)
|
||||
assert expected == getattr(message, type_)
|
||||
|
||||
assert len(recwarn) == 1
|
||||
assert recwarn[0].category is PTBDeprecationWarning
|
||||
assert str(recwarn[0].message).startswith(
|
||||
"Custom emoji entities are not supported for Markdown version 1"
|
||||
)
|
||||
assert recwarn[0].filename == __file__
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"caption_markdown_v2",
|
||||
"caption_markdown_v2_urled",
|
||||
],
|
||||
)
|
||||
def test_caption_custom_emoji(self, type_):
|
||||
def test_caption_custom_emoji_md_v2(self, type_):
|
||||
caption = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: 😎"
|
||||
expected = "Look a custom emoji: ![😎](tg://emoji?id=5472409228461217725)"
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
length=2,
|
||||
custom_emoji_id="5472409228461217725",
|
||||
)
|
||||
message = Message(
|
||||
1,
|
||||
from_user=self.from_user,
|
||||
date=self.date,
|
||||
chat=self.chat,
|
||||
caption=caption,
|
||||
caption_entities=[emoji_entity],
|
||||
)
|
||||
assert expected == message[type_]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_",
|
||||
argvalues=[
|
||||
"caption_html",
|
||||
"caption_html_urled",
|
||||
],
|
||||
)
|
||||
def test_caption_custom_emoji_html(self, type_):
|
||||
caption = "Look a custom emoji: 😎"
|
||||
expected = 'Look a custom emoji: <tg-emoji emoji-id="5472409228461217725">😎</tg-emoji>'
|
||||
emoji_entity = MessageEntity(
|
||||
type=MessageEntity.CUSTOM_EMOJI,
|
||||
offset=21,
|
||||
|
@ -955,7 +1073,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
"[links](http://github.com/abc\\\\\\)def), "
|
||||
"[text\\-mention](tg://user?id=123456789) and ```\\`\\\\pre```\\. "
|
||||
r"http://google\.com and _bold *nested in ~strk\>trgh~ nested in* italic_\. "
|
||||
"```python\nPython pre```\\. ||Spoiled||\\."
|
||||
"```python\nPython pre```\\. ||Spoiled||\\. ![👍](tg://emoji?id=1)\\."
|
||||
)
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
@ -995,7 +1113,8 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
r"<pre>`\pre</pre>. http://google.com "
|
||||
"and <i>bold <b>nested in <s>strk>trgh</s> nested in</b> italic</i>. "
|
||||
'<pre><code class="python">Python pre</code></pre>. '
|
||||
'<span class="tg-spoiler">Spoiled</span>.'
|
||||
'<span class="tg-spoiler">Spoiled</span>. '
|
||||
'<tg-emoji emoji-id="1">👍</tg-emoji>.'
|
||||
)
|
||||
|
||||
async def make_assertion(*_, **kwargs):
|
||||
|
|
|
@ -154,6 +154,7 @@ BACKWARDS_COMPAT_KWARGS = {
|
|||
"thumb_url",
|
||||
},
|
||||
"InlineQueryResult(Game|Gif|Mpeg4Gif)": {"thumb_mime_type"},
|
||||
"answer_inline_query": {"switch_pm_text", "switch_pm_parameter"},
|
||||
}
|
||||
|
||||
|
||||
|
|
87
tests/test_switchinlinequerychosenchat.py
Normal file
87
tests/test_switchinlinequerychosenchat.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2023
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import SwitchInlineQueryChosenChat
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def switch_inline_query_chosen_chat():
|
||||
return SwitchInlineQueryChosenChat(
|
||||
query=TestSwitchInlineQueryChosenChatBase.query,
|
||||
allow_user_chats=TestSwitchInlineQueryChosenChatBase.allow_user_chats,
|
||||
allow_bot_chats=TestSwitchInlineQueryChosenChatBase.allow_bot_chats,
|
||||
allow_channel_chats=TestSwitchInlineQueryChosenChatBase.allow_channel_chats,
|
||||
allow_group_chats=TestSwitchInlineQueryChosenChatBase.allow_group_chats,
|
||||
)
|
||||
|
||||
|
||||
class TestSwitchInlineQueryChosenChatBase:
|
||||
query = "query"
|
||||
allow_user_chats = True
|
||||
allow_bot_chats = True
|
||||
allow_channel_chats = False
|
||||
allow_group_chats = True
|
||||
|
||||
|
||||
class TestSwitchInlineQueryChosenChat(TestSwitchInlineQueryChosenChatBase):
|
||||
def test_slot_behaviour(self, switch_inline_query_chosen_chat):
|
||||
inst = switch_inline_query_chosen_chat
|
||||
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, switch_inline_query_chosen_chat):
|
||||
assert switch_inline_query_chosen_chat.query == self.query
|
||||
assert switch_inline_query_chosen_chat.allow_user_chats == self.allow_user_chats
|
||||
assert switch_inline_query_chosen_chat.allow_bot_chats == self.allow_bot_chats
|
||||
assert switch_inline_query_chosen_chat.allow_channel_chats == self.allow_channel_chats
|
||||
assert switch_inline_query_chosen_chat.allow_group_chats == self.allow_group_chats
|
||||
|
||||
def test_to_dict(self, switch_inline_query_chosen_chat):
|
||||
siqcc = switch_inline_query_chosen_chat.to_dict()
|
||||
|
||||
assert isinstance(siqcc, dict)
|
||||
assert siqcc["query"] == switch_inline_query_chosen_chat.query
|
||||
assert siqcc["allow_user_chats"] == switch_inline_query_chosen_chat.allow_user_chats
|
||||
assert siqcc["allow_bot_chats"] == switch_inline_query_chosen_chat.allow_bot_chats
|
||||
assert siqcc["allow_channel_chats"] == switch_inline_query_chosen_chat.allow_channel_chats
|
||||
assert siqcc["allow_group_chats"] == switch_inline_query_chosen_chat.allow_group_chats
|
||||
|
||||
def test_equality(self):
|
||||
siqcc = SwitchInlineQueryChosenChat
|
||||
a = siqcc(self.query, self.allow_user_chats, self.allow_bot_chats)
|
||||
b = siqcc(self.query, self.allow_user_chats, self.allow_bot_chats)
|
||||
c = siqcc(self.query, self.allow_user_chats)
|
||||
d = siqcc("", self.allow_user_chats, self.allow_bot_chats)
|
||||
e = siqcc(self.query, self.allow_user_chats, self.allow_bot_chats, self.allow_group_chats)
|
||||
|
||||
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)
|
Loading…
Reference in a new issue