mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-28 07:20:17 +01:00
Co-authored-by: Mahdyar Hasanpour <mahdyar@duck.com> Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Co-authored-by: Abdelrahman Elkheir <90580077+aelkheir@users.noreply.github.com> Co-authored-by: Aditya <adityayadav11082@gmail.com>
This commit is contained in:
parent
3ec7bb819c
commit
5fa457974d
53 changed files with 3264 additions and 162 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-7.1-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.2-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 **7.1** are supported.
|
||||
All types and methods of the Telegram Bot API **7.2** 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-7.1-blue?logo=telegram
|
||||
.. image:: https://img.shields.io/badge/Bot%20API-7.2-blue?logo=telegram
|
||||
:target: https://core.telegram.org/bots/api-changelog
|
||||
:alt: Supported Bot API versions
|
||||
|
||||
|
@ -85,7 +85,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 **7.1** are supported.
|
||||
All types and methods of the Telegram Bot API **7.2** are supported.
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
|
|
@ -113,6 +113,10 @@
|
|||
:align: left
|
||||
:widths: 1 4
|
||||
|
||||
* - :meth:`~telegram.Bot.approve_chat_join_request`
|
||||
- Used for approving a chat join request
|
||||
* - :meth:`~telegram.Bot.decline_chat_join_request`
|
||||
- Used for declining a chat join request
|
||||
* - :meth:`~telegram.Bot.ban_chat_member`
|
||||
- Used for banning a member from the chat
|
||||
* - :meth:`~telegram.Bot.unban_chat_member`
|
||||
|
@ -137,10 +141,6 @@
|
|||
- Used for editing a non-primary invite link
|
||||
* - :meth:`~telegram.Bot.revoke_chat_invite_link`
|
||||
- Used for revoking an invite link created by the bot
|
||||
* - :meth:`~telegram.Bot.approve_chat_join_request`
|
||||
- Used for approving a chat join request
|
||||
* - :meth:`~telegram.Bot.decline_chat_join_request`
|
||||
- Used for declining a chat join request
|
||||
* - :meth:`~telegram.Bot.set_chat_photo`
|
||||
- Used for setting a photo to a chat
|
||||
* - :meth:`~telegram.Bot.delete_chat_photo`
|
||||
|
@ -155,6 +155,8 @@
|
|||
- Used for unpinning a message
|
||||
* - :meth:`~telegram.Bot.unpin_all_chat_messages`
|
||||
- Used for unpinning all pinned chat messages
|
||||
* - :meth:`~telegram.Bot.get_business_connection`
|
||||
- Used for getting information about the business account.
|
||||
* - :meth:`~telegram.Bot.get_user_profile_photos`
|
||||
- Used for obtaining user's profile pictures
|
||||
* - :meth:`~telegram.Bot.get_chat`
|
||||
|
@ -237,6 +239,8 @@
|
|||
- Used for setting a sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.delete_chat_sticker_set`
|
||||
- Used for deleting the set sticker set of a chat
|
||||
* - :meth:`~telegram.Bot.replace_sticker_in_set`
|
||||
- Used for replacing a sticker in a set
|
||||
* - :meth:`~telegram.Bot.set_sticker_position_in_set`
|
||||
- Used for moving a sticker's position in the set
|
||||
* - :meth:`~telegram.Bot.set_sticker_set_title`
|
||||
|
|
|
@ -6,6 +6,7 @@ Available Types
|
|||
|
||||
telegram.animation
|
||||
telegram.audio
|
||||
telegram.birthdate
|
||||
telegram.botcommand
|
||||
telegram.botcommandscope
|
||||
telegram.botcommandscopeallchatadministrators
|
||||
|
@ -18,6 +19,12 @@ Available Types
|
|||
telegram.botdescription
|
||||
telegram.botname
|
||||
telegram.botshortdescription
|
||||
telegram.businessconnection
|
||||
telegram.businessintro
|
||||
telegram.businesslocation
|
||||
telegram.businessopeninghours
|
||||
telegram.businessopeninghoursinterval
|
||||
telegram.businessmessagesdeleted
|
||||
telegram.callbackquery
|
||||
telegram.chat
|
||||
telegram.chatadministratorrights
|
||||
|
@ -107,6 +114,7 @@ Available Types
|
|||
telegram.replykeyboardremove
|
||||
telegram.replyparameters
|
||||
telegram.sentwebappmessage
|
||||
telegram.shareduser
|
||||
telegram.story
|
||||
telegram.switchinlinequerychosenchat
|
||||
telegram.telegramobject
|
||||
|
|
7
docs/source/telegram.birthdate.rst
Normal file
7
docs/source/telegram.birthdate.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
Birthdate
|
||||
=========
|
||||
|
||||
.. autoclass:: telegram.Birthdate
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
6
docs/source/telegram.businessconnection.rst
Normal file
6
docs/source/telegram.businessconnection.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessConnection
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessConnection
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.businessintro.rst
Normal file
6
docs/source/telegram.businessintro.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessIntro
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessIntro
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.businesslocation.rst
Normal file
6
docs/source/telegram.businesslocation.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessLocation
|
||||
==================
|
||||
|
||||
.. autoclass:: telegram.BusinessLocation
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.businessmessagesdeleted.rst
Normal file
6
docs/source/telegram.businessmessagesdeleted.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessMessagesDeleted
|
||||
=======================
|
||||
|
||||
.. autoclass:: telegram.BusinessMessagesDeleted
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.businessopeninghours.rst
Normal file
6
docs/source/telegram.businessopeninghours.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessOpeningHours
|
||||
====================
|
||||
|
||||
.. autoclass:: telegram.BusinessOpeningHours
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.businessopeninghoursinterval.rst
Normal file
6
docs/source/telegram.businessopeninghoursinterval.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessOpeningHoursInterval
|
||||
============================
|
||||
|
||||
.. autoclass:: telegram.BusinessOpeningHoursInterval
|
||||
:members:
|
||||
:show-inheritance:
|
6
docs/source/telegram.ext.businessconnectionhandler.rst
Normal file
6
docs/source/telegram.ext.businessconnectionhandler.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
BusinessConnectionHandler
|
||||
=========================
|
||||
|
||||
.. autoclass:: telegram.ext.BusinessConnectionHandler
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -0,0 +1,6 @@
|
|||
BusinessMessagesDeletedHandler
|
||||
==============================
|
||||
|
||||
.. autoclass:: telegram.ext.BusinessMessagesDeletedHandler
|
||||
:members:
|
||||
:show-inheritance:
|
|
@ -5,6 +5,8 @@ Handlers
|
|||
:titlesonly:
|
||||
|
||||
telegram.ext.basehandler
|
||||
telegram.ext.businessconnectionhandler
|
||||
telegram.ext.businessmessagesdeletedhandler
|
||||
telegram.ext.callbackqueryhandler
|
||||
telegram.ext.chatboosthandler
|
||||
telegram.ext.chatjoinrequesthandler
|
||||
|
|
7
docs/source/telegram.shareduser.rst
Normal file
7
docs/source/telegram.shareduser.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
SharedUser
|
||||
==========
|
||||
|
||||
.. autoclass:: telegram.SharedUser
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
|
@ -79,3 +79,5 @@
|
|||
.. |do_quote| replace:: If set to :obj:`True`, the replied message is quoted. For a dict, it must be the output of :meth:`~telegram.Message.build_reply_arguments` to specify exact ``reply_parameters``. If ``reply_to_message_id`` or ``reply_parameters`` are passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats.
|
||||
|
||||
.. |non_optional_story_argument| replace:: As of this version, this argument is now required. In accordance with our `stability policy <https://docs.python-telegram-bot.org/en/stable/stability_policy.html>`__, the signature will be kept as optional for now, though they are mandatory and an error will be raised if you don't pass it.
|
||||
|
||||
.. |business_id_str| replace:: Unique identifier of the business connection on behalf of which the message will be sent.
|
||||
|
|
|
@ -20,7 +20,7 @@ explicit-preview-rules = true
|
|||
ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PERF203"]
|
||||
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
||||
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "RUF022",
|
||||
"RUF023", "Q", "INP",]
|
||||
"RUF023", "Q", "INP", "W"]
|
||||
# Add "FURB" after it's out of preview
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
|
|
|
@ -22,6 +22,7 @@ __author__ = "devs@python-telegram-bot.org"
|
|||
__all__ = (
|
||||
"Animation",
|
||||
"Audio",
|
||||
"Birthdate",
|
||||
"Bot",
|
||||
"BotCommand",
|
||||
"BotCommandScope",
|
||||
|
@ -35,6 +36,12 @@ __all__ = (
|
|||
"BotDescription",
|
||||
"BotName",
|
||||
"BotShortDescription",
|
||||
"BusinessConnection",
|
||||
"BusinessIntro",
|
||||
"BusinessLocation",
|
||||
"BusinessMessagesDeleted",
|
||||
"BusinessOpeningHours",
|
||||
"BusinessOpeningHoursInterval",
|
||||
"CallbackGame",
|
||||
"CallbackQuery",
|
||||
"Chat",
|
||||
|
@ -184,6 +191,7 @@ __all__ = (
|
|||
"SecureData",
|
||||
"SecureValue",
|
||||
"SentWebAppMessage",
|
||||
"SharedUser",
|
||||
"ShippingAddress",
|
||||
"ShippingOption",
|
||||
"ShippingQuery",
|
||||
|
@ -224,6 +232,7 @@ __all__ = (
|
|||
|
||||
|
||||
from . import _version, constants, error, helpers, request, warnings
|
||||
from ._birthdate import Birthdate
|
||||
from ._bot import Bot
|
||||
from ._botcommand import BotCommand
|
||||
from ._botcommandscope import (
|
||||
|
@ -238,6 +247,14 @@ from ._botcommandscope import (
|
|||
)
|
||||
from ._botdescription import BotDescription, BotShortDescription
|
||||
from ._botname import BotName
|
||||
from ._business import (
|
||||
BusinessConnection,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessMessagesDeleted,
|
||||
BusinessOpeningHours,
|
||||
BusinessOpeningHoursInterval,
|
||||
)
|
||||
from ._callbackquery import CallbackQuery
|
||||
from ._chat import Chat
|
||||
from ._chatadministratorrights import ChatAdministratorRights
|
||||
|
@ -393,7 +410,7 @@ from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
|
|||
from ._replykeyboardmarkup import ReplyKeyboardMarkup
|
||||
from ._replykeyboardremove import ReplyKeyboardRemove
|
||||
from ._sentwebappmessage import SentWebAppMessage
|
||||
from ._shared import ChatShared, UsersShared
|
||||
from ._shared import ChatShared, SharedUser, UsersShared
|
||||
from ._story import Story
|
||||
from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
|
||||
from ._telegramobject import TelegramObject
|
||||
|
|
88
telegram/_birthdate.py
Normal file
88
telegram/_birthdate.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Birthday."""
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class Birthdate(TelegramObject):
|
||||
"""
|
||||
This object represents a user's birthday.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`day`, and :attr:`month` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
day (:obj:`int`): Day of the user's birth; 1-31.
|
||||
month (:obj:`int`): Month of the user's birth; 1-12.
|
||||
year (:obj:`int`, optional): Year of the user's birth.
|
||||
|
||||
Attributes:
|
||||
day (:obj:`int`): Day of the user's birth; 1-31.
|
||||
month (:obj:`int`): Month of the user's birth; 1-12.
|
||||
year (:obj:`int`): Optional. Year of the user's birth.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("day", "month", "year")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
day: int,
|
||||
month: int,
|
||||
year: Optional[int] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.day: int = day
|
||||
self.month: int = month
|
||||
# Optional
|
||||
self.year: Optional[int] = year
|
||||
|
||||
self._id_attrs = (
|
||||
self.day,
|
||||
self.month,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def to_date(self, year: Optional[int] = None) -> datetime:
|
||||
"""Return the birthdate as a datetime object.
|
||||
|
||||
Args:
|
||||
year (:obj:`int`, optional): The year to use. Required, if the :attr:`year` was not
|
||||
present.
|
||||
|
||||
Returns:
|
||||
:obj:`datetime.datetime`: The birthdate as a datetime object.
|
||||
"""
|
||||
if self.year is None and year is None:
|
||||
raise ValueError(
|
||||
"The `year` argument is required if the `year` attribute was not present."
|
||||
)
|
||||
|
||||
return datetime(year or self.year, self.month, self.day) # type: ignore[arg-type]
|
220
telegram/_bot.py
220
telegram/_bot.py
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=no-self-argument, not-callable, no-member, too-many-arguments
|
||||
# pylint: disable=too-many-arguments
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
|
@ -57,6 +57,7 @@ from telegram._botcommand import BotCommand
|
|||
from telegram._botcommandscope import BotCommandScope
|
||||
from telegram._botdescription import BotDescription, BotShortDescription
|
||||
from telegram._botname import BotName
|
||||
from telegram._business import BusinessConnection
|
||||
from telegram._chat import Chat
|
||||
from telegram._chatadministratorrights import ChatAdministratorRights
|
||||
from telegram._chatboost import UserChatBoosts
|
||||
|
@ -667,6 +668,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -723,6 +725,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
if caption_entities is not None:
|
||||
data["caption_entities"] = caption_entities
|
||||
|
||||
if business_connection_id is not None:
|
||||
data["business_connection_id"] = business_connection_id
|
||||
|
||||
result = await self._post(
|
||||
endpoint,
|
||||
data,
|
||||
|
@ -911,6 +916,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -956,6 +962,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1009,6 +1018,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
parse_mode=parse_mode,
|
||||
link_preview_options=link_preview_options,
|
||||
reply_parameters=reply_parameters,
|
||||
|
@ -1259,6 +1269,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1319,6 +1330,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1376,6 +1390,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -1394,6 +1409,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1463,6 +1479,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:obj:`ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1523,6 +1542,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -1539,6 +1559,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1607,6 +1628,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1663,6 +1687,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -1675,6 +1700,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1693,8 +1719,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
|
||||
sticker (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | \
|
||||
:class:`telegram.Sticker`): Sticker to send.
|
||||
|fileinput| Video stickers can only be sent by a ``file_id``. Animated stickers
|
||||
can't be sent via an HTTP URL.
|
||||
|fileinput| Video stickers can only be sent by a ``file_id``. Video and animated
|
||||
stickers can't be sent via an HTTP URL.
|
||||
|
||||
Lastly you can pass an existing :class:`telegram.Sticker` object to send.
|
||||
|
||||
|
@ -1723,6 +1749,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1771,6 +1800,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -1791,6 +1821,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -1868,6 +1899,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -1930,6 +1964,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -1944,6 +1979,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2006,6 +2042,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2062,6 +2101,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
|
@ -2081,6 +2121,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2152,6 +2193,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2213,6 +2257,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -2228,6 +2273,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2292,6 +2338,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2349,6 +2398,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
|
@ -2361,6 +2411,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2408,6 +2459,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2500,6 +2554,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"protect_content": protect_content,
|
||||
"message_thread_id": message_thread_id,
|
||||
"reply_parameters": reply_parameters,
|
||||
"business_connection_id": business_connection_id,
|
||||
}
|
||||
|
||||
result = await self._post(
|
||||
|
@ -2528,6 +2583,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2579,6 +2635,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2647,6 +2706,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def edit_message_live_location(
|
||||
|
@ -2806,6 +2866,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2855,6 +2916,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -2934,6 +2998,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_contact(
|
||||
|
@ -2948,6 +3013,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2987,6 +3053,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -3057,6 +3126,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -3068,6 +3138,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -3097,6 +3168,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -3142,6 +3216,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
|
@ -3149,6 +3224,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
chat_id: Union[str, int],
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -3170,6 +3246,9 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
|
||||
|
||||
.. versionadded:: 20.0
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
@ -3182,6 +3261,7 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
|||
"chat_id": chat_id,
|
||||
"action": action,
|
||||
"message_thread_id": message_thread_id,
|
||||
"business_connection_id": business_connection_id,
|
||||
}
|
||||
return await self._post(
|
||||
"sendChatAction",
|
||||
|
@ -6147,9 +6227,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""
|
||||
Use this method to add a new sticker to a set created by the bot. The format of the added
|
||||
sticker must match the format of the other stickers in the set. Emoji sticker sets can have
|
||||
up to :tg-const:`telegram.constants.StickerSetLimit.MAX_EMOJI_STICKERS` stickers. Animated
|
||||
and video sticker sets can have up to
|
||||
:tg-const:`telegram.constants.StickerSetLimit.MAX_ANIMATED_STICKERS` stickers. Static
|
||||
up to :tg-const:`telegram.constants.StickerSetLimit.MAX_EMOJI_STICKERS` stickers. Other
|
||||
sticker sets can have up to
|
||||
:tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_STICKERS` stickers.
|
||||
|
||||
|
@ -6234,7 +6312,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
name: str,
|
||||
title: str,
|
||||
stickers: Sequence["InputSticker"],
|
||||
sticker_format: str,
|
||||
sticker_format: Optional[str] = None,
|
||||
sticker_type: Optional[str] = None,
|
||||
needs_repainting: Optional[bool] = None,
|
||||
*,
|
||||
|
@ -6287,6 +6365,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Use :paramref:`telegram.InputSticker.format` instead.
|
||||
|
||||
sticker_type (:obj:`str`, optional): Type of stickers in the set, pass
|
||||
:attr:`telegram.Sticker.REGULAR` or :attr:`telegram.Sticker.MASK`, or
|
||||
:attr:`telegram.Sticker.CUSTOM_EMOJI`. By default, a regular sticker set is created
|
||||
|
@ -6306,6 +6387,14 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
if sticker_format is not None:
|
||||
warn(
|
||||
"The parameter `sticker_format` is deprecated. Use the parameter"
|
||||
" `InputSticker.format` in the parameter `stickers` instead.",
|
||||
stacklevel=2,
|
||||
category=PTBDeprecationWarning,
|
||||
)
|
||||
|
||||
data: JSONDict = {
|
||||
"user_id": user_id,
|
||||
"name": name,
|
||||
|
@ -6399,6 +6488,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
self,
|
||||
name: str,
|
||||
user_id: int,
|
||||
format: str, # pylint: disable=redefined-builtin
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -6412,9 +6502,21 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
As per Bot API 7.2, the new argument :paramref:`format` will be required, and thus the
|
||||
order of the arguments had to be changed.
|
||||
|
||||
Args:
|
||||
name (:obj:`str`): Sticker set name
|
||||
user_id (:obj:`int`): User identifier of created sticker set owner.
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a
|
||||
WEBM video.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
thumbnail (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path`, \
|
||||
optional): A **.WEBP** or **.PNG** image with the thumbnail, must
|
||||
be up to :tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_THUMBNAIL_SIZE`
|
||||
|
@ -6447,6 +6549,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"name": name,
|
||||
"user_id": user_id,
|
||||
"thumbnail": self._parse_file_input(thumbnail) if thumbnail else None,
|
||||
"format": format,
|
||||
}
|
||||
|
||||
return await self._post(
|
||||
|
@ -6728,6 +6831,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -6803,6 +6907,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -6862,6 +6969,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def stop_poll(
|
||||
|
@ -6918,6 +7026,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -6961,6 +7070,9 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
|
||||
|
||||
.. versionadded:: 20.8
|
||||
business_connection_id (:obj:`str`, optional): |business_id_str|
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Keyword Args:
|
||||
allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
|
||||
|
@ -7007,6 +7119,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def get_my_default_administrator_rights(
|
||||
|
@ -8665,6 +8778,95 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
async def get_business_connection(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> BusinessConnection:
|
||||
"""
|
||||
Use this method to get information about the connection of the bot with a business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.BusinessConnection`: On success, the object containing the business
|
||||
connection information is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {"business_connection_id": business_connection_id}
|
||||
return BusinessConnection.de_json( # type: ignore[return-value]
|
||||
await self._post(
|
||||
"getBusinessConnection",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
),
|
||||
bot=self,
|
||||
)
|
||||
|
||||
async def replace_sticker_in_set(
|
||||
self,
|
||||
user_id: int,
|
||||
name: str,
|
||||
old_sticker: str,
|
||||
sticker: "InputSticker",
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> bool:
|
||||
"""Use this method to replace an existing sticker in a sticker set with a new one.
|
||||
The method is equivalent to calling :meth:`delete_sticker_from_set`,
|
||||
then :meth:`add_sticker_to_set`, then :meth:`set_sticker_position_in_set`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
user_id (:obj:`int`): User identifier of the sticker set owner.
|
||||
name (:obj:`str`): Sticker set name.
|
||||
old_sticker (:obj:`str`): File identifier of the replaced sticker.
|
||||
sticker (:obj:`telegram.InputSticker`): An object with information about the added
|
||||
sticker. If exactly the same sticker had already been added to the set, then the
|
||||
set remains unchanged.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: On success, :obj:`True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
"""
|
||||
data: JSONDict = {
|
||||
"user_id": user_id,
|
||||
"name": name,
|
||||
"old_sticker": old_sticker,
|
||||
"sticker": sticker,
|
||||
}
|
||||
|
||||
return await self._post(
|
||||
"replaceStickerInSet",
|
||||
data,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict`."""
|
||||
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
|
||||
|
@ -8911,3 +9113,7 @@ CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
|
|||
"""Alias for :meth:`get_user_chat_boosts`"""
|
||||
setMessageReaction = set_message_reaction
|
||||
"""Alias for :meth:`set_message_reaction`"""
|
||||
getBusinessConnection = get_business_connection
|
||||
"""Alias for :meth:`get_business_connection`"""
|
||||
replaceStickerInSet = replace_sticker_in_set
|
||||
"""Alias for :meth:`replace_sticker_in_set`"""
|
||||
|
|
445
telegram/_business.py
Normal file
445
telegram/_business.py
Normal file
|
@ -0,0 +1,445 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=redefined-builtin
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/]
|
||||
"""This module contains the Telegram Business related classes."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._chat import Chat
|
||||
from telegram._files.location import Location
|
||||
from telegram._files.sticker import Sticker
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._user import User
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
class BusinessConnection(TelegramObject):
|
||||
"""
|
||||
Describes the connection of the bot with a business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal if their :attr:`id`, :attr:`user`, :attr:`user_chat_id`, :attr:`date`,
|
||||
:attr:`can_reply`, and :attr:`is_enabled` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
id (:obj:`str`): Unique identifier of the business connection.
|
||||
user (:class:`telegram.User`): Business account user that created the business connection.
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
|
||||
business connection.
|
||||
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
|
||||
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
|
||||
chats that were active in the last 24 hours.
|
||||
is_enabled (:obj:`bool`): True, if the connection is active.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`str`): Unique identifier of the business connection.
|
||||
user (:class:`telegram.User`): Business account user that created the business connection.
|
||||
user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
|
||||
business connection.
|
||||
date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
|
||||
can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
|
||||
chats that were active in the last 24 hours.
|
||||
is_enabled (:obj:`bool`): True, if the connection is active.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"can_reply",
|
||||
"date",
|
||||
"id",
|
||||
"is_enabled",
|
||||
"user",
|
||||
"user_chat_id",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
user: "User",
|
||||
user_chat_id: int,
|
||||
date: datetime,
|
||||
can_reply: bool,
|
||||
is_enabled: bool,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.id: str = id
|
||||
self.user: User = user
|
||||
self.user_chat_id: int = user_chat_id
|
||||
self.date: datetime = date
|
||||
self.can_reply: bool = can_reply
|
||||
self.is_enabled: bool = is_enabled
|
||||
|
||||
self._id_attrs = (
|
||||
self.id,
|
||||
self.user,
|
||||
self.user_chat_id,
|
||||
self.date,
|
||||
self.can_reply,
|
||||
self.is_enabled,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessConnection"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Get the local timezone from the bot if it has defaults
|
||||
loc_tzinfo = extract_tzinfo_from_defaults(bot)
|
||||
|
||||
data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
|
||||
data["user"] = User.de_json(data.get("user"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessMessagesDeleted(TelegramObject):
|
||||
"""
|
||||
This object is received when messages are deleted from a connected business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal if their :attr:`business_connection_id`, :attr:`message_ids`, and
|
||||
:attr:`chat` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
|
||||
may not have access to the chat or the corresponding user.
|
||||
message_ids (Sequence[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
chat of the business account.
|
||||
|
||||
Attributes:
|
||||
business_connection_id (:obj:`str`): Unique identifier of the business connection.
|
||||
chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
|
||||
may not have access to the chat or the corresponding user.
|
||||
message_ids (Tuple[:obj:`int`]): A list of identifiers of the deleted messages in the
|
||||
chat of the business account.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"business_connection_id",
|
||||
"chat",
|
||||
"message_ids",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
chat: Chat,
|
||||
message_ids: Sequence[int],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.business_connection_id: str = business_connection_id
|
||||
self.chat: Chat = chat
|
||||
self.message_ids: Tuple[int, ...] = parse_sequence_arg(message_ids)
|
||||
|
||||
self._id_attrs = (
|
||||
self.business_connection_id,
|
||||
self.chat,
|
||||
self.message_ids,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessMessagesDeleted"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["chat"] = Chat.de_json(data.get("chat"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessIntro(TelegramObject):
|
||||
"""
|
||||
This object represents the intro of a business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`title`, :attr:`message` and :attr:`sticker` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
title (:obj:`str`, optional): Title text of the business intro.
|
||||
message (:obj:`str`, optional): Message text of the business intro.
|
||||
sticker (:class:`telegram.Sticker`, optional): Sticker of the business intro.
|
||||
|
||||
Attributes:
|
||||
title (:obj:`str`): Optional. Title text of the business intro.
|
||||
message (:obj:`str`): Optional. Message text of the business intro.
|
||||
sticker (:class:`telegram.Sticker`): Optional. Sticker of the business intro.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"message",
|
||||
"sticker",
|
||||
"title",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
title: Optional[str] = None,
|
||||
message: Optional[str] = None,
|
||||
sticker: Optional[Sticker] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.title: Optional[str] = title
|
||||
self.message: Optional[str] = message
|
||||
self.sticker: Optional[Sticker] = sticker
|
||||
|
||||
self._id_attrs = (self.title, self.message, self.sticker)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessIntro"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessLocation(TelegramObject):
|
||||
"""
|
||||
This object represents the location of a business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`address` is equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
address (:obj:`str`): Address of the business.
|
||||
location (:class:`telegram.Location`, optional): Location of the business.
|
||||
|
||||
Attributes:
|
||||
address (:obj:`str`): Address of the business.
|
||||
location (:class:`telegram.Location`): Optional. Location of the business.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"address",
|
||||
"location",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: str,
|
||||
location: Optional[Location] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.address: str = address
|
||||
self.location: Optional[Location] = location
|
||||
|
||||
self._id_attrs = (self.address,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessLocation"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["location"] = Location.de_json(data.get("location"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class BusinessOpeningHoursInterval(TelegramObject):
|
||||
"""
|
||||
This object represents the time intervals describing business opening hours.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`opening_minute` and :attr:`closing_minute` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Examples:
|
||||
A day has (24 * 60 =) 1440 minutes, a week has (7 * 1440 =) 10080 minutes.
|
||||
Starting the the minute's sequence from Monday, example values of
|
||||
:attr:`opening_minute`, :attr:`closing_minute` will map to the following day times:
|
||||
|
||||
* Monday - 8am to 8:30pm:
|
||||
- ``opening_minute = 480`` :guilabel:`8 * 60`
|
||||
- ``closing_minute = 1230`` :guilabel:`20 * 60 + 30`
|
||||
* Tuesday - 24 hours:
|
||||
- ``opening_minute = 1440`` :guilabel:`24 * 60`
|
||||
- ``closing_minute = 2879`` :guilabel:`2 * 24 * 60 - 1`
|
||||
* Sunday - 12am - 11:58pm:
|
||||
- ``opening_minute = 8640`` :guilabel:`6 * 24 * 60`
|
||||
- ``closing_minute = 10078`` :guilabel:`7 * 24 * 60 - 2`
|
||||
|
||||
Args:
|
||||
opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
|
||||
marking the start of the time interval during which the business is open;
|
||||
0 - 7 * 24 * 60.
|
||||
closing_minute (:obj:`int`): The minute's
|
||||
sequence number in a week, starting on Monday, marking the end of the time interval
|
||||
during which the business is open; 0 - 8 * 24 * 60
|
||||
|
||||
Attributes:
|
||||
opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
|
||||
marking the start of the time interval during which the business is open;
|
||||
0 - 7 * 24 * 60.
|
||||
closing_minute (:obj:`int`): The minute's
|
||||
sequence number in a week, starting on Monday, marking the end of the time interval
|
||||
during which the business is open; 0 - 8 * 24 * 60
|
||||
"""
|
||||
|
||||
__slots__ = ("_closing_time", "_opening_time", "closing_minute", "opening_minute")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
opening_minute: int,
|
||||
closing_minute: int,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.opening_minute: int = opening_minute
|
||||
self.closing_minute: int = closing_minute
|
||||
|
||||
self._opening_time: Optional[Tuple[int, int, int]] = None
|
||||
self._closing_time: Optional[Tuple[int, int, int]] = None
|
||||
|
||||
self._id_attrs = (self.opening_minute, self.closing_minute)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def _parse_minute(self, minute: int) -> Tuple[int, int, int]:
|
||||
return (minute // 1440, minute % 1440 // 60, minute % 1440 % 60)
|
||||
|
||||
@property
|
||||
def opening_time(self) -> Tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`opening_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._opening_time is None:
|
||||
self._opening_time = self._parse_minute(self.opening_minute)
|
||||
return self._opening_time
|
||||
|
||||
@property
|
||||
def closing_time(self) -> Tuple[int, int, int]:
|
||||
"""Convenience attribute. A :obj:`tuple` parsed from :attr:`closing_minute`. It contains
|
||||
the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
|
||||
:attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
|
||||
|
||||
Returns:
|
||||
Tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
|
||||
"""
|
||||
if self._closing_time is None:
|
||||
self._closing_time = self._parse_minute(self.closing_minute)
|
||||
return self._closing_time
|
||||
|
||||
|
||||
class BusinessOpeningHours(TelegramObject):
|
||||
"""
|
||||
This object represents the opening hours of a business account.
|
||||
|
||||
Objects of this class are comparable in terms of equality.
|
||||
Two objects of this class are considered equal, if their
|
||||
:attr:`time_zone_name` and :attr:`opening_hours` are equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
|
||||
hours are defined.
|
||||
opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
|
||||
time intervals describing business opening hours.
|
||||
|
||||
Attributes:
|
||||
time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
|
||||
hours are defined.
|
||||
opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
|
||||
time intervals describing business opening hours.
|
||||
"""
|
||||
|
||||
__slots__ = ("opening_hours", "time_zone_name")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
time_zone_name: str,
|
||||
opening_hours: Sequence[BusinessOpeningHoursInterval],
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.time_zone_name: str = time_zone_name
|
||||
self.opening_hours: Sequence[BusinessOpeningHoursInterval] = parse_sequence_arg(
|
||||
opening_hours
|
||||
)
|
||||
|
||||
self._id_attrs = (self.time_zone_name, self.opening_hours)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["BusinessOpeningHours"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["opening_hours"] = BusinessOpeningHoursInterval.de_list(
|
||||
data.get("opening_hours"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
|
@ -23,6 +23,7 @@ from html import escape
|
|||
from typing import TYPE_CHECKING, Final, Optional, Sequence, Tuple, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._birthdate import Birthdate
|
||||
from telegram._chatlocation import ChatLocation
|
||||
from telegram._chatpermissions import ChatPermissions
|
||||
from telegram._files.chatphoto import ChatPhoto
|
||||
|
@ -44,6 +45,9 @@ if TYPE_CHECKING:
|
|||
Animation,
|
||||
Audio,
|
||||
Bot,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
ChatInviteLink,
|
||||
ChatMember,
|
||||
Contact,
|
||||
|
@ -169,6 +173,21 @@ class Chat(TelegramObject):
|
|||
only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
business_intro (:class:`telegram.BusinessIntro`, optional): For private chats with
|
||||
business accounts, the intro of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
business_location (:class:`telegram.BusinessLocation`, optional): For private chats with
|
||||
business accounts, the location of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
business_opening_hours (:class:`telegram.BusinessOpeningHours`, optional): For private
|
||||
chats with business accounts, the opening hours of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
available_reactions (Sequence[:class:`telegram.ReactionType`], optional): List of available
|
||||
reactions allowed in the chat. If omitted, then all of
|
||||
:const:`telegram.constants.ReactionEmoji` are allowed. Returned only in
|
||||
|
@ -229,6 +248,14 @@ class Chat(TelegramObject):
|
|||
and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
birthdate (:obj:`telegram.Birthdate`, optional): For private chats,
|
||||
the date of birth of the user. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
personal_chat (:obj:`telegram.Chat`, optional): For private chats, the personal channel of
|
||||
the user. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits
|
||||
|
@ -312,6 +339,21 @@ class Chat(TelegramObject):
|
|||
obtained via :meth:`~telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
business_intro (:class:`telegram.BusinessIntro`): Optional. For private chats with
|
||||
business accounts, the intro of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
business_location (:class:`telegram.BusinessLocation`): Optional. For private chats with
|
||||
business accounts, the location of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
business_opening_hours (:class:`telegram.BusinessOpeningHours`): Optional. For private
|
||||
chats with business accounts, the opening hours of the business. Returned only in
|
||||
:meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
available_reactions (Tuple[:class:`telegram.ReactionType`]): Optional. List of available
|
||||
reactions allowed in the chat. If omitted, then all of
|
||||
:const:`telegram.constants.ReactionEmoji` are allowed. Returned only in
|
||||
|
@ -372,6 +414,14 @@ class Chat(TelegramObject):
|
|||
and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
birthdate (:obj:`telegram.Birthdate`): Optional. For private chats,
|
||||
the date of birth of the user. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
personal_chat (:obj:`telegram.Chat`): Optional. For private chats, the personal channel of
|
||||
the user. Returned only in :meth:`telegram.Bot.get_chat`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
.. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
|
||||
.. _accent colors: https://core.telegram.org/bots/api#accent-colors
|
||||
|
@ -383,6 +433,10 @@ class Chat(TelegramObject):
|
|||
"available_reactions",
|
||||
"background_custom_emoji_id",
|
||||
"bio",
|
||||
"birthdate",
|
||||
"business_intro",
|
||||
"business_location",
|
||||
"business_opening_hours",
|
||||
"can_set_sticker_set",
|
||||
"custom_emoji_sticker_set_name",
|
||||
"description",
|
||||
|
@ -405,6 +459,7 @@ class Chat(TelegramObject):
|
|||
"location",
|
||||
"message_auto_delete_time",
|
||||
"permissions",
|
||||
"personal_chat",
|
||||
"photo",
|
||||
"pinned_message",
|
||||
"profile_accent_color_id",
|
||||
|
@ -470,6 +525,11 @@ class Chat(TelegramObject):
|
|||
has_visible_history: Optional[bool] = None,
|
||||
unrestrict_boost_count: Optional[int] = None,
|
||||
custom_emoji_sticker_set_name: Optional[str] = None,
|
||||
birthdate: Optional[Birthdate] = None,
|
||||
personal_chat: Optional["Chat"] = None,
|
||||
business_intro: Optional["BusinessIntro"] = None,
|
||||
business_location: Optional["BusinessLocation"] = None,
|
||||
business_opening_hours: Optional["BusinessOpeningHours"] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -519,6 +579,11 @@ class Chat(TelegramObject):
|
|||
self.profile_background_custom_emoji_id: Optional[str] = profile_background_custom_emoji_id
|
||||
self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count
|
||||
self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name
|
||||
self.birthdate: Optional[Birthdate] = birthdate
|
||||
self.personal_chat: Optional["Chat"] = personal_chat
|
||||
self.business_intro: Optional["BusinessIntro"] = business_intro
|
||||
self.business_location: Optional["BusinessLocation"] = business_location
|
||||
self.business_opening_hours: Optional["BusinessOpeningHours"] = business_opening_hours
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
|
@ -581,12 +646,24 @@ class Chat(TelegramObject):
|
|||
)
|
||||
|
||||
data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
|
||||
from telegram import Message # pylint: disable=import-outside-toplevel
|
||||
from telegram import ( # pylint: disable=import-outside-toplevel
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
Message,
|
||||
)
|
||||
|
||||
data["pinned_message"] = Message.de_json(data.get("pinned_message"), bot)
|
||||
data["permissions"] = ChatPermissions.de_json(data.get("permissions"), bot)
|
||||
data["location"] = ChatLocation.de_json(data.get("location"), bot)
|
||||
data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot)
|
||||
data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot)
|
||||
data["personal_chat"] = cls.de_json(data.get("personal_chat"), bot)
|
||||
data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot)
|
||||
data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot)
|
||||
data["business_opening_hours"] = BusinessOpeningHours.de_json(
|
||||
data.get("business_opening_hours"), bot
|
||||
)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
|
@ -1444,6 +1521,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1483,6 +1561,7 @@ class Chat(TelegramObject):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def delete_message(
|
||||
|
@ -1558,6 +1637,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1598,12 +1678,14 @@ class Chat(TelegramObject):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
reply_parameters=reply_parameters,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
self,
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -1630,6 +1712,7 @@ class Chat(TelegramObject):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
send_action = send_chat_action
|
||||
|
@ -1647,6 +1730,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1687,6 +1771,7 @@ class Chat(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_contact(
|
||||
|
@ -1700,6 +1785,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1739,6 +1825,7 @@ class Chat(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -1756,6 +1843,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1799,6 +1887,7 @@ class Chat(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -1814,6 +1903,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1855,6 +1945,7 @@ class Chat(TelegramObject):
|
|||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
|
@ -1865,6 +1956,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1899,6 +1991,7 @@ class Chat(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -1909,6 +2002,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1943,6 +2037,7 @@ class Chat(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
|
@ -2052,6 +2147,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2093,6 +2189,7 @@ class Chat(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
|
@ -2111,6 +2208,7 @@ class Chat(TelegramObject):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2155,6 +2253,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -2166,6 +2265,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2201,6 +2301,7 @@ class Chat(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
|
@ -2218,6 +2319,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2261,6 +2363,7 @@ class Chat(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -2280,6 +2383,7 @@ class Chat(TelegramObject):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2325,6 +2429,7 @@ class Chat(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -2338,6 +2443,7 @@ class Chat(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2377,6 +2483,7 @@ class Chat(TelegramObject):
|
|||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -2391,6 +2498,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2431,6 +2539,7 @@ class Chat(TelegramObject):
|
|||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
|
@ -2452,6 +2561,7 @@ class Chat(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2497,6 +2607,7 @@ class Chat(TelegramObject):
|
|||
explanation_entities=explanation_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_copy(
|
||||
|
|
|
@ -36,6 +36,10 @@ class InputSticker(TelegramObject):
|
|||
|
||||
.. versionadded:: 20.2
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
As of Bot API 7.2, the new argument :paramref:`format` is a required argument, and thus the
|
||||
order of the arguments has changed.
|
||||
|
||||
Args:
|
||||
sticker (:obj:`str` | :term:`file object` | :obj:`bytes` | :class:`pathlib.Path`): The
|
||||
added sticker. |uploadinputnopath| Animated and video stickers can't be uploaded via
|
||||
|
@ -52,6 +56,13 @@ class InputSticker(TelegramObject):
|
|||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
sticker (:obj:`str` | :class:`telegram.InputFile`): The added sticker.
|
||||
|
@ -67,15 +78,23 @@ class InputSticker(TelegramObject):
|
|||
:tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
|
||||
":tg-const:`telegram.constants.StickerType.REGULAR`" and
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
|
||||
format (:obj:`str`): Format of the added sticker, must be one of
|
||||
:tg-const:`telegram.constants.StickerFormat.STATIC` for a
|
||||
``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
|
||||
for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
|
||||
video.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = ("emoji_list", "keywords", "mask_position", "sticker")
|
||||
__slots__ = ("emoji_list", "format", "keywords", "mask_position", "sticker")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sticker: FileInput,
|
||||
emoji_list: Sequence[str],
|
||||
format: str, # pylint: disable=redefined-builtin
|
||||
mask_position: Optional[MaskPosition] = None,
|
||||
keywords: Optional[Sequence[str]] = None,
|
||||
*,
|
||||
|
@ -91,6 +110,7 @@ class InputSticker(TelegramObject):
|
|||
attach=True,
|
||||
)
|
||||
self.emoji_list: Tuple[str, ...] = parse_sequence_arg(emoji_list)
|
||||
self.format: str = format
|
||||
self.mask_position: Optional[MaskPosition] = mask_position
|
||||
self.keywords: Tuple[str, ...] = parse_sequence_arg(keywords)
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ from telegram._telegramobject import TelegramObject
|
|||
from telegram._utils import enum
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
@ -227,6 +229,11 @@ class StickerSet(TelegramObject):
|
|||
.. versionchanged:: 20.0
|
||||
The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead.
|
||||
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
The parameters ``is_video`` and ``is_animated`` are deprecated and now made optional. Thus,
|
||||
the order of the arguments had to be changed.
|
||||
|
||||
.. versionchanged:: 20.5
|
||||
|removed_thumb_note|
|
||||
|
||||
|
@ -234,9 +241,16 @@ class StickerSet(TelegramObject):
|
|||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Bot API 7.2 deprecated this field. This parameter will be removed in a future
|
||||
version of the library.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
.. versionadded:: 13.11
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Bot API 7.2 deprecated this field. This parameter will be removed in a future
|
||||
version of the library.
|
||||
stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
@ -256,9 +270,16 @@ class StickerSet(TelegramObject):
|
|||
name (:obj:`str`): Sticker set name.
|
||||
title (:obj:`str`): Sticker set title.
|
||||
is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Bot API 7.2 deprecated this field. This parameter will be removed in a future
|
||||
version of the library.
|
||||
is_video (:obj:`bool`): :obj:`True`, if the sticker set contains video stickers.
|
||||
.. versionadded:: 13.11
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Bot API 7.2 deprecated this field. This parameter will be removed in a future
|
||||
version of the library.
|
||||
stickers (Tuple[:class:`telegram.Sticker`]): List of all set stickers.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
@ -289,10 +310,10 @@ class StickerSet(TelegramObject):
|
|||
self,
|
||||
name: str,
|
||||
title: str,
|
||||
is_animated: bool,
|
||||
stickers: Sequence[Sticker],
|
||||
is_video: bool,
|
||||
sticker_type: str,
|
||||
is_animated: Optional[bool] = None,
|
||||
is_video: Optional[bool] = None,
|
||||
thumbnail: Optional[PhotoSize] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
|
@ -300,13 +321,19 @@ class StickerSet(TelegramObject):
|
|||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.name: str = name
|
||||
self.title: str = title
|
||||
self.is_animated: bool = is_animated
|
||||
self.is_video: bool = is_video
|
||||
self.stickers: Tuple[Sticker, ...] = parse_sequence_arg(stickers)
|
||||
self.sticker_type: str = sticker_type
|
||||
# Optional
|
||||
|
||||
self.thumbnail: Optional[PhotoSize] = thumbnail
|
||||
if is_animated is not None or is_video is not None:
|
||||
warn(
|
||||
"The parameters `is_animated` and `is_video` are deprecated and will be removed "
|
||||
"in a future version.",
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.is_animated: Optional[bool] = is_animated
|
||||
self.is_video: Optional[bool] = is_video
|
||||
self._id_attrs = (self.name,)
|
||||
|
||||
self._freeze()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# 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 two objects to request chats/users."""
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._chatadministratorrights import ChatAdministratorRights
|
||||
|
@ -56,6 +57,16 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
|||
.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
request_name (:obj:`bool`, optional): Pass :obj:`True` to request the users' first and last
|
||||
name.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_username (:obj:`bool`, optional): Pass :obj:`True` to request the users' username.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the users' photo.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
|
@ -71,11 +82,25 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
|||
.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
request_name (:obj:`bool`): Optional. Pass :obj:`True` to request the users' first and last
|
||||
name.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the users' username.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the users' photo.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"max_quantity",
|
||||
"request_id",
|
||||
"request_name",
|
||||
"request_photo",
|
||||
"request_username",
|
||||
"user_is_bot",
|
||||
"user_is_premium",
|
||||
)
|
||||
|
@ -86,6 +111,9 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
|||
user_is_bot: Optional[bool] = None,
|
||||
user_is_premium: Optional[bool] = None,
|
||||
max_quantity: Optional[int] = None,
|
||||
request_name: Optional[bool] = None,
|
||||
request_username: Optional[bool] = None,
|
||||
request_photo: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -97,6 +125,9 @@ class KeyboardButtonRequestUsers(TelegramObject):
|
|||
self.user_is_bot: Optional[bool] = user_is_bot
|
||||
self.user_is_premium: Optional[bool] = user_is_premium
|
||||
self.max_quantity: Optional[int] = max_quantity
|
||||
self.request_name: Optional[bool] = request_name
|
||||
self.request_username: Optional[bool] = request_username
|
||||
self.request_photo: Optional[bool] = request_photo
|
||||
|
||||
self._id_attrs = (self.request_id,)
|
||||
|
||||
|
@ -138,6 +169,15 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
applied.
|
||||
bot_is_member (:obj:`bool`, optional): Pass :obj:`True` to request a chat with the bot
|
||||
as a member. Otherwise, no additional restrictions are applied.
|
||||
request_title (:obj:`bool`, optional): Pass :obj:`True` to request the chat's title.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_username (:obj:`bool`, optional): Pass :obj:`True` to request the chat's username.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the chat's photo.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass
|
||||
|
@ -145,7 +185,7 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
chat_is_forum (:obj:`bool`): Optional. Pass :obj:`True` to request a forum supergroup, pass
|
||||
:obj:`False` to request a non-forum chat. If not specified, no additional
|
||||
restrictions are applied.
|
||||
chat_has_username (:obj:`bool`, optional): Pass :obj:`True` to request a supergroup or a
|
||||
chat_has_username (:obj:`bool`): Optional. Pass :obj:`True` to request a supergroup or a
|
||||
channel with a username, pass :obj:`False` to request a chat without a username. If
|
||||
not specified, no additional restrictions are applied.
|
||||
chat_is_created (:obj:`bool`) Optional. Pass :obj:`True` to request a chat owned by the
|
||||
|
@ -159,6 +199,15 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
applied.
|
||||
bot_is_member (:obj:`bool`) Optional. Pass :obj:`True` to request a chat with the bot
|
||||
as a member. Otherwise, no additional restrictions are applied.
|
||||
request_title (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's title.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's username.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's photo.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
|
@ -169,6 +218,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
"chat_is_created",
|
||||
"chat_is_forum",
|
||||
"request_id",
|
||||
"request_photo",
|
||||
"request_title",
|
||||
"request_username",
|
||||
"user_administrator_rights",
|
||||
)
|
||||
|
||||
|
@ -182,6 +234,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
user_administrator_rights: Optional[ChatAdministratorRights] = None,
|
||||
bot_administrator_rights: Optional[ChatAdministratorRights] = None,
|
||||
bot_is_member: Optional[bool] = None,
|
||||
request_title: Optional[bool] = None,
|
||||
request_username: Optional[bool] = None,
|
||||
request_photo: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -199,6 +254,9 @@ class KeyboardButtonRequestChat(TelegramObject):
|
|||
)
|
||||
self.bot_administrator_rights: Optional[ChatAdministratorRights] = bot_administrator_rights
|
||||
self.bot_is_member: Optional[bool] = bot_is_member
|
||||
self.request_title: Optional[bool] = request_title
|
||||
self.request_username: Optional[bool] = request_username
|
||||
self.request_photo: Optional[bool] = request_photo
|
||||
|
||||
self._id_attrs = (self.request_id,)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Message."""
|
||||
|
||||
import datetime
|
||||
import re
|
||||
from html import escape
|
||||
|
@ -301,6 +302,11 @@ class Message(MaybeInaccessibleMessage):
|
|||
forwarded.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
is_from_offline (:obj:`bool`, optional): :obj:`True`, if the message was sent
|
||||
by an implicit action, for example, as an away or a greeting business message,
|
||||
or as a scheduled message.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
media_group_id (:obj:`str`, optional): The unique identifier of a media message group this
|
||||
message belongs to.
|
||||
text (:obj:`str`, optional): For text messages, the actual UTF-8 text of the message,
|
||||
|
@ -534,6 +540,18 @@ class Message(MaybeInaccessibleMessage):
|
|||
message boosted the chat, the number of boosts added by the user.
|
||||
|
||||
.. versionadded:: 21.0
|
||||
business_connection_id (:obj:`str`, optional): Unique identifier of the business connection
|
||||
from which the message was received. If non-empty, the message belongs to a chat of the
|
||||
corresponding business account that is independent from any potential bot chat which
|
||||
might share the same identifier.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
sender_business_bot (:obj:`telegram.User`, optional): The bot that actually sent the
|
||||
message on behalf of the business account. Available only for outgoing messages sent
|
||||
on behalf of the connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
message_id (:obj:`int`): Unique message identifier inside this chat.
|
||||
|
@ -568,6 +586,11 @@ class Message(MaybeInaccessibleMessage):
|
|||
forwarded.
|
||||
|
||||
.. versionadded:: 13.9
|
||||
is_from_offline (:obj:`bool`): Optional. :obj:`True`, if the message was sent
|
||||
by an implicit action, for example, as an away or a greeting business message,
|
||||
or as a scheduled message.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this
|
||||
message belongs to.
|
||||
text (:obj:`str`): Optional. For text messages, the actual UTF-8 text of the message,
|
||||
|
@ -817,6 +840,19 @@ class Message(MaybeInaccessibleMessage):
|
|||
|
||||
.. versionadded:: 21.0
|
||||
|
||||
business_connection_id (:obj:`str`): Optional. Unique identifier of the business connection
|
||||
from which the message was received. If non-empty, the message belongs to a chat of the
|
||||
corresponding business account that is independent from any potential bot chat which
|
||||
might share the same identifier.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
sender_business_bot (:obj:`telegram.User`): Optional. The bot that actually sent the
|
||||
message on behalf of the business account. Available only for outgoing messages sent
|
||||
on behalf of the connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
.. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
|
||||
:attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
|
||||
:exc:`ValueError` when encountering a custom emoji.
|
||||
|
@ -836,6 +872,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
"audio",
|
||||
"author_signature",
|
||||
"boost_added",
|
||||
"business_connection_id",
|
||||
"caption",
|
||||
"caption_entities",
|
||||
"channel_chat_created",
|
||||
|
@ -866,6 +903,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
"has_protected_content",
|
||||
"invoice",
|
||||
"is_automatic_forward",
|
||||
"is_from_offline",
|
||||
"is_topic_message",
|
||||
"left_chat_member",
|
||||
"link_preview_options",
|
||||
|
@ -888,6 +926,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
"reply_to_message",
|
||||
"reply_to_story",
|
||||
"sender_boost_count",
|
||||
"sender_business_bot",
|
||||
"sender_chat",
|
||||
"sticker",
|
||||
"story",
|
||||
|
@ -987,6 +1026,9 @@ class Message(MaybeInaccessibleMessage):
|
|||
reply_to_story: Optional[Story] = None,
|
||||
boost_added: Optional[ChatBoostAdded] = None,
|
||||
sender_boost_count: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
sender_business_bot: Optional[User] = None,
|
||||
is_from_offline: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -1082,6 +1124,9 @@ class Message(MaybeInaccessibleMessage):
|
|||
self.reply_to_story: Optional[Story] = reply_to_story
|
||||
self.boost_added: Optional[ChatBoostAdded] = boost_added
|
||||
self.sender_boost_count: Optional[int] = sender_boost_count
|
||||
self.business_connection_id: Optional[str] = business_connection_id
|
||||
self.sender_business_bot: Optional[User] = sender_business_bot
|
||||
self.is_from_offline: Optional[bool] = is_from_offline
|
||||
|
||||
self._effective_attachment = DEFAULT_NONE
|
||||
|
||||
|
@ -1224,6 +1269,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot)
|
||||
data["reply_to_story"] = Story.de_json(data.get("reply_to_story"), bot)
|
||||
data["boost_added"] = ChatBoostAdded.de_json(data.get("boost_added"), bot)
|
||||
data["sender_business_bot"] = User.de_json(data.get("sender_business_bot"), bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
|
@ -1575,6 +1621,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_message(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -1620,6 +1667,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_markdown(
|
||||
|
@ -1650,6 +1698,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
parse_mode=ParseMode.MARKDOWN,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -1700,6 +1749,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_markdown_v2(
|
||||
|
@ -1730,6 +1780,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -1776,6 +1827,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_html(
|
||||
|
@ -1806,6 +1858,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
parse_mode=ParseMode.HTML,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -1852,6 +1905,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_media_group(
|
||||
|
@ -1882,6 +1936,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_media_group(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -1927,6 +1982,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_photo(
|
||||
|
@ -1958,6 +2014,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_photo(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2004,6 +2061,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_audio(
|
||||
|
@ -2038,6 +2096,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_audio(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2087,6 +2146,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_document(
|
||||
|
@ -2119,6 +2179,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_document(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2166,6 +2227,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_animation(
|
||||
|
@ -2201,6 +2263,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_animation(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2251,6 +2314,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_sticker(
|
||||
|
@ -2278,6 +2342,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_sticker(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2320,6 +2385,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_video(
|
||||
|
@ -2356,6 +2422,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_video(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2407,6 +2474,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_video_note(
|
||||
|
@ -2437,6 +2505,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_video_note(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2482,6 +2551,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_voice(
|
||||
|
@ -2513,6 +2583,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_voice(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2559,6 +2630,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_location(
|
||||
|
@ -2591,6 +2663,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_location(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2638,6 +2711,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_venue(
|
||||
|
@ -2672,6 +2746,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_venue(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2721,6 +2796,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_contact(
|
||||
|
@ -2751,6 +2827,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_contact(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2796,6 +2873,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_poll(
|
||||
|
@ -2833,6 +2911,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_poll(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2885,6 +2964,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
explanation_entities=explanation_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_dice(
|
||||
|
@ -2911,6 +2991,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_dice(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2952,6 +3033,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_chat_action(
|
||||
|
@ -2970,6 +3052,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_chat_action(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -2994,6 +3077,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_game(
|
||||
|
@ -3020,6 +3104,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
await bot.send_game(
|
||||
update.effective_message.chat_id,
|
||||
message_thread_id=update.effective_message.message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
@ -3063,6 +3148,7 @@ class Message(MaybeInaccessibleMessage):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=self.business_connection_id,
|
||||
)
|
||||
|
||||
async def reply_invoice(
|
||||
|
|
|
@ -17,10 +17,21 @@
|
|||
# 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 two objects used for request chats/users service messages."""
|
||||
from typing import Optional, Sequence, Tuple
|
||||
from typing import TYPE_CHECKING, Optional, Sequence, Tuple
|
||||
|
||||
from telegram._files.photosize import PhotoSize
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram._utils.warnings_transition import (
|
||||
build_deprecation_warning_message,
|
||||
warn_about_deprecated_attr_in_property,
|
||||
)
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram._bot import Bot
|
||||
|
||||
|
||||
class UsersShared(TelegramObject):
|
||||
|
@ -29,48 +40,118 @@ class UsersShared(TelegramObject):
|
|||
using a :class:`telegram.KeyboardButtonRequestUsers` button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`request_id` and :attr:`user_ids` are equal.
|
||||
considered equal, if their :attr:`request_id` and :attr:`users` are equal.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now
|
||||
the :attr:`user_ids` is a sequence instead of a single integer.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
The argument :attr:`users` is now considered for the equality comparison instead of
|
||||
:attr:`user_ids`.
|
||||
|
||||
Args:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
user_ids (Sequence[:obj:`int`]): Identifiers of the shared users. These numbers may have
|
||||
more than 32 significant bits and some programming languages may have difficulty/silent
|
||||
defects in interpreting them. But they have at most 52 significant bits, so 64-bit
|
||||
integers or double-precision float types are safe for storing these identifiers. The
|
||||
bot may not have access to the users and could be unable to use these identifiers,
|
||||
unless the users are already known to the bot by some other means.
|
||||
users (Sequence[:class:`telegram.SharedUser`]): Information about users shared with the
|
||||
bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
In future versions, this argument will become keyword only.
|
||||
user_ids (Sequence[:obj:`int`], optional): Identifiers of the shared users. These numbers
|
||||
may have more than 32 significant bits and some programming languages may have
|
||||
difficulty/silent defects in interpreting them. But they have at most 52 significant
|
||||
bits, so 64-bit integers or double-precision float types are safe for storing these
|
||||
identifiers. The bot may not have access to the users and could be unable to use
|
||||
these identifiers, unless the users are already known to the bot by some other means.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
Bot API 7.2 introduced by :paramref:`users`, replacing this argument. Hence, this
|
||||
argument is now optional and will be removed in future versions.
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
user_ids (Tuple[:obj:`int`]): Identifiers of the shared users. These numbers may have
|
||||
more than 32 significant bits and some programming languages may have difficulty/silent
|
||||
defects in interpreting them. But they have at most 52 significant bits, so 64-bit
|
||||
integers or double-precision float types are safe for storing these identifiers. The
|
||||
bot may not have access to the users and could be unable to use these identifiers,
|
||||
unless the users are already known to the bot by some other means.
|
||||
users (Tuple[:class:`telegram.SharedUser`]): Information about users shared with the
|
||||
bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = ("request_id", "user_ids")
|
||||
__slots__ = ("request_id", "users")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_id: int,
|
||||
user_ids: Sequence[int],
|
||||
user_ids: Optional[Sequence[int]] = None,
|
||||
users: Optional[Sequence["SharedUser"]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.request_id: int = request_id
|
||||
self.user_ids: Tuple[int, ...] = tuple(user_ids)
|
||||
|
||||
self._id_attrs = (self.request_id, self.user_ids)
|
||||
if users is None:
|
||||
raise TypeError("`users` is a required argument since Bot API 7.2")
|
||||
|
||||
self.users: Tuple[SharedUser, ...] = parse_sequence_arg(users)
|
||||
|
||||
if user_ids is not None:
|
||||
warn(
|
||||
build_deprecation_warning_message(
|
||||
deprecated_name="user_ids",
|
||||
new_name="users",
|
||||
object_type="parameter",
|
||||
bot_api_version="7.2",
|
||||
),
|
||||
PTBDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
self._id_attrs = (self.request_id, self.users)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["UsersShared"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["users"] = SharedUser.de_list(data.get("users"), bot)
|
||||
|
||||
api_kwargs = {}
|
||||
# This is a deprecated field that TG still returns for backwards compatibility
|
||||
# Let's filter it out to speed up the de-json process
|
||||
if user_ids := data.get("user_ids"):
|
||||
api_kwargs = {"user_ids": user_ids}
|
||||
|
||||
return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
|
||||
|
||||
@property
|
||||
def user_ids(self) -> Tuple[int, ...]:
|
||||
"""
|
||||
Tuple[:obj:`int`]: Identifiers of the shared users. These numbers may have
|
||||
more than 32 significant bits and some programming languages may have difficulty/silent
|
||||
defects in interpreting them. But they have at most 52 significant bits, so 64-bit
|
||||
integers or double-precision float types are safe for storing these identifiers. The
|
||||
bot may not have access to the users and could be unable to use these identifiers,
|
||||
unless the users are already known to the bot by some other means.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
As Bot API 7.2 replaces this attribute with :attr:`users`, this attribute will be
|
||||
removed in future versions.
|
||||
"""
|
||||
warn_about_deprecated_attr_in_property(
|
||||
deprecated_attr_name="user_ids",
|
||||
new_attr_name="users",
|
||||
bot_api_version="7.2",
|
||||
stacklevel=2,
|
||||
)
|
||||
return tuple(user.user_id for user in self.users)
|
||||
|
||||
|
||||
class ChatShared(TelegramObject):
|
||||
"""
|
||||
|
@ -88,6 +169,17 @@ class ChatShared(TelegramObject):
|
|||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
||||
float type are safe for storing this identifier.
|
||||
title (:obj:`str`, optional): Title of the chat, if the title was requested by the bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
username (:obj:`str`, optional): Username of the chat, if the username was requested by
|
||||
the bot and available.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
||||
if the photo was requested by the bot
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
request_id (:obj:`int`): Identifier of the request.
|
||||
|
@ -95,21 +187,127 @@ class ChatShared(TelegramObject):
|
|||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it is smaller than 52 bits, so a signed 64-bit integer or double-precision
|
||||
float type are safe for storing this identifier.
|
||||
title (:obj:`str`): Optional. Title of the chat, if the title was requested by the bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
username (:obj:`str`): Optional. Username of the chat, if the username was requested by
|
||||
the bot and available.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
photo (Tuple[:class:`telegram.PhotoSize`]): Optional. Available sizes of the chat photo,
|
||||
if the photo was requested by the bot
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = ("chat_id", "request_id")
|
||||
__slots__ = ("chat_id", "photo", "request_id", "title", "username")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_id: int,
|
||||
chat_id: int,
|
||||
title: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
photo: Optional[Sequence[PhotoSize]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.request_id: int = request_id
|
||||
self.chat_id: int = chat_id
|
||||
self.title: Optional[str] = title
|
||||
self.username: Optional[str] = username
|
||||
self.photo: Optional[Tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
||||
|
||||
self._id_attrs = (self.request_id, self.chat_id)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["ChatShared"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class SharedUser(TelegramObject):
|
||||
"""
|
||||
This object contains information about a user that was shared with the bot using a
|
||||
:class:`telegram.KeyboardButtonRequestUsers` button.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`user_id` is equal.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
||||
float types are safe for storing these identifiers. The bot may not have access to the
|
||||
user and could be unable to use this identifier, unless the user is already known to
|
||||
the bot by some other means.
|
||||
first_name (:obj:`str`, optional): First name of the user, if the name was requested by the
|
||||
bot.
|
||||
last_name (:obj:`str`, optional): Last name of the user, if the name was requested by the
|
||||
bot.
|
||||
username (:obj:`str`, optional): Username of the user, if the username was requested by the
|
||||
bot.
|
||||
photo (Sequence[:class:`telegram.PhotoSize`], optional): Available sizes of the chat photo,
|
||||
if the photo was requested by the bot.
|
||||
|
||||
Attributes:
|
||||
user_id (:obj:`int`): Identifier of the shared user. This number may have 32 significant
|
||||
bits and some programming languages may have difficulty/silent defects in interpreting
|
||||
it. But it has atmost 52 significant bits, so 64-bit integers or double-precision
|
||||
float types are safe for storing these identifiers. The bot may not have access to the
|
||||
user and could be unable to use this identifier, unless the user is already known to
|
||||
the bot by some other means.
|
||||
first_name (:obj:`str`): Optional. First name of the user, if the name was requested by the
|
||||
bot.
|
||||
last_name (:obj:`str`): Optional. Last name of the user, if the name was requested by the
|
||||
bot.
|
||||
username (:obj:`str`): Optional. Username of the user, if the username was requested by the
|
||||
bot.
|
||||
photo (Tuple[:class:`telegram.PhotoSize`]): Available sizes of the chat photo, if
|
||||
the photo was requested by the bot. This list is empty if the photo was not requsted.
|
||||
"""
|
||||
|
||||
__slots__ = ("first_name", "last_name", "photo", "user_id", "username")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
user_id: int,
|
||||
first_name: Optional[str] = None,
|
||||
last_name: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
photo: Optional[Sequence[PhotoSize]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.user_id: int = user_id
|
||||
self.first_name: Optional[str] = first_name
|
||||
self.last_name: Optional[str] = last_name
|
||||
self.username: Optional[str] = username
|
||||
self.photo: Optional[Tuple[PhotoSize, ...]] = parse_sequence_arg(photo)
|
||||
|
||||
self._id_attrs = (self.user_id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["SharedUser"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from typing import TYPE_CHECKING, Final, List, Optional, Union
|
||||
|
||||
from telegram import constants
|
||||
from telegram._business import BusinessConnection, BusinessMessagesDeleted
|
||||
from telegram._callbackquery import CallbackQuery
|
||||
from telegram._chatboost import ChatBoostRemoved, ChatBoostUpdated
|
||||
from telegram._chatjoinrequest import ChatJoinRequest
|
||||
|
@ -134,6 +135,28 @@ class Update(TelegramObject):
|
|||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
business_connection (:class:`telegram.BusinessConnection`, optional): The bot was connected
|
||||
to or disconnected from a business account, or a user edited an existing connection
|
||||
with the bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
business_message (:class:`telegram.Message`, optional): New non-service message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
edited_business_message (:class:`telegram.Message`, optional): New version of a message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`, optional): Messages
|
||||
were deleted from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
|
||||
Attributes:
|
||||
update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a
|
||||
certain positive number and increase sequentially. This ID becomes especially handy if
|
||||
|
@ -219,6 +242,27 @@ class Update(TelegramObject):
|
|||
with delay up to a few minutes.
|
||||
|
||||
.. versionadded:: 20.8
|
||||
|
||||
business_connection (:class:`telegram.BusinessConnection`): Optional. The bot was connected
|
||||
to or disconnected from a business account, or a user edited an existing connection
|
||||
with the bot.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
business_message (:class:`telegram.Message`): Optional. New non-service message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
edited_business_message (:class:`telegram.Message`): Optional. New version of a message
|
||||
from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
deleted_business_messages (:class:`telegram.BusinessMessagesDeleted`): Optional. Messages
|
||||
were deleted from a connected business account.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
|
@ -226,12 +270,16 @@ class Update(TelegramObject):
|
|||
"_effective_message",
|
||||
"_effective_sender",
|
||||
"_effective_user",
|
||||
"business_connection",
|
||||
"business_message",
|
||||
"callback_query",
|
||||
"channel_post",
|
||||
"chat_boost",
|
||||
"chat_join_request",
|
||||
"chat_member",
|
||||
"chosen_inline_result",
|
||||
"deleted_business_messages",
|
||||
"edited_business_message",
|
||||
"edited_channel_post",
|
||||
"edited_message",
|
||||
"inline_query",
|
||||
|
@ -319,6 +367,22 @@ class Update(TelegramObject):
|
|||
""":const:`telegram.constants.UpdateType.MESSAGE_REACTION_COUNT`
|
||||
|
||||
.. versionadded:: 20.8"""
|
||||
BUSINESS_CONNECTION: Final[str] = constants.UpdateType.BUSINESS_CONNECTION
|
||||
""":const:`telegram.constants.UpdateType.BUSINESS_CONNECTION`
|
||||
|
||||
.. versionadded:: NEXT.VERSION"""
|
||||
BUSINESS_MESSAGE: Final[str] = constants.UpdateType.BUSINESS_MESSAGE
|
||||
""":const:`telegram.constants.UpdateType.BUSINESS_MESSAGE`
|
||||
|
||||
.. versionadded:: NEXT.VERSION"""
|
||||
EDITED_BUSINESS_MESSAGE: Final[str] = constants.UpdateType.EDITED_BUSINESS_MESSAGE
|
||||
""":const:`telegram.constants.UpdateType.EDITED_BUSINESS_MESSAGE`
|
||||
|
||||
.. versionadded:: NEXT.VERSION"""
|
||||
DELETED_BUSINESS_MESSAGES: Final[str] = constants.UpdateType.DELETED_BUSINESS_MESSAGES
|
||||
""":const:`telegram.constants.UpdateType.DELETED_BUSINESS_MESSAGES`
|
||||
|
||||
.. versionadded:: NEXT.VERSION"""
|
||||
ALL_TYPES: Final[List[str]] = list(constants.UpdateType)
|
||||
"""List[:obj:`str`]: A list of all available update types.
|
||||
|
||||
|
@ -345,6 +409,10 @@ class Update(TelegramObject):
|
|||
removed_chat_boost: Optional[ChatBoostRemoved] = None,
|
||||
message_reaction: Optional[MessageReactionUpdated] = None,
|
||||
message_reaction_count: Optional[MessageReactionCountUpdated] = None,
|
||||
business_connection: Optional[BusinessConnection] = None,
|
||||
business_message: Optional[Message] = None,
|
||||
edited_business_message: Optional[Message] = None,
|
||||
deleted_business_messages: Optional[BusinessMessagesDeleted] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -370,6 +438,12 @@ class Update(TelegramObject):
|
|||
self.removed_chat_boost: Optional[ChatBoostRemoved] = removed_chat_boost
|
||||
self.message_reaction: Optional[MessageReactionUpdated] = message_reaction
|
||||
self.message_reaction_count: Optional[MessageReactionCountUpdated] = message_reaction_count
|
||||
self.business_connection: Optional[BusinessConnection] = business_connection
|
||||
self.business_message: Optional[Message] = business_message
|
||||
self.edited_business_message: Optional[Message] = edited_business_message
|
||||
self.deleted_business_messages: Optional[BusinessMessagesDeleted] = (
|
||||
deleted_business_messages
|
||||
)
|
||||
|
||||
self._effective_user: Optional[User] = None
|
||||
self._effective_sender: Optional[Union["User", "Chat"]] = None
|
||||
|
@ -393,9 +467,14 @@ class Update(TelegramObject):
|
|||
* :attr:`chat_boost`
|
||||
* :attr:`removed_chat_boost`
|
||||
* :attr:`message_reaction_count`
|
||||
* :attr:`deleted_business_messages`
|
||||
|
||||
is present.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
This property now also considers :attr:`business_connection`, :attr:`business_message`
|
||||
and :attr:`edited_business_message`.
|
||||
|
||||
Example:
|
||||
* If :attr:`message` is present, this will give
|
||||
:attr:`telegram.Message.from_user`.
|
||||
|
@ -443,6 +522,15 @@ class Update(TelegramObject):
|
|||
elif self.message_reaction:
|
||||
user = self.message_reaction.user
|
||||
|
||||
elif self.business_message:
|
||||
user = self.business_message.from_user
|
||||
|
||||
elif self.edited_business_message:
|
||||
user = self.edited_business_message.from_user
|
||||
|
||||
elif self.business_connection:
|
||||
user = self.business_connection.user
|
||||
|
||||
self._effective_user = user
|
||||
return user
|
||||
|
||||
|
@ -463,6 +551,7 @@ class Update(TelegramObject):
|
|||
* :attr:`chat_boost`
|
||||
* :attr:`removed_chat_boost`
|
||||
* :attr:`message_reaction_count`
|
||||
* :attr:`deleted_business_messages`
|
||||
|
||||
is present.
|
||||
|
||||
|
@ -482,7 +571,12 @@ class Update(TelegramObject):
|
|||
sender: Optional[Union["User", "Chat"]] = None
|
||||
|
||||
if message := (
|
||||
self.message or self.edited_message or self.channel_post or self.edited_channel_post
|
||||
self.message
|
||||
or self.edited_message
|
||||
or self.channel_post
|
||||
or self.edited_channel_post
|
||||
or self.business_message
|
||||
or self.edited_business_message
|
||||
):
|
||||
sender = message.sender_chat
|
||||
|
||||
|
@ -506,8 +600,12 @@ class Update(TelegramObject):
|
|||
If no chat is associated with this update, this gives :obj:`None`.
|
||||
This is the case, if :attr:`inline_query`,
|
||||
:attr:`chosen_inline_result`, :attr:`callback_query` from inline messages,
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` or
|
||||
:attr:`poll_answer` is present.
|
||||
:attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll`,
|
||||
:attr:`poll_answer`, or :attr:`business_connection` is present.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
This property now also considers :attr:`business_message`,
|
||||
:attr:`edited_business_message`, and :attr:`deleted_business_messages`.
|
||||
|
||||
Example:
|
||||
If :attr:`message` is present, this will give :attr:`telegram.Message.chat`.
|
||||
|
@ -554,6 +652,15 @@ class Update(TelegramObject):
|
|||
elif self.message_reaction_count:
|
||||
chat = self.message_reaction_count.chat
|
||||
|
||||
elif self.business_message:
|
||||
chat = self.business_message.chat
|
||||
|
||||
elif self.edited_business_message:
|
||||
chat = self.edited_business_message.chat
|
||||
|
||||
elif self.deleted_business_messages:
|
||||
chat = self.deleted_business_messages.chat
|
||||
|
||||
self._effective_chat = chat
|
||||
return chat
|
||||
|
||||
|
@ -566,6 +673,10 @@ class Update(TelegramObject):
|
|||
:attr:`callback_query` (i.e. :attr:`telegram.CallbackQuery.message`) or :obj:`None`, if
|
||||
none of those are present.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
This property now also considers :attr:`business_message`, and
|
||||
:attr:`edited_business_message`.
|
||||
|
||||
Tip:
|
||||
This property will only ever return objects of type :class:`telegram.Message` or
|
||||
:obj:`None`, never :class:`telegram.MaybeInaccessibleMessage` or
|
||||
|
@ -608,6 +719,12 @@ class Update(TelegramObject):
|
|||
elif self.edited_channel_post:
|
||||
message = self.edited_channel_post
|
||||
|
||||
elif self.business_message:
|
||||
message = self.business_message
|
||||
|
||||
elif self.edited_business_message:
|
||||
message = self.edited_business_message
|
||||
|
||||
self._effective_message = message
|
||||
return message
|
||||
|
||||
|
@ -643,5 +760,13 @@ class Update(TelegramObject):
|
|||
data["message_reaction_count"] = MessageReactionCountUpdated.de_json(
|
||||
data.get("message_reaction_count"), bot
|
||||
)
|
||||
data["business_connection"] = BusinessConnection.de_json(
|
||||
data.get("business_connection"), bot
|
||||
)
|
||||
data["business_message"] = Message.de_json(data.get("business_message"), bot)
|
||||
data["edited_business_message"] = Message.de_json(data.get("edited_business_message"), bot)
|
||||
data["deleted_business_messages"] = BusinessMessagesDeleted.de_json(
|
||||
data.get("deleted_business_messages"), bot
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
|
|
@ -78,11 +78,11 @@ class User(TelegramObject):
|
|||
username (:obj:`str`, optional): User's or bot's username.
|
||||
language_code (:obj:`str`, optional): IETF language tag of the user's language.
|
||||
can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups.
|
||||
Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
Returned only in :meth:`telegram.Bot.get_me`.
|
||||
can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is
|
||||
disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
disabled for the bot. Returned only in :meth:`telegram.Bot.get_me`.
|
||||
supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline
|
||||
queries. Returned only in :attr:`telegram.Bot.get_me` requests.
|
||||
queries. Returned only in :meth:`telegram.Bot.get_me`.
|
||||
|
||||
is_premium (:obj:`bool`, optional): :obj:`True`, if this user is a Telegram Premium user.
|
||||
|
||||
|
@ -91,6 +91,12 @@ class User(TelegramObject):
|
|||
the bot to the attachment menu.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_connect_to_business (:obj:`bool`, optional): :obj:`True`, if the bot can be connected
|
||||
to a Telegram Business account to receive its messages. Returned only in
|
||||
:meth:`telegram.Bot.get_me`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int`): Unique identifier for this user or bot.
|
||||
is_bot (:obj:`bool`): :obj:`True`, if this user is a bot.
|
||||
|
@ -112,6 +118,11 @@ class User(TelegramObject):
|
|||
the bot to the attachment menu.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
can_connect_to_business (:obj:`bool`): Optional. :obj:`True`, if the bot can be connected
|
||||
to a Telegram Business account to receive its messages. Returned only in
|
||||
:meth:`telegram.Bot.get_me`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
.. |user_chat_id_note| replace:: This shortcuts build on the assumption that :attr:`User.id`
|
||||
coincides with the :attr:`Chat.id` of the private chat with the user. This has been the
|
||||
case so far, but Telegram does not guarantee that this stays this way.
|
||||
|
@ -119,6 +130,7 @@ class User(TelegramObject):
|
|||
|
||||
__slots__ = (
|
||||
"added_to_attachment_menu",
|
||||
"can_connect_to_business",
|
||||
"can_join_groups",
|
||||
"can_read_all_group_messages",
|
||||
"first_name",
|
||||
|
@ -144,6 +156,7 @@ class User(TelegramObject):
|
|||
supports_inline_queries: Optional[bool] = None,
|
||||
is_premium: Optional[bool] = None,
|
||||
added_to_attachment_menu: Optional[bool] = None,
|
||||
can_connect_to_business: Optional[bool] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
|
@ -161,6 +174,7 @@ class User(TelegramObject):
|
|||
self.supports_inline_queries: Optional[bool] = supports_inline_queries
|
||||
self.is_premium: Optional[bool] = is_premium
|
||||
self.added_to_attachment_menu: Optional[bool] = added_to_attachment_menu
|
||||
self.can_connect_to_business: Optional[bool] = can_connect_to_business
|
||||
|
||||
self._id_attrs = (self.id,)
|
||||
|
||||
|
@ -393,6 +407,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
|
@ -435,6 +450,7 @@ class User(TelegramObject):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def delete_message(
|
||||
|
@ -513,6 +529,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -556,6 +573,7 @@ class User(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_media_group(
|
||||
|
@ -567,6 +585,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -610,6 +629,7 @@ class User(TelegramObject):
|
|||
caption=caption,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_audio(
|
||||
|
@ -627,6 +647,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -673,12 +694,14 @@ class User(TelegramObject):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_chat_action(
|
||||
self,
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -708,6 +731,7 @@ class User(TelegramObject):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
send_action = send_chat_action
|
||||
|
@ -724,6 +748,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -766,6 +791,7 @@ class User(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_dice(
|
||||
|
@ -776,6 +802,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -813,6 +840,7 @@ class User(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_document(
|
||||
|
@ -828,6 +856,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -872,6 +901,7 @@ class User(TelegramObject):
|
|||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_game(
|
||||
|
@ -882,6 +912,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -919,6 +950,7 @@ class User(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_invoice(
|
||||
|
@ -1031,6 +1063,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1075,6 +1108,7 @@ class User(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_animation(
|
||||
|
@ -1093,6 +1127,7 @@ class User(TelegramObject):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1140,6 +1175,7 @@ class User(TelegramObject):
|
|||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_sticker(
|
||||
|
@ -1151,6 +1187,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1189,6 +1226,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
emoji=emoji,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video(
|
||||
|
@ -1208,6 +1246,7 @@ class User(TelegramObject):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1256,6 +1295,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
has_spoiler=has_spoiler,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_venue(
|
||||
|
@ -1273,6 +1313,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1319,6 +1360,7 @@ class User(TelegramObject):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_video_note(
|
||||
|
@ -1332,6 +1374,7 @@ class User(TelegramObject):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1374,6 +1417,7 @@ class User(TelegramObject):
|
|||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -1388,6 +1432,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1431,6 +1476,7 @@ class User(TelegramObject):
|
|||
filename=filename,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_poll(
|
||||
|
@ -1452,6 +1498,7 @@ class User(TelegramObject):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -1500,6 +1547,7 @@ class User(TelegramObject):
|
|||
explanation_entities=explanation_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_copy(
|
||||
|
|
|
@ -142,7 +142,7 @@ class _AccentColor(NamedTuple):
|
|||
#: :data:`telegram.__bot_api_version_info__`.
|
||||
#:
|
||||
#: .. versionadded:: 20.0
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=1)
|
||||
BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=2)
|
||||
#: :obj:`str`: Telegram Bot API
|
||||
#: version supported by this version of `python-telegram-bot`. Also available as
|
||||
#: :data:`telegram.__bot_api_version__`.
|
||||
|
@ -1710,6 +1710,11 @@ class MessageType(StringEnum):
|
|||
|
||||
.. versionadded:: 21.0
|
||||
"""
|
||||
BUSINESS_CONNECTION_ID = "business_connection_id"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.business_connection_id`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
CHANNEL_CHAT_CREATED = "channel_chat_created"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`."""
|
||||
CHAT_SHARED = "chat_shared"
|
||||
|
@ -1817,6 +1822,11 @@ class MessageType(StringEnum):
|
|||
|
||||
.. versionadded:: 21.0
|
||||
"""
|
||||
SENDER_BUSINESS_BOT = "sender_business_bot"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sender_business_bot`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
STICKER = "sticker"
|
||||
""":obj:`str`: Messages with :attr:`telegram.Message.sticker`."""
|
||||
STORY = "story"
|
||||
|
@ -2312,6 +2322,9 @@ class StickerSetLimit(IntEnum):
|
|||
MAX_ANIMATED_STICKERS = 50
|
||||
""":obj:`int`: Maximum number of stickers allowed in an animated or video sticker set, as given
|
||||
in :meth:`telegram.Bot.add_sticker_to_set`.
|
||||
|
||||
.. deprecated:: NEXT.VERSION
|
||||
The animated sticker limit is now 120, the same as :attr:`MAX_STATIC_STICKERS`.
|
||||
"""
|
||||
MAX_STATIC_STICKERS = 120
|
||||
""":obj:`int`: Maximum number of stickers allowed in a static sticker set, as given in
|
||||
|
@ -2504,6 +2517,26 @@ class UpdateType(StringEnum):
|
|||
|
||||
.. versionadded:: 20.8
|
||||
"""
|
||||
BUSINESS_CONNECTION = "business_connection"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.business_connection`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
BUSINESS_MESSAGE = "business_message"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.business_message`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
EDITED_BUSINESS_MESSAGE = "edited_business_message"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.edited_business_message`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
DELETED_BUSINESS_MESSAGES = "deleted_business_messages"
|
||||
""":obj:`str`: Updates with :attr:`telegram.Update.deleted_business_messages`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
|
||||
class InvoiceLimit(IntEnum):
|
||||
|
|
|
@ -27,6 +27,8 @@ __all__ = (
|
|||
"BasePersistence",
|
||||
"BaseRateLimiter",
|
||||
"BaseUpdateProcessor",
|
||||
"BusinessConnectionHandler",
|
||||
"BusinessMessagesDeletedHandler",
|
||||
"CallbackContext",
|
||||
"CallbackDataCache",
|
||||
"CallbackQueryHandler",
|
||||
|
@ -75,6 +77,8 @@ from ._defaults import Defaults
|
|||
from ._dictpersistence import DictPersistence
|
||||
from ._extbot import ExtBot
|
||||
from ._handlers.basehandler import BaseHandler
|
||||
from ._handlers.businessconnectionhandler import BusinessConnectionHandler
|
||||
from ._handlers.businessmessagesdeletedhandler import BusinessMessagesDeletedHandler
|
||||
from ._handlers.callbackqueryhandler import CallbackQueryHandler
|
||||
from ._handlers.chatboosthandler import ChatBoostHandler
|
||||
from ._handlers.chatjoinrequesthandler import ChatJoinRequestHandler
|
||||
|
|
|
@ -48,6 +48,7 @@ from telegram import (
|
|||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
BusinessConnection,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChatAdministratorRights,
|
||||
|
@ -571,6 +572,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
caption_entities: Optional[Sequence["MessageEntity"]] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -601,6 +603,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
if isinstance(result, Message):
|
||||
self._insert_callback_data(result)
|
||||
|
@ -1182,7 +1185,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
name: str,
|
||||
title: str,
|
||||
stickers: Sequence["InputSticker"],
|
||||
sticker_format: str,
|
||||
sticker_format: Optional[str] = None,
|
||||
sticker_type: Optional[str] = None,
|
||||
needs_repainting: Optional[bool] = None,
|
||||
*,
|
||||
|
@ -2355,6 +2358,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2388,6 +2392,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
@ -2408,6 +2413,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2424,6 +2430,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
audio=audio,
|
||||
duration=duration,
|
||||
performer=performer,
|
||||
business_connection_id=business_connection_id,
|
||||
title=title,
|
||||
caption=caption,
|
||||
disable_notification=disable_notification,
|
||||
|
@ -2449,6 +2456,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
chat_id: Union[str, int],
|
||||
action: str,
|
||||
message_thread_id: Optional[int] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -2459,6 +2467,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
) -> bool:
|
||||
return await super().send_chat_action(
|
||||
chat_id=chat_id,
|
||||
business_connection_id=business_connection_id,
|
||||
action=action,
|
||||
message_thread_id=message_thread_id,
|
||||
read_timeout=read_timeout,
|
||||
|
@ -2480,6 +2489,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2509,6 +2519,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
|
@ -2521,6 +2532,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2534,6 +2546,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
return await super().send_dice(
|
||||
chat_id=chat_id,
|
||||
disable_notification=disable_notification,
|
||||
business_connection_id=business_connection_id,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
emoji=emoji,
|
||||
|
@ -2562,6 +2575,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2585,6 +2599,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
business_connection_id=business_connection_id,
|
||||
message_thread_id=message_thread_id,
|
||||
thumbnail=thumbnail,
|
||||
reply_parameters=reply_parameters,
|
||||
|
@ -2605,6 +2620,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2621,6 +2637,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
business_connection_id=business_connection_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
|
@ -2722,6 +2739,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2752,6 +2770,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
business_connection_id=business_connection_id,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
@ -2766,6 +2785,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2794,6 +2814,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
caption=caption,
|
||||
business_connection_id=business_connection_id,
|
||||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
)
|
||||
|
@ -2810,6 +2831,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
|
@ -2828,6 +2850,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
entities=entities,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
disable_notification=disable_notification,
|
||||
business_connection_id=business_connection_id,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
|
@ -2855,6 +2878,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
has_spoiler: Optional[bool] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2881,6 +2905,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
has_spoiler=has_spoiler,
|
||||
reply_parameters=reply_parameters,
|
||||
filename=filename,
|
||||
business_connection_id=business_connection_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
@ -2908,6 +2933,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2936,6 +2962,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
close_date=close_date,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
explanation_entities=explanation_entities,
|
||||
business_connection_id=business_connection_id,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
|
@ -2956,6 +2983,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
emoji: Optional[str] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -2972,6 +3000,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
disable_notification=disable_notification,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
reply_markup=reply_markup,
|
||||
business_connection_id=business_connection_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
|
@ -3000,6 +3029,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3026,6 +3056,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
google_place_type=google_place_type,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
protect_content=protect_content,
|
||||
business_connection_id=business_connection_id,
|
||||
message_thread_id=message_thread_id,
|
||||
reply_parameters=reply_parameters,
|
||||
venue=venue,
|
||||
|
@ -3054,6 +3085,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
has_spoiler: Optional[bool] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3081,6 +3113,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
caption_entities=caption_entities,
|
||||
protect_content=protect_content,
|
||||
message_thread_id=message_thread_id,
|
||||
business_connection_id=business_connection_id,
|
||||
has_spoiler=has_spoiler,
|
||||
thumbnail=thumbnail,
|
||||
filename=filename,
|
||||
|
@ -3104,6 +3137,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
message_thread_id: Optional[int] = None,
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3134,6 +3168,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def send_voice(
|
||||
|
@ -3149,6 +3184,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
protect_content: ODVInput[bool] = DEFAULT_NONE,
|
||||
message_thread_id: Optional[int] = None,
|
||||
reply_parameters: Optional["ReplyParameters"] = None,
|
||||
business_connection_id: Optional[str] = None,
|
||||
*,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
|
||||
|
@ -3180,6 +3216,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
business_connection_id=business_connection_id,
|
||||
)
|
||||
|
||||
async def set_chat_administrator_custom_title(
|
||||
|
@ -3466,6 +3503,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
self,
|
||||
name: str,
|
||||
user_id: int,
|
||||
format: str, # pylint: disable=redefined-builtin
|
||||
thumbnail: Optional[FileInput] = None,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
|
@ -3479,6 +3517,7 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
name=name,
|
||||
user_id=user_id,
|
||||
thumbnail=thumbnail,
|
||||
format=format,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
|
@ -4002,6 +4041,52 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def get_business_connection(
|
||||
self,
|
||||
business_connection_id: str,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> BusinessConnection:
|
||||
return await super().get_business_connection(
|
||||
business_connection_id=business_connection_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
async def replace_sticker_in_set(
|
||||
self,
|
||||
user_id: int,
|
||||
name: str,
|
||||
old_sticker: str,
|
||||
sticker: "InputSticker",
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
rate_limit_args: Optional[RLARGS] = None,
|
||||
) -> bool:
|
||||
return await super().replace_sticker_in_set(
|
||||
user_id=user_id,
|
||||
name=name,
|
||||
old_sticker=old_sticker,
|
||||
sticker=sticker,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args),
|
||||
)
|
||||
|
||||
# updated camelCase aliases
|
||||
getMe = get_me
|
||||
sendMessage = send_message
|
||||
|
@ -4121,3 +4206,5 @@ class ExtBot(Bot, Generic[RLARGS]):
|
|||
unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages
|
||||
getUserChatBoosts = get_user_chat_boosts
|
||||
setMessageReaction = set_message_reaction
|
||||
getBusinessConnection = get_business_connection
|
||||
replaceStickerInSet = replace_sticker_in_set
|
||||
|
|
95
telegram/ext/_handlers/businessconnectionhandler.py
Normal file
95
telegram/ext/_handlers/businessconnectionhandler.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the BusinessConnectionHandler class."""
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessConnectionHandler(BaseHandler[Update, CCT]):
|
||||
"""Handler class to handle Telegram
|
||||
:attr:`Business Connections <telegram.Update.business_connection>`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
callback (:term:`coroutine function`): The callback function for this handler. Will be
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
user_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only
|
||||
those which are from the specified user ID(s).
|
||||
|
||||
username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only
|
||||
those which are from the specified username(s).
|
||||
|
||||
block (:obj:`bool`, optional): Determines whether the return value of the callback should
|
||||
be awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
block (:obj:`bool`): Determines whether the return value of the callback should be
|
||||
awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_user_ids",
|
||||
"_usernames",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
user_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self._user_ids = parse_chat_id(user_id)
|
||||
self._usernames = parse_username(username)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update) and update.business_connection:
|
||||
if not self._user_ids and not self._usernames:
|
||||
return True
|
||||
if update.business_connection.user.id in self._user_ids:
|
||||
return True
|
||||
return update.business_connection.user.username in self._usernames
|
||||
return False
|
95
telegram/ext/_handlers/businessmessagesdeletedhandler.py
Normal file
95
telegram/ext/_handlers/businessmessagesdeletedhandler.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains the BusinessMessagesDeletedHandler class."""
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from telegram import Update
|
||||
from telegram._utils.defaultvalue import DEFAULT_TRUE
|
||||
from telegram._utils.types import SCT, DVType
|
||||
from telegram.ext._handlers.basehandler import BaseHandler
|
||||
from telegram.ext._utils._update_parsing import parse_chat_id, parse_username
|
||||
from telegram.ext._utils.types import CCT, HandlerCallback
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class BusinessMessagesDeletedHandler(BaseHandler[Update, CCT]):
|
||||
"""Handler class to handle
|
||||
:attr:`deleted Telegram Business messages <telegram.Update.deleted_business_messages>`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
|
||||
Args:
|
||||
callback (:term:`coroutine function`): The callback function for this handler. Will be
|
||||
called when :meth:`check_update` has determined that an update should be processed by
|
||||
this handler. Callback signature::
|
||||
|
||||
async def callback(update: Update, context: CallbackContext)
|
||||
chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters requests to allow only
|
||||
those which are from the specified chat ID(s).
|
||||
|
||||
username (:obj:`str` | Collection[:obj:`str`], optional): Filters requests to allow only
|
||||
those which are from the specified username(s).
|
||||
|
||||
block (:obj:`bool`, optional): Determines whether the return value of the callback should
|
||||
be awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
|
||||
|
||||
.. seealso:: :wiki:`Concurrency`
|
||||
Attributes:
|
||||
callback (:term:`coroutine function`): The callback function for this handler.
|
||||
block (:obj:`bool`): Determines whether the return value of the callback should be
|
||||
awaited before processing the next handler in
|
||||
:meth:`telegram.ext.Application.process_update`.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_chat_ids",
|
||||
"_usernames",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: HandlerCallback[Update, CCT, RT],
|
||||
chat_id: Optional[SCT[int]] = None,
|
||||
username: Optional[SCT[str]] = None,
|
||||
block: DVType[bool] = DEFAULT_TRUE,
|
||||
):
|
||||
super().__init__(callback, block=block)
|
||||
|
||||
self._chat_ids = parse_chat_id(chat_id)
|
||||
self._usernames = parse_username(username)
|
||||
|
||||
def check_update(self, update: object) -> bool:
|
||||
"""Determines whether an update should be passed to this handler's :attr:`callback`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`
|
||||
|
||||
"""
|
||||
if isinstance(update, Update) and update.deleted_business_messages:
|
||||
if not self._chat_ids and not self._usernames:
|
||||
return True
|
||||
if update.deleted_business_messages.chat.id in self._chat_ids:
|
||||
return True
|
||||
return update.deleted_business_messages.chat.username in self._usernames
|
||||
return False
|
|
@ -54,6 +54,7 @@ __all__ = (
|
|||
"HAS_PROTECTED_CONTENT",
|
||||
"INVOICE",
|
||||
"IS_AUTOMATIC_FORWARD",
|
||||
"IS_FROM_OFFLINE",
|
||||
"IS_TOPIC_MESSAGE",
|
||||
"LOCATION",
|
||||
"PASSPORT_DATA",
|
||||
|
@ -272,20 +273,28 @@ class BaseFilter:
|
|||
def check_update(self, update: Update) -> Optional[Union[bool, FilterDataDict]]:
|
||||
"""Checks if the specified update should be handled by this filter.
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
This filter now also returns :obj:`True` if the update contains
|
||||
:attr:`~telegram.Update.business_message`
|
||||
or :attr:`~telegram.Update.edited_business_message`.
|
||||
|
||||
Args:
|
||||
update (:class:`telegram.Update`): The update to check.
|
||||
|
||||
Returns:
|
||||
:obj:`bool`: :obj:`True` if the update contains one of
|
||||
:attr:`~telegram.Update.channel_post`, :attr:`~telegram.Update.message`,
|
||||
:attr:`~telegram.Update.edited_channel_post` or
|
||||
:attr:`~telegram.Update.edited_message`, :obj:`False` otherwise.
|
||||
:attr:`~telegram.Update.edited_channel_post`,
|
||||
:attr:`~telegram.Update.edited_message`, :attr:`telegram.Update.business_message`,
|
||||
:attr:`telegram.Update.edited_business_message`, or :obj:`False` otherwise.
|
||||
"""
|
||||
return bool( # Only message updates should be handled.
|
||||
update.channel_post
|
||||
update.channel_post # pylint: disable=too-many-boolean-expressions
|
||||
or update.message
|
||||
or update.edited_channel_post
|
||||
or update.edited_message
|
||||
or update.business_message
|
||||
or update.edited_business_message
|
||||
)
|
||||
|
||||
|
||||
|
@ -1554,6 +1563,20 @@ IS_TOPIC_MESSAGE = _IsTopicMessage(name="filters.IS_TOPIC_MESSAGE")
|
|||
"""
|
||||
|
||||
|
||||
class _IsFromOffline(MessageFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.is_from_offline)
|
||||
|
||||
|
||||
IS_FROM_OFFLINE = _IsFromOffline(name="filters.IS_FROM_OFFLINE")
|
||||
"""Messages that contain :attr:`telegram.Message.is_from_offline`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
|
||||
class Language(MessageFilter):
|
||||
"""Filters messages to only allow those which are from users with a certain language code.
|
||||
|
||||
|
@ -2486,13 +2509,21 @@ class UpdateType:
|
|||
__slots__ = ()
|
||||
|
||||
def filter(self, update: Update) -> bool:
|
||||
return update.edited_message is not None or update.edited_channel_post is not None
|
||||
return (
|
||||
update.edited_message is not None
|
||||
or update.edited_channel_post is not None
|
||||
or update.edited_business_message is not None
|
||||
)
|
||||
|
||||
EDITED = _Edited(name="filters.UpdateType.EDITED")
|
||||
"""Updates with either :attr:`telegram.Update.edited_message` or
|
||||
:attr:`telegram.Update.edited_channel_post`.
|
||||
"""Updates with :attr:`telegram.Update.edited_message`,
|
||||
:attr:`telegram.Update.edited_channel_post`, or
|
||||
:attr:`telegram.Update.edited_business_message`.
|
||||
|
||||
.. versionadded:: 20.0
|
||||
|
||||
.. versionchanged:: NEXT.VERSION
|
||||
Added :attr:`telegram.Update.edited_business_message` to the filter.
|
||||
"""
|
||||
|
||||
class _EditedChannelPost(UpdateFilter):
|
||||
|
@ -2530,7 +2561,48 @@ class UpdateType:
|
|||
|
||||
MESSAGES = _Messages(name="filters.UpdateType.MESSAGES")
|
||||
"""Updates with either :attr:`telegram.Update.message` or
|
||||
:attr:`telegram.Update.edited_message`."""
|
||||
:attr:`telegram.Update.edited_message`.
|
||||
"""
|
||||
|
||||
class _BusinessMessage(UpdateFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, update: Update) -> bool:
|
||||
return update.business_message is not None
|
||||
|
||||
BUSINESS_MESSAGE = _BusinessMessage(name="filters.UpdateType.BUSINESS_MESSAGE")
|
||||
"""Updates with :attr:`telegram.Update.business_message`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION"""
|
||||
|
||||
class _EditedBusinessMessage(UpdateFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, update: Update) -> bool:
|
||||
return update.edited_business_message is not None
|
||||
|
||||
EDITED_BUSINESS_MESSAGE = _EditedBusinessMessage(
|
||||
name="filters.UpdateType.EDITED_BUSINESS_MESSAGE"
|
||||
)
|
||||
"""Updates with :attr:`telegram.Update.edited_business_message`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
class _BusinessMessages(UpdateFilter):
|
||||
__slots__ = ()
|
||||
|
||||
def filter(self, update: Update) -> bool:
|
||||
return (
|
||||
update.business_message is not None or update.edited_business_message is not None
|
||||
)
|
||||
|
||||
BUSINESS_MESSAGES = _BusinessMessages(name="filters.UpdateType.BUSINESS_MESSAGES")
|
||||
"""Updates with either :attr:`telegram.Update.business_message` or
|
||||
:attr:`telegram.Update.edited_business_message`.
|
||||
|
||||
.. versionadded:: NEXT.VERSION
|
||||
"""
|
||||
|
||||
|
||||
class User(_ChatUserBaseFilter):
|
||||
|
@ -2675,6 +2747,8 @@ class ViaBot(_ChatUserBaseFilter):
|
|||
Examples:
|
||||
``MessageHandler(filters.ViaBot(1234), callback_method)``
|
||||
|
||||
.. seealso:: :attr:`~telegram.ext.filters.VIA_BOT`
|
||||
|
||||
Args:
|
||||
bot_id(:obj:`int` | Collection[:obj:`int`], optional): Which bot ID(s) to
|
||||
allow through.
|
||||
|
@ -2756,7 +2830,9 @@ class _ViaBot(MessageFilter):
|
|||
|
||||
|
||||
VIA_BOT = _ViaBot(name="filters.VIA_BOT")
|
||||
"""This filter filters for message that were sent via *any* bot."""
|
||||
"""This filter filters for message that were sent via *any* bot.
|
||||
|
||||
.. seealso:: :class:`~telegram.ext.filters.ViaBot`"""
|
||||
|
||||
|
||||
class _Video(MessageFilter):
|
||||
|
|
|
@ -33,6 +33,7 @@ def input_sticker():
|
|||
emoji_list=TestInputStickerBase.emoji_list,
|
||||
mask_position=TestInputStickerBase.mask_position,
|
||||
keywords=TestInputStickerBase.keywords,
|
||||
format=TestInputStickerBase.format,
|
||||
)
|
||||
|
||||
|
||||
|
@ -41,9 +42,10 @@ class TestInputStickerBase:
|
|||
emoji_list = ("👍", "👎")
|
||||
mask_position = MaskPosition("forehead", 0.5, 0.5, 0.5)
|
||||
keywords = ("thumbsup", "thumbsdown")
|
||||
format = "static"
|
||||
|
||||
|
||||
class TestInputStickerNoRequest(TestInputStickerBase):
|
||||
class TestInputStickerWithoutRequest(TestInputStickerBase):
|
||||
def test_slot_behaviour(self, input_sticker):
|
||||
inst = input_sticker
|
||||
for attr in inst.__slots__:
|
||||
|
@ -56,11 +58,12 @@ class TestInputStickerNoRequest(TestInputStickerBase):
|
|||
assert input_sticker.emoji_list == self.emoji_list
|
||||
assert input_sticker.mask_position == self.mask_position
|
||||
assert input_sticker.keywords == self.keywords
|
||||
assert input_sticker.format == self.format
|
||||
|
||||
def test_attributes_tuple(self, input_sticker):
|
||||
assert isinstance(input_sticker.keywords, tuple)
|
||||
assert isinstance(input_sticker.emoji_list, tuple)
|
||||
a = InputSticker("sticker", ["emoji"])
|
||||
a = InputSticker("sticker", ["emoji"], "static")
|
||||
assert isinstance(a.emoji_list, tuple)
|
||||
assert a.keywords == ()
|
||||
|
||||
|
@ -72,9 +75,10 @@ class TestInputStickerNoRequest(TestInputStickerBase):
|
|||
assert input_sticker_dict["emoji_list"] == list(input_sticker.emoji_list)
|
||||
assert input_sticker_dict["mask_position"] == input_sticker.mask_position.to_dict()
|
||||
assert input_sticker_dict["keywords"] == list(input_sticker.keywords)
|
||||
assert input_sticker_dict["format"] == input_sticker.format
|
||||
|
||||
def test_with_sticker_input_types(self, video_sticker_file): # noqa: F811
|
||||
sticker = InputSticker(sticker=video_sticker_file, emoji_list=["👍"])
|
||||
sticker = InputSticker(sticker=video_sticker_file, emoji_list=["👍"], format="video")
|
||||
assert isinstance(sticker.sticker, InputFile)
|
||||
sticker = InputSticker(data_file("telegram_video_sticker.webm"), ["👍"])
|
||||
sticker = InputSticker(data_file("telegram_video_sticker.webm"), ["👍"], "video")
|
||||
assert sticker.sticker == data_file("telegram_video_sticker.webm").as_uri()
|
||||
|
|
|
@ -39,6 +39,7 @@ from telegram import (
|
|||
from telegram.constants import ParseMode, StickerFormat, StickerType
|
||||
from telegram.error import BadRequest, TelegramError
|
||||
from telegram.request import RequestData
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.bot_method_checks import (
|
||||
check_defaults_handling,
|
||||
check_shortcut_call,
|
||||
|
@ -471,7 +472,6 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
assert protected.has_protected_content
|
||||
assert not unprotected.has_protected_content
|
||||
|
||||
@pytest.mark.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
async def test_premium_animation(self, bot):
|
||||
# testing animation sucks a bit since we can't create a premium sticker. What we can do is
|
||||
# get a sticker set which includes a premium sticker and check that specific one.
|
||||
|
@ -489,7 +489,6 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
}
|
||||
assert premium_sticker.premium_animation.to_dict() == premium_sticker_dict
|
||||
|
||||
@pytest.mark.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
async def test_custom_emoji(self, bot):
|
||||
# testing custom emoji stickers is as much of an annoyance as the premium animation, see
|
||||
# in test_premium_animation
|
||||
|
@ -528,7 +527,6 @@ class TestStickerWithRequest(TestStickerBase):
|
|||
|
||||
@pytest.fixture()
|
||||
async def sticker_set(bot):
|
||||
pytest.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
ss = await bot.get_sticker_set(f"test_by_{bot.username}")
|
||||
if len(ss.stickers) > 100:
|
||||
try:
|
||||
|
@ -543,7 +541,6 @@ async def sticker_set(bot):
|
|||
|
||||
@pytest.fixture()
|
||||
async def animated_sticker_set(bot):
|
||||
pytest.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
ss = await bot.get_sticker_set(f"animated_test_by_{bot.username}")
|
||||
if len(ss.stickers) > 100:
|
||||
try:
|
||||
|
@ -578,8 +575,6 @@ def sticker_set_thumb_file():
|
|||
|
||||
class TestStickerSetBase:
|
||||
title = "Test stickers"
|
||||
is_animated = True
|
||||
is_video = True
|
||||
stickers = [Sticker("file_id", "file_un_id", 512, 512, True, True, Sticker.REGULAR)]
|
||||
name = "NOTAREALNAME"
|
||||
sticker_type = Sticker.REGULAR
|
||||
|
@ -588,7 +583,7 @@ class TestStickerSetBase:
|
|||
|
||||
class TestStickerSetWithoutRequest(TestStickerSetBase):
|
||||
def test_slot_behaviour(self):
|
||||
inst = StickerSet("this", "is", True, self.stickers, True, "not")
|
||||
inst = StickerSet("this", "is", self.stickers, "not")
|
||||
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"
|
||||
|
@ -598,8 +593,6 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
json_dict = {
|
||||
"name": name,
|
||||
"title": self.title,
|
||||
"is_animated": self.is_animated,
|
||||
"is_video": self.is_video,
|
||||
"stickers": [x.to_dict() for x in self.stickers],
|
||||
"thumbnail": sticker.thumbnail.to_dict(),
|
||||
"sticker_type": self.sticker_type,
|
||||
|
@ -609,8 +602,6 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
|
||||
assert sticker_set.name == name
|
||||
assert sticker_set.title == self.title
|
||||
assert sticker_set.is_animated == self.is_animated
|
||||
assert sticker_set.is_video == self.is_video
|
||||
assert sticker_set.stickers == tuple(self.stickers)
|
||||
assert sticker_set.thumbnail == sticker.thumbnail
|
||||
assert sticker_set.sticker_type == self.sticker_type
|
||||
|
@ -622,8 +613,6 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
assert isinstance(sticker_set_dict, dict)
|
||||
assert sticker_set_dict["name"] == sticker_set.name
|
||||
assert sticker_set_dict["title"] == sticker_set.title
|
||||
assert sticker_set_dict["is_animated"] == sticker_set.is_animated
|
||||
assert sticker_set_dict["is_video"] == sticker_set.is_video
|
||||
assert sticker_set_dict["stickers"][0] == sticker_set.stickers[0].to_dict()
|
||||
assert sticker_set_dict["thumbnail"] == sticker_set.thumbnail.to_dict()
|
||||
assert sticker_set_dict["sticker_type"] == sticker_set.sticker_type
|
||||
|
@ -632,26 +621,20 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
a = StickerSet(
|
||||
self.name,
|
||||
self.title,
|
||||
self.is_animated,
|
||||
self.stickers,
|
||||
self.is_video,
|
||||
self.sticker_type,
|
||||
)
|
||||
b = StickerSet(
|
||||
self.name,
|
||||
self.title,
|
||||
self.is_animated,
|
||||
self.stickers,
|
||||
self.is_video,
|
||||
self.sticker_type,
|
||||
)
|
||||
c = StickerSet(self.name, "title", False, [], True, Sticker.CUSTOM_EMOJI)
|
||||
c = StickerSet(self.name, "title", [], Sticker.CUSTOM_EMOJI)
|
||||
d = StickerSet(
|
||||
"blah",
|
||||
self.title,
|
||||
self.is_animated,
|
||||
self.stickers,
|
||||
self.is_video,
|
||||
self.sticker_type,
|
||||
)
|
||||
e = Audio(self.name, "", 0, None, None)
|
||||
|
@ -689,7 +672,9 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.upload_sticker_file(chat_id, sticker=file, sticker_format="static")
|
||||
await bot.upload_sticker_file(
|
||||
chat_id, sticker=file, sticker_format=StickerFormat.STATIC
|
||||
)
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
@ -719,8 +704,7 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
chat_id,
|
||||
"name",
|
||||
"title",
|
||||
stickers=[InputSticker(file, emoji_list=["emoji"])],
|
||||
sticker_format=StickerFormat.STATIC,
|
||||
stickers=[InputSticker(file, emoji_list=["emoji"], format=StickerFormat.STATIC)],
|
||||
)
|
||||
assert test_flag
|
||||
|
||||
|
@ -759,7 +743,9 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.add_sticker_to_set(
|
||||
chat_id, "name", sticker=InputSticker(sticker=file, emoji_list=["this"])
|
||||
chat_id,
|
||||
"name",
|
||||
sticker=InputSticker(sticker=file, emoji_list=["this"], format="static"),
|
||||
)
|
||||
assert test_flag
|
||||
|
||||
|
@ -782,7 +768,7 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
test_flag = isinstance(data.get("thumbnail"), InputFile)
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
await bot.set_sticker_set_thumbnail("name", chat_id, thumbnail=file)
|
||||
await bot.set_sticker_set_thumbnail("name", chat_id, thumbnail=file, format="static")
|
||||
assert test_flag
|
||||
finally:
|
||||
bot._local_mode = False
|
||||
|
@ -798,9 +784,29 @@ class TestStickerSetWithoutRequest(TestStickerSetBase):
|
|||
monkeypatch.setattr(sticker.get_bot(), "get_file", make_assertion)
|
||||
assert await sticker.get_file()
|
||||
|
||||
async def test_create_new_sticker_set_format_arg_depr(
|
||||
self, bot, chat_id, sticker_file, monkeypatch
|
||||
):
|
||||
async def make_assertion(*_, **kwargs):
|
||||
pass
|
||||
|
||||
monkeypatch.setattr(bot, "_post", make_assertion)
|
||||
with pytest.warns(PTBDeprecationWarning, match="`sticker_format` is deprecated"):
|
||||
await bot.create_new_sticker_set(
|
||||
chat_id,
|
||||
"name",
|
||||
"title",
|
||||
stickers=sticker_file,
|
||||
sticker_format="static",
|
||||
)
|
||||
|
||||
async def test_deprecation_creation_args(self, recwarn):
|
||||
with pytest.warns(PTBDeprecationWarning, match="The parameters `is_animated` and ") as w:
|
||||
StickerSet("name", "title", [], "static", is_animated=True)
|
||||
assert w[0].filename == __file__, "wrong stacklevel!"
|
||||
|
||||
|
||||
@pytest.mark.xdist_group("stickerset")
|
||||
@pytest.mark.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
class TestStickerSetWithRequest:
|
||||
async def test_create_sticker_set(
|
||||
self, bot, chat_id, sticker_file, animated_sticker_file, video_sticker_file
|
||||
|
@ -822,8 +828,11 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
name=sticker_set,
|
||||
title="Sticker Test",
|
||||
stickers=[InputSticker(sticker_file, emoji_list=["😄"])],
|
||||
sticker_format=StickerFormat.STATIC,
|
||||
stickers=[
|
||||
InputSticker(
|
||||
sticker_file, emoji_list=["😄"], format=StickerFormat.STATIC
|
||||
)
|
||||
],
|
||||
)
|
||||
assert s
|
||||
elif sticker_set.startswith("animated"):
|
||||
|
@ -831,8 +840,13 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
name=sticker_set,
|
||||
title="Animated Test",
|
||||
stickers=[InputSticker(animated_sticker_file, emoji_list=["😄"])],
|
||||
sticker_format=StickerFormat.ANIMATED,
|
||||
stickers=[
|
||||
InputSticker(
|
||||
animated_sticker_file,
|
||||
emoji_list=["😄"],
|
||||
format=StickerFormat.ANIMATED,
|
||||
)
|
||||
],
|
||||
)
|
||||
assert a
|
||||
elif sticker_set.startswith("video"):
|
||||
|
@ -840,8 +854,11 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
name=sticker_set,
|
||||
title="Video Test",
|
||||
stickers=[InputSticker(video_sticker_file, emoji_list=["😄"])],
|
||||
sticker_format=StickerFormat.VIDEO,
|
||||
stickers=[
|
||||
InputSticker(
|
||||
video_sticker_file, emoji_list=["😄"], format=StickerFormat.VIDEO
|
||||
)
|
||||
],
|
||||
)
|
||||
assert v
|
||||
|
||||
|
@ -855,8 +872,7 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
name=name,
|
||||
title="Stickerset delete Test",
|
||||
stickers=[InputSticker(sticker_file, emoji_list=["😄"])],
|
||||
sticker_format=StickerFormat.STATIC,
|
||||
stickers=[InputSticker(sticker_file, emoji_list=["😄"], format="static")],
|
||||
)
|
||||
# this prevents a second issue when calling delete too soon after creating the set leads
|
||||
# to it failing as well
|
||||
|
@ -875,8 +891,11 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
name=ss_name,
|
||||
title="Custom Emoji Sticker Set",
|
||||
stickers=[InputSticker(animated_sticker_file, emoji_list=["😄"])],
|
||||
sticker_format=StickerFormat.ANIMATED,
|
||||
stickers=[
|
||||
InputSticker(
|
||||
animated_sticker_file, emoji_list=["😄"], format=StickerFormat.ANIMATED
|
||||
)
|
||||
],
|
||||
sticker_type=Sticker.CUSTOM_EMOJI,
|
||||
)
|
||||
assert await bot.set_custom_emoji_sticker_set_thumbnail(ss_name, "")
|
||||
|
@ -895,7 +914,9 @@ class TestStickerSetWithRequest:
|
|||
bot.add_sticker_to_set(
|
||||
chat_id,
|
||||
f"test_by_{bot.username}",
|
||||
sticker=InputSticker(sticker=file.file_id, emoji_list=["😄"]),
|
||||
sticker=InputSticker(
|
||||
sticker=file.file_id, emoji_list=["😄"], format=StickerFormat.STATIC
|
||||
),
|
||||
),
|
||||
bot.add_sticker_to_set( # Also test with file input and mask
|
||||
chat_id,
|
||||
|
@ -904,6 +925,7 @@ class TestStickerSetWithRequest:
|
|||
sticker=sticker_file,
|
||||
emoji_list=["😄"],
|
||||
mask_position=MaskPosition(MaskPosition.EYES, -1, 1, 2),
|
||||
format=StickerFormat.STATIC,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -915,7 +937,9 @@ class TestStickerSetWithRequest:
|
|||
chat_id,
|
||||
f"animated_test_by_{bot.username}",
|
||||
sticker=InputSticker(
|
||||
sticker=data_file("telegram_animated_sticker.tgs").open("rb"), emoji_list=["😄"]
|
||||
sticker=data_file("telegram_animated_sticker.tgs").open("rb"),
|
||||
emoji_list=["😄"],
|
||||
format=StickerFormat.ANIMATED,
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -925,7 +949,7 @@ class TestStickerSetWithRequest:
|
|||
assert await bot.add_sticker_to_set(
|
||||
chat_id,
|
||||
f"video_test_by_{bot.username}",
|
||||
sticker=InputSticker(sticker=f, emoji_list=["🤔"]),
|
||||
sticker=InputSticker(sticker=f, emoji_list=["🤔"], format=StickerFormat.VIDEO),
|
||||
)
|
||||
|
||||
# Test set_sticker_position_in_set
|
||||
|
@ -948,7 +972,7 @@ class TestStickerSetWithRequest:
|
|||
async def test_bot_methods_3_png(self, bot, chat_id, sticker_set_thumb_file):
|
||||
await asyncio.sleep(1)
|
||||
assert await bot.set_sticker_set_thumbnail(
|
||||
f"test_by_{bot.username}", chat_id, sticker_set_thumb_file
|
||||
f"test_by_{bot.username}", chat_id, format="static", thumbnail=sticker_set_thumb_file
|
||||
)
|
||||
|
||||
async def test_bot_methods_3_tgs(
|
||||
|
@ -958,8 +982,13 @@ class TestStickerSetWithRequest:
|
|||
animated_test = f"animated_test_by_{bot.username}"
|
||||
file_id = animated_sticker_set.stickers[-1].file_id
|
||||
tasks = asyncio.gather(
|
||||
bot.set_sticker_set_thumbnail(animated_test, chat_id, animated_sticker_file),
|
||||
bot.set_sticker_set_thumbnail(animated_test, chat_id, file_id),
|
||||
bot.set_sticker_set_thumbnail(
|
||||
animated_test,
|
||||
chat_id,
|
||||
"animated",
|
||||
thumbnail=animated_sticker_file,
|
||||
),
|
||||
bot.set_sticker_set_thumbnail(animated_test, chat_id, "animated", thumbnail=file_id),
|
||||
)
|
||||
assert all(await tasks)
|
||||
|
||||
|
@ -1042,6 +1071,19 @@ class TestStickerSetWithRequest:
|
|||
file_id = video_sticker_set.stickers[-1].file_id
|
||||
assert await bot.set_sticker_keywords(file_id, ["test", "test2"])
|
||||
|
||||
async def test_bot_methods_8_png(self, bot, sticker_set, sticker_file):
|
||||
file_id = sticker_set.stickers[-1].file_id
|
||||
assert await bot.replace_sticker_in_set(
|
||||
bot.id,
|
||||
f"test_by_{bot.username}",
|
||||
file_id,
|
||||
sticker=InputSticker(
|
||||
sticker=sticker_file,
|
||||
emoji_list=["😄"],
|
||||
format=StickerFormat.STATIC,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def mask_position():
|
||||
|
@ -1112,7 +1154,6 @@ class TestMaskPositionWithoutRequest(TestMaskPositionBase):
|
|||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="API 7.2 incompatibility, see #4181")
|
||||
class TestMaskPositionWithRequest(TestMaskPositionBase):
|
||||
async def test_create_new_mask_sticker_set(self, bot, chat_id, sticker_file, mask_position):
|
||||
name = f"masks_by_{bot.username}"
|
||||
|
@ -1132,9 +1173,9 @@ class TestMaskPositionWithRequest(TestMaskPositionBase):
|
|||
emoji_list=["😔"],
|
||||
mask_position=mask_position,
|
||||
keywords=["sad"],
|
||||
format=StickerFormat.STATIC,
|
||||
)
|
||||
],
|
||||
sticker_format=StickerFormat.STATIC,
|
||||
sticker_type=Sticker.MASK,
|
||||
)
|
||||
assert sticker_set
|
||||
|
|
173
tests/ext/test_businessconnectionhandler.py
Normal file
173
tests/ext/test_businessconnectionhandler.py
Normal file
|
@ -0,0 +1,173 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Bot,
|
||||
BusinessConnection,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChosenInlineResult,
|
||||
Message,
|
||||
PreCheckoutQuery,
|
||||
ShippingQuery,
|
||||
Update,
|
||||
User,
|
||||
)
|
||||
from telegram._utils.datetime import UTC
|
||||
from telegram.ext import BusinessConnectionHandler, CallbackContext, JobQueue
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
message = Message(1, None, Chat(1, ""), from_user=User(1, "", False), text="Text")
|
||||
|
||||
params = [
|
||||
{"message": message},
|
||||
{"edited_message": message},
|
||||
{"callback_query": CallbackQuery(1, User(1, "", False), "chat", message=message)},
|
||||
{"channel_post": message},
|
||||
{"edited_channel_post": message},
|
||||
{"chosen_inline_result": ChosenInlineResult("id", User(1, "", False), "")},
|
||||
{"shipping_query": ShippingQuery("id", User(1, "", False), "", None)},
|
||||
{"pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "")},
|
||||
{"callback_query": CallbackQuery(1, User(1, "", False), "chat")},
|
||||
]
|
||||
|
||||
ids = (
|
||||
"message",
|
||||
"edited_message",
|
||||
"callback_query",
|
||||
"channel_post",
|
||||
"edited_channel_post",
|
||||
"chosen_inline_result",
|
||||
"shipping_query",
|
||||
"pre_checkout_query",
|
||||
"callback_query_without_message",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", params=params, ids=ids)
|
||||
def false_update(request):
|
||||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time():
|
||||
return datetime.datetime.now(tz=UTC)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def business_connection(bot):
|
||||
bc = BusinessConnection(
|
||||
id="1",
|
||||
user_chat_id=1,
|
||||
user=User(1, "name", username="user_a", is_bot=False),
|
||||
date=datetime.datetime.now(tz=UTC),
|
||||
can_reply=True,
|
||||
is_enabled=True,
|
||||
)
|
||||
bc.set_bot(bot)
|
||||
return bc
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def business_connection_update(bot, business_connection):
|
||||
return Update(0, business_connection=business_connection)
|
||||
|
||||
|
||||
class TestBusinessConnectionHandler:
|
||||
test_flag = False
|
||||
|
||||
def test_slot_behaviour(self):
|
||||
action = BusinessConnectionHandler(self.callback)
|
||||
for attr in action.__slots__:
|
||||
assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
self.test_flag = (
|
||||
isinstance(context, CallbackContext)
|
||||
and isinstance(context.bot, Bot)
|
||||
and isinstance(update, Update)
|
||||
and isinstance(context.update_queue, asyncio.Queue)
|
||||
and isinstance(context.job_queue, JobQueue)
|
||||
and isinstance(context.user_data, dict)
|
||||
and isinstance(context.bot_data, dict)
|
||||
and isinstance(
|
||||
update.business_connection,
|
||||
BusinessConnection,
|
||||
)
|
||||
)
|
||||
|
||||
def test_with_user_id(self, business_connection_update):
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=1)
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=[1])
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=2, username="@user_a")
|
||||
assert handler.check_update(business_connection_update)
|
||||
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=2)
|
||||
assert not handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=[2])
|
||||
assert not handler.check_update(business_connection_update)
|
||||
|
||||
def test_with_username(self, business_connection_update):
|
||||
handler = BusinessConnectionHandler(self.callback, username="user_a")
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username="@user_a")
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username=["user_a"])
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username=["@user_a"])
|
||||
assert handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, user_id=1, username="@user_b")
|
||||
assert handler.check_update(business_connection_update)
|
||||
|
||||
handler = BusinessConnectionHandler(self.callback, username="user_b")
|
||||
assert not handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username="@user_b")
|
||||
assert not handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username=["user_b"])
|
||||
assert not handler.check_update(business_connection_update)
|
||||
handler = BusinessConnectionHandler(self.callback, username=["@user_b"])
|
||||
assert not handler.check_update(business_connection_update)
|
||||
|
||||
business_connection_update.business_connection.user._unfreeze()
|
||||
business_connection_update.business_connection.user.username = None
|
||||
assert not handler.check_update(business_connection_update)
|
||||
|
||||
def test_other_update_types(self, false_update):
|
||||
handler = BusinessConnectionHandler(self.callback)
|
||||
assert not handler.check_update(false_update)
|
||||
assert not handler.check_update(True)
|
||||
|
||||
async def test_context(self, app, business_connection_update):
|
||||
handler = BusinessConnectionHandler(callback=self.callback)
|
||||
app.add_handler(handler)
|
||||
|
||||
async with app:
|
||||
await app.process_update(business_connection_update)
|
||||
assert self.test_flag
|
170
tests/ext/test_businessmessagesdeletedhandler.py
Normal file
170
tests/ext/test_businessmessagesdeletedhandler.py
Normal file
|
@ -0,0 +1,170 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Bot,
|
||||
BusinessMessagesDeleted,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChosenInlineResult,
|
||||
Message,
|
||||
PreCheckoutQuery,
|
||||
ShippingQuery,
|
||||
Update,
|
||||
User,
|
||||
)
|
||||
from telegram._utils.datetime import UTC
|
||||
from telegram.ext import BusinessMessagesDeletedHandler, CallbackContext, JobQueue
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
message = Message(1, None, Chat(1, ""), from_user=User(1, "", False), text="Text")
|
||||
|
||||
params = [
|
||||
{"message": message},
|
||||
{"edited_message": message},
|
||||
{"callback_query": CallbackQuery(1, User(1, "", False), "chat", message=message)},
|
||||
{"channel_post": message},
|
||||
{"edited_channel_post": message},
|
||||
{"chosen_inline_result": ChosenInlineResult("id", User(1, "", False), "")},
|
||||
{"shipping_query": ShippingQuery("id", User(1, "", False), "", None)},
|
||||
{"pre_checkout_query": PreCheckoutQuery("id", User(1, "", False), "", 0, "")},
|
||||
{"callback_query": CallbackQuery(1, User(1, "", False), "chat")},
|
||||
]
|
||||
|
||||
ids = (
|
||||
"message",
|
||||
"edited_message",
|
||||
"callback_query",
|
||||
"channel_post",
|
||||
"edited_channel_post",
|
||||
"chosen_inline_result",
|
||||
"shipping_query",
|
||||
"pre_checkout_query",
|
||||
"callback_query_without_message",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class", params=params, ids=ids)
|
||||
def false_update(request):
|
||||
return Update(update_id=2, **request.param)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time():
|
||||
return datetime.datetime.now(tz=UTC)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def business_messages_deleted(bot):
|
||||
bmd = BusinessMessagesDeleted(
|
||||
business_connection_id="1",
|
||||
chat=Chat(1, Chat.PRIVATE, username="user_a"),
|
||||
message_ids=[1, 2, 3],
|
||||
)
|
||||
bmd.set_bot(bot)
|
||||
return bmd
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def business_messages_deleted_update(bot, business_messages_deleted):
|
||||
return Update(0, deleted_business_messages=business_messages_deleted)
|
||||
|
||||
|
||||
class TestBusinessMessagesDeletedHandler:
|
||||
test_flag = False
|
||||
|
||||
def test_slot_behaviour(self):
|
||||
action = BusinessMessagesDeletedHandler(self.callback)
|
||||
for attr in action.__slots__:
|
||||
assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset(self):
|
||||
self.test_flag = False
|
||||
|
||||
async def callback(self, update, context):
|
||||
self.test_flag = (
|
||||
isinstance(context, CallbackContext)
|
||||
and isinstance(context.bot, Bot)
|
||||
and isinstance(update, Update)
|
||||
and isinstance(context.update_queue, asyncio.Queue)
|
||||
and isinstance(context.job_queue, JobQueue)
|
||||
and isinstance(context.chat_data, dict)
|
||||
and isinstance(context.bot_data, dict)
|
||||
and isinstance(
|
||||
update.deleted_business_messages,
|
||||
BusinessMessagesDeleted,
|
||||
)
|
||||
)
|
||||
|
||||
def test_with_chat_id(self, business_messages_deleted_update):
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=1)
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=[1])
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=2, username="@user_a")
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=2)
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=[2])
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
|
||||
def test_with_username(self, business_messages_deleted_update):
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username="user_a")
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username="@user_a")
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username=["user_a"])
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username=["@user_a"])
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, chat_id=1, username="@user_b")
|
||||
assert handler.check_update(business_messages_deleted_update)
|
||||
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username="user_b")
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username="@user_b")
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username=["user_b"])
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
handler = BusinessMessagesDeletedHandler(self.callback, username=["@user_b"])
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
|
||||
business_messages_deleted_update.deleted_business_messages.chat._unfreeze()
|
||||
business_messages_deleted_update.deleted_business_messages.chat.username = None
|
||||
assert not handler.check_update(business_messages_deleted_update)
|
||||
|
||||
def test_other_update_types(self, false_update):
|
||||
handler = BusinessMessagesDeletedHandler(self.callback)
|
||||
assert not handler.check_update(false_update)
|
||||
assert not handler.check_update(True)
|
||||
|
||||
async def test_context(self, app, business_messages_deleted_update):
|
||||
handler = BusinessMessagesDeletedHandler(callback=self.callback)
|
||||
app.add_handler(handler)
|
||||
|
||||
async with app:
|
||||
await app.process_update(business_messages_deleted_update)
|
||||
assert self.test_flag
|
|
@ -32,6 +32,7 @@ from telegram import (
|
|||
from telegram.error import TelegramError
|
||||
from telegram.ext import ApplicationBuilder, CallbackContext, Job
|
||||
from telegram.warnings import PTBUserWarning
|
||||
from tests.auxil.pytest_classes import make_bot
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
"""
|
||||
|
@ -211,8 +212,9 @@ class TestCallbackContext:
|
|||
finally:
|
||||
app.bot = bot
|
||||
|
||||
async def test_drop_callback_data(self, bot, monkeypatch, chat_id):
|
||||
app = ApplicationBuilder().token(bot.token).arbitrary_callback_data(True).build()
|
||||
async def test_drop_callback_data(self, bot, chat_id):
|
||||
new_bot = make_bot(token=bot.token, arbitrary_callback_data=True)
|
||||
app = ApplicationBuilder().bot(new_bot).build()
|
||||
|
||||
update = Update(
|
||||
0, message=Message(0, None, Chat(1, "chat"), from_user=User(1, "user", False))
|
||||
|
|
|
@ -2035,6 +2035,11 @@ class TestFilters:
|
|||
update.message.is_automatic_forward = True
|
||||
assert filters.IS_AUTOMATIC_FORWARD.check_update(update)
|
||||
|
||||
def test_filters_is_from_offline(self, update):
|
||||
assert not filters.IS_FROM_OFFLINE.check_update(update)
|
||||
update.message.is_from_offline = True
|
||||
assert filters.IS_FROM_OFFLINE.check_update(update)
|
||||
|
||||
def test_filters_is_topic_message(self, update):
|
||||
assert not filters.IS_TOPIC_MESSAGE.check_update(update)
|
||||
update.message.is_topic_message = True
|
||||
|
@ -2343,6 +2348,9 @@ class TestFilters:
|
|||
assert not filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert not filters.UpdateType.EDITED.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_update_type_edited_message(self, update):
|
||||
update.edited_message, update.message = update.message, update.edited_message
|
||||
|
@ -2353,6 +2361,9 @@ class TestFilters:
|
|||
assert not filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert filters.UpdateType.EDITED.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_update_type_channel_post(self, update):
|
||||
update.channel_post, update.message = update.message, update.edited_message
|
||||
|
@ -2363,6 +2374,9 @@ class TestFilters:
|
|||
assert not filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert not filters.UpdateType.EDITED.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_update_type_edited_channel_post(self, update):
|
||||
update.edited_channel_post, update.message = update.message, update.edited_message
|
||||
|
@ -2373,6 +2387,35 @@ class TestFilters:
|
|||
assert filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert filters.UpdateType.EDITED.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_update_type_business_message(self, update):
|
||||
update.business_message, update.message = update.message, update.edited_message
|
||||
assert not filters.UpdateType.MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert not filters.UpdateType.EDITED.check_update(update)
|
||||
assert filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_update_type_edited_business_message(self, update):
|
||||
update.edited_business_message, update.message = update.message, update.edited_message
|
||||
assert not filters.UpdateType.MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_MESSAGE.check_update(update)
|
||||
assert not filters.UpdateType.MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.EDITED_CHANNEL_POST.check_update(update)
|
||||
assert not filters.UpdateType.CHANNEL_POSTS.check_update(update)
|
||||
assert filters.UpdateType.EDITED.check_update(update)
|
||||
assert filters.UpdateType.BUSINESS_MESSAGES.check_update(update)
|
||||
assert not filters.UpdateType.BUSINESS_MESSAGE.check_update(update)
|
||||
assert filters.UpdateType.EDITED_BUSINESS_MESSAGE.check_update(update)
|
||||
|
||||
def test_merged_short_circuit_and(self, update, base_class):
|
||||
update.message.text = "/test"
|
||||
|
|
|
@ -163,7 +163,7 @@ class TestRequestParameterWithoutRequest:
|
|||
assert request_parameter.input_files == [input_media.media, input_media.thumbnail]
|
||||
|
||||
def test_from_input_inputsticker(self):
|
||||
input_sticker = InputSticker(data_file("telegram.png").read_bytes(), ["emoji"])
|
||||
input_sticker = InputSticker(data_file("telegram.png").read_bytes(), ["emoji"], "static")
|
||||
expected = input_sticker.to_dict()
|
||||
expected.update({"sticker": input_sticker.sticker.attach_uri})
|
||||
request_parameter = RequestParameter.from_input("key", input_sticker)
|
||||
|
|
83
tests/test_birthdate.py
Normal file
83
tests/test_birthdate.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import Birthdate
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
class TestBirthdateBase:
|
||||
day = 1
|
||||
month = 1
|
||||
year = 2022
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def birthdate():
|
||||
return Birthdate(TestBirthdateBase.day, TestBirthdateBase.month, TestBirthdateBase.year)
|
||||
|
||||
|
||||
class TestBirthdateWithoutRequest(TestBirthdateBase):
|
||||
def test_slot_behaviour(self, birthdate):
|
||||
for attr in birthdate.__slots__:
|
||||
assert getattr(birthdate, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(birthdate)) == len(set(mro_slots(birthdate))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, birthdate):
|
||||
bd_dict = birthdate.to_dict()
|
||||
assert isinstance(bd_dict, dict)
|
||||
assert bd_dict["day"] == self.day
|
||||
assert bd_dict["month"] == self.month
|
||||
assert bd_dict["year"] == self.year
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {"day": self.day, "month": self.month, "year": self.year}
|
||||
bd = Birthdate.de_json(json_dict, bot)
|
||||
assert isinstance(bd, Birthdate)
|
||||
assert bd.day == self.day
|
||||
assert bd.month == self.month
|
||||
assert bd.year == self.year
|
||||
|
||||
def test_equality(self):
|
||||
bd1 = Birthdate(1, 1, 2022)
|
||||
bd2 = Birthdate(1, 1, 2022)
|
||||
bd3 = Birthdate(1, 1, 2023)
|
||||
bd4 = Birthdate(1, 2, 2022)
|
||||
|
||||
assert bd1 == bd2
|
||||
assert hash(bd1) == hash(bd2)
|
||||
|
||||
assert bd1 == bd3
|
||||
assert hash(bd1) == hash(bd3)
|
||||
|
||||
assert bd1 != bd4
|
||||
assert hash(bd1) != hash(bd4)
|
||||
|
||||
def test_to_date(self, birthdate):
|
||||
assert isinstance(birthdate.to_date(), datetime)
|
||||
assert birthdate.to_date() == datetime(self.year, self.month, self.day)
|
||||
new_bd = birthdate.to_date(2023)
|
||||
assert new_bd == datetime(2023, self.month, self.day)
|
||||
|
||||
def test_to_date_no_year(self):
|
||||
bd = Birthdate(1, 1)
|
||||
with pytest.raises(ValueError, match="The `year` argument is required"):
|
||||
bd.to_date()
|
|
@ -39,6 +39,7 @@ from telegram import (
|
|||
BotDescription,
|
||||
BotName,
|
||||
BotShortDescription,
|
||||
BusinessConnection,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChatAdministratorRights,
|
||||
|
@ -2087,6 +2088,37 @@ class TestBotWithoutRequest:
|
|||
api_kwargs={"chat_id": 2, "user_id": 32, "until_date": until_timestamp},
|
||||
)
|
||||
|
||||
async def test_business_connection_id_argument(self, bot, monkeypatch):
|
||||
"""We can't connect to a business acc, so we just test that the correct data is passed.
|
||||
We also can't test every single method easily, so we just test one. Our linting will catch
|
||||
any unused args with the others."""
|
||||
|
||||
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
|
||||
return request_data.parameters.get("business_connection_id") == 42
|
||||
|
||||
monkeypatch.setattr(bot.request, "post", make_assertion)
|
||||
assert await bot.send_message(2, "text", business_connection_id=42)
|
||||
|
||||
async def test_get_business_connection(self, bot, monkeypatch):
|
||||
bci = "42"
|
||||
user = User(1, "first", False)
|
||||
user_chat_id = 1
|
||||
date = dtm.datetime.utcnow()
|
||||
can_reply = True
|
||||
is_enabled = True
|
||||
bc = BusinessConnection(bci, user, user_chat_id, date, can_reply, is_enabled).to_json()
|
||||
|
||||
async def do_request(*args, **kwargs):
|
||||
data = kwargs.get("request_data")
|
||||
obj = data.parameters.get("business_connection_id")
|
||||
if obj == bci:
|
||||
return 200, f'{{"ok": true, "result": {bc}}}'.encode()
|
||||
return 400, b'{"ok": false, "result": []}'
|
||||
|
||||
monkeypatch.setattr(bot.request, "do_request", do_request)
|
||||
obj = await bot.get_business_connection(business_connection_id=bci)
|
||||
assert isinstance(obj, BusinessConnection)
|
||||
|
||||
|
||||
class TestBotWithRequest:
|
||||
"""
|
||||
|
@ -3373,8 +3405,8 @@ class TestBotWithRequest:
|
|||
assert await bot.unpin_all_chat_messages(super_group_id, read_timeout=10)
|
||||
|
||||
# get_sticker_set, upload_sticker_file, create_new_sticker_set, add_sticker_to_set,
|
||||
# set_sticker_position_in_set, delete_sticker_from_set and get_custom_emoji_stickers
|
||||
# are tested in the test_sticker module.
|
||||
# set_sticker_position_in_set, delete_sticker_from_set and get_custom_emoji_stickers,
|
||||
# replace_sticker_in_set are tested in the test_sticker module.
|
||||
|
||||
# get_forum_topic_icon_stickers, edit_forum_topic, general_forum etc...
|
||||
# are tested in the test_forum module.
|
||||
|
|
412
tests/test_business.py
Normal file
412
tests/test_business.py
Normal file
|
@ -0,0 +1,412 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import (
|
||||
BusinessConnection,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessMessagesDeleted,
|
||||
BusinessOpeningHours,
|
||||
BusinessOpeningHoursInterval,
|
||||
Chat,
|
||||
Location,
|
||||
Sticker,
|
||||
User,
|
||||
)
|
||||
from telegram._utils.datetime import UTC, to_timestamp
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
class TestBusinessBase:
|
||||
id_ = "123"
|
||||
user = User(123, "test_user", False)
|
||||
user_chat_id = 123
|
||||
date = datetime.now(tz=UTC).replace(microsecond=0)
|
||||
can_reply = True
|
||||
is_enabled = True
|
||||
message_ids = (123, 321)
|
||||
business_connection_id = "123"
|
||||
chat = Chat(123, "test_chat")
|
||||
title = "Business Title"
|
||||
message = "Business description"
|
||||
sticker = Sticker("sticker_id", "unique_id", 50, 50, True, False, Sticker.REGULAR)
|
||||
address = "address"
|
||||
location = Location(-23.691288, 46.788279)
|
||||
opening_minute = 0
|
||||
closing_minute = 60
|
||||
time_zone_name = "Country/City"
|
||||
opening_hours = [
|
||||
BusinessOpeningHoursInterval(opening, opening + 60) for opening in (0, 24 * 60)
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_connection():
|
||||
return BusinessConnection(
|
||||
TestBusinessBase.id_,
|
||||
TestBusinessBase.user,
|
||||
TestBusinessBase.user_chat_id,
|
||||
TestBusinessBase.date,
|
||||
TestBusinessBase.can_reply,
|
||||
TestBusinessBase.is_enabled,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_messages_deleted():
|
||||
return BusinessMessagesDeleted(
|
||||
TestBusinessBase.business_connection_id,
|
||||
TestBusinessBase.chat,
|
||||
TestBusinessBase.message_ids,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_intro():
|
||||
return BusinessIntro(
|
||||
TestBusinessBase.title,
|
||||
TestBusinessBase.message,
|
||||
TestBusinessBase.sticker,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_location():
|
||||
return BusinessLocation(
|
||||
TestBusinessBase.address,
|
||||
TestBusinessBase.location,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_opening_hours_interval():
|
||||
return BusinessOpeningHoursInterval(
|
||||
TestBusinessBase.opening_minute,
|
||||
TestBusinessBase.closing_minute,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def business_opening_hours():
|
||||
return BusinessOpeningHours(
|
||||
TestBusinessBase.time_zone_name,
|
||||
TestBusinessBase.opening_hours,
|
||||
)
|
||||
|
||||
|
||||
class TestBusinessConnectionWithoutRequest(TestBusinessBase):
|
||||
def test_slots(self, business_connection):
|
||||
bc = business_connection
|
||||
for attr in bc.__slots__:
|
||||
assert getattr(bc, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(bc)) == len(set(mro_slots(bc))), "duplicate slot"
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"user": self.user.to_dict(),
|
||||
"user_chat_id": self.user_chat_id,
|
||||
"date": to_timestamp(self.date),
|
||||
"can_reply": self.can_reply,
|
||||
"is_enabled": self.is_enabled,
|
||||
}
|
||||
bc = BusinessConnection.de_json(json_dict, None)
|
||||
assert bc.id == self.id_
|
||||
assert bc.user == self.user
|
||||
assert bc.user_chat_id == self.user_chat_id
|
||||
assert bc.date == self.date
|
||||
assert bc.can_reply == self.can_reply
|
||||
assert bc.is_enabled == self.is_enabled
|
||||
assert bc.api_kwargs == {}
|
||||
assert isinstance(bc, BusinessConnection)
|
||||
|
||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
"id": self.id_,
|
||||
"user": self.user.to_dict(),
|
||||
"user_chat_id": self.user_chat_id,
|
||||
"date": to_timestamp(self.date),
|
||||
"can_reply": self.can_reply,
|
||||
"is_enabled": self.is_enabled,
|
||||
}
|
||||
chat_bot = BusinessConnection.de_json(json_dict, bot)
|
||||
chat_bot_raw = BusinessConnection.de_json(json_dict, raw_bot)
|
||||
chat_bot_tz = BusinessConnection.de_json(json_dict, tz_bot)
|
||||
|
||||
# comparing utcoffsets because comparing tzinfo objects is not reliable
|
||||
date_offset = chat_bot_tz.date.utcoffset()
|
||||
date_offset_tz = tz_bot.defaults.tzinfo.utcoffset(chat_bot_tz.date.replace(tzinfo=None))
|
||||
|
||||
assert chat_bot.date.tzinfo == UTC
|
||||
assert chat_bot_raw.date.tzinfo == UTC
|
||||
assert date_offset_tz == date_offset
|
||||
|
||||
def test_to_dict(self, business_connection):
|
||||
bc_dict = business_connection.to_dict()
|
||||
assert isinstance(bc_dict, dict)
|
||||
assert bc_dict["id"] == self.id_
|
||||
assert bc_dict["user"] == self.user.to_dict()
|
||||
assert bc_dict["user_chat_id"] == self.user_chat_id
|
||||
assert bc_dict["date"] == to_timestamp(self.date)
|
||||
assert bc_dict["can_reply"] == self.can_reply
|
||||
assert bc_dict["is_enabled"] == self.is_enabled
|
||||
|
||||
def test_equality(self):
|
||||
bc1 = BusinessConnection(
|
||||
self.id_, self.user, self.user_chat_id, self.date, self.can_reply, self.is_enabled
|
||||
)
|
||||
bc2 = BusinessConnection(
|
||||
self.id_, self.user, self.user_chat_id, self.date, self.can_reply, self.is_enabled
|
||||
)
|
||||
bc3 = BusinessConnection(
|
||||
"321", self.user, self.user_chat_id, self.date, self.can_reply, self.is_enabled
|
||||
)
|
||||
|
||||
assert bc1 == bc2
|
||||
assert hash(bc1) == hash(bc2)
|
||||
|
||||
assert bc1 != bc3
|
||||
assert hash(bc1) != hash(bc3)
|
||||
|
||||
|
||||
class TestBusinessMessagesDeleted(TestBusinessBase):
|
||||
def test_slots(self, business_messages_deleted):
|
||||
bmd = business_messages_deleted
|
||||
for attr in bmd.__slots__:
|
||||
assert getattr(bmd, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(bmd)) == len(set(mro_slots(bmd))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, business_messages_deleted):
|
||||
bmd_dict = business_messages_deleted.to_dict()
|
||||
assert isinstance(bmd_dict, dict)
|
||||
assert bmd_dict["message_ids"] == list(self.message_ids)
|
||||
assert bmd_dict["business_connection_id"] == self.business_connection_id
|
||||
assert bmd_dict["chat"] == self.chat.to_dict()
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"business_connection_id": self.business_connection_id,
|
||||
"chat": self.chat.to_dict(),
|
||||
"message_ids": self.message_ids,
|
||||
}
|
||||
bmd = BusinessMessagesDeleted.de_json(json_dict, None)
|
||||
assert bmd.business_connection_id == self.business_connection_id
|
||||
assert bmd.chat == self.chat
|
||||
assert bmd.message_ids == self.message_ids
|
||||
assert bmd.api_kwargs == {}
|
||||
assert isinstance(bmd, BusinessMessagesDeleted)
|
||||
|
||||
def test_equality(self):
|
||||
bmd1 = BusinessMessagesDeleted(self.business_connection_id, self.chat, self.message_ids)
|
||||
bmd2 = BusinessMessagesDeleted(self.business_connection_id, self.chat, self.message_ids)
|
||||
bmd3 = BusinessMessagesDeleted("1", Chat(4, "random"), [321, 123])
|
||||
|
||||
assert bmd1 == bmd2
|
||||
assert hash(bmd1) == hash(bmd2)
|
||||
|
||||
assert bmd1 != bmd3
|
||||
assert hash(bmd1) != hash(bmd3)
|
||||
|
||||
|
||||
class TestBusinessIntroWithoutRequest(TestBusinessBase):
|
||||
def test_slot_behaviour(self, business_intro):
|
||||
intro = business_intro
|
||||
for attr in intro.__slots__:
|
||||
assert getattr(intro, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(intro)) == len(set(mro_slots(intro))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, business_intro):
|
||||
intro_dict = business_intro.to_dict()
|
||||
assert isinstance(intro_dict, dict)
|
||||
assert intro_dict["title"] == self.title
|
||||
assert intro_dict["message"] == self.message
|
||||
assert intro_dict["sticker"] == self.sticker.to_dict()
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"title": self.title,
|
||||
"message": self.message,
|
||||
"sticker": self.sticker.to_dict(),
|
||||
}
|
||||
intro = BusinessIntro.de_json(json_dict, None)
|
||||
assert intro.title == self.title
|
||||
assert intro.message == self.message
|
||||
assert intro.sticker == self.sticker
|
||||
assert intro.api_kwargs == {}
|
||||
assert isinstance(intro, BusinessIntro)
|
||||
|
||||
def test_equality(self):
|
||||
intro1 = BusinessIntro(self.title, self.message, self.sticker)
|
||||
intro2 = BusinessIntro(self.title, self.message, self.sticker)
|
||||
intro3 = BusinessIntro("Other Business", self.message, self.sticker)
|
||||
|
||||
assert intro1 == intro2
|
||||
assert hash(intro1) == hash(intro2)
|
||||
assert intro1 is not intro2
|
||||
|
||||
assert intro1 != intro3
|
||||
assert hash(intro1) != hash(intro3)
|
||||
|
||||
|
||||
class TestBusinessLocationWithoutRequest(TestBusinessBase):
|
||||
def test_slot_behaviour(self, business_location):
|
||||
inst = business_location
|
||||
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, business_location):
|
||||
blc_dict = business_location.to_dict()
|
||||
assert isinstance(blc_dict, dict)
|
||||
assert blc_dict["address"] == self.address
|
||||
assert blc_dict["location"] == self.location.to_dict()
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"address": self.address,
|
||||
"location": self.location.to_dict(),
|
||||
}
|
||||
blc = BusinessLocation.de_json(json_dict, None)
|
||||
assert blc.address == self.address
|
||||
assert blc.location == self.location
|
||||
assert blc.api_kwargs == {}
|
||||
assert isinstance(blc, BusinessLocation)
|
||||
|
||||
def test_equality(self):
|
||||
blc1 = BusinessLocation(self.address, self.location)
|
||||
blc2 = BusinessLocation(self.address, self.location)
|
||||
blc3 = BusinessLocation("Other Address", self.location)
|
||||
|
||||
assert blc1 == blc2
|
||||
assert hash(blc1) == hash(blc2)
|
||||
assert blc1 is not blc2
|
||||
|
||||
assert blc1 != blc3
|
||||
assert hash(blc1) != hash(blc3)
|
||||
|
||||
|
||||
class TestBusinessOpeningHoursIntervalWithoutRequest(TestBusinessBase):
|
||||
def test_slot_behaviour(self, business_opening_hours_interval):
|
||||
inst = business_opening_hours_interval
|
||||
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, business_opening_hours_interval):
|
||||
bohi_dict = business_opening_hours_interval.to_dict()
|
||||
assert isinstance(bohi_dict, dict)
|
||||
assert bohi_dict["opening_minute"] == self.opening_minute
|
||||
assert bohi_dict["closing_minute"] == self.closing_minute
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"opening_minute": self.opening_minute,
|
||||
"closing_minute": self.closing_minute,
|
||||
}
|
||||
bohi = BusinessOpeningHoursInterval.de_json(json_dict, None)
|
||||
assert bohi.opening_minute == self.opening_minute
|
||||
assert bohi.closing_minute == self.closing_minute
|
||||
assert bohi.api_kwargs == {}
|
||||
assert isinstance(bohi, BusinessOpeningHoursInterval)
|
||||
|
||||
def test_equality(self):
|
||||
bohi1 = BusinessOpeningHoursInterval(self.opening_minute, self.closing_minute)
|
||||
bohi2 = BusinessOpeningHoursInterval(self.opening_minute, self.closing_minute)
|
||||
bohi3 = BusinessOpeningHoursInterval(61, 100)
|
||||
|
||||
assert bohi1 == bohi2
|
||||
assert hash(bohi1) == hash(bohi2)
|
||||
assert bohi1 is not bohi2
|
||||
|
||||
assert bohi1 != bohi3
|
||||
assert hash(bohi1) != hash(bohi3)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("opening_minute", "expected"),
|
||||
[ # openings per docstring
|
||||
(8 * 60, (0, 8, 0)),
|
||||
(24 * 60, (1, 0, 0)),
|
||||
(6 * 24 * 60, (6, 0, 0)),
|
||||
],
|
||||
)
|
||||
def test_opening_time(self, opening_minute, expected):
|
||||
bohi = BusinessOpeningHoursInterval(opening_minute, -0)
|
||||
|
||||
opening_time = bohi.opening_time
|
||||
assert opening_time == expected
|
||||
|
||||
cached = bohi.opening_time
|
||||
assert cached is opening_time
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("closing_minute", "expected"),
|
||||
[ # closings per docstring
|
||||
(20 * 60 + 30, (0, 20, 30)),
|
||||
(2 * 24 * 60 - 1, (1, 23, 59)),
|
||||
(7 * 24 * 60 - 2, (6, 23, 58)),
|
||||
],
|
||||
)
|
||||
def test_closing_time(self, closing_minute, expected):
|
||||
bohi = BusinessOpeningHoursInterval(-0, closing_minute)
|
||||
|
||||
closing_time = bohi.closing_time
|
||||
assert closing_time == expected
|
||||
|
||||
cached = bohi.closing_time
|
||||
assert cached is closing_time
|
||||
|
||||
|
||||
class TestBusinessOpeningHoursWithoutRequest(TestBusinessBase):
|
||||
def test_slot_behaviour(self, business_opening_hours):
|
||||
inst = business_opening_hours
|
||||
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, business_opening_hours):
|
||||
boh_dict = business_opening_hours.to_dict()
|
||||
assert isinstance(boh_dict, dict)
|
||||
assert boh_dict["time_zone_name"] == self.time_zone_name
|
||||
assert boh_dict["opening_hours"] == [opening.to_dict() for opening in self.opening_hours]
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
"time_zone_name": self.time_zone_name,
|
||||
"opening_hours": [opening.to_dict() for opening in self.opening_hours],
|
||||
}
|
||||
boh = BusinessOpeningHours.de_json(json_dict, None)
|
||||
assert boh.time_zone_name == self.time_zone_name
|
||||
assert boh.opening_hours == tuple(self.opening_hours)
|
||||
assert boh.api_kwargs == {}
|
||||
assert isinstance(boh, BusinessOpeningHours)
|
||||
|
||||
def test_equality(self):
|
||||
boh1 = BusinessOpeningHours(self.time_zone_name, self.opening_hours)
|
||||
boh2 = BusinessOpeningHours(self.time_zone_name, self.opening_hours)
|
||||
boh3 = BusinessOpeningHours("Other/Timezone", self.opening_hours)
|
||||
|
||||
assert boh1 == boh2
|
||||
assert hash(boh1) == hash(boh2)
|
||||
assert boh1 is not boh2
|
||||
|
||||
assert boh1 != boh3
|
||||
assert hash(boh1) != hash(boh3)
|
|
@ -21,7 +21,12 @@ import datetime
|
|||
import pytest
|
||||
|
||||
from telegram import (
|
||||
Birthdate,
|
||||
Bot,
|
||||
BusinessIntro,
|
||||
BusinessLocation,
|
||||
BusinessOpeningHours,
|
||||
BusinessOpeningHoursInterval,
|
||||
Chat,
|
||||
ChatLocation,
|
||||
ChatPermissions,
|
||||
|
@ -74,6 +79,11 @@ def chat(bot):
|
|||
profile_background_custom_emoji_id=TestChatBase.profile_background_custom_emoji_id,
|
||||
unrestrict_boost_count=TestChatBase.unrestrict_boost_count,
|
||||
custom_emoji_sticker_set_name=TestChatBase.custom_emoji_sticker_set_name,
|
||||
business_intro=TestChatBase.business_intro,
|
||||
business_location=TestChatBase.business_location,
|
||||
business_opening_hours=TestChatBase.business_opening_hours,
|
||||
birthdate=Birthdate(1, 1),
|
||||
personal_chat=TestChatBase.personal_chat,
|
||||
)
|
||||
chat.set_bot(bot)
|
||||
chat._unfreeze()
|
||||
|
@ -113,12 +123,20 @@ class TestChatBase:
|
|||
ReactionTypeEmoji(ReactionEmoji.THUMBS_DOWN),
|
||||
ReactionTypeCustomEmoji("custom_emoji_id"),
|
||||
]
|
||||
business_intro = BusinessIntro("Title", "Description", None)
|
||||
business_location = BusinessLocation("Address", Location(123, 456))
|
||||
business_opening_hours = BusinessOpeningHours(
|
||||
"Country/City",
|
||||
[BusinessOpeningHoursInterval(opening, opening + 60) for opening in (0, 24 * 60)],
|
||||
)
|
||||
accent_color_id = 1
|
||||
background_custom_emoji_id = "background_custom_emoji_id"
|
||||
profile_accent_color_id = 2
|
||||
profile_background_custom_emoji_id = "profile_background_custom_emoji_id"
|
||||
unrestrict_boost_count = 100
|
||||
custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name"
|
||||
birthdate = Birthdate(1, 1)
|
||||
personal_chat = Chat(3, "private", "private")
|
||||
|
||||
|
||||
class TestChatWithoutRequest(TestChatBase):
|
||||
|
@ -139,6 +157,9 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"permissions": self.permissions.to_dict(),
|
||||
"slow_mode_delay": self.slow_mode_delay,
|
||||
"bio": self.bio,
|
||||
"business_intro": self.business_intro.to_dict(),
|
||||
"business_location": self.business_location.to_dict(),
|
||||
"business_opening_hours": self.business_opening_hours.to_dict(),
|
||||
"has_protected_content": self.has_protected_content,
|
||||
"has_visible_history": self.has_visible_history,
|
||||
"has_private_forwards": self.has_private_forwards,
|
||||
|
@ -162,6 +183,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
"profile_background_custom_emoji_id": self.profile_background_custom_emoji_id,
|
||||
"unrestrict_boost_count": self.unrestrict_boost_count,
|
||||
"custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name,
|
||||
"birthdate": self.birthdate.to_dict(),
|
||||
"personal_chat": self.personal_chat.to_dict(),
|
||||
}
|
||||
chat = Chat.de_json(json_dict, bot)
|
||||
|
||||
|
@ -174,6 +197,9 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.permissions == self.permissions
|
||||
assert chat.slow_mode_delay == self.slow_mode_delay
|
||||
assert chat.bio == self.bio
|
||||
assert chat.business_intro == self.business_intro
|
||||
assert chat.business_location == self.business_location
|
||||
assert chat.business_opening_hours == self.business_opening_hours
|
||||
assert chat.has_protected_content == self.has_protected_content
|
||||
assert chat.has_visible_history == self.has_visible_history
|
||||
assert chat.has_private_forwards == self.has_private_forwards
|
||||
|
@ -202,6 +228,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat.profile_background_custom_emoji_id == self.profile_background_custom_emoji_id
|
||||
assert chat.unrestrict_boost_count == self.unrestrict_boost_count
|
||||
assert chat.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name
|
||||
assert chat.birthdate == self.birthdate
|
||||
assert chat.personal_chat == self.personal_chat
|
||||
|
||||
def test_de_json_localization(self, bot, raw_bot, tz_bot):
|
||||
json_dict = {
|
||||
|
@ -234,6 +262,9 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
assert chat_dict["permissions"] == chat.permissions.to_dict()
|
||||
assert chat_dict["slow_mode_delay"] == chat.slow_mode_delay
|
||||
assert chat_dict["bio"] == chat.bio
|
||||
assert chat_dict["business_intro"] == chat.business_intro.to_dict()
|
||||
assert chat_dict["business_location"] == chat.business_location.to_dict()
|
||||
assert chat_dict["business_opening_hours"] == chat.business_opening_hours.to_dict()
|
||||
assert chat_dict["has_private_forwards"] == chat.has_private_forwards
|
||||
assert chat_dict["has_protected_content"] == chat.has_protected_content
|
||||
assert chat_dict["has_visible_history"] == chat.has_visible_history
|
||||
|
@ -267,6 +298,8 @@ class TestChatWithoutRequest(TestChatBase):
|
|||
)
|
||||
assert chat_dict["custom_emoji_sticker_set_name"] == chat.custom_emoji_sticker_set_name
|
||||
assert chat_dict["unrestrict_boost_count"] == chat.unrestrict_boost_count
|
||||
assert chat_dict["birthdate"] == chat.birthdate.to_dict()
|
||||
assert chat_dict["personal_chat"] == chat.personal_chat.to_dict()
|
||||
|
||||
def test_always_tuples_attributes(self):
|
||||
chat = Chat(
|
||||
|
|
|
@ -176,6 +176,7 @@ class TestConstantsWithoutRequest:
|
|||
# attribute is deprecated, no need to add it to MessageType
|
||||
"user_shared",
|
||||
"via_bot",
|
||||
"is_from_offline",
|
||||
}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
@ -50,6 +50,7 @@ from telegram import (
|
|||
PollOption,
|
||||
ProximityAlertTriggered,
|
||||
ReplyParameters,
|
||||
SharedUser,
|
||||
Sticker,
|
||||
Story,
|
||||
SuccessfulPayment,
|
||||
|
@ -89,6 +90,7 @@ def message(bot):
|
|||
date=TestMessageBase.date,
|
||||
chat=copy(TestMessageBase.chat),
|
||||
from_user=copy(TestMessageBase.from_user),
|
||||
business_connection_id="123456789",
|
||||
)
|
||||
message.set_bot(bot)
|
||||
message._unfreeze()
|
||||
|
@ -218,7 +220,7 @@ def message(bot):
|
|||
},
|
||||
{"web_app_data": WebAppData("some_data", "some_button_text")},
|
||||
{"message_thread_id": 123},
|
||||
{"users_shared": UsersShared(1, [2, 3])},
|
||||
{"users_shared": UsersShared(1, users=[SharedUser(2, "user2"), SharedUser(3, "user3")])},
|
||||
{"chat_shared": ChatShared(3, 4)},
|
||||
{
|
||||
"giveaway": Giveaway(
|
||||
|
@ -263,6 +265,9 @@ def message(bot):
|
|||
{"reply_to_story": Story(Chat(1, Chat.PRIVATE), 0)},
|
||||
{"boost_added": ChatBoostAdded(100)},
|
||||
{"sender_boost_count": 1},
|
||||
{"is_from_offline": True},
|
||||
{"sender_business_bot": User(1, "BusinessBot", True)},
|
||||
{"business_connection_id": "123456789"},
|
||||
],
|
||||
ids=[
|
||||
"reply",
|
||||
|
@ -328,6 +333,9 @@ def message(bot):
|
|||
"reply_to_story",
|
||||
"boost_added",
|
||||
"sender_boost_count",
|
||||
"sender_business_bot",
|
||||
"business_connection_id",
|
||||
"is_from_offline",
|
||||
],
|
||||
)
|
||||
def message_params(bot, request):
|
||||
|
@ -1386,7 +1394,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_text,
|
||||
Bot.send_message,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1394,6 +1402,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_message",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_text, message.get_bot())
|
||||
|
||||
|
@ -1424,7 +1433,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_markdown,
|
||||
Bot.send_message,
|
||||
["chat_id", "parse_mode", "reply_to_message_id"],
|
||||
["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1432,6 +1441,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_message",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_text, message.get_bot())
|
||||
|
||||
|
@ -1466,7 +1476,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_markdown_v2,
|
||||
Bot.send_message,
|
||||
["chat_id", "parse_mode", "reply_to_message_id"],
|
||||
["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1474,6 +1484,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_message",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_text, message.get_bot())
|
||||
|
||||
|
@ -1513,7 +1524,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_html,
|
||||
Bot.send_message,
|
||||
["chat_id", "parse_mode", "reply_to_message_id"],
|
||||
["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1521,6 +1532,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_message",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_text, message.get_bot())
|
||||
|
||||
|
@ -1546,7 +1558,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_media_group,
|
||||
Bot.send_media_group,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1554,6 +1566,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_media_group",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_media_group, message.get_bot())
|
||||
|
||||
|
@ -1584,7 +1597,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_photo,
|
||||
Bot.send_photo,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1592,6 +1605,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_photo",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_photo, message.get_bot())
|
||||
|
||||
|
@ -1614,7 +1628,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_audio,
|
||||
Bot.send_audio,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1622,6 +1636,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_audio",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_audio, message.get_bot())
|
||||
|
||||
|
@ -1644,7 +1659,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_document,
|
||||
Bot.send_document,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1652,6 +1667,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_document",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_document, message.get_bot())
|
||||
|
||||
|
@ -1674,7 +1690,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_animation,
|
||||
Bot.send_animation,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1682,6 +1698,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_animation",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_animation, message.get_bot())
|
||||
|
||||
|
@ -1704,7 +1721,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_sticker,
|
||||
Bot.send_sticker,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1712,6 +1729,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_sticker",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_sticker, message.get_bot())
|
||||
|
||||
|
@ -1734,7 +1752,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_video,
|
||||
Bot.send_video,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1742,6 +1760,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_video",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_video, message.get_bot())
|
||||
|
||||
|
@ -1764,7 +1783,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_video_note,
|
||||
Bot.send_video_note,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1772,6 +1791,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_video_note",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_video_note, message.get_bot())
|
||||
|
||||
|
@ -1794,7 +1814,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_voice,
|
||||
Bot.send_voice,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1802,6 +1822,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_voice",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_voice, message.get_bot())
|
||||
|
||||
|
@ -1824,7 +1845,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_location,
|
||||
Bot.send_location,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1832,6 +1853,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_location",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_location, message.get_bot())
|
||||
|
||||
|
@ -1854,7 +1876,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_venue,
|
||||
Bot.send_venue,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1862,6 +1884,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_venue",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_venue, message.get_bot())
|
||||
|
||||
|
@ -1884,7 +1907,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_contact,
|
||||
Bot.send_contact,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -1892,6 +1915,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_contact",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_contact, message.get_bot())
|
||||
|
||||
|
@ -1915,11 +1939,15 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_poll,
|
||||
Bot.send_poll,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.reply_poll, message.get_bot(), "send_poll", skip_params=["reply_to_message_id"]
|
||||
message.reply_poll,
|
||||
message.get_bot(),
|
||||
"send_poll",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_poll, message.get_bot())
|
||||
|
||||
|
@ -1942,11 +1970,15 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_dice,
|
||||
Bot.send_dice,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.reply_dice, message.get_bot(), "send_dice", skip_params=["reply_to_message_id"]
|
||||
message.reply_dice,
|
||||
message.get_bot(),
|
||||
"send_dice",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_dice, message.get_bot())
|
||||
|
||||
|
@ -1971,10 +2003,16 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
return id_ and action
|
||||
|
||||
assert check_shortcut_signature(
|
||||
Message.reply_chat_action, Bot.send_chat_action, ["chat_id", "reply_to_message_id"], []
|
||||
Message.reply_chat_action,
|
||||
Bot.send_chat_action,
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
[],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.reply_chat_action, message.get_bot(), "send_chat_action"
|
||||
message.reply_chat_action,
|
||||
message.get_bot(),
|
||||
"send_chat_action",
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_chat_action, message.get_bot())
|
||||
|
||||
|
@ -1998,11 +2036,15 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_game,
|
||||
Bot.send_game,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
message.reply_game, message.get_bot(), "send_game", skip_params=["reply_to_message_id"]
|
||||
message.reply_game,
|
||||
message.get_bot(),
|
||||
"send_game",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_game, message.get_bot())
|
||||
|
||||
|
@ -2034,7 +2076,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_invoice,
|
||||
Bot.send_invoice,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(
|
||||
|
@ -2042,6 +2084,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
message.get_bot(),
|
||||
"send_invoice",
|
||||
skip_params=["reply_to_message_id"],
|
||||
shortcut_kwargs=["business_connection_id"],
|
||||
)
|
||||
assert await check_defaults_handling(message.reply_invoice, message.get_bot())
|
||||
|
||||
|
@ -2159,7 +2202,7 @@ class TestMessageWithoutRequest(TestMessageBase):
|
|||
assert check_shortcut_signature(
|
||||
Message.reply_copy,
|
||||
Bot.copy_message,
|
||||
["chat_id", "reply_to_message_id"],
|
||||
["chat_id", "reply_to_message_id", "business_connection_id"],
|
||||
["quote", "do_quote", "reply_to_message_id"],
|
||||
)
|
||||
assert await check_shortcut_call(message.copy, message.get_bot(), "copy_message")
|
||||
|
|
|
@ -166,7 +166,11 @@ def ignored_param_requirements(object_name: str) -> set[str]:
|
|||
|
||||
|
||||
# Arguments that are optional arguments for now for backwards compatibility
|
||||
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {}
|
||||
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {
|
||||
"create_new_sticker_set": {"sticker_format"}, # removed by bot api 7.2
|
||||
"StickerSet": {"is_animated", "is_video"}, # removed by bot api 7.2
|
||||
"UsersShared": {"user_ids", "users"}, # removed/added by bot api 7.2
|
||||
}
|
||||
|
||||
|
||||
def backwards_compat_kwargs(object_name: str) -> set[str]:
|
||||
|
|
|
@ -19,19 +19,20 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import ChatShared, UsersShared
|
||||
from telegram import ChatShared, PhotoSize, SharedUser, UsersShared
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
from tests.auxil.slots import mro_slots
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def users_shared():
|
||||
return UsersShared(TestUsersSharedBase.request_id, TestUsersSharedBase.user_ids)
|
||||
return UsersShared(TestUsersSharedBase.request_id, users=TestUsersSharedBase.users)
|
||||
|
||||
|
||||
class TestUsersSharedBase:
|
||||
request_id = 789
|
||||
user_id = 101112
|
||||
user_ids = (user_id, 101113)
|
||||
user_ids = (101112, 101113)
|
||||
users = (SharedUser(101112, "user1"), SharedUser(101113, "user2"))
|
||||
|
||||
|
||||
class TestUsersSharedWithoutRequest(TestUsersSharedBase):
|
||||
|
@ -45,24 +46,43 @@ class TestUsersSharedWithoutRequest(TestUsersSharedBase):
|
|||
|
||||
assert isinstance(users_shared_dict, dict)
|
||||
assert users_shared_dict["request_id"] == self.request_id
|
||||
assert users_shared_dict["user_ids"] == list(self.user_ids)
|
||||
assert users_shared_dict["users"] == [user.to_dict() for user in self.users]
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
"request_id": self.request_id,
|
||||
"users": [user.to_dict() for user in self.users],
|
||||
"user_ids": self.user_ids,
|
||||
}
|
||||
users_shared = UsersShared.de_json(json_dict, bot)
|
||||
assert users_shared.api_kwargs == {}
|
||||
assert users_shared.api_kwargs == {"user_ids": self.user_ids}
|
||||
|
||||
assert users_shared.request_id == self.request_id
|
||||
assert users_shared.users == self.users
|
||||
assert users_shared.user_ids == tuple(self.user_ids)
|
||||
|
||||
assert UsersShared.de_json({}, bot) is None
|
||||
|
||||
def test_users_is_required_argument(self):
|
||||
with pytest.raises(TypeError, match="`users` is a required argument"):
|
||||
UsersShared(self.request_id, user_ids=self.user_ids)
|
||||
|
||||
def test_user_ids_deprecation_warning(self):
|
||||
with pytest.warns(
|
||||
PTBDeprecationWarning, match="'user_ids' was renamed to 'users' in Bot API 7.2"
|
||||
):
|
||||
users_shared = UsersShared(self.request_id, user_ids=self.user_ids, users=self.users)
|
||||
with pytest.warns(
|
||||
PTBDeprecationWarning, match="renamed the attribute 'user_ids' to 'users'"
|
||||
):
|
||||
users_shared.user_ids
|
||||
|
||||
def test_equality(self):
|
||||
a = UsersShared(self.request_id, self.user_ids)
|
||||
b = UsersShared(self.request_id, self.user_ids)
|
||||
c = UsersShared(1, self.user_ids)
|
||||
d = UsersShared(self.request_id, [1, 2])
|
||||
a = UsersShared(self.request_id, users=self.users)
|
||||
b = UsersShared(self.request_id, users=self.users)
|
||||
c = UsersShared(1, users=self.users)
|
||||
d = UsersShared(self.request_id, users=(SharedUser(1, "user1"), SharedUser(1, "user2")))
|
||||
e = PhotoSize("file_id", "1", 1, 1)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
@ -74,6 +94,9 @@ class TestUsersSharedWithoutRequest(TestUsersSharedBase):
|
|||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def chat_shared():
|
||||
|
@ -112,11 +135,109 @@ class TestChatSharedWithoutRequest(TestChatSharedBase):
|
|||
assert chat_shared.request_id == self.request_id
|
||||
assert chat_shared.chat_id == self.chat_id
|
||||
|
||||
def test_equality(self):
|
||||
def test_equality(self, users_shared):
|
||||
a = ChatShared(self.request_id, self.chat_id)
|
||||
b = ChatShared(self.request_id, self.chat_id)
|
||||
c = ChatShared(1, self.chat_id)
|
||||
d = ChatShared(self.request_id, 1)
|
||||
e = users_shared
|
||||
|
||||
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)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def shared_user():
|
||||
return SharedUser(
|
||||
TestSharedUserBase.user_id,
|
||||
TestSharedUserBase.first_name,
|
||||
last_name=TestSharedUserBase.last_name,
|
||||
username=TestSharedUserBase.username,
|
||||
photo=TestSharedUserBase.photo,
|
||||
)
|
||||
|
||||
|
||||
class TestSharedUserBase:
|
||||
user_id = 101112
|
||||
first_name = "first"
|
||||
last_name = "last"
|
||||
username = "user"
|
||||
photo = (
|
||||
PhotoSize(file_id="file_id", width=1, height=1, file_unique_id="1"),
|
||||
PhotoSize(file_id="file_id", width=2, height=2, file_unique_id="2"),
|
||||
)
|
||||
|
||||
|
||||
class TestSharedUserWithoutRequest(TestSharedUserBase):
|
||||
def test_slot_behaviour(self, shared_user):
|
||||
for attr in shared_user.__slots__:
|
||||
assert getattr(shared_user, attr, "err") != "err", f"got extra slot '{attr}'"
|
||||
assert len(mro_slots(shared_user)) == len(set(mro_slots(shared_user))), "duplicate slot"
|
||||
|
||||
def test_to_dict(self, shared_user):
|
||||
shared_user_dict = shared_user.to_dict()
|
||||
|
||||
assert isinstance(shared_user_dict, dict)
|
||||
assert shared_user_dict["user_id"] == self.user_id
|
||||
assert shared_user_dict["first_name"] == self.first_name
|
||||
assert shared_user_dict["last_name"] == self.last_name
|
||||
assert shared_user_dict["username"] == self.username
|
||||
assert shared_user_dict["photo"] == [photo.to_dict() for photo in self.photo]
|
||||
|
||||
def test_de_json_required(self, bot):
|
||||
json_dict = {
|
||||
"user_id": self.user_id,
|
||||
"first_name": self.first_name,
|
||||
}
|
||||
shared_user = SharedUser.de_json(json_dict, bot)
|
||||
assert shared_user.api_kwargs == {}
|
||||
|
||||
assert shared_user.user_id == self.user_id
|
||||
assert shared_user.first_name == self.first_name
|
||||
assert shared_user.last_name is None
|
||||
assert shared_user.username is None
|
||||
assert shared_user.photo == ()
|
||||
|
||||
def test_de_json_all(self, bot):
|
||||
json_dict = {
|
||||
"user_id": self.user_id,
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
"username": self.username,
|
||||
"photo": [photo.to_dict() for photo in self.photo],
|
||||
}
|
||||
shared_user = SharedUser.de_json(json_dict, bot)
|
||||
assert shared_user.api_kwargs == {}
|
||||
|
||||
assert shared_user.user_id == self.user_id
|
||||
assert shared_user.first_name == self.first_name
|
||||
assert shared_user.last_name == self.last_name
|
||||
assert shared_user.username == self.username
|
||||
assert shared_user.photo == self.photo
|
||||
|
||||
assert SharedUser.de_json({}, bot) is None
|
||||
|
||||
def test_equality(self, chat_shared):
|
||||
a = SharedUser(
|
||||
self.user_id,
|
||||
self.first_name,
|
||||
last_name=self.last_name,
|
||||
username=self.username,
|
||||
photo=self.photo,
|
||||
)
|
||||
b = SharedUser(self.user_id, "other_firs_name")
|
||||
c = SharedUser(self.user_id + 1, self.first_name)
|
||||
d = chat_shared
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
|
|
|
@ -23,6 +23,8 @@ from datetime import datetime
|
|||
import pytest
|
||||
|
||||
from telegram import (
|
||||
BusinessConnection,
|
||||
BusinessMessagesDeleted,
|
||||
CallbackQuery,
|
||||
Chat,
|
||||
ChatBoost,
|
||||
|
@ -119,6 +121,28 @@ message_reaction_count = MessageReactionCountUpdated(
|
|||
reactions=(ReactionCount(ReactionTypeEmoji("👍"), 1),),
|
||||
)
|
||||
|
||||
business_connection = BusinessConnection(
|
||||
"1",
|
||||
User(1, "name", False),
|
||||
1,
|
||||
from_timestamp(int(time.time())),
|
||||
True,
|
||||
True,
|
||||
)
|
||||
|
||||
deleted_business_messages = BusinessMessagesDeleted(
|
||||
"1",
|
||||
Chat(1, ""),
|
||||
(1, 2),
|
||||
)
|
||||
|
||||
business_message = Message(
|
||||
1,
|
||||
datetime.utcnow(),
|
||||
Chat(1, ""),
|
||||
User(1, "", False),
|
||||
)
|
||||
|
||||
|
||||
params = [
|
||||
{"message": message},
|
||||
|
@ -150,6 +174,10 @@ params = [
|
|||
{"removed_chat_boost": removed_chat_boost},
|
||||
{"message_reaction": message_reaction},
|
||||
{"message_reaction_count": message_reaction_count},
|
||||
{"business_connection": business_connection},
|
||||
{"deleted_business_messages": deleted_business_messages},
|
||||
{"business_message": business_message},
|
||||
{"edited_business_message": business_message},
|
||||
# Must be last to conform with `ids` below!
|
||||
{"callback_query": CallbackQuery(1, User(1, "", False), "chat")},
|
||||
]
|
||||
|
@ -173,6 +201,10 @@ all_types = (
|
|||
"removed_chat_boost",
|
||||
"message_reaction",
|
||||
"message_reaction_count",
|
||||
"business_connection",
|
||||
"deleted_business_messages",
|
||||
"business_message",
|
||||
"edited_business_message",
|
||||
)
|
||||
|
||||
ids = (*all_types, "callback_query_without_message")
|
||||
|
@ -257,6 +289,7 @@ class TestUpdateWithoutRequest(TestUpdateBase):
|
|||
or update.pre_checkout_query is not None
|
||||
or update.poll is not None
|
||||
or update.poll_answer is not None
|
||||
or update.business_connection is not None
|
||||
):
|
||||
assert chat.id == 1
|
||||
else:
|
||||
|
@ -272,6 +305,7 @@ class TestUpdateWithoutRequest(TestUpdateBase):
|
|||
or update.chat_boost is not None
|
||||
or update.removed_chat_boost is not None
|
||||
or update.message_reaction_count is not None
|
||||
or update.deleted_business_messages is not None
|
||||
):
|
||||
assert user.id == 1
|
||||
else:
|
||||
|
@ -297,6 +331,7 @@ class TestUpdateWithoutRequest(TestUpdateBase):
|
|||
or update.chat_boost is not None
|
||||
or update.removed_chat_boost is not None
|
||||
or update.message_reaction_count is not None
|
||||
or update.deleted_business_messages is not None
|
||||
):
|
||||
if update.channel_post or update.edited_channel_post:
|
||||
assert isinstance(sender, Chat)
|
||||
|
@ -329,6 +364,7 @@ class TestUpdateWithoutRequest(TestUpdateBase):
|
|||
or update.chat_boost is not None
|
||||
or update.removed_chat_boost is not None
|
||||
or update.message_reaction_count is not None
|
||||
or update.deleted_business_messages is not None
|
||||
):
|
||||
if (
|
||||
update.message
|
||||
|
@ -365,6 +401,8 @@ class TestUpdateWithoutRequest(TestUpdateBase):
|
|||
or update.removed_chat_boost is not None
|
||||
or update.message_reaction is not None
|
||||
or update.message_reaction_count is not None
|
||||
or update.deleted_business_messages is not None
|
||||
or update.business_connection is not None
|
||||
):
|
||||
assert eff_message.message_id == message.message_id
|
||||
else:
|
||||
|
|
|
@ -42,6 +42,7 @@ def json_dict():
|
|||
"supports_inline_queries": TestUserBase.supports_inline_queries,
|
||||
"is_premium": TestUserBase.is_premium,
|
||||
"added_to_attachment_menu": TestUserBase.added_to_attachment_menu,
|
||||
"can_connect_to_business": TestUserBase.can_connect_to_business,
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,6 +60,7 @@ def user(bot):
|
|||
supports_inline_queries=TestUserBase.supports_inline_queries,
|
||||
is_premium=TestUserBase.is_premium,
|
||||
added_to_attachment_menu=TestUserBase.added_to_attachment_menu,
|
||||
can_connect_to_business=TestUserBase.can_connect_to_business,
|
||||
)
|
||||
user.set_bot(bot)
|
||||
user._unfreeze()
|
||||
|
@ -77,6 +79,7 @@ class TestUserBase:
|
|||
supports_inline_queries = False
|
||||
is_premium = True
|
||||
added_to_attachment_menu = False
|
||||
can_connect_to_business = True
|
||||
|
||||
|
||||
class TestUserWithoutRequest(TestUserBase):
|
||||
|
@ -100,6 +103,7 @@ class TestUserWithoutRequest(TestUserBase):
|
|||
assert user.supports_inline_queries == self.supports_inline_queries
|
||||
assert user.is_premium == self.is_premium
|
||||
assert user.added_to_attachment_menu == self.added_to_attachment_menu
|
||||
assert user.can_connect_to_business == self.can_connect_to_business
|
||||
|
||||
def test_to_dict(self, user):
|
||||
user_dict = user.to_dict()
|
||||
|
@ -116,6 +120,7 @@ class TestUserWithoutRequest(TestUserBase):
|
|||
assert user_dict["supports_inline_queries"] == user.supports_inline_queries
|
||||
assert user_dict["is_premium"] == user.is_premium
|
||||
assert user_dict["added_to_attachment_menu"] == user.added_to_attachment_menu
|
||||
assert user_dict["can_connect_to_business"] == user.can_connect_to_business
|
||||
|
||||
def test_equality(self):
|
||||
a = User(self.id_, self.first_name, self.is_bot, self.last_name)
|
||||
|
|
Loading…
Reference in a new issue