From 1fdb12ae721348ba092df3bf90c84890da8f59e6 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:17:37 +0100 Subject: [PATCH 1/5] New UniqueGiftInfo origin constants --- src/telegram/_uniquegift.py | 30 ++++++++++++++++++++++++------ src/telegram/constants.py | 18 ++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/telegram/_uniquegift.py b/src/telegram/_uniquegift.py index 93a2a101138..f023ea24cf4 100644 --- a/src/telegram/_uniquegift.py +++ b/src/telegram/_uniquegift.py @@ -432,10 +432,14 @@ class UniqueGiftInfo(TelegramObject): gift (:class:`UniqueGift`): Information about the gift. origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE` for gifts upgraded from regular gifts, :attr:`TRANSFER` for gifts transferred from other users - or channels, or :attr:`RESALE` for gifts bought from other users. + or channels, :attr:`RESALE` for gifts bought from other users, + :attr:`GIFTED_UPGRADE` for upgrades purchased after the gift was sent, or :attr:`OFFER` + for gifts bought or sold through gift purchase offers .. versionchanged:: 22.3 The :attr:`RESALE` origin was added. + .. versionchanged:: NEXT.VERSION + Bot API 9.3 added the :attr:`GIFTED_UPGRADE` and :attr:`OFFER` origins. owned_gift_id (:obj:`str`, optional) Unique identifier of the received gift for the bot; only present for gifts received on behalf of business accounts. transfer_star_count (:obj:`int`, optional): Number of Telegram Stars that must be paid @@ -454,10 +458,14 @@ class UniqueGiftInfo(TelegramObject): gift (:class:`UniqueGift`): Information about the gift. origin (:obj:`str`): Origin of the gift. Currently, either :attr:`UPGRADE` for gifts upgraded from regular gifts, :attr:`TRANSFER` for gifts transferred from other users - or channels, or :attr:`RESALE` for gifts bought from other users. + or channels, :attr:`RESALE` for gifts bought from other users, + :attr:`GIFTED_UPGRADE` for upgrades purchased after the gift was sent, or :attr:`OFFER` + for gifts bought or sold through gift purchase offers .. versionchanged:: 22.3 The :attr:`RESALE` origin was added. + .. versionchanged:: NEXT.VERSION + Bot API 9.3 added the :attr:`GIFTED_UPGRADE` and :attr:`OFFER` origins. owned_gift_id (:obj:`str`) Optional. Unique identifier of the received gift for the bot; only present for gifts received on behalf of business accounts. transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid @@ -473,15 +481,25 @@ class UniqueGiftInfo(TelegramObject): .. versionadded:: 22.3 """ - UPGRADE: Final[str] = constants.UniqueGiftInfoOrigin.UPGRADE - """:const:`telegram.constants.UniqueGiftInfoOrigin.UPGRADE`""" - TRANSFER: Final[str] = constants.UniqueGiftInfoOrigin.TRANSFER - """:const:`telegram.constants.UniqueGiftInfoOrigin.TRANSFER`""" + GIFTED_UPGRADE: Final[str] = constants.UniqueGiftInfoOrigin.GIFTED_UPGRADE + """:const:`telegram.constants.UniqueGiftInfoOrigin.GIFTED_UPGRADE` + + .. versionadded:: NEXT.VERSION + """ + OFFER: Final[str] = constants.UniqueGiftInfoOrigin.OFFER + """:const:`telegram.constants.UniqueGiftInfoOrigin.OFFER` + + .. versionadded:: NEXT.VERSION + """ RESALE: Final[str] = constants.UniqueGiftInfoOrigin.RESALE """:const:`telegram.constants.UniqueGiftInfoOrigin.RESALE` .. versionadded:: 22.3 """ + TRANSFER: Final[str] = constants.UniqueGiftInfoOrigin.TRANSFER + """:const:`telegram.constants.UniqueGiftInfoOrigin.TRANSFER`""" + UPGRADE: Final[str] = constants.UniqueGiftInfoOrigin.UPGRADE + """:const:`telegram.constants.UniqueGiftInfoOrigin.UPGRADE`""" __slots__ = ( "gift", diff --git a/src/telegram/constants.py b/src/telegram/constants.py index 80c44eda10e..038c08bc339 100644 --- a/src/telegram/constants.py +++ b/src/telegram/constants.py @@ -3333,15 +3333,25 @@ class UniqueGiftInfoOrigin(StringEnum): __slots__ = () - UPGRADE = "upgrade" - """:obj:`str` gift upgraded""" - TRANSFER = "transfer" - """:obj:`str` gift transfered""" + GIFTED_UPGRADE = "gifted_upgrade" + """:obj:`str` upgrades purchased after the gift was sent + + .. versionadded:: NEXT.VERSION + """ + OFFER = "OFFER" + """:obj:`str` gift bought or sold through gift purchase offers + + .. versionadded:: NEXT.VERSION + """ RESALE = "resale" """:obj:`str` gift bought from other users .. versionadded:: 22.3 """ + TRANSFER = "transfer" + """:obj:`str` gift transfered""" + UPGRADE = "upgrade" + """:obj:`str` gift upgraded""" class UpdateType(StringEnum): From 6cf2b65811ecce019ad7350585f30ce44d75bb93 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:43:24 +0100 Subject: [PATCH 2/5] UniqueGiftInfo updated fields + deprecation --- src/telegram/_uniquegift.py | 73 ++++++++++++++++++++++++++++++++++--- tests/test_uniquegift.py | 32 +++++++++++++++- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/telegram/_uniquegift.py b/src/telegram/_uniquegift.py index f023ea24cf4..3d5cabcf675 100644 --- a/src/telegram/_uniquegift.py +++ b/src/telegram/_uniquegift.py @@ -30,6 +30,12 @@ from telegram._utils.argumentparsing import de_json_optional, parse_sequence_arg from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp from telegram._utils.types import JSONDict +from telegram._utils.warnings import warn +from telegram._utils.warnings_transition import ( + build_deprecation_warning_message, + warn_about_deprecated_attr_in_property, +) +from telegram.warnings import PTBDeprecationWarning if TYPE_CHECKING: from telegram import Bot @@ -448,6 +454,18 @@ class UniqueGiftInfo(TelegramObject): paid for the gift. .. versionadded:: 22.3 + .. deprecated:: NEXT.VERSION + Bot API 9.3 deprecated this field. Use :attr:`last_resale_currency` and + :attr:`last_resale_amount` instead. + last_resale_currency (:obj:`str`, optional): For gifts bought from other users, the + currency in which the payment for the gift was done. Currently, one of ``XTR`` for + Telegram Stars or ``TON`` for toncoins. + + .. versionadded:: NEXT.VERSION + last_resale_amount (:obj:`int`, optional): For gifts bought from other users, the price + paid for the gift in either Telegram Stars or nanotoncoins. + + .. versionadded:: NEXT.VERSION next_transfer_date (:obj:`datetime.datetime`, optional): Date when the gift can be transferred. If it's in the past, then the gift can be transferred now. |datetime_localization| @@ -470,10 +488,15 @@ class UniqueGiftInfo(TelegramObject): bot; only present for gifts received on behalf of business accounts. transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid to transfer the gift; omitted if the bot cannot transfer the gift. - last_resale_star_count (:obj:`int`): Optional. For gifts bought from other users, the price - paid for the gift. + last_resale_currency (:obj:`str`, optional): For gifts bought from other users, the + currency in which the payment for the gift was done. Currently, one of ``XTR`` for + Telegram Stars or ``TON`` for toncoins. - .. versionadded:: 22.3 + .. versionadded:: NEXT.VERSION + last_resale_amount (:obj:`int`, optional): For gifts bought from other users, the price + paid for the gift in either Telegram Stars or nanotoncoins. + + .. versionadded:: NEXT.VERSION next_transfer_date (:obj:`datetime.datetime`): Optional. Date when the gift can be transferred. If it's in the past, then the gift can be transferred now. |datetime_localization| @@ -502,8 +525,10 @@ class UniqueGiftInfo(TelegramObject): """:const:`telegram.constants.UniqueGiftInfoOrigin.UPGRADE`""" __slots__ = ( + "_last_resale_star_count", "gift", - "last_resale_star_count", + "last_resale_amount", + "last_resale_currency", "next_transfer_date", "origin", "owned_gift_id", @@ -516,11 +541,28 @@ def __init__( origin: str, owned_gift_id: str | None = None, transfer_star_count: int | None = None, + # tags: deprecated NEXT.VERSION; bot api 9.3 last_resale_star_count: int | None = None, next_transfer_date: dtm.datetime | None = None, + last_resale_currency: str | None = None, + last_resale_amount: int | None = None, *, api_kwargs: JSONDict | None = None, ): + if last_resale_star_count is not None: + warn( + PTBDeprecationWarning( + version="NEXT.VERSION", + message=build_deprecation_warning_message( + deprecated_name="last_resale_star_count", + new_name="last_resale_currency/amount", + bot_api_version="9.3", + object_type="parameter", + ), + ), + stacklevel=2, + ) + super().__init__(api_kwargs=api_kwargs) # Required self.gift: UniqueGift = gift @@ -528,13 +570,34 @@ def __init__( # Optional self.owned_gift_id: str | None = owned_gift_id self.transfer_star_count: int | None = transfer_star_count - self.last_resale_star_count: int | None = last_resale_star_count + self._last_resale_star_count: int | None = last_resale_star_count self.next_transfer_date: dtm.datetime | None = next_transfer_date + self.last_resale_currency: str | None = last_resale_currency + self.last_resale_amount: int | None = last_resale_amount self._id_attrs = (self.gift, self.origin) self._freeze() + # tags: deprecated NEXT.VERSION; bot api 9.3 + @property + def last_resale_star_count(self) -> int | None: + """:obj:`int`: Optional. For gifts bought from other users, the price + paid for the gift. + + .. versionadded:: 22.3 + .. deprecated:: NEXT.VERSION + Bot API 9.3 deprecated this field. Use :attr:`last_resale_currency` and + :attr:`last_resale_amount` instead. + """ + warn_about_deprecated_attr_in_property( + deprecated_attr_name="last_resale_star_count", + new_attr_name="last_resale_currency/amount", + bot_api_version="9.3", + ptb_version="NEXT.VERSION", + ) + return self._last_resale_star_count + @classmethod def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGiftInfo": """See :meth:`telegram.TelegramObject.de_json`.""" diff --git a/tests/test_uniquegift.py b/tests/test_uniquegift.py index 30926343259..eb20165269d 100644 --- a/tests/test_uniquegift.py +++ b/tests/test_uniquegift.py @@ -35,6 +35,7 @@ ) from telegram._utils.datetime import UTC, to_timestamp from telegram.constants import UniqueGiftInfoOrigin +from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -483,6 +484,8 @@ def unique_gift_info(): owned_gift_id=UniqueGiftInfoTestBase.owned_gift_id, transfer_star_count=UniqueGiftInfoTestBase.transfer_star_count, last_resale_star_count=UniqueGiftInfoTestBase.last_resale_star_count, + last_resale_currency=UniqueGiftInfoTestBase.last_resale_currency, + last_resale_amount=UniqueGiftInfoTestBase.last_resale_amount, next_transfer_date=UniqueGiftInfoTestBase.next_transfer_date, ) @@ -512,6 +515,8 @@ class UniqueGiftInfoTestBase: owned_gift_id = "some_id" transfer_star_count = 10 last_resale_star_count = 5 + last_resale_currency = "XTR" + last_resale_amount = 1234 next_transfer_date = dtm.datetime.now(tz=UTC).replace(microsecond=0) @@ -530,6 +535,8 @@ def test_de_json(self, offline_bot): "owned_gift_id": self.owned_gift_id, "transfer_star_count": self.transfer_star_count, "last_resale_star_count": self.last_resale_star_count, + "last_resale_currency": self.last_resale_currency, + "last_resale_amount": self.last_resale_amount, "next_transfer_date": to_timestamp(self.next_transfer_date), } unique_gift_info = UniqueGiftInfo.de_json(json_dict, offline_bot) @@ -539,6 +546,8 @@ def test_de_json(self, offline_bot): assert unique_gift_info.owned_gift_id == self.owned_gift_id assert unique_gift_info.transfer_star_count == self.transfer_star_count assert unique_gift_info.last_resale_star_count == self.last_resale_star_count + assert unique_gift_info.last_resale_currency == self.last_resale_currency + assert unique_gift_info.last_resale_amount == self.last_resale_amount assert unique_gift_info.next_transfer_date == self.next_transfer_date def test_de_json_localization(self, tz_bot, offline_bot, raw_bot): @@ -548,6 +557,8 @@ def test_de_json_localization(self, tz_bot, offline_bot, raw_bot): "owned_gift_id": self.owned_gift_id, "transfer_star_count": self.transfer_star_count, "last_resale_star_count": self.last_resale_star_count, + "last_resale_currency": self.last_resale_currency, + "last_resale_amount": self.last_resale_amount, "next_transfer_date": to_timestamp(self.next_transfer_date), } @@ -571,7 +582,8 @@ def test_to_dict(self, unique_gift_info): assert json_dict["origin"] == self.origin assert json_dict["owned_gift_id"] == self.owned_gift_id assert json_dict["transfer_star_count"] == self.transfer_star_count - assert json_dict["last_resale_star_count"] == self.last_resale_star_count + assert json_dict["last_resale_currency"] == self.last_resale_currency + assert json_dict["last_resale_amount"] == self.last_resale_amount assert json_dict["next_transfer_date"] == to_timestamp(self.next_transfer_date) def test_enum_type_conversion(self, unique_gift_info): @@ -594,3 +606,21 @@ def test_equality(self, unique_gift_info): assert a != d assert hash(a) != hash(d) + + def test_last_resale_star_count_argument_deprecation(self): + with pytest.warns(PTBDeprecationWarning, match=r"9\.3.*last_resale_star_count") as record: + UniqueGiftInfo( + gift=self.gift, + origin=UniqueGiftInfo.TRANSFER, + last_resale_star_count=self.last_resale_star_count, + ) + + assert record[0].category == PTBDeprecationWarning + assert record[0].filename == __file__, "wrong stacklevel!" + + def test_last_resale_star_count_attribute_deprecation(self, unique_gift_info): + with pytest.warns(PTBDeprecationWarning, match=r"9\.3.*last_resale_star_count") as record: + assert unique_gift_info.last_resale_star_count == self.last_resale_star_count + + assert record[0].category == PTBDeprecationWarning + assert record[0].filename == __file__, "wrong stacklevel!" From 5c262c18e6ea1389b30d18dc3d00a9d5d5082a60 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:46:16 +0100 Subject: [PATCH 3/5] chango --- changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml b/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml index a1cac9e3ab2..ea197123445 100644 --- a/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml +++ b/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml @@ -1,8 +1,15 @@ -features = "Full Support for Bot API 9.3" +features = """ +Full Support for Bot API 9.3 + +.. warning:: + + Bot API 9.3 deprecates the field ``last_resale_star_count`` of ``UniqueGiftInfo`` in favor of the new fields ``last_resale_currency`` and ``last_resale_amount``. The field ``last_resale_star_count`` is still present in PTB for backward compatibility, but it will be removed in future releases. Please update your code accordingly. +""" pull_requests = [ { uid = "5078", author_uid = "aelkheir", closes_threads = ["5077"] }, { uid = "5079", author_uid = "aelkheir" }, { uid = "5084", author_uids = ["Bibo-Joshi"] }, { uid = "5085", author_uids = ["Bibo-Joshi"] }, + { uid = "5093", author_uids = ["Bibo-Joshi"] }, ] From d2657bb541657379490781fcbb8bb81679da4a00 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:47:30 +0100 Subject: [PATCH 4/5] chango --- changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml b/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml index ea197123445..f4ed2c51067 100644 --- a/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml +++ b/changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml @@ -11,5 +11,5 @@ pull_requests = [ { uid = "5079", author_uid = "aelkheir" }, { uid = "5084", author_uids = ["Bibo-Joshi"] }, { uid = "5085", author_uids = ["Bibo-Joshi"] }, - { uid = "5093", author_uids = ["Bibo-Joshi"] }, + { uid = "5094", author_uids = ["Bibo-Joshi"] }, ] From 75bd1071420da09c18e9f0bb1a7606df116cdf94 Mon Sep 17 00:00:00 2001 From: aelkheir <90580077+aelkheir@users.noreply.github.com> Date: Sun, 18 Jan 2026 15:16:42 +0200 Subject: [PATCH 5/5] review: update new fields docstrings --- src/telegram/_uniquegift.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/telegram/_uniquegift.py b/src/telegram/_uniquegift.py index c4e0b5144b6..6ff3d145543 100644 --- a/src/telegram/_uniquegift.py +++ b/src/telegram/_uniquegift.py @@ -539,12 +539,12 @@ class UniqueGiftInfo(TelegramObject): bot; only present for gifts received on behalf of business accounts. transfer_star_count (:obj:`int`): Optional. Number of Telegram Stars that must be paid to transfer the gift; omitted if the bot cannot transfer the gift. - last_resale_currency (:obj:`str`, optional): For gifts bought from other users, the + last_resale_currency (:obj:`str`): Optional. For gifts bought from other users, the currency in which the payment for the gift was done. Currently, one of ``XTR`` for Telegram Stars or ``TON`` for toncoins. .. versionadded:: NEXT.VERSION - last_resale_amount (:obj:`int`, optional): For gifts bought from other users, the price + last_resale_amount (:obj:`int`): Optional. For gifts bought from other users, the price paid for the gift in either Telegram Stars or nanotoncoins. .. versionadded:: NEXT.VERSION