Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion changes/unreleased/5078.FoNwUYLbXQFRebTFhR6UPn.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
features = "Full Support for Bot API 9.3"
features = """
Full Support for Bot API 9.3

.. warning::

Bot API 9.3 introduces a now required argument ``gift_id`` to ``UniqueGift``. For backward compatibility, the argument is currently still marked as optional in the signature and it's presence is enforced through a runtime check
In future versions, this argument will be made required in the signature as well.
Please make sure to update your code accordingly to avoid potential issues in the future. We recommend using keyword arguments when creating ``UniqueGift`` instances to ensure compatibility with future updates.
"""

pull_requests = [
{ uid = "5086", author_uids = ["Bibo-Joshi"] },
Expand All @@ -9,4 +17,5 @@ pull_requests = [
{ uid = "5091", author_uids = ["Bibo-Joshi"] },
{ uid = "5090", author_uids = ["Bibo-Joshi"] },
{ uid = "5089", author_uids = ["Bibo-Joshi"] },
{ uid = "5092", author_uids = ["Bibo-Joshi"] },
]
51 changes: 51 additions & 0 deletions src/telegram/_uniquegift.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ class UniqueGift(TelegramObject):
.. versionadded:: 22.1

Args:
gift_id (:obj:`str`): Identifier of the regular gift from which the gift was upgraded.

.. versionadded:: NEXT.VERSION
base_name (:obj:`str`): Human-readable name of the regular gift from which this unique
gift was upgraded.
name (:obj:`str`): Unique name of the gift. This name can be used
Expand All @@ -347,8 +350,24 @@ class UniqueGift(TelegramObject):
published the gift.

.. versionadded:: 22.4
is_premium (:obj:`bool`, optional): :obj:`True`, if the original regular gift was
exclusively purchaseable by Telegram Premium subscribers.

.. versionadded:: NEXT.VERSION
is_from_blockchain (:obj:`bool`, optional): :obj:`True`, if the gift is assigned from the
TON blockchain and can't be resold or transferred in Telegram.

.. versionadded:: NEXT.VERSION
colors (:class:`telegram.UniqueGiftColors`, optional): The color scheme that can be used
by the gift's owner for the chat's name, replies to messages and link previews; for
business account gifts and gifts that are currently on sale only.

.. versionadded:: NEXT.VERSION

Attributes:
gift_id (:obj:`str`): Identifier of the regular gift from which the gift was upgraded.

.. versionadded:: NEXT.VERSION
base_name (:obj:`str`): Human-readable name of the regular gift from which this unique
gift was upgraded.
name (:obj:`str`): Unique name of the gift. This name can be used
Expand All @@ -362,12 +381,29 @@ class UniqueGift(TelegramObject):
published the gift.

.. versionadded:: 22.4
is_premium (:obj:`bool`): Optional. :obj:`True`, if the original regular gift was
exclusively purchaseable by Telegram Premium subscribers.

.. versionadded:: NEXT.VERSION
is_from_blockchain (:obj:`bool`): Optional. :obj:`True`, if the gift is assigned from the
TON blockchain and can't be resold or transferred in Telegram.

.. versionadded:: NEXT.VERSION
colors (:class:`telegram.UniqueGiftColors`): Optional. The color scheme that can be used
by the gift's owner for the chat's name, replies to messages and link previews; for
business account gifts and gifts that are currently on sale only.

.. versionadded:: NEXT.VERSION

"""

__slots__ = (
"backdrop",
"base_name",
"colors",
"gift_id",
"is_from_blockchain",
"is_premium",
"model",
"name",
"number",
Expand All @@ -384,17 +420,31 @@ def __init__(
symbol: UniqueGiftSymbol,
backdrop: UniqueGiftBackdrop,
publisher_chat: Chat | None = None,
# tags: deprecated NEXT.VERSION, bot api 9.3
# temporarily optional to account for changed signature
gift_id: str | None = None,
is_from_blockchain: bool | None = None,
is_premium: bool | None = None,
colors: UniqueGiftColors | None = None,
*,
api_kwargs: JSONDict | None = None,
):
# tags: deprecated NEXT.VERSION, bot api 9.3
if gift_id is None:
raise TypeError("`gift_id` is a required argument since Bot API 9.3")

super().__init__(api_kwargs=api_kwargs)
self.gift_id: str = gift_id
self.base_name: str = base_name
self.name: str = name
self.number: int = number
self.model: UniqueGiftModel = model
self.symbol: UniqueGiftSymbol = symbol
self.backdrop: UniqueGiftBackdrop = backdrop
self.publisher_chat: Chat | None = publisher_chat
self.is_from_blockchain: bool | None = is_from_blockchain
self.is_premium: bool | None = is_premium
self.colors: UniqueGiftColors | None = colors

self._id_attrs = (
self.base_name,
Expand All @@ -416,6 +466,7 @@ def de_json(cls, data: JSONDict, bot: "Bot | None" = None) -> "UniqueGift":
data["symbol"] = de_json_optional(data.get("symbol"), UniqueGiftSymbol, bot)
data["backdrop"] = de_json_optional(data.get("backdrop"), UniqueGiftBackdrop, bot)
data["publisher_chat"] = de_json_optional(data.get("publisher_chat"), Chat, bot)
data["colors"] = de_json_optional(data.get("colors"), UniqueGiftColors, bot)

return super().de_json(data=data, bot=bot)

Expand Down
13 changes: 7 additions & 6 deletions tests/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,20 +268,21 @@ def message(bot):
{
"unique_gift": UniqueGiftInfo(
gift=UniqueGift(
"human_readable_name",
"unique_name",
2,
UniqueGiftModel(
gift_id="gift_id",
base_name="human_readable_name",
name="unique_name",
number=2,
model=UniqueGiftModel(
"model_name",
Sticker("file_id1", "file_unique_id1", 512, 512, False, False, "regular"),
10,
),
UniqueGiftSymbol(
symbol=UniqueGiftSymbol(
"symbol_name",
Sticker("file_id2", "file_unique_id2", 512, 512, True, True, "mask"),
20,
),
UniqueGiftBackdrop(
backdrop=UniqueGiftBackdrop(
"backdrop_name",
UniqueGiftBackdropColors(0x00FF00, 0xEE00FF, 0xAA22BB, 0x20FE8F),
30,
Expand Down
2 changes: 2 additions & 0 deletions tests/test_ownedgift.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class OwnedGiftTestBase:
star_count=5,
)
unique_gift = UniqueGift(
gift_id="gift_id",
base_name="human_readable",
name="unique_name",
number=10,
Expand Down Expand Up @@ -403,6 +404,7 @@ class OwnedGiftsTestBase:
),
OwnedGiftUnique(
gift=UniqueGift(
gift_id="gift_id",
base_name="human_readable",
name="unique_name",
number=10,
Expand Down
82 changes: 62 additions & 20 deletions tests/test_uniquegift.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,22 @@ def test_equality(self, unique_gift_colors):
@pytest.fixture
def unique_gift():
return UniqueGift(
gift_id=UniqueGiftTestBase.gift_id,
base_name=UniqueGiftTestBase.base_name,
name=UniqueGiftTestBase.name,
number=UniqueGiftTestBase.number,
model=UniqueGiftTestBase.model,
symbol=UniqueGiftTestBase.symbol,
backdrop=UniqueGiftTestBase.backdrop,
publisher_chat=UniqueGiftTestBase.publisher_chat,
is_premium=UniqueGiftTestBase.is_premium,
is_from_blockchain=UniqueGiftTestBase.is_from_blockchain,
colors=UniqueGiftTestBase.colors,
)


class UniqueGiftTestBase:
gift_id = "gift_id"
base_name = "human_readable"
name = "unique_name"
number = 10
Expand All @@ -157,6 +162,16 @@ class UniqueGiftTestBase:
rarity_per_mille=30,
)
publisher_chat = Chat(1, Chat.PRIVATE)
is_premium = False
is_from_blockchain = True
colors = UniqueGiftColors(
model_custom_emoji_id="M",
symbol_custom_emoji_id="S",
light_theme_main_color=0xFFFFFF,
light_theme_other_colors=[0xAAAAAA],
dark_theme_main_color=0x000000,
dark_theme_other_colors=[0x111111],
)


class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
Expand All @@ -167,13 +182,17 @@ def test_slot_behaviour(self, unique_gift):

def test_de_json(self, offline_bot):
json_dict = {
"gift_id": self.gift_id,
"base_name": self.base_name,
"name": self.name,
"number": self.number,
"model": self.model.to_dict(),
"symbol": self.symbol.to_dict(),
"backdrop": self.backdrop.to_dict(),
"publisher_chat": self.publisher_chat.to_dict(),
"is_premium": self.is_premium,
"is_from_blockchain": self.is_from_blockchain,
"colors": self.colors.to_dict(),
}
unique_gift = UniqueGift.de_json(json_dict, offline_bot)
assert unique_gift.api_kwargs == {}
Expand All @@ -185,38 +204,47 @@ def test_de_json(self, offline_bot):
assert unique_gift.symbol == self.symbol
assert unique_gift.backdrop == self.backdrop
assert unique_gift.publisher_chat == self.publisher_chat
assert unique_gift.is_premium == self.is_premium
assert unique_gift.is_from_blockchain == self.is_from_blockchain
assert unique_gift.colors == self.colors

def test_to_dict(self, unique_gift):
gift_dict = unique_gift.to_dict()

assert isinstance(gift_dict, dict)
assert gift_dict["gift_id"] == self.gift_id
assert gift_dict["base_name"] == self.base_name
assert gift_dict["name"] == self.name
assert gift_dict["number"] == self.number
assert gift_dict["model"] == self.model.to_dict()
assert gift_dict["symbol"] == self.symbol.to_dict()
assert gift_dict["backdrop"] == self.backdrop.to_dict()
assert gift_dict["publisher_chat"] == self.publisher_chat.to_dict()
assert gift_dict["is_premium"] == self.is_premium
assert gift_dict["is_from_blockchain"] == self.is_from_blockchain
assert gift_dict["colors"] == self.colors.to_dict()

def test_equality(self, unique_gift):
a = unique_gift
b = UniqueGift(
self.base_name,
self.name,
self.number,
self.model,
self.symbol,
self.backdrop,
self.publisher_chat,
gift_id=self.gift_id,
base_name=self.base_name,
name=self.name,
number=self.number,
model=self.model,
symbol=self.symbol,
backdrop=self.backdrop,
publisher_chat=self.publisher_chat,
)
c = UniqueGift(
"other_base_name",
self.name,
self.number,
self.model,
self.symbol,
self.backdrop,
self.publisher_chat,
gift_id=self.gift_id,
base_name="other_base_name",
name=self.name,
number=self.number,
model=self.model,
symbol=self.symbol,
backdrop=self.backdrop,
publisher_chat=self.publisher_chat,
)
d = BotCommand("start", "description")

Expand All @@ -229,6 +257,19 @@ def test_equality(self, unique_gift):
assert a != d
assert hash(a) != hash(d)

def test_gift_id_required_workaround(self):
# tags: deprecated NEXT.VERSION, bot api 9.3
with pytest.raises(TypeError, match="`gift_id` is a required"):
UniqueGift(
base_name=self.base_name,
name=self.name,
number=self.number,
model=self.model,
symbol=self.symbol,
backdrop=self.backdrop,
publisher_chat=self.publisher_chat,
)


@pytest.fixture
def unique_gift_model():
Expand Down Expand Up @@ -489,20 +530,21 @@ def unique_gift_info():

class UniqueGiftInfoTestBase:
gift = UniqueGift(
"human_readable_name",
"unique_name",
10,
UniqueGiftModel(
gift_id="gift_id",
base_name="human_readable_name",
name="unique_name",
number=10,
model=UniqueGiftModel(
name="model_name",
sticker=Sticker("file_id1", "file_unique_id1", 512, 512, False, False, "regular"),
rarity_per_mille=10,
),
UniqueGiftSymbol(
symbol=UniqueGiftSymbol(
name="symbol_name",
sticker=Sticker("file_id2", "file_unique_id2", 512, 512, True, True, "mask"),
rarity_per_mille=20,
),
UniqueGiftBackdrop(
backdrop=UniqueGiftBackdrop(
name="backdrop_name",
colors=UniqueGiftBackdropColors(0x00FF00, 0xEE00FF, 0xAA22BB, 0x20FE8F),
rarity_per_mille=2,
Expand Down
Loading