From c6e4ab0e8e072b73da48077e4738c021da54496b Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sat, 16 Aug 2025 22:53:48 +0300 Subject: [PATCH 1/9] Add classes `SuggesstedPost[Parameters/Price]`. --- src/telegram/_suggestedpost.py | 143 +++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/telegram/_suggestedpost.py diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py new file mode 100644 index 00000000000..518b8fcfd19 --- /dev/null +++ b/src/telegram/_suggestedpost.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2025 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains objects related to Telegram suggested posts.""" + +import datetime as dtm +from typing import TYPE_CHECKING, Optional + +from telegram._telegramobject import TelegramObject +from telegram._utils.argumentparsing import de_json_optional +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 SuggestedPostPrice(TelegramObject): + """ + Desribes price of a suggested post. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`currency` and :attr:`amount` are equal. + + Args: + currency (:obj:`str`): + Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram + Stars or “TON” for toncoins. + amount (:obj:`int`): + The amount of the currency that will be paid for the post in the smallest units of the + currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must + be between 5 and 100000, and price in nanotoncoins must be between + 10000000 and 10000000000000. + + Attributes: + currency (:obj:`str`): + Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram + Stars or “TON” for toncoins. + amount (:obj:`int`): + The amount of the currency that will be paid for the post in the smallest units of the + currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must + be between 5 and 100000, and price in nanotoncoins must be between + 10000000 and 10000000000000. + + """ + + __slots__ = ("amount", "currency") + + def __init__( + self, + currency: str, + amount: int, + *, + api_kwargs: Optional[JSONDict] = None, + ): + super().__init__(api_kwargs=api_kwargs) + self.currency: str = currency + self.amount: Optional[dtm.datetime] = amount + + self._id_attrs = (self.currency, self.amount) + + self._freeze() + + +class SuggestedPostParameters(TelegramObject): + """ + Contains parameters of a post that is being suggested by the bot. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`price` and :attr:`send_date` are equal. + + Args: + price (:class:`telegram.SuggestedPostPrice`, optional): + Proposed price for the post. If the field is omitted, then the post is unpaid.. + send_date (:class:`datetime.datetime`, optional): + Proposed send date of the post. If specified, then the date + must be between 300 second and 2678400 seconds (30 days) in the future. If the field is + omitted, then the post can be published at any time within 30 days at the sole + discretion of the user who approves it. + + |datetime_localization| + + Attributes: + price (:class:`telegram.SuggestedPostPrice`): + Optional. Proposed price for the post. If the field is omitted, then the post + is unpaid. + send_date (:obj:`d`): + Optional. Proposed send date of the post. If specified, then the date + must be between 300 second and 2678400 seconds (30 days) in the future. If the field is + omitted, then the post can be published at any time within 30 days at the sole + discretion of the user who approves it. + + |datetime_localization| + + """ + + __slots__ = ("price", "send_date") + + def __init__( + self, + price: Optional[SuggestedPostPrice], + send_date: Optional[dtm.datetime] = None, + *, + api_kwargs: Optional[JSONDict] = None, + ): + super().__init__(api_kwargs=api_kwargs) + self.price: Optional[SuggestedPostPrice] = price + self.send_date: Optional[dtm.datetime] = send_date + + self._id_attrs = (self.price, self.send_date) + + self._freeze() + + @classmethod + def de_json( + cls, data: JSONDict, bot: Optional["Bot"] = None + ) -> "SuggestedPostParameters": + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot) + + # Get the local timezone from the bot if it has defaults + loc_tzinfo = extract_tzinfo_from_defaults(bot) + + data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo) + + return super().de_json(data=data, bot=bot) From c31eaaeef987dc2c85e1208ede948de9613240c7 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sat, 16 Aug 2025 21:28:10 +0000 Subject: [PATCH 2/9] Add chango fragment for PR #4912 --- changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml diff --git a/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml b/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml new file mode 100644 index 00000000000..cf866ca3793 --- /dev/null +++ b/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml @@ -0,0 +1,5 @@ +other = "Add classes `SuggestedPost[Parameters/Price]`." +[[pull_requests]] +uid = "4912" +author_uid = "aelkheir" +closes_threads = [] From d846de10ad6e6b4103ea5f89feeb96c47a24f2c7 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sun, 17 Aug 2025 05:25:19 +0300 Subject: [PATCH 3/9] Add tests and constants. --- docs/source/telegram.at-tree.rst | 2 + .../telegram.suggestedpostparameters.rst | 6 + docs/source/telegram.suggestedpostprice.rst | 6 + src/telegram/__init__.py | 3 + src/telegram/_suggestedpost.py | 53 +++--- src/telegram/constants.py | 41 +++++ tests/test_suggestedpost.py | 159 ++++++++++++++++++ 7 files changed, 248 insertions(+), 22 deletions(-) create mode 100644 docs/source/telegram.suggestedpostparameters.rst create mode 100644 docs/source/telegram.suggestedpostprice.rst create mode 100644 tests/test_suggestedpost.py diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index acfaf866f46..02816b8ecb1 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -168,6 +168,8 @@ Available Types telegram.storyareatypesuggestedreaction telegram.storyareatypeuniquegift telegram.storyareatypeweather + telegram.suggestedpostparameters.rst + telegram.suggestedpostprice.rst telegram.switchinlinequerychosenchat telegram.telegramobject telegram.textquote diff --git a/docs/source/telegram.suggestedpostparameters.rst b/docs/source/telegram.suggestedpostparameters.rst new file mode 100644 index 00000000000..5111d8fdd48 --- /dev/null +++ b/docs/source/telegram.suggestedpostparameters.rst @@ -0,0 +1,6 @@ +SuggestedPostParameters +======================= + +.. autoclass:: telegram.SuggestedPostParameters + :members: + :show-inheritance: diff --git a/docs/source/telegram.suggestedpostprice.rst b/docs/source/telegram.suggestedpostprice.rst new file mode 100644 index 00000000000..f5034e8f047 --- /dev/null +++ b/docs/source/telegram.suggestedpostprice.rst @@ -0,0 +1,6 @@ +SuggestedPostPrice +================== + +.. autoclass:: telegram.SuggestedPostPrice + :members: + :show-inheritance: diff --git a/src/telegram/__init__.py b/src/telegram/__init__.py index b0277a7e77a..5cf89142c5e 100644 --- a/src/telegram/__init__.py +++ b/src/telegram/__init__.py @@ -264,6 +264,8 @@ "StoryAreaTypeUniqueGift", "StoryAreaTypeWeather", "SuccessfulPayment", + "SuggestedPostParameters", + "SuggestedPostPrice", "SwitchInlineQueryChosenChat", "TelegramObject", "TextQuote", @@ -571,6 +573,7 @@ StoryAreaTypeUniqueGift, StoryAreaTypeWeather, ) +from ._suggestedpost import SuggestedPostParameters, SuggestedPostPrice from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat from ._telegramobject import TelegramObject from ._uniquegift import ( diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py index 518b8fcfd19..177a8c811a9 100644 --- a/src/telegram/_suggestedpost.py +++ b/src/telegram/_suggestedpost.py @@ -37,26 +37,33 @@ class SuggestedPostPrice(TelegramObject): Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`currency` and :attr:`amount` are equal. + .. versionadded:: NEXT.VERSION + Args: currency (:obj:`str`): - Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram - Stars or “TON” for toncoins. + Currency in which the post will be paid. Currently, must be one of `“XTR”` for Telegram + Stars or `“TON”` for toncoins. amount (:obj:`int`): The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must - be between 5 and 100000, and price in nanotoncoins must be between - 10000000 and 10000000000000. + be between :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_STARS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_STARS`, and price in + nanotoncoins must be between + :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_NANOTONCOINS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_NANOTONCOINS`. Attributes: currency (:obj:`str`): - Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram - Stars or “TON” for toncoins. + Currency in which the post will be paid. Currently, must be one of `“XTR”` for Telegram + Stars or `“TON”` for toncoins. amount (:obj:`int`): The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must - be between 5 and 100000, and price in nanotoncoins must be between - 10000000 and 10000000000000. - + be between :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_STARS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_STARS`, and price in + nanotoncoins must be between + :tg-const:`telegram.constants.SuggestedPost.MIN_PRICE_NANOTONCOINS` + and :tg-const:`telegram.constants.SuggestedPost.MAX_PRICE_NANOTONCOINS`. """ __slots__ = ("amount", "currency") @@ -70,7 +77,7 @@ def __init__( ): super().__init__(api_kwargs=api_kwargs) self.currency: str = currency - self.amount: Optional[dtm.datetime] = amount + self.amount: int = amount self._id_attrs = (self.currency, self.amount) @@ -84,15 +91,18 @@ class SuggestedPostParameters(TelegramObject): Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`price` and :attr:`send_date` are equal. + .. versionadded:: NEXT.VERSION + Args: price (:class:`telegram.SuggestedPostPrice`, optional): - Proposed price for the post. If the field is omitted, then the post is unpaid.. + Proposed price for the post. If the field is omitted, then the post is unpaid. send_date (:class:`datetime.datetime`, optional): Proposed send date of the post. If specified, then the date - must be between 300 second and 2678400 seconds (30 days) in the future. If the field is - omitted, then the post can be published at any time within 30 days at the sole - discretion of the user who approves it. - + must be between :tg-const:`telegram.constants.SuggestedPost.MIN_SEND_DATE` + second and :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) + in the future. If the field is omitted, then the post can be published at any time + within :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) at + the sole discretion of the user who approves it. |datetime_localization| Attributes: @@ -101,10 +111,11 @@ class SuggestedPostParameters(TelegramObject): is unpaid. send_date (:obj:`d`): Optional. Proposed send date of the post. If specified, then the date - must be between 300 second and 2678400 seconds (30 days) in the future. If the field is - omitted, then the post can be published at any time within 30 days at the sole - discretion of the user who approves it. - + must be between :tg-const:`telegram.constants.SuggestedPost.MIN_SEND_DATE` + second and :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) + in the future. If the field is omitted, then the post can be published at any time + within :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) at + the sole discretion of the user who approves it. |datetime_localization| """ @@ -127,9 +138,7 @@ def __init__( self._freeze() @classmethod - def de_json( - cls, data: JSONDict, bot: Optional["Bot"] = None - ) -> "SuggestedPostParameters": + def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostParameters": """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) diff --git a/src/telegram/constants.py b/src/telegram/constants.py index a403a78e0cd..3e277d08be4 100644 --- a/src/telegram/constants.py +++ b/src/telegram/constants.py @@ -117,6 +117,7 @@ "StoryAreaTypeLimit", "StoryAreaTypeType", "StoryLimit", + "SuggestedPost", "TransactionPartnerType", "TransactionPartnerUser", "UniqueGiftInfoOrigin", @@ -3054,6 +3055,46 @@ class StoryLimit(StringEnum): :meth:`telegram.Bot.post_story`.""" +class SuggestedPost(StringEnum): + """This enum contains limitations for :class:`telegram.SuggestedPostPrice`\ +/:class:`telegram.SuggestedPostParameters`. The enum + members of this enumeration are instances of :class:`int` and can be treated as such. + + .. versionadded:: NEXT.VERSION + """ + + __slots__ = () + + MIN_PRICE_STARS = 5 + """:obj:`int`: Minimum number of Telegram Stars in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MAX_PRICE_STARS = 100000 + """:obj:`int`: Maximum number of Telegram Stars in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MIN_PRICE_NANOTONCOINS = 10000000 + """:obj:`int`: Minimum number of nanotoncoins in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MAX_PRICE_NANOTONCOINS = 10000000000000 + """:obj:`int`: Maximum number of nanotoncoins in + :paramref:`~telegram.SuggestedPostPrice.amount` + parameter of :class:`telegram.SuggestedPostPrice`. + """ + MIN_SEND_DATE = 300 + """:obj:`int`: Minimum number of seconds in the future for + the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of + :class:`telegram.SuggestedPostParameters`.""" + MAX_SEND_DATE = 2678400 + """:obj:`int`: Maximum number of seconds in the future for + the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of + :class:`telegram.SuggestedPostParameters`.""" + + class TransactionPartnerType(StringEnum): """This enum contains the available types of :class:`telegram.TransactionPartner`. The enum members of this enumeration are instances of :class:`str` and can be treated as such. diff --git a/tests/test_suggestedpost.py b/tests/test_suggestedpost.py new file mode 100644 index 00000000000..603f0ee5084 --- /dev/null +++ b/tests/test_suggestedpost.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2025 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. + +import datetime as dtm + +import pytest + +from telegram import Dice +from telegram._suggestedpost import SuggestedPostParameters, SuggestedPostPrice +from telegram._utils.datetime import UTC, to_timestamp +from tests.auxil.slots import mro_slots + + +@pytest.fixture(scope="module") +def suggested_post_parameters(): + return SuggestedPostParameters( + price=SuggestedPostParameterTestBase.price, + send_date=SuggestedPostParameterTestBase.send_date, + ) + + +class SuggestedPostParameterTestBase: + price = SuggestedPostPrice(currency="XTR", amount=100) + send_date = dtm.datetime.now(tz=UTC).replace(microsecond=0) + + +class TestSuggestedPostParameterWithoutRequest(SuggestedPostParameterTestBase): + def test_slot_behaviour(self, suggested_post_parameters): + for attr in suggested_post_parameters.__slots__: + assert getattr(suggested_post_parameters, attr, "err") != "err", ( + f"got extra slot '{attr}'" + ) + assert len(mro_slots(suggested_post_parameters)) == len( + set(mro_slots(suggested_post_parameters)) + ), "duplicate slot" + + def test_de_json(self, offline_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + spp = SuggestedPostParameters.de_json(json_dict, offline_bot) + assert spp.price == self.price + assert spp.send_date == self.send_date + assert spp.api_kwargs == {} + + def test_de_json_localization(self, offline_bot, raw_bot, tz_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + + spp_bot = SuggestedPostParameters.de_json(json_dict, offline_bot) + spp_bot_raw = SuggestedPostParameters.de_json(json_dict, raw_bot) + spp_bot_tz = SuggestedPostParameters.de_json(json_dict, tz_bot) + + # comparing utcoffsets because comparing tzinfo objects is not reliable + send_date_offset = spp_bot_tz.send_date.utcoffset() + send_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset( + spp_bot_tz.send_date.replace(tzinfo=None) + ) + + assert spp_bot.send_date.tzinfo == UTC + assert spp_bot_raw.send_date.tzinfo == UTC + assert send_date_offset_tz == send_date_offset + + def test_to_dict(self, suggested_post_parameters): + spp_dict = suggested_post_parameters.to_dict() + + assert isinstance(spp_dict, dict) + assert spp_dict["price"] == self.price.to_dict() + assert spp_dict["send_date"] == to_timestamp(self.send_date) + + def test_equality(self, suggested_post_parameters): + a = suggested_post_parameters + b = SuggestedPostParameters(price=self.price, send_date=self.send_date) + c = SuggestedPostParameters( + price=self.price, send_date=self.send_date + dtm.timedelta(seconds=1) + ) + e = Dice(4, "emoji") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != e + assert hash(a) != hash(e) + + +@pytest.fixture(scope="module") +def suggested_post_price(): + return SuggestedPostPrice( + currency=SuggestedPostPriceTestBase.currency, + amount=SuggestedPostPriceTestBase.amount, + ) + + +class SuggestedPostPriceTestBase: + currency = "XTR" + amount = 100 + + +class TestSuggestedPostPriceWithoutRequest(SuggestedPostPriceTestBase): + def test_slot_behaviour(self, suggested_post_price): + for attr in suggested_post_price.__slots__: + assert getattr(suggested_post_price, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(suggested_post_price)) == len(set(mro_slots(suggested_post_price))), ( + "duplicate slot" + ) + + def test_de_json(self, offline_bot): + json_dict = { + "currency": self.currency, + "amount": self.amount, + } + spp = SuggestedPostPrice.de_json(json_dict, offline_bot) + assert spp.currency == self.currency + assert spp.amount == self.amount + assert spp.api_kwargs == {} + + def test_to_dict(self, suggested_post_price): + spp_dict = suggested_post_price.to_dict() + + assert isinstance(spp_dict, dict) + assert spp_dict["currency"] == self.currency + assert spp_dict["amount"] == self.amount + + def test_equality(self, suggested_post_price): + a = suggested_post_price + b = SuggestedPostPrice(currency=self.currency, amount=self.amount) + c = SuggestedPostPrice(currency="TON", amount=self.amount) + e = Dice(4, "emoji") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != e + assert hash(a) != hash(e) From 5431050c84aa1237f2375d47a3f3ade409312305 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:16:33 +0300 Subject: [PATCH 4/9] Add `suggested_post_parameters` to bot methods and shorcuts. --- docs/substitutions/global.rst | 2 + src/telegram/_bot.py | 106 +++++++++++++++++++++++++++++++++ src/telegram/_callbackquery.py | 3 + src/telegram/_chat.py | 39 ++++++++++++ src/telegram/_message.py | 43 +++++++++++++ src/telegram/_suggestedpost.py | 2 +- src/telegram/_user.py | 37 ++++++++++++ src/telegram/ext/_extbot.py | 37 ++++++++++++ tests/test_bot.py | 18 ++++++ 9 files changed, 286 insertions(+), 1 deletion(-) diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index c161278591a..35b387e2e54 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -96,6 +96,8 @@ .. |allow_paid_broadcast| replace:: Pass True to allow up to :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second, ignoring `broadcasting limits `__ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance. +.. |suggested_post_parameters| replace:: An object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined. + .. |tz-naive-dtms| replace:: For timezone naive :obj:`datetime.datetime` objects, the default timezone of the bot will be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used. .. |org-verify| replace:: `on behalf of the organization `__ diff --git a/src/telegram/_bot.py b/src/telegram/_bot.py index 33fba87e798..b9d603dde26 100644 --- a/src/telegram/_bot.py +++ b/src/telegram/_bot.py @@ -136,6 +136,7 @@ PassportElementError, ShippingOption, StoryArea, + SuggestedPostParameters, ) BT = TypeVar("BT", bound="Bot") @@ -758,6 +759,7 @@ async def _send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -808,6 +810,7 @@ async def _send_message( "protect_content": protect_content, "reply_markup": reply_markup, "reply_parameters": reply_parameters, + "suggested_post_parameters": suggested_post_parameters, } ) @@ -1003,6 +1006,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1057,6 +1061,10 @@ async def send_message( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1116,6 +1124,7 @@ async def send_message( reply_parameters=reply_parameters, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -1232,6 +1241,7 @@ async def forward_message( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1267,6 +1277,10 @@ async def forward_message( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 + suggested_post_parameters (:obj:`bool`, optional): An object containing the parameters + of the suggested post to send; for direct messages chats only. + + .. versionadded:: NEXT.VERSION Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -1287,6 +1301,7 @@ async def forward_message( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -1373,6 +1388,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1445,6 +1461,11 @@ async def send_photo( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1506,6 +1527,7 @@ async def send_photo( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -1527,6 +1549,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1609,6 +1632,10 @@ async def send_audio( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1672,6 +1699,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -1691,6 +1719,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1768,6 +1797,10 @@ async def send_document( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1827,6 +1860,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1842,6 +1876,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -1899,6 +1934,10 @@ async def send_sticker( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -1950,6 +1989,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1976,6 +2016,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2076,6 +2117,10 @@ async def send_video( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2144,6 +2189,7 @@ async def send_video( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -2161,6 +2207,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2237,6 +2284,10 @@ async def send_video_note( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2296,6 +2347,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -2319,6 +2371,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2406,6 +2459,10 @@ async def send_animation( show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med| .. versionadded:: 21.3 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2471,6 +2528,7 @@ async def send_animation( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -2489,6 +2547,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2567,6 +2626,10 @@ async def send_voice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2627,6 +2690,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -2824,6 +2888,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -2890,6 +2955,10 @@ async def send_location( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -2961,6 +3030,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def edit_message_live_location( @@ -3148,6 +3218,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3206,6 +3277,10 @@ async def send_venue( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -3288,6 +3363,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_contact( @@ -3305,6 +3381,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3353,6 +3430,10 @@ async def send_contact( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -3426,6 +3507,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -5231,6 +5313,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -5351,6 +5434,10 @@ async def send_invoice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -5421,6 +5508,7 @@ async def send_invoice( api_kwargs=api_kwargs, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def answer_shipping_query( @@ -7707,6 +7795,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -7759,6 +7848,10 @@ async def send_dice( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -7808,6 +7901,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def get_my_default_administrator_rights( @@ -8140,6 +8234,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -8194,6 +8289,10 @@ async def copy_message( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -8254,6 +8353,7 @@ async def copy_message( "show_caption_above_media": show_caption_above_media, "allow_paid_broadcast": allow_paid_broadcast, "video_start_timestamp": video_start_timestamp, + "suggested_post_parameters": suggested_post_parameters, } result = await self._post( @@ -10729,6 +10829,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -10775,6 +10876,10 @@ async def send_paid_media( allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast| .. versionadded:: 21.7 + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): + |suggested_post_parameters| + + .. versionadded:: NEXT.VERSION Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| @@ -10819,6 +10924,7 @@ async def send_paid_media( api_kwargs=api_kwargs, business_connection_id=business_connection_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def create_chat_subscription_invite_link( diff --git a/src/telegram/_callbackquery.py b/src/telegram/_callbackquery.py index 18b5980e6c6..666bdc03bde 100644 --- a/src/telegram/_callbackquery.py +++ b/src/telegram/_callbackquery.py @@ -42,6 +42,7 @@ MessageEntity, MessageId, ReplyParameters, + SuggestedPostParameters, ) @@ -871,6 +872,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -920,6 +922,7 @@ async def copy_message( reply_parameters=reply_parameters, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) MAX_ANSWER_TEXT_LENGTH: Final[int] = ( diff --git a/src/telegram/_chat.py b/src/telegram/_chat.py index 53e4934523b..64c6d640c05 100644 --- a/src/telegram/_chat.py +++ b/src/telegram/_chat.py @@ -71,6 +71,7 @@ PhotoSize, ReplyParameters, Sticker, + SuggestedPostParameters, UserChatBoosts, Venue, Video, @@ -1018,6 +1019,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1060,6 +1062,7 @@ async def send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def delete_message( @@ -1236,6 +1239,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1280,6 +1284,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_contact( @@ -1296,6 +1301,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1338,6 +1344,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -1358,6 +1365,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1404,6 +1412,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -1422,6 +1431,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1466,6 +1476,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_checklist( @@ -1527,6 +1538,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1564,6 +1576,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -1646,6 +1659,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1712,6 +1726,7 @@ async def send_invoice( reply_parameters=reply_parameters, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -1730,6 +1745,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1774,6 +1790,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -1796,6 +1813,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1844,6 +1862,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1858,6 +1877,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1896,6 +1916,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -1916,6 +1937,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1962,6 +1984,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1987,6 +2010,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2038,6 +2062,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -2054,6 +2079,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2096,6 +2122,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -2113,6 +2140,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2156,6 +2184,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -2249,6 +2278,7 @@ async def send_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2292,6 +2322,7 @@ async def send_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_message( @@ -2309,6 +2340,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2352,6 +2384,7 @@ async def copy_message( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_copies( @@ -2452,6 +2485,7 @@ async def forward_from( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2486,6 +2520,7 @@ async def forward_from( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_to( @@ -2496,6 +2531,7 @@ async def forward_to( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2531,6 +2567,7 @@ async def forward_to( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_messages_from( @@ -3456,6 +3493,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -3499,6 +3537,7 @@ async def send_paid_media( business_connection_id=business_connection_id, payload=payload, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_gift( diff --git a/src/telegram/_message.py b/src/telegram/_message.py index 16a4cd65ea3..8c20f1a9e13 100644 --- a/src/telegram/_message.py +++ b/src/telegram/_message.py @@ -118,6 +118,7 @@ MessageId, MessageOrigin, ReactionType, + SuggestedPostParameters, TextQuote, ) @@ -1865,6 +1866,7 @@ async def reply_text( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1927,6 +1929,7 @@ async def reply_text( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_markdown( @@ -1941,6 +1944,7 @@ async def reply_markdown( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2009,6 +2013,7 @@ async def reply_markdown( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_markdown_v2( @@ -2023,6 +2028,7 @@ async def reply_markdown_v2( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2087,6 +2093,7 @@ async def reply_markdown_v2( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_html( @@ -2101,6 +2108,7 @@ async def reply_html( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2165,6 +2173,7 @@ async def reply_html( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_media_group( @@ -2259,6 +2268,7 @@ async def reply_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2323,6 +2333,7 @@ async def reply_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_audio( @@ -2342,6 +2353,7 @@ async def reply_audio( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2408,6 +2420,7 @@ async def reply_audio( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_document( @@ -2425,6 +2438,7 @@ async def reply_document( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2489,6 +2503,7 @@ async def reply_document( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_animation( @@ -2510,6 +2525,7 @@ async def reply_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2578,6 +2594,7 @@ async def reply_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_sticker( @@ -2591,6 +2608,7 @@ async def reply_sticker( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2649,6 +2667,7 @@ async def reply_sticker( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_video( @@ -2673,6 +2692,7 @@ async def reply_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2744,6 +2764,7 @@ async def reply_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def reply_video_note( @@ -2759,6 +2780,7 @@ async def reply_video_note( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2821,6 +2843,7 @@ async def reply_video_note( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_voice( @@ -2837,6 +2860,7 @@ async def reply_voice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2900,6 +2924,7 @@ async def reply_voice( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_location( @@ -2917,6 +2942,7 @@ async def reply_location( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2981,6 +3007,7 @@ async def reply_location( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_venue( @@ -3000,6 +3027,7 @@ async def reply_venue( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3066,6 +3094,7 @@ async def reply_venue( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_contact( @@ -3081,6 +3110,7 @@ async def reply_contact( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3143,6 +3173,7 @@ async def reply_contact( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_poll( @@ -3250,6 +3281,7 @@ async def reply_dice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3307,6 +3339,7 @@ async def reply_dice( business_connection_id=self.business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_checklist( @@ -3511,6 +3544,7 @@ async def reply_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3598,6 +3632,7 @@ async def reply_invoice( message_thread_id=message_thread_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def forward( @@ -3607,6 +3642,7 @@ async def forward( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3645,6 +3681,7 @@ async def forward( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -3666,6 +3703,7 @@ async def copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3713,6 +3751,7 @@ async def copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_copy( @@ -3730,6 +3769,7 @@ async def reply_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3791,6 +3831,7 @@ async def reply_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def reply_paid_media( @@ -3807,6 +3848,7 @@ async def reply_paid_media( reply_markup: Optional[ReplyMarkup] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3860,6 +3902,7 @@ async def reply_paid_media( protect_content=protect_content, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def edit_text( diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py index 177a8c811a9..3c7c7e60d7b 100644 --- a/src/telegram/_suggestedpost.py +++ b/src/telegram/_suggestedpost.py @@ -124,7 +124,7 @@ class SuggestedPostParameters(TelegramObject): def __init__( self, - price: Optional[SuggestedPostPrice], + price: Optional[SuggestedPostPrice] = None, send_date: Optional[dtm.datetime] = None, *, api_kwargs: Optional[JSONDict] = None, diff --git a/src/telegram/_user.py b/src/telegram/_user.py index ca9cd637193..370f41b7d7c 100644 --- a/src/telegram/_user.py +++ b/src/telegram/_user.py @@ -61,6 +61,7 @@ PhotoSize, ReplyParameters, Sticker, + SuggestedPostParameters, UserChatBoosts, UserProfilePhotos, Venue, @@ -435,6 +436,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, disable_web_page_preview: Optional[bool] = None, @@ -480,6 +482,7 @@ async def send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def delete_message( @@ -562,6 +565,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -609,6 +613,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -689,6 +694,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -738,6 +744,7 @@ async def send_audio( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_chat_action( @@ -794,6 +801,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -839,6 +847,7 @@ async def send_contact( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_dice( @@ -852,6 +861,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -892,6 +902,7 @@ async def send_dice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -910,6 +921,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -957,6 +969,7 @@ async def send_document( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -1042,6 +1055,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1111,6 +1125,7 @@ async def send_invoice( message_thread_id=message_thread_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -1129,6 +1144,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1176,6 +1192,7 @@ async def send_location( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_animation( @@ -1198,6 +1215,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1249,6 +1267,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_sticker( @@ -1263,6 +1282,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1304,6 +1324,7 @@ async def send_sticker( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -1329,6 +1350,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1383,6 +1405,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -1403,6 +1426,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1452,6 +1476,7 @@ async def send_venue( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -1468,6 +1493,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1513,6 +1539,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -1530,6 +1557,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1576,6 +1604,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -1752,6 +1781,7 @@ async def send_copy( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1796,6 +1826,7 @@ async def send_copy( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_message( @@ -1813,6 +1844,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -1857,6 +1889,7 @@ async def copy_message( message_thread_id=message_thread_id, show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_copies( @@ -1957,6 +1990,7 @@ async def forward_from( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1991,6 +2025,7 @@ async def forward_from( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_to( @@ -2001,6 +2036,7 @@ async def forward_to( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2036,6 +2072,7 @@ async def forward_to( api_kwargs=api_kwargs, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, ) async def forward_messages_from( diff --git a/src/telegram/ext/_extbot.py b/src/telegram/ext/_extbot.py index 1f9e14644c9..32c0f245bd9 100644 --- a/src/telegram/ext/_extbot.py +++ b/src/telegram/ext/_extbot.py @@ -129,6 +129,7 @@ PassportElementError, ShippingOption, StoryArea, + SuggestedPostParameters, ) from telegram.ext import BaseRateLimiter, Defaults @@ -617,6 +618,7 @@ async def _send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -650,6 +652,7 @@ async def _send_message( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) if isinstance(result, Message): self._insert_callback_data(result) @@ -829,6 +832,7 @@ async def copy_message( show_caption_above_media: Optional[bool] = None, allow_paid_broadcast: Optional[bool] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -862,6 +866,7 @@ async def copy_message( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), show_caption_above_media=show_caption_above_media, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def copy_messages( @@ -1768,6 +1773,7 @@ async def forward_message( protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, video_start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1784,6 +1790,7 @@ async def forward_message( disable_notification=disable_notification, protect_content=protect_content, message_thread_id=message_thread_id, + suggested_post_parameters=suggested_post_parameters, read_timeout=read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, @@ -2466,6 +2473,7 @@ async def send_animation( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2505,6 +2513,7 @@ async def send_animation( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_audio( @@ -2526,6 +2535,7 @@ async def send_audio( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2563,6 +2573,7 @@ async def send_audio( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_chat_action( @@ -2606,6 +2617,7 @@ async def send_contact( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2639,6 +2651,7 @@ async def send_contact( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_checklist( @@ -2719,6 +2732,7 @@ async def send_dice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2747,6 +2761,7 @@ async def send_dice( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_document( @@ -2766,6 +2781,7 @@ async def send_document( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2801,6 +2817,7 @@ async def send_document( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_game( @@ -2876,6 +2893,7 @@ async def send_invoice( reply_parameters: Optional["ReplyParameters"] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2923,6 +2941,7 @@ async def send_invoice( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_location( @@ -2942,6 +2961,7 @@ async def send_location( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -2977,6 +2997,7 @@ async def send_location( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_media_group( @@ -3042,6 +3063,7 @@ async def send_message( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, disable_web_page_preview: Optional[bool] = None, reply_to_message_id: Optional[int] = None, @@ -3075,6 +3097,7 @@ async def send_message( link_preview_options=link_preview_options, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_photo( @@ -3094,6 +3117,7 @@ async def send_photo( message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, show_caption_above_media: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3129,6 +3153,7 @@ async def send_photo( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_poll( @@ -3212,6 +3237,7 @@ async def send_sticker( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3241,6 +3267,7 @@ async def send_sticker( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_venue( @@ -3262,6 +3289,7 @@ async def send_venue( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3299,6 +3327,7 @@ async def send_venue( api_kwargs=self._merge_api_rl_kwargs(api_kwargs, rate_limit_args), message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_video( @@ -3325,6 +3354,7 @@ async def send_video( show_caption_above_media: Optional[bool] = None, cover: Optional[FileInput] = None, start_timestamp: Optional[int] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3367,6 +3397,7 @@ async def send_video( message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, show_caption_above_media=show_caption_above_media, + suggested_post_parameters=suggested_post_parameters, ) async def send_video_note( @@ -3384,6 +3415,7 @@ async def send_video_note( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3417,6 +3449,7 @@ async def send_video_note( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def send_voice( @@ -3435,6 +3468,7 @@ async def send_voice( business_connection_id: Optional[str] = None, message_effect_id: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, reply_to_message_id: Optional[int] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, @@ -3469,6 +3503,7 @@ async def send_voice( business_connection_id=business_connection_id, message_effect_id=message_effect_id, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def set_chat_administrator_custom_title( @@ -4907,6 +4942,7 @@ async def send_paid_media( business_connection_id: Optional[str] = None, payload: Optional[str] = None, allow_paid_broadcast: Optional[bool] = None, + suggested_post_parameters: Optional["SuggestedPostParameters"] = None, *, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_to_message_id: Optional[int] = None, @@ -4939,6 +4975,7 @@ async def send_paid_media( business_connection_id=business_connection_id, payload=payload, allow_paid_broadcast=allow_paid_broadcast, + suggested_post_parameters=suggested_post_parameters, ) async def create_chat_subscription_invite_link( diff --git a/tests/test_bot.py b/tests/test_bot.py index 6ecf041f77a..c54bc0b3697 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -75,6 +75,8 @@ ShippingOption, StarTransaction, StarTransactions, + SuggestedPostParameters, + SuggestedPostPrice, Update, User, WebAppInfo, @@ -2373,6 +2375,22 @@ async def make_assertion(url, request_data: RequestData, *args, **kwargs): monkeypatch.setattr(offline_bot.request, "post", make_assertion) assert await offline_bot.send_message(2, "text", allow_paid_broadcast=42) + async def test_suggested_post_parameters_argument(self, offline_bot, monkeypatch): + """We can't test every single method easily, so we just test one. Our linting will catch + any unused args with the others.""" + suggested_post_parameters = SuggestedPostParameters(price=SuggestedPostPrice("TON", 10)) + + async def make_assertion(url, request_data: RequestData, *args, **kwargs): + return ( + request_data.parameters.get("suggested_post_parameters") + == suggested_post_parameters.to_dict() + ) + + monkeypatch.setattr(offline_bot.request, "post", make_assertion) + assert await offline_bot.send_message( + 2, "text", suggested_post_parameters=suggested_post_parameters + ) + async def test_send_chat_action_all_args(self, bot, chat_id, monkeypatch): async def make_assertion(*args, **_): kwargs = args[1] From 3a1212c39762e8a97b5e26c8110a5c56a88dda11 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:36:44 +0300 Subject: [PATCH 5/9] Update master chango fragment and remove local. --- changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml | 1 + changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml diff --git a/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml b/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml index 771c28c63ba..94cef0849eb 100644 --- a/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml +++ b/changes/unreleased/4911.kiF45Y4cfPGMq5cuLpa5da.toml @@ -2,4 +2,5 @@ features = "Full Support for Bot API 9.2" pull_requests = [ { uid = "4911", author_uid = "aelkheir", closes_threads = ["4910"] }, + { uid = "4912", author_uid = "aelkheir" }, ] diff --git a/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml b/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml deleted file mode 100644 index cf866ca3793..00000000000 --- a/changes/unreleased/4912.b8UNeWAyD2KQtDT6gHsPXK.toml +++ /dev/null @@ -1,5 +0,0 @@ -other = "Add classes `SuggestedPost[Parameters/Price]`." -[[pull_requests]] -uid = "4912" -author_uid = "aelkheir" -closes_threads = [] From 94e8ffa377664633494750fee2125152dfb73b1d Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sun, 17 Aug 2025 17:47:14 +0300 Subject: [PATCH 6/9] Remove redundant `de_json`s. --- src/telegram/_suggestedpost.py | 21 +--------------- tests/test_suggestedpost.py | 44 +++++----------------------------- 2 files changed, 7 insertions(+), 58 deletions(-) diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py index 3c7c7e60d7b..dd67c174b99 100644 --- a/src/telegram/_suggestedpost.py +++ b/src/telegram/_suggestedpost.py @@ -19,16 +19,11 @@ """This module contains objects related to Telegram suggested posts.""" import datetime as dtm -from typing import TYPE_CHECKING, Optional +from typing import Optional from telegram._telegramobject import TelegramObject -from telegram._utils.argumentparsing import de_json_optional -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 SuggestedPostPrice(TelegramObject): """ @@ -136,17 +131,3 @@ def __init__( self._id_attrs = (self.price, self.send_date) self._freeze() - - @classmethod - def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostParameters": - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot) - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo) - - return super().de_json(data=data, bot=bot) diff --git a/tests/test_suggestedpost.py b/tests/test_suggestedpost.py index 603f0ee5084..f3c609eb388 100644 --- a/tests/test_suggestedpost.py +++ b/tests/test_suggestedpost.py @@ -50,35 +50,9 @@ def test_slot_behaviour(self, suggested_post_parameters): set(mro_slots(suggested_post_parameters)) ), "duplicate slot" - def test_de_json(self, offline_bot): - json_dict = { - "price": self.price.to_dict(), - "send_date": to_timestamp(self.send_date), - } - spp = SuggestedPostParameters.de_json(json_dict, offline_bot) - assert spp.price == self.price - assert spp.send_date == self.send_date - assert spp.api_kwargs == {} - - def test_de_json_localization(self, offline_bot, raw_bot, tz_bot): - json_dict = { - "price": self.price.to_dict(), - "send_date": to_timestamp(self.send_date), - } - - spp_bot = SuggestedPostParameters.de_json(json_dict, offline_bot) - spp_bot_raw = SuggestedPostParameters.de_json(json_dict, raw_bot) - spp_bot_tz = SuggestedPostParameters.de_json(json_dict, tz_bot) - - # comparing utcoffsets because comparing tzinfo objects is not reliable - send_date_offset = spp_bot_tz.send_date.utcoffset() - send_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset( - spp_bot_tz.send_date.replace(tzinfo=None) - ) - - assert spp_bot.send_date.tzinfo == UTC - assert spp_bot_raw.send_date.tzinfo == UTC - assert send_date_offset_tz == send_date_offset + def test_expected_values(self, suggested_post_parameters): + assert suggested_post_parameters.price == self.price + assert suggested_post_parameters.send_date == self.send_date def test_to_dict(self, suggested_post_parameters): spp_dict = suggested_post_parameters.to_dict() @@ -126,15 +100,9 @@ def test_slot_behaviour(self, suggested_post_price): "duplicate slot" ) - def test_de_json(self, offline_bot): - json_dict = { - "currency": self.currency, - "amount": self.amount, - } - spp = SuggestedPostPrice.de_json(json_dict, offline_bot) - assert spp.currency == self.currency - assert spp.amount == self.amount - assert spp.api_kwargs == {} + def test_expected_values(self, suggested_post_price): + assert suggested_post_price.currency == self.currency + assert suggested_post_price.amount == self.amount def test_to_dict(self, suggested_post_price): spp_dict = suggested_post_price.to_dict() From 8682c77e38d91f1f7fa4d1f21c78df886d8daf19 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Mon, 18 Aug 2025 20:37:49 +0300 Subject: [PATCH 7/9] review: address comments --- src/telegram/_bot.py | 5 +++-- src/telegram/_suggestedpost.py | 18 +++++++++--------- src/telegram/constants.py | 10 +++++----- tests/test_suggestedpost.py | 8 ++++---- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/telegram/_bot.py b/src/telegram/_bot.py index b9d603dde26..03c3a03992e 100644 --- a/src/telegram/_bot.py +++ b/src/telegram/_bot.py @@ -1277,8 +1277,9 @@ async def forward_message( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - suggested_post_parameters (:obj:`bool`, optional): An object containing the parameters - of the suggested post to send; for direct messages chats only. + suggested_post_parameters (:class:`telegram.SuggestedPostParameters`, optional): An + object containing the parameters of the suggested post to send; for direct messages + chats only. .. versionadded:: NEXT.VERSION diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py index dd67c174b99..fc21852f451 100644 --- a/src/telegram/_suggestedpost.py +++ b/src/telegram/_suggestedpost.py @@ -19,7 +19,7 @@ """This module contains objects related to Telegram suggested posts.""" import datetime as dtm -from typing import Optional +from typing import Literal, Optional from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict @@ -27,7 +27,7 @@ class SuggestedPostPrice(TelegramObject): """ - Desribes price of a suggested post. + Desribes the price of a suggested post. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`currency` and :attr:`amount` are equal. @@ -36,8 +36,8 @@ class SuggestedPostPrice(TelegramObject): Args: currency (:obj:`str`): - Currency in which the post will be paid. Currently, must be one of `“XTR”` for Telegram - Stars or `“TON”` for toncoins. + Currency in which the post will be paid. Currently, must be one of ``“XTR”`` for + Telegram Stars or ``“TON”`` for toncoins. amount (:obj:`int`): The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must @@ -49,8 +49,8 @@ class SuggestedPostPrice(TelegramObject): Attributes: currency (:obj:`str`): - Currency in which the post will be paid. Currently, must be one of `“XTR”` for Telegram - Stars or `“TON”` for toncoins. + Currency in which the post will be paid. Currently, must be one of ``“XTR”`` for + Telegram Stars or ``“TON”`` for toncoins. amount (:obj:`int`): The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must @@ -65,13 +65,13 @@ class SuggestedPostPrice(TelegramObject): def __init__( self, - currency: str, + currency: Literal["XTR", "TON"], amount: int, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) - self.currency: str = currency + self.currency: Literal["XTR", "TON"] = currency self.amount: int = amount self._id_attrs = (self.currency, self.amount) @@ -104,7 +104,7 @@ class SuggestedPostParameters(TelegramObject): price (:class:`telegram.SuggestedPostPrice`): Optional. Proposed price for the post. If the field is omitted, then the post is unpaid. - send_date (:obj:`d`): + send_date (:class:`datetime.datetime`): Optional. Proposed send date of the post. If specified, then the date must be between :tg-const:`telegram.constants.SuggestedPost.MIN_SEND_DATE` second and :tg-const:`telegram.constants.SuggestedPost.MAX_SEND_DATE` seconds (30 days) diff --git a/src/telegram/constants.py b/src/telegram/constants.py index e194be3b042..0fdd801c017 100644 --- a/src/telegram/constants.py +++ b/src/telegram/constants.py @@ -3055,7 +3055,7 @@ class StoryLimit(StringEnum): :meth:`telegram.Bot.post_story`.""" -class SuggestedPost(StringEnum): +class SuggestedPost(IntEnum): """This enum contains limitations for :class:`telegram.SuggestedPostPrice`\ /:class:`telegram.SuggestedPostParameters`. The enum members of this enumeration are instances of :class:`int` and can be treated as such. @@ -3070,17 +3070,17 @@ class SuggestedPost(StringEnum): :paramref:`~telegram.SuggestedPostPrice.amount` parameter of :class:`telegram.SuggestedPostPrice`. """ - MAX_PRICE_STARS = 100000 + MAX_PRICE_STARS = 100_000 """:obj:`int`: Maximum number of Telegram Stars in :paramref:`~telegram.SuggestedPostPrice.amount` parameter of :class:`telegram.SuggestedPostPrice`. """ - MIN_PRICE_NANOTONCOINS = 10000000 + MIN_PRICE_NANOTONCOINS = 10_000_000 """:obj:`int`: Minimum number of nanotoncoins in :paramref:`~telegram.SuggestedPostPrice.amount` parameter of :class:`telegram.SuggestedPostPrice`. """ - MAX_PRICE_NANOTONCOINS = 10000000000000 + MAX_PRICE_NANOTONCOINS = 10_000_000_000_000 """:obj:`int`: Maximum number of nanotoncoins in :paramref:`~telegram.SuggestedPostPrice.amount` parameter of :class:`telegram.SuggestedPostPrice`. @@ -3089,7 +3089,7 @@ class SuggestedPost(StringEnum): """:obj:`int`: Minimum number of seconds in the future for the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of :class:`telegram.SuggestedPostParameters`.""" - MAX_SEND_DATE = 2678400 + MAX_SEND_DATE = 2_678_400 """:obj:`int`: Maximum number of seconds in the future for the :paramref:`~telegram.SuggestedPostParameters.send_date` parameter of :class:`telegram.SuggestedPostParameters`.""" diff --git a/tests/test_suggestedpost.py b/tests/test_suggestedpost.py index f3c609eb388..d400fa88bdd 100644 --- a/tests/test_suggestedpost.py +++ b/tests/test_suggestedpost.py @@ -30,17 +30,17 @@ @pytest.fixture(scope="module") def suggested_post_parameters(): return SuggestedPostParameters( - price=SuggestedPostParameterTestBase.price, - send_date=SuggestedPostParameterTestBase.send_date, + price=SuggestedPostParametersTestBase.price, + send_date=SuggestedPostParametersTestBase.send_date, ) -class SuggestedPostParameterTestBase: +class SuggestedPostParametersTestBase: price = SuggestedPostPrice(currency="XTR", amount=100) send_date = dtm.datetime.now(tz=UTC).replace(microsecond=0) -class TestSuggestedPostParameterWithoutRequest(SuggestedPostParameterTestBase): +class TestSuggestedPostParametersWithoutRequest(SuggestedPostParametersTestBase): def test_slot_behaviour(self, suggested_post_parameters): for attr in suggested_post_parameters.__slots__: assert getattr(suggested_post_parameters, attr, "err") != "err", ( From 2d988468b9665c4dc5bdace8372b6f18b94a7944 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:58:36 +0300 Subject: [PATCH 8/9] Revert "Remove redundant `de_json`s." This reverts commit 94e8ffa377664633494750fee2125152dfb73b1d. Conflicts: src/telegram/_suggestedpost.py --- src/telegram/_suggestedpost.py | 21 +++++++++++++++- tests/test_suggestedpost.py | 44 +++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/telegram/_suggestedpost.py b/src/telegram/_suggestedpost.py index fc21852f451..fc597e3aad1 100644 --- a/src/telegram/_suggestedpost.py +++ b/src/telegram/_suggestedpost.py @@ -19,11 +19,16 @@ """This module contains objects related to Telegram suggested posts.""" import datetime as dtm -from typing import Literal, Optional +from typing import TYPE_CHECKING, Literal, Optional from telegram._telegramobject import TelegramObject +from telegram._utils.argumentparsing import de_json_optional +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 SuggestedPostPrice(TelegramObject): """ @@ -131,3 +136,17 @@ def __init__( self._id_attrs = (self.price, self.send_date) self._freeze() + + @classmethod + def de_json(cls, data: JSONDict, bot: Optional["Bot"] = None) -> "SuggestedPostParameters": + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + data["price"] = de_json_optional(data.get("price"), SuggestedPostPrice, bot) + + # Get the local timezone from the bot if it has defaults + loc_tzinfo = extract_tzinfo_from_defaults(bot) + + data["send_date"] = from_timestamp(data.get("send_date"), tzinfo=loc_tzinfo) + + return super().de_json(data=data, bot=bot) diff --git a/tests/test_suggestedpost.py b/tests/test_suggestedpost.py index d400fa88bdd..73fa9206779 100644 --- a/tests/test_suggestedpost.py +++ b/tests/test_suggestedpost.py @@ -50,9 +50,35 @@ def test_slot_behaviour(self, suggested_post_parameters): set(mro_slots(suggested_post_parameters)) ), "duplicate slot" - def test_expected_values(self, suggested_post_parameters): - assert suggested_post_parameters.price == self.price - assert suggested_post_parameters.send_date == self.send_date + def test_de_json(self, offline_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + spp = SuggestedPostParameters.de_json(json_dict, offline_bot) + assert spp.price == self.price + assert spp.send_date == self.send_date + assert spp.api_kwargs == {} + + def test_de_json_localization(self, offline_bot, raw_bot, tz_bot): + json_dict = { + "price": self.price.to_dict(), + "send_date": to_timestamp(self.send_date), + } + + spp_bot = SuggestedPostParameters.de_json(json_dict, offline_bot) + spp_bot_raw = SuggestedPostParameters.de_json(json_dict, raw_bot) + spp_bot_tz = SuggestedPostParameters.de_json(json_dict, tz_bot) + + # comparing utcoffsets because comparing tzinfo objects is not reliable + send_date_offset = spp_bot_tz.send_date.utcoffset() + send_date_offset_tz = tz_bot.defaults.tzinfo.utcoffset( + spp_bot_tz.send_date.replace(tzinfo=None) + ) + + assert spp_bot.send_date.tzinfo == UTC + assert spp_bot_raw.send_date.tzinfo == UTC + assert send_date_offset_tz == send_date_offset def test_to_dict(self, suggested_post_parameters): spp_dict = suggested_post_parameters.to_dict() @@ -100,9 +126,15 @@ def test_slot_behaviour(self, suggested_post_price): "duplicate slot" ) - def test_expected_values(self, suggested_post_price): - assert suggested_post_price.currency == self.currency - assert suggested_post_price.amount == self.amount + def test_de_json(self, offline_bot): + json_dict = { + "currency": self.currency, + "amount": self.amount, + } + spp = SuggestedPostPrice.de_json(json_dict, offline_bot) + assert spp.currency == self.currency + assert spp.amount == self.amount + assert spp.api_kwargs == {} def test_to_dict(self, suggested_post_price): spp_dict = suggested_post_price.to_dict() From e4e2adc92e1f89fecf4089c5bcdcb50b84d0dcd7 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Fri, 22 Aug 2025 19:36:26 +0300 Subject: [PATCH 9/9] remove `.rst` from new classes at at-tree. --- docs/source/telegram.at-tree.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index 02816b8ecb1..a792aedee58 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -168,8 +168,8 @@ Available Types telegram.storyareatypesuggestedreaction telegram.storyareatypeuniquegift telegram.storyareatypeweather - telegram.suggestedpostparameters.rst - telegram.suggestedpostprice.rst + telegram.suggestedpostparameters + telegram.suggestedpostprice telegram.switchinlinequerychosenchat telegram.telegramobject telegram.textquote