Full Support for Bot API 9.3 (#5078)

Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com>
This commit is contained in:
Abdelrahman Elkheir
2026-01-24 16:20:28 +03:00
committed by GitHub
parent 327f469cb4
commit 432a67efdd
41 changed files with 2570 additions and 134 deletions
+5 -1
View File
@@ -81,7 +81,11 @@ _PREPARED_DUMMY_OBJECTS: dict[str, object] = {
accent_color_id=1,
max_reaction_count=1,
accepted_gift_types=AcceptedGiftTypes(
unlimited_gifts=True, limited_gifts=True, unique_gifts=True, premium_subscription=True
unlimited_gifts=True,
limited_gifts=True,
unique_gifts=True,
premium_subscription=True,
gifts_from_channels=True,
),
),
"ChatInviteLink": ChatInviteLink(
+5
View File
@@ -1136,6 +1136,11 @@ class TestFilters:
assert filters.StatusUpdate.UNIQUE_GIFT.check_update(update)
update.message.unique_gift = None
update.message.gift_upgrade_sent = "gift_upgrade_sent"
assert filters.StatusUpdate.ALL.check_update(update)
assert filters.StatusUpdate.GIFT_UPGRADE_SENT.check_update(update)
update.message.gift_upgrade_sent = None
update.message.paid_message_price_changed = "paid_message_price_changed"
assert filters.StatusUpdate.ALL.check_update(update)
assert filters.StatusUpdate.PAID_MESSAGE_PRICE_CHANGED.check_update(update)
+132
View File
@@ -65,6 +65,7 @@ from telegram import (
MenuButtonWebApp,
Message,
MessageEntity,
OwnedGifts,
Poll,
PollOption,
PreparedInlineMessage,
@@ -1477,6 +1478,61 @@ class TestBotWithoutRequest:
"SoSecretToken",
)
async def test_send_message_draft(self, offline_bot, monkeypatch):
entities = [
MessageEntity(MessageEntity.BOLD, 0, 3),
MessageEntity(MessageEntity.ITALIC, 5, 8),
]
async def make_assertions(*args, **kwargs):
params = kwargs.get("request_data").parameters
assert params.get("chat_id") == 123
assert params.get("draft_id") == 1
assert params.get("text") == "test test"
assert params.get("message_thread_id") == 9
assert params.get("parse_mode") == "markdown"
assert params.get("entities") == [e.to_dict() for e in entities]
return True
monkeypatch.setattr(offline_bot.request, "post", make_assertions)
assert await offline_bot.send_message_draft(
chat_id=123,
draft_id=1,
text="test test",
message_thread_id=9,
parse_mode="markdown",
entities=entities,
)
@pytest.mark.parametrize("default_bot", [{"parse_mode": "Markdown"}], indirect=True)
@pytest.mark.parametrize(
("passed_value", "expected_value"),
[(DEFAULT_NONE, "Markdown"), ("HTML", "HTML"), (None, None)],
)
async def test_send_message_draft_default_parse_mode(
self, default_bot, monkeypatch, passed_value, expected_value
):
async def make_assertion(url, request_data, *args, **kwargs):
assert request_data.parameters.get("parse_mode") == expected_value
return True
monkeypatch.setattr(default_bot.request, "post", make_assertion)
kwargs = {
"chat_id": 123,
"draft_id": 1,
"text": "test test",
"message_thread_id": 9,
"entities": [
MessageEntity(MessageEntity.BOLD, 0, 3),
MessageEntity(MessageEntity.ITALIC, 5, 8),
],
}
if passed_value is not DEFAULT_NONE:
kwargs["parse_mode"] = passed_value
await default_bot.send_message_draft(**kwargs)
# TODO: Needs improvement. Need incoming shipping queries to test
async def test_answer_shipping_query_ok(self, monkeypatch, offline_bot):
# For now just test that our internals pass the correct data
@@ -2712,6 +2768,72 @@ class TestBotWithoutRequest:
await offline_bot.decline_suggested_post(1234, 5678, "declined")
async def test_get_user_gifts_parameter_passing(self, offline_bot, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
for param in (
"user_id",
"exclude_unlimited",
"exclude_limited_upgradable",
"exclude_limited_non_upgradable",
"exclude_from_blockchain",
"exclude_unique",
"sort_by_price",
"offset",
"limit",
):
assert request_data.parameters.get(param) == param
return OwnedGifts(0, [], "null").to_dict()
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.get_user_gifts(
user_id="user_id",
exclude_unlimited="exclude_unlimited",
exclude_limited_upgradable="exclude_limited_upgradable",
exclude_limited_non_upgradable="exclude_limited_non_upgradable",
exclude_from_blockchain="exclude_from_blockchain",
exclude_unique="exclude_unique",
sort_by_price="sort_by_price",
offset="offset",
limit="limit",
)
async def test_get_chat_gifts_parameter_passing(self, offline_bot, monkeypatch):
async def make_assertion(url, request_data: RequestData, *args, **kwargs):
for param in (
"chat_id",
"exclude_saved",
"exclude_unsaved",
"exclude_unlimited",
"exclude_limited_upgradable",
"exclude_limited_non_upgradable",
"exclude_from_blockchain",
"exclude_unique",
"sort_by_price",
"offset",
"limit",
):
assert request_data.parameters.get(param) == param
return OwnedGifts(0, [], "null").to_dict()
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
await offline_bot.get_chat_gifts(
chat_id="chat_id",
exclude_saved="exclude_saved",
exclude_unsaved="exclude_unsaved",
exclude_unlimited="exclude_unlimited",
exclude_limited_upgradable="exclude_limited_upgradable",
exclude_limited_non_upgradable="exclude_limited_non_upgradable",
exclude_from_blockchain="exclude_from_blockchain",
exclude_unique="exclude_unique",
sort_by_price="sort_by_price",
offset="offset",
limit="limit",
)
class TestBotWithRequest:
"""
@@ -4687,6 +4809,16 @@ class TestBotWithRequest:
assert isinstance(balance, StarAmount)
assert balance.amount == 0
async def test_get_user_gifts_basic(self, bot):
gifts = await bot.get_user_gifts(bot.bot.id)
assert isinstance(gifts, OwnedGifts)
assert gifts.total_count == 0
async def test_get_chat_gifts_basic(self, bot, chat_id):
gifts = await bot.get_chat_gifts(chat_id)
assert isinstance(gifts, OwnedGifts)
assert gifts.total_count == 0
async def test_initialize_tracks_requests_and_bot_separately(self, offline_bot, monkeypatch):
"""Test that requests and bot user are initialized separately and only once."""
request_init_count = 0
+97 -1
View File
@@ -21,6 +21,7 @@ import datetime as dtm
import pytest
from telegram import (
Bot,
BusinessBotRights,
BusinessConnection,
Chat,
@@ -45,7 +46,10 @@ from telegram._reply import ReplyParameters
from telegram._utils.datetime import UTC
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram.constants import InputProfilePhotoType, InputStoryContentType
from telegram.ext import ExtBot
from telegram.warnings import PTBDeprecationWarning
from tests.auxil.files import data_file
from tests.auxil.networking import OfflineRequest
class BusinessMethodsTestBase:
@@ -107,7 +111,10 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
assert data.get("exclude_saved") is bool_param
assert data.get("exclude_unlimited") is bool_param
assert data.get("exclude_limited") is bool_param
assert data.get("exclude_limited_upgradable") is bool_param
assert data.get("exclude_limited_non_upgradable") is bool_param
assert data.get("exclude_unique") is bool_param
assert data.get("exclude_from_blockchain") is bool_param
assert data.get("sort_by_price") is bool_param
assert data.get("offset") == offset
assert data.get("limit") == limit
@@ -121,13 +128,50 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
exclude_saved=bool_param,
exclude_unlimited=bool_param,
exclude_limited=bool_param,
exclude_limited_upgradable=bool_param,
exclude_limited_non_upgradable=bool_param,
exclude_unique=bool_param,
exclude_from_blockchain=bool_param,
sort_by_price=bool_param,
offset=offset,
limit=limit,
)
assert isinstance(obj, OwnedGifts)
@pytest.mark.parametrize("bot_class", [Bot, ExtBot])
async def test_get_business_account_gifts_exclude_limited_deprecation(
self, offline_bot, monkeypatch, bot_class
):
bot = bot_class(offline_bot.token, request=OfflineRequest())
async def dummy_response(*args, **kwargs):
return OwnedGifts(
total_count=1,
gifts=[
OwnedGiftRegular(
gift=Gift(
id="id1",
sticker=Sticker(
"file_id", "file_unique_id", 512, 512, False, False, "regular"
),
star_count=5,
),
send_date=dtm.datetime.now(tz=UTC).replace(microsecond=0),
owned_gift_id="some_id_1",
)
],
).to_dict()
monkeypatch.setattr(bot.request, "post", dummy_response)
with pytest.warns(PTBDeprecationWarning, match=r"9\.3.*exclude_limited") as record:
await bot.get_business_account_gifts(
business_connection_id=self.bci,
exclude_limited=True,
)
assert record[0].category == PTBDeprecationWarning
assert record[0].filename == __file__, "wrong stacklevel!"
async def test_get_business_account_star_balance(self, offline_bot, monkeypatch):
star_amount_json = StarAmount(amount=100, nanostar_amount=356).to_json()
@@ -214,7 +258,7 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
async def test_set_business_account_gift_settings(self, offline_bot, monkeypatch):
show_gift_button = True
accepted_gift_types = AcceptedGiftTypes(True, True, True, True)
accepted_gift_types = AcceptedGiftTypes(True, True, True, True, True)
async def make_assertion(*args, **kwargs):
data = kwargs.get("request_data").json_parameters
@@ -789,3 +833,55 @@ class TestBusinessMethodsWithoutRequest(BusinessMethodsTestBase):
reply_markup=reply_markup,
)
assert isinstance(obj, Message)
async def test_repost_story(self, offline_bot, monkeypatch):
"""No way to test this without stories"""
async def make_assertion(url, request_data, *args, **kwargs):
for param in (
"business_connection_id",
"from_chat_id",
"from_story_id",
"active_period",
"post_to_chat_page",
"protect_content",
):
assert request_data.parameters.get(param) == param
return Story(chat=Chat(id=1, type=Chat.PRIVATE), id=42).to_dict()
monkeypatch.setattr(offline_bot.request, "post", make_assertion)
story = await offline_bot.repost_story(
business_connection_id="business_connection_id",
from_chat_id="from_chat_id",
from_story_id="from_story_id",
active_period="active_period",
post_to_chat_page="post_to_chat_page",
protect_content="protect_content",
)
assert story.chat.id == 1
assert story.id == 42
@pytest.mark.parametrize("default_bot", [{"protect_content": True}], indirect=True)
@pytest.mark.parametrize(
("passed_value", "expected_value"),
[(DEFAULT_NONE, True), (False, False), (None, None)],
)
async def test_repost_story_default_protect_content(
self, default_bot, monkeypatch, passed_value, expected_value
):
async def make_assertion(url, request_data, *args, **kwargs):
assert request_data.parameters.get("protect_content") == expected_value
return Story(chat=Chat(123, "private"), id=123).to_dict()
monkeypatch.setattr(default_bot.request, "post", make_assertion)
kwargs = {
"business_connection_id": self.bci,
"from_chat_id": 123,
"from_story_id": 456,
"active_period": dtm.timedelta(seconds=20),
}
if passed_value is not DEFAULT_NONE:
kwargs["protect_content"] = passed_value
await default_bot.repost_story(**kwargs)
+53
View File
@@ -524,6 +524,21 @@ class TestChatWithoutRequest(ChatTestBase):
monkeypatch.setattr(chat.get_bot(), "send_message", make_assertion)
assert await chat.send_message(text="test")
async def test_instance_method_send_message_draft(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["text"] == "test"
assert check_shortcut_signature(
Chat.send_message_draft, Bot.send_message_draft, ["chat_id"], []
)
assert await check_shortcut_call(
chat.send_message_draft, chat.get_bot(), "send_message_draft"
)
assert await check_defaults_handling(chat.send_message_draft, chat.get_bot())
monkeypatch.setattr(chat.get_bot(), "send_message_draft", make_assertion)
assert await chat.send_message_draft(draft_id=1, text="test")
async def test_instance_method_send_media_group(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id and kwargs["media"] == "test_media_group"
@@ -1495,6 +1510,44 @@ class TestChatWithoutRequest(ChatTestBase):
monkeypatch.setattr(chat.get_bot(), "decline_suggested_post", make_assertion)
assert await chat.decline_suggested_post(message_id="message_id", comment="comment")
async def test_instance_method_repost_story(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return kwargs["from_chat_id"] == chat.id
assert check_shortcut_signature(
Chat.repost_story,
Bot.repost_story,
[
"from_chat_id",
],
additional_kwargs=[],
)
assert await check_shortcut_call(
chat.repost_story,
chat.get_bot(),
"repost_story",
shortcut_kwargs=["from_chat_id"],
)
assert await check_defaults_handling(chat.repost_story, chat.get_bot())
monkeypatch.setattr(chat.get_bot(), "repost_story", make_assertion)
assert await chat.repost_story(
business_connection_id="bcid",
from_story_id=123,
active_period=3600,
)
async def test_instance_method_get_gifts(self, monkeypatch, chat):
async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == chat.id
assert check_shortcut_signature(Chat.get_gifts, Bot.get_chat_gifts, ["chat_id"], [])
assert await check_shortcut_call(chat.get_gifts, chat.get_bot(), "get_chat_gifts")
assert await check_defaults_handling(chat.get_gifts, chat.get_bot())
monkeypatch.setattr(chat.get_bot(), "get_chat_gifts", make_assertion)
assert await chat.get_gifts()
def test_mention_html(self):
chat = Chat(id=1, type="foo")
with pytest.raises(TypeError, match="Can not create a mention to a private group chat"):
+25 -1
View File
@@ -33,6 +33,8 @@ from telegram import (
Location,
ReactionTypeCustomEmoji,
ReactionTypeEmoji,
UniqueGiftColors,
UserRating,
)
from telegram._gifts import AcceptedGiftTypes
from telegram._utils.datetime import UTC, to_timestamp
@@ -89,6 +91,9 @@ def chat_full_info(bot):
can_send_paid_media=ChatFullInfoTestBase.can_send_paid_media,
is_direct_messages=ChatFullInfoTestBase.is_direct_messages,
parent_chat=ChatFullInfoTestBase.parent_chat,
rating=ChatFullInfoTestBase.rating,
unique_gift_colors=ChatFullInfoTestBase.unique_gift_colors,
paid_message_star_count=ChatFullInfoTestBase.paid_message_star_count,
)
chat.set_bot(bot)
chat._unfreeze()
@@ -147,9 +152,19 @@ class ChatFullInfoTestBase:
first_name = "first_name"
last_name = "last_name"
can_send_paid_media = True
accepted_gift_types = AcceptedGiftTypes(True, True, True, True)
accepted_gift_types = AcceptedGiftTypes(True, True, True, True, True)
is_direct_messages = True
parent_chat = Chat(4, "channel", "channel")
rating = UserRating(level=1, rating=2, current_level_rating=3, next_level_rating=4)
unique_gift_colors = UniqueGiftColors(
model_custom_emoji_id="model_custom_emoji_id",
symbol_custom_emoji_id="symbol_custom_emoji_id",
light_theme_main_color=0xFF5733,
light_theme_other_colors=[0x33FF57, 0x3357FF],
dark_theme_main_color=0xC70039,
dark_theme_other_colors=[0x900C3F, 0x581845],
)
paid_message_star_count = 1234
class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
@@ -207,6 +222,9 @@ class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
"can_send_paid_media": self.can_send_paid_media,
"is_direct_messages": self.is_direct_messages,
"parent_chat": self.parent_chat.to_dict(),
"rating": self.rating.to_dict(),
"unique_gift_colors": self.unique_gift_colors.to_dict(),
"paid_message_star_count": self.paid_message_star_count,
}
cfi = ChatFullInfo.de_json(json_dict, offline_bot)
@@ -258,6 +276,9 @@ class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
assert cfi.can_send_paid_media == self.can_send_paid_media
assert cfi.is_direct_messages == self.is_direct_messages
assert cfi.parent_chat == self.parent_chat
assert cfi.rating == self.rating
assert cfi.unique_gift_colors == self.unique_gift_colors
assert cfi.paid_message_star_count == self.paid_message_star_count
def test_de_json_localization(self, offline_bot, raw_bot, tz_bot):
json_dict = {
@@ -341,6 +362,9 @@ class TestChatFullInfoWithoutRequest(ChatFullInfoTestBase):
assert cfi_dict["max_reaction_count"] == cfi.max_reaction_count
assert cfi_dict["is_direct_messages"] == cfi.is_direct_messages
assert cfi_dict["parent_chat"] == cfi.parent_chat.to_dict()
assert cfi_dict["rating"] == cfi.rating.to_dict()
assert cfi_dict["unique_gift_colors"] == cfi.unique_gift_colors.to_dict()
assert cfi_dict["paid_message_star_count"] == cfi.paid_message_star_count
def test_time_period_properties(self, PTB_TIMEDELTA, chat_full_info):
cfi = chat_full_info
+6
View File
@@ -21,6 +21,7 @@ import datetime as dtm
import pytest
from telegram import (
Chat,
Checklist,
ChecklistTask,
ChecklistTasksAdded,
@@ -43,6 +44,7 @@ class ChecklistTaskTestBase:
MessageEntity(type="italic", offset=5, length=2),
]
completed_by_user = User(id=1, first_name="Test", last_name="User", is_bot=False)
completed_by_chat = Chat(id=-100, type=Chat.SUPERGROUP, title="Test Chat")
completion_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
@@ -53,6 +55,7 @@ def checklist_task():
text=ChecklistTaskTestBase.text,
text_entities=ChecklistTaskTestBase.text_entities,
completed_by_user=ChecklistTaskTestBase.completed_by_user,
completed_by_chat=ChecklistTaskTestBase.completed_by_chat,
completion_date=ChecklistTaskTestBase.completion_date,
)
@@ -72,6 +75,7 @@ class TestChecklistTaskWithoutRequest(ChecklistTaskTestBase):
assert clt_dict["text"] == self.text
assert clt_dict["text_entities"] == [entity.to_dict() for entity in self.text_entities]
assert clt_dict["completed_by_user"] == self.completed_by_user.to_dict()
assert clt_dict["completed_by_chat"] == self.completed_by_chat.to_dict()
assert clt_dict["completion_date"] == to_timestamp(self.completion_date)
def test_de_json(self, offline_bot):
@@ -80,6 +84,7 @@ class TestChecklistTaskWithoutRequest(ChecklistTaskTestBase):
"text": self.text,
"text_entities": [entity.to_dict() for entity in self.text_entities],
"completed_by_user": self.completed_by_user.to_dict(),
"completed_by_chat": self.completed_by_chat.to_dict(),
"completion_date": to_timestamp(self.completion_date),
}
clt = ChecklistTask.de_json(json_dict, offline_bot)
@@ -88,6 +93,7 @@ class TestChecklistTaskWithoutRequest(ChecklistTaskTestBase):
assert clt.text == self.text
assert clt.text_entities == tuple(self.text_entities)
assert clt.completed_by_user == self.completed_by_user
assert clt.completed_by_chat == self.completed_by_chat
assert clt.completion_date == self.completion_date
assert clt.api_kwargs == {}
+48 -20
View File
@@ -40,13 +40,20 @@ from tests.auxil.slots import mro_slots
async def forum_topic_object(forum_group_id, emoji_id):
return ForumTopic(
message_thread_id=forum_group_id,
name=TEST_TOPIC_NAME,
icon_color=TEST_TOPIC_ICON_COLOR,
name=ForumTopicTestBase.TEST_TOPIC_NAME,
icon_color=ForumTopicTestBase.TEST_TOPIC_ICON_COLOR,
icon_custom_emoji_id=emoji_id,
is_name_implicit=ForumTopicTestBase.is_name_implicit,
)
class TestForumTopicWithoutRequest:
class ForumTopicTestBase:
TEST_TOPIC_NAME = TEST_TOPIC_NAME
TEST_TOPIC_ICON_COLOR = TEST_TOPIC_ICON_COLOR
is_name_implicit = False
class TestForumTopicWithoutRequest(ForumTopicTestBase):
def test_slot_behaviour(self, forum_topic_object):
inst = forum_topic_object
for attr in inst.__slots__:
@@ -55,33 +62,37 @@ class TestForumTopicWithoutRequest:
async def test_expected_values(self, emoji_id, forum_group_id, forum_topic_object):
assert forum_topic_object.message_thread_id == forum_group_id
assert forum_topic_object.icon_color == TEST_TOPIC_ICON_COLOR
assert forum_topic_object.name == TEST_TOPIC_NAME
assert forum_topic_object.icon_color == self.TEST_TOPIC_ICON_COLOR
assert forum_topic_object.name == self.TEST_TOPIC_NAME
assert forum_topic_object.icon_custom_emoji_id == emoji_id
assert forum_topic_object.is_name_implicit == self.is_name_implicit
def test_de_json(self, offline_bot, emoji_id, forum_group_id):
json_dict = {
"message_thread_id": forum_group_id,
"name": TEST_TOPIC_NAME,
"icon_color": TEST_TOPIC_ICON_COLOR,
"name": self.TEST_TOPIC_NAME,
"icon_color": self.TEST_TOPIC_ICON_COLOR,
"icon_custom_emoji_id": emoji_id,
"is_name_implicit": self.is_name_implicit,
}
topic = ForumTopic.de_json(json_dict, offline_bot)
assert topic.api_kwargs == {}
assert topic.message_thread_id == forum_group_id
assert topic.icon_color == TEST_TOPIC_ICON_COLOR
assert topic.name == TEST_TOPIC_NAME
assert topic.icon_color == self.TEST_TOPIC_ICON_COLOR
assert topic.name == self.TEST_TOPIC_NAME
assert topic.icon_custom_emoji_id == emoji_id
assert topic.is_name_implicit == self.is_name_implicit
def test_to_dict(self, emoji_id, forum_group_id, forum_topic_object):
topic_dict = forum_topic_object.to_dict()
assert isinstance(topic_dict, dict)
assert topic_dict["message_thread_id"] == forum_group_id
assert topic_dict["name"] == TEST_TOPIC_NAME
assert topic_dict["icon_color"] == TEST_TOPIC_ICON_COLOR
assert topic_dict["name"] == self.TEST_TOPIC_NAME
assert topic_dict["icon_color"] == self.TEST_TOPIC_ICON_COLOR
assert topic_dict["icon_custom_emoji_id"] == emoji_id
assert topic_dict["is_name_implicit"] == self.is_name_implicit
def test_equality(self, emoji_id, forum_group_id):
a = ForumTopic(
@@ -289,10 +300,20 @@ class TestForumMethodsWithRequest:
@pytest.fixture(scope="module")
def topic_created():
return ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=TEST_TOPIC_ICON_COLOR)
return ForumTopicCreated(
name=ForumTopicCreatedTestBase.TEST_TOPIC_NAME,
icon_color=ForumTopicCreatedTestBase.TEST_TOPIC_ICON_COLOR,
is_name_implicit=ForumTopicCreatedTestBase.is_name_implicit,
)
class TestForumTopicCreatedWithoutRequest:
class ForumTopicCreatedTestBase:
TEST_TOPIC_NAME = TEST_TOPIC_NAME
TEST_TOPIC_ICON_COLOR = TEST_TOPIC_ICON_COLOR
is_name_implicit = False
class TestForumTopicCreatedWithoutRequest(ForumTopicCreatedTestBase):
def test_slot_behaviour(self, topic_created):
for attr in topic_created.__slots__:
assert getattr(topic_created, attr, "err") != "err", f"got extra slot '{attr}'"
@@ -301,23 +322,30 @@ class TestForumTopicCreatedWithoutRequest:
)
def test_expected_values(self, topic_created):
assert topic_created.icon_color == TEST_TOPIC_ICON_COLOR
assert topic_created.name == TEST_TOPIC_NAME
assert topic_created.icon_color == self.TEST_TOPIC_ICON_COLOR
assert topic_created.name == self.TEST_TOPIC_NAME
assert topic_created.is_name_implicit == self.is_name_implicit
def test_de_json(self, offline_bot):
json_dict = {"icon_color": TEST_TOPIC_ICON_COLOR, "name": TEST_TOPIC_NAME}
json_dict = {
"icon_color": self.TEST_TOPIC_ICON_COLOR,
"name": self.TEST_TOPIC_NAME,
"is_name_implicit": self.is_name_implicit,
}
action = ForumTopicCreated.de_json(json_dict, offline_bot)
assert action.api_kwargs == {}
assert action.icon_color == TEST_TOPIC_ICON_COLOR
assert action.name == TEST_TOPIC_NAME
assert action.icon_color == self.TEST_TOPIC_ICON_COLOR
assert action.name == self.TEST_TOPIC_NAME
assert action.is_name_implicit == self.is_name_implicit
def test_to_dict(self, topic_created):
action_dict = topic_created.to_dict()
assert isinstance(action_dict, dict)
assert action_dict["name"] == TEST_TOPIC_NAME
assert action_dict["icon_color"] == TEST_TOPIC_ICON_COLOR
assert action_dict["name"] == self.TEST_TOPIC_NAME
assert action_dict["icon_color"] == self.TEST_TOPIC_ICON_COLOR
assert action_dict["is_name_implicit"] == self.is_name_implicit
def test_equality(self, emoji_id):
a = ForumTopicCreated(name=TEST_TOPIC_NAME, icon_color=TEST_TOPIC_ICON_COLOR)
+117 -2
View File
@@ -21,12 +21,77 @@ from collections.abc import Sequence
import pytest
from telegram import BotCommand, Chat, Gift, GiftInfo, Gifts, MessageEntity, Sticker
from telegram._gifts import AcceptedGiftTypes
from telegram._gifts import AcceptedGiftTypes, GiftBackground
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram.request import RequestData
from tests.auxil.slots import mro_slots
@pytest.fixture
def gift_background():
return GiftBackground(
center_color=GiftBackgroundTestBase.center_color,
edge_color=GiftBackgroundTestBase.edge_color,
text_color=GiftBackgroundTestBase.text_color,
)
class GiftBackgroundTestBase:
center_color = 0xFFFFFF
edge_color = 0x000000
text_color = 0xFF0000
class TestGiftBackgroundWithoutRequest(GiftBackgroundTestBase):
def test_slot_behaviour(self, gift_background):
for attr in gift_background.__slots__:
assert getattr(gift_background, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(gift_background)) == len(set(mro_slots(gift_background))), (
"duplicate slot"
)
def test_de_json(self, offline_bot):
json_dict = {
"center_color": self.center_color,
"edge_color": self.edge_color,
"text_color": self.text_color,
}
gift_background = GiftBackground.de_json(json_dict, offline_bot)
assert gift_background.api_kwargs == {}
assert gift_background.center_color == self.center_color
assert gift_background.edge_color == self.edge_color
assert gift_background.text_color == self.text_color
def test_to_dict(self, gift_background):
json_dict = gift_background.to_dict()
assert json_dict["center_color"] == self.center_color
assert json_dict["edge_color"] == self.edge_color
assert json_dict["text_color"] == self.text_color
def test_equality(self, gift_background):
a = gift_background
b = GiftBackground(
self.center_color,
self.edge_color,
self.text_color,
)
c = GiftBackground(
0x000000,
self.edge_color,
self.text_color,
)
d = BotCommand("start", "description")
assert a == b
assert hash(a) == hash(b)
assert a != c
assert hash(a) != hash(c)
assert a != d
assert hash(a) != hash(d)
@pytest.fixture
def gift(request):
return Gift(
@@ -37,6 +102,12 @@ def gift(request):
remaining_count=GiftTestBase.remaining_count,
upgrade_star_count=GiftTestBase.upgrade_star_count,
publisher_chat=GiftTestBase.publisher_chat,
personal_total_count=GiftTestBase.personal_total_count,
personal_remaining_count=GiftTestBase.personal_remaining_count,
background=GiftTestBase.background,
is_premium=GiftTestBase.is_premium,
has_colors=GiftTestBase.has_colors,
unique_gift_variant_count=GiftTestBase.unique_gift_variant_count,
)
@@ -56,6 +127,12 @@ class GiftTestBase:
remaining_count = 5
upgrade_star_count = 10
publisher_chat = Chat(1, Chat.PRIVATE)
personal_total_count = 37
personal_remaining_count = 23
background = GiftBackground(0xFFFFFF, 0x000000, 0xFF0000)
is_premium = True
has_colors = True
unique_gift_variant_count = 42
class TestGiftWithoutRequest(GiftTestBase):
@@ -73,6 +150,12 @@ class TestGiftWithoutRequest(GiftTestBase):
"remaining_count": self.remaining_count,
"upgrade_star_count": self.upgrade_star_count,
"publisher_chat": self.publisher_chat.to_dict(),
"personal_total_count": self.personal_total_count,
"personal_remaining_count": self.personal_remaining_count,
"background": self.background.to_dict(),
"is_premium": self.is_premium,
"has_colors": self.has_colors,
"unique_gift_variant_count": self.unique_gift_variant_count,
}
gift = Gift.de_json(json_dict, offline_bot)
assert gift.api_kwargs == {}
@@ -84,6 +167,12 @@ class TestGiftWithoutRequest(GiftTestBase):
assert gift.remaining_count == self.remaining_count
assert gift.upgrade_star_count == self.upgrade_star_count
assert gift.publisher_chat == self.publisher_chat
assert gift.personal_total_count == self.personal_total_count
assert gift.personal_remaining_count == self.personal_remaining_count
assert gift.background == self.background
assert gift.is_premium == self.is_premium
assert gift.has_colors == self.has_colors
assert gift.unique_gift_variant_count == self.unique_gift_variant_count
def test_to_dict(self, gift):
gift_dict = gift.to_dict()
@@ -96,6 +185,12 @@ class TestGiftWithoutRequest(GiftTestBase):
assert gift_dict["remaining_count"] == self.remaining_count
assert gift_dict["upgrade_star_count"] == self.upgrade_star_count
assert gift_dict["publisher_chat"] == self.publisher_chat.to_dict()
assert gift_dict["personal_total_count"] == self.personal_total_count
assert gift_dict["personal_remaining_count"] == self.personal_remaining_count
assert gift_dict["background"] == self.background.to_dict()
assert gift_dict["is_premium"] == self.is_premium
assert gift_dict["has_colors"] == self.has_colors
assert gift_dict["unique_gift_variant_count"] == self.unique_gift_variant_count
def test_equality(self, gift):
a = gift
@@ -316,6 +411,8 @@ def gift_info():
text=GiftInfoTestBase.text,
entities=GiftInfoTestBase.entities,
is_private=GiftInfoTestBase.is_private,
is_upgrade_separate=GiftInfoTestBase.is_upgrade_separate,
unique_gift_number=GiftInfoTestBase.unique_gift_number,
)
@@ -338,6 +435,8 @@ class GiftInfoTestBase:
MessageEntity(MessageEntity.ITALIC, 5, 8),
)
is_private = True
is_upgrade_separate = False
unique_gift_number = 42
class TestGiftInfoWithoutRequest(GiftInfoTestBase):
@@ -356,6 +455,8 @@ class TestGiftInfoWithoutRequest(GiftInfoTestBase):
"text": self.text,
"entities": [e.to_dict() for e in self.entities],
"is_private": self.is_private,
"is_upgrade_separate": self.is_upgrade_separate,
"unique_gift_number": self.unique_gift_number,
}
gift_info = GiftInfo.de_json(json_dict, offline_bot)
assert gift_info.api_kwargs == {}
@@ -367,6 +468,8 @@ class TestGiftInfoWithoutRequest(GiftInfoTestBase):
assert gift_info.text == self.text
assert gift_info.entities == self.entities
assert gift_info.is_private == self.is_private
assert gift_info.is_upgrade_separate == self.is_upgrade_separate
assert gift_info.unique_gift_number == self.unique_gift_number
def test_to_dict(self, gift_info):
json_dict = gift_info.to_dict()
@@ -378,6 +481,8 @@ class TestGiftInfoWithoutRequest(GiftInfoTestBase):
assert json_dict["text"] == self.text
assert json_dict["entities"] == [e.to_dict() for e in self.entities]
assert json_dict["is_private"] == self.is_private
assert json_dict["is_upgrade_separate"] == self.is_upgrade_separate
assert json_dict["unique_gift_number"] == self.unique_gift_number
def test_parse_entity(self, gift_info):
entity = MessageEntity(MessageEntity.BOLD, 0, 4)
@@ -430,6 +535,7 @@ def accepted_gift_types():
limited_gifts=AcceptedGiftTypesTestBase.limited_gifts,
unique_gifts=AcceptedGiftTypesTestBase.unique_gifts,
premium_subscription=AcceptedGiftTypesTestBase.premium_subscription,
gifts_from_channels=AcceptedGiftTypesTestBase.gifts_from_channels,
)
@@ -438,6 +544,7 @@ class AcceptedGiftTypesTestBase:
limited_gifts = True
unique_gifts = True
premium_subscription = True
gifts_from_channels = False
class TestAcceptedGiftTypesWithoutRequest(AcceptedGiftTypesTestBase):
@@ -454,6 +561,7 @@ class TestAcceptedGiftTypesWithoutRequest(AcceptedGiftTypesTestBase):
"limited_gifts": self.limited_gifts,
"unique_gifts": self.unique_gifts,
"premium_subscription": self.premium_subscription,
"gifts_from_channels": self.gifts_from_channels,
}
accepted_gift_types = AcceptedGiftTypes.de_json(json_dict, offline_bot)
assert accepted_gift_types.api_kwargs == {}
@@ -461,6 +569,7 @@ class TestAcceptedGiftTypesWithoutRequest(AcceptedGiftTypesTestBase):
assert accepted_gift_types.limited_gifts == self.limited_gifts
assert accepted_gift_types.unique_gifts == self.unique_gifts
assert accepted_gift_types.premium_subscription == self.premium_subscription
assert accepted_gift_types.gifts_from_channels == self.gifts_from_channels
def test_to_dict(self, accepted_gift_types):
json_dict = accepted_gift_types.to_dict()
@@ -468,17 +577,23 @@ class TestAcceptedGiftTypesWithoutRequest(AcceptedGiftTypesTestBase):
assert json_dict["limited_gifts"] == self.limited_gifts
assert json_dict["unique_gifts"] == self.unique_gifts
assert json_dict["premium_subscription"] == self.premium_subscription
assert json_dict["gifts_from_channels"] == self.gifts_from_channels
def test_equality(self, accepted_gift_types):
a = accepted_gift_types
b = AcceptedGiftTypes(
self.unlimited_gifts, self.limited_gifts, self.unique_gifts, self.premium_subscription
self.unlimited_gifts,
self.limited_gifts,
self.unique_gifts,
self.premium_subscription,
self.gifts_from_channels,
)
c = AcceptedGiftTypes(
not self.unlimited_gifts,
self.limited_gifts,
self.unique_gifts,
self.premium_subscription,
self.gifts_from_channels,
)
d = BotCommand("start", "description")
+50 -7
View File
@@ -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,
@@ -420,6 +421,15 @@ def message(bot):
send_date=dtm.datetime.utcnow(),
)
},
{
"gift_upgrade_sent": GiftInfo(
gift=Gift(
"gift_id",
Sticker("file_id", "file_unique_id", 512, 512, False, False, "regular"),
5,
)
)
},
],
ids=[
"reply",
@@ -510,6 +520,7 @@ def message(bot):
"suggested_post_approved",
"suggested_post_approval_failed",
"suggested_post_info",
"gift_upgrade_sent",
],
)
def message_params(bot, request):
@@ -735,7 +746,8 @@ class TestMessageWithoutRequest(MessageTestBase):
message_thread_id = await method(*args, message_thread_id=None)
assert message_thread_id is None
if bot_method_name == "send_chat_action":
# These methods do not accept `do_quote` as passed below
if bot_method_name in ["send_chat_action", "send_message_draft"]:
return
message_thread_id = await method(
@@ -1831,6 +1843,37 @@ class TestMessageWithoutRequest(MessageTestBase):
message, message.reply_html, "send_message", ["test"], monkeypatch
)
async def test_reply_text_draft(self, monkeypatch, message):
async def make_assertion(*_, **kwargs):
id_ = kwargs["chat_id"] == message.chat_id
text = kwargs["text"] == "test"
return id_ and text
assert check_shortcut_signature(
Message.reply_text_draft,
Bot.send_message_draft,
["chat_id"],
[],
annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)},
)
assert await check_shortcut_call(
message.reply_text_draft,
message.get_bot(),
"send_message_draft",
skip_params=[""],
shortcut_kwargs=["chat_id"],
)
assert await check_defaults_handling(
message.reply_text_draft, message.get_bot(), no_default_kwargs={"message_thread_id"}
)
monkeypatch.setattr(message.get_bot(), "send_message_draft", make_assertion)
assert await message.reply_text_draft(draft_id=1, text="test")
await self.check_thread_id_parsing(
message, message.reply_text_draft, "send_message_draft", [1, "test"], monkeypatch
)
async def test_reply_media_group(self, monkeypatch, message):
async def make_assertion(*_, **kwargs):
id_ = kwargs["chat_id"] == message.chat_id
+10 -3
View File
@@ -159,6 +159,9 @@ PTB_EXTRA_PARAMS = {
"InputStoryContent": {"type"}, # attributes common to all subclasses
"StoryAreaType": {"type"}, # attributes common to all subclasses
"InputProfilePhoto": {"type"}, # attributes common to all subclasses
# backwards compatibility for api 9.3 changes
# tags: deprecated NEXT.VERSION, bot api 9.3
"UniqueGiftInfo": {"last_resale_star_count"},
}
@@ -191,8 +194,6 @@ PTB_IGNORED_PARAMS = {
r"OwnedGift\w+": {"type"},
r"InputStoryContent\w+": {"type"},
r"StoryAreaType\w+": {"type"},
# Official API field not yet implemented in PTB
"User": {"has_topics_enabled"},
}
@@ -208,6 +209,9 @@ IGNORED_PARAM_REQUIREMENTS = {
"send_venue": {"latitude", "longitude", "title", "address"},
"send_contact": {"phone_number", "first_name"},
# ---->
# backwards compatibility for api 9.3 changes
# tags: deprecated NEXT.VERSION, bot api 9.3
"UniqueGift": {"gift_id"},
}
@@ -216,7 +220,10 @@ def ignored_param_requirements(object_name: str) -> set[str]:
# Arguments that are optional arguments for now for backwards compatibility
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {}
BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {
# tags: deprecated NEXT.VERSION, bot api 9.3
"get_business_account_gifts": {"exclude_limited"},
}
def backwards_compat_kwargs(object_name: str) -> set[str]:
+12
View File
@@ -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,
@@ -96,6 +97,8 @@ class OwnedGiftTestBase:
can_be_transferred = True
transfer_star_count = 300
next_transfer_date = dtm.datetime.now(tz=UTC).replace(microsecond=0)
is_upgrade_separate = False
unique_gift_number = 37
class TestOwnedGiftWithoutRequest(OwnedGiftTestBase):
@@ -183,6 +186,8 @@ def owned_gift_regular():
was_refunded=TestOwnedGiftRegularWithoutRequest.was_refunded,
convert_star_count=TestOwnedGiftRegularWithoutRequest.convert_star_count,
prepaid_upgrade_star_count=TestOwnedGiftRegularWithoutRequest.prepaid_upgrade_star_count,
is_upgrade_separate=TestOwnedGiftRegularWithoutRequest.is_upgrade_separate,
unique_gift_number=TestOwnedGiftRegularWithoutRequest.unique_gift_number,
)
@@ -209,6 +214,8 @@ class TestOwnedGiftRegularWithoutRequest(OwnedGiftTestBase):
"was_refunded": self.was_refunded,
"convert_star_count": self.convert_star_count,
"prepaid_upgrade_star_count": self.prepaid_upgrade_star_count,
"is_upgrade_separate": self.is_upgrade_separate,
"unique_gift_number": self.unique_gift_number,
}
ogr = OwnedGiftRegular.de_json(json_dict, offline_bot)
assert ogr.gift == self.gift
@@ -223,6 +230,8 @@ class TestOwnedGiftRegularWithoutRequest(OwnedGiftTestBase):
assert ogr.was_refunded == self.was_refunded
assert ogr.convert_star_count == self.convert_star_count
assert ogr.prepaid_upgrade_star_count == self.prepaid_upgrade_star_count
assert ogr.is_upgrade_separate == self.is_upgrade_separate
assert ogr.unique_gift_number == self.unique_gift_number
assert ogr.api_kwargs == {}
def test_to_dict(self, owned_gift_regular):
@@ -241,6 +250,8 @@ class TestOwnedGiftRegularWithoutRequest(OwnedGiftTestBase):
assert json_dict["was_refunded"] == self.was_refunded
assert json_dict["convert_star_count"] == self.convert_star_count
assert json_dict["prepaid_upgrade_star_count"] == self.prepaid_upgrade_star_count
assert json_dict["is_upgrade_separate"] == self.is_upgrade_separate
assert json_dict["unique_gift_number"] == self.unique_gift_number
def test_parse_entity(self, owned_gift_regular):
entity = MessageEntity(MessageEntity.BOLD, 0, 4)
@@ -393,6 +404,7 @@ class OwnedGiftsTestBase:
),
OwnedGiftUnique(
gift=UniqueGift(
gift_id="gift_id",
base_name="human_readable",
name="unique_name",
number=10,
+39 -3
View File
@@ -18,13 +18,20 @@
import pytest
from telegram import Chat, Story
from telegram import Bot, Chat, Story
from tests.auxil.bot_method_checks import (
check_defaults_handling,
check_shortcut_call,
check_shortcut_signature,
)
from tests.auxil.slots import mro_slots
@pytest.fixture(scope="module")
def story():
return Story(StoryTestBase.chat, StoryTestBase.id)
def story(bot):
story = Story(StoryTestBase.chat, StoryTestBase.id)
story.set_bot(bot)
return story
class StoryTestBase:
@@ -69,3 +76,32 @@ class TestStoryWithoutRequest(StoryTestBase):
assert a != e
assert hash(a) != hash(e)
async def test_instance_method_repost(self, monkeypatch, story):
async def make_assertion(*_, **kwargs):
chat_id = kwargs["from_chat_id"] == story.chat.id
story_id = kwargs["from_story_id"] == story.id
return chat_id and story_id
assert check_shortcut_signature(
Story.repost,
Bot.repost_story,
[
"from_chat_id",
"from_story_id",
],
additional_kwargs=[],
)
assert await check_shortcut_call(
story.repost,
story.get_bot(),
"repost_story",
shortcut_kwargs=["from_chat_id", "from_story_id"],
)
assert await check_defaults_handling(story.repost, story.get_bot())
monkeypatch.setattr(story.get_bot(), "repost_story", make_assertion)
assert await story.repost(
business_connection_id="bcid",
active_period=3600,
)
+180 -21
View File
@@ -28,18 +28,107 @@ from telegram import (
UniqueGift,
UniqueGiftBackdrop,
UniqueGiftBackdropColors,
UniqueGiftColors,
UniqueGiftInfo,
UniqueGiftModel,
UniqueGiftSymbol,
)
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
@pytest.fixture
def unique_gift_colors():
return UniqueGiftColors(
model_custom_emoji_id=UniqueGiftColorsTestBase.model_custom_emoji_id,
symbol_custom_emoji_id=UniqueGiftColorsTestBase.symbol_custom_emoji_id,
light_theme_main_color=UniqueGiftColorsTestBase.light_theme_main_color,
light_theme_other_colors=UniqueGiftColorsTestBase.light_theme_other_colors,
dark_theme_main_color=UniqueGiftColorsTestBase.dark_theme_main_color,
dark_theme_other_colors=UniqueGiftColorsTestBase.dark_theme_other_colors,
)
class UniqueGiftColorsTestBase:
model_custom_emoji_id = "model_emoji_id"
symbol_custom_emoji_id = "symbol_emoji_id"
light_theme_main_color = 0xFFFFFF
light_theme_other_colors = [0xAAAAAA, 0xBBBBBB]
dark_theme_main_color = 0x000000
dark_theme_other_colors = [0x111111, 0x222222]
class TestUniqueGiftColorsWithoutRequest(UniqueGiftColorsTestBase):
def test_slot_behaviour(self, unique_gift_colors):
for attr in unique_gift_colors.__slots__:
assert getattr(unique_gift_colors, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(unique_gift_colors)) == len(set(mro_slots(unique_gift_colors))), (
"duplicate slot"
)
def test_de_json(self, offline_bot):
json_dict = {
"model_custom_emoji_id": self.model_custom_emoji_id,
"symbol_custom_emoji_id": self.symbol_custom_emoji_id,
"light_theme_main_color": self.light_theme_main_color,
"light_theme_other_colors": self.light_theme_other_colors,
"dark_theme_main_color": self.dark_theme_main_color,
"dark_theme_other_colors": self.dark_theme_other_colors,
}
unique_gift_colors = UniqueGiftColors.de_json(json_dict, offline_bot)
assert unique_gift_colors.api_kwargs == {}
assert unique_gift_colors.model_custom_emoji_id == self.model_custom_emoji_id
assert unique_gift_colors.symbol_custom_emoji_id == self.symbol_custom_emoji_id
assert unique_gift_colors.light_theme_main_color == self.light_theme_main_color
assert unique_gift_colors.light_theme_other_colors == tuple(self.light_theme_other_colors)
assert unique_gift_colors.dark_theme_main_color == self.dark_theme_main_color
assert unique_gift_colors.dark_theme_other_colors == tuple(self.dark_theme_other_colors)
def test_to_dict(self, unique_gift_colors):
json_dict = unique_gift_colors.to_dict()
assert json_dict["model_custom_emoji_id"] == self.model_custom_emoji_id
assert json_dict["symbol_custom_emoji_id"] == self.symbol_custom_emoji_id
assert json_dict["light_theme_main_color"] == self.light_theme_main_color
assert json_dict["light_theme_other_colors"] == self.light_theme_other_colors
assert json_dict["dark_theme_main_color"] == self.dark_theme_main_color
assert json_dict["dark_theme_other_colors"] == self.dark_theme_other_colors
def test_equality(self, unique_gift_colors):
a = unique_gift_colors
b = UniqueGiftColors(
self.model_custom_emoji_id,
self.symbol_custom_emoji_id,
self.light_theme_main_color,
self.light_theme_other_colors,
self.dark_theme_main_color,
self.dark_theme_other_colors,
)
c = UniqueGiftColors(
"other_model_emoji_id",
self.symbol_custom_emoji_id,
self.light_theme_main_color,
self.light_theme_other_colors,
self.dark_theme_main_color,
self.dark_theme_other_colors,
)
d = BotCommand("start", "description")
assert a == b
assert hash(a) == hash(b)
assert a != c
assert hash(a) != hash(c)
assert a != d
assert hash(a) != hash(d)
@pytest.fixture
def unique_gift():
return UniqueGift(
gift_id=UniqueGiftTestBase.gift_id,
base_name=UniqueGiftTestBase.base_name,
name=UniqueGiftTestBase.name,
number=UniqueGiftTestBase.number,
@@ -47,10 +136,14 @@ def unique_gift():
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
@@ -70,6 +163,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):
@@ -80,6 +183,7 @@ class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
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,
@@ -87,6 +191,9 @@ class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
"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 == {}
@@ -98,11 +205,15 @@ class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
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
@@ -110,26 +221,31 @@ class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
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")
@@ -142,6 +258,19 @@ class TestUniqueGiftWithoutRequest(UniqueGiftTestBase):
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():
@@ -396,26 +525,29 @@ 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,
)
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,
@@ -425,6 +557,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)
@@ -443,6 +577,8 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
"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)
@@ -452,6 +588,8 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
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):
@@ -461,6 +599,8 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
"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),
}
@@ -484,7 +624,8 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
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):
@@ -507,3 +648,21 @@ class TestUniqueGiftInfoWithoutRequest(UniqueGiftInfoTestBase):
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!"
+62
View File
@@ -44,6 +44,7 @@ def json_dict():
"added_to_attachment_menu": UserTestBase.added_to_attachment_menu,
"can_connect_to_business": UserTestBase.can_connect_to_business,
"has_main_web_app": UserTestBase.has_main_web_app,
"has_topics_enabled": UserTestBase.has_topics_enabled,
}
@@ -63,6 +64,7 @@ def user(bot):
added_to_attachment_menu=UserTestBase.added_to_attachment_menu,
can_connect_to_business=UserTestBase.can_connect_to_business,
has_main_web_app=UserTestBase.has_main_web_app,
has_topics_enabled=UserTestBase.has_topics_enabled,
)
user.set_bot(bot)
user._unfreeze()
@@ -83,6 +85,7 @@ class UserTestBase:
added_to_attachment_menu = False
can_connect_to_business = True
has_main_web_app = False
has_topics_enabled = False
class TestUserWithoutRequest(UserTestBase):
@@ -108,6 +111,7 @@ class TestUserWithoutRequest(UserTestBase):
assert user.added_to_attachment_menu == self.added_to_attachment_menu
assert user.can_connect_to_business == self.can_connect_to_business
assert user.has_main_web_app == self.has_main_web_app
assert user.has_topics_enabled == self.has_topics_enabled
def test_to_dict(self, user):
user_dict = user.to_dict()
@@ -126,6 +130,7 @@ class TestUserWithoutRequest(UserTestBase):
assert user_dict["added_to_attachment_menu"] == user.added_to_attachment_menu
assert user_dict["can_connect_to_business"] == user.can_connect_to_business
assert user_dict["has_main_web_app"] == user.has_main_web_app
assert user_dict["has_topics_enabled"] == user.has_topics_enabled
def test_equality(self):
a = User(self.id_, self.first_name, self.is_bot, self.last_name)
@@ -231,6 +236,25 @@ class TestUserWithoutRequest(UserTestBase):
monkeypatch.setattr(user.get_bot(), "send_message", make_assertion)
assert await user.send_message("test")
async def test_instance_method_send_message_draft(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return (
kwargs["chat_id"] == user.id
and kwargs["draft_id"] == 123
and kwargs["text"] == "test"
)
assert check_shortcut_signature(
User.send_message_draft, Bot.send_message_draft, ["chat_id"], []
)
assert await check_shortcut_call(
user.send_message_draft, user.get_bot(), "send_message_draft"
)
assert await check_defaults_handling(user.send_message_draft, user.get_bot())
monkeypatch.setattr(user.get_bot(), "send_message_draft", make_assertion)
assert await user.send_message_draft(123, "test")
async def test_instance_method_send_photo(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return kwargs["chat_id"] == user.id and kwargs["photo"] == "test_photo"
@@ -805,3 +829,41 @@ class TestUserWithoutRequest(UserTestBase):
monkeypatch.setattr(user.get_bot(), "remove_user_verification", make_assertion)
assert await user.remove_verification()
async def test_instance_method_repost_story(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return kwargs["from_chat_id"] == user.id
assert check_shortcut_signature(
User.repost_story,
Bot.repost_story,
[
"from_chat_id",
],
additional_kwargs=[],
)
assert await check_shortcut_call(
user.repost_story,
user.get_bot(),
"repost_story",
shortcut_kwargs=["from_chat_id"],
)
assert await check_defaults_handling(user.repost_story, user.get_bot())
monkeypatch.setattr(user.get_bot(), "repost_story", make_assertion)
assert await user.repost_story(
business_connection_id="bcid",
from_story_id=123,
active_period=3600,
)
async def test_instance_method_get_gifts(self, monkeypatch, user):
async def make_assertion(*_, **kwargs):
return kwargs["user_id"] == user.id
assert check_shortcut_signature(user.get_gifts, Bot.get_user_gifts, ["user_id"], [])
assert await check_shortcut_call(user.get_gifts, user.get_bot(), "get_user_gifts")
assert await check_defaults_handling(user.get_gifts, user.get_bot())
monkeypatch.setattr(user.get_bot(), "get_user_gifts", make_assertion)
assert await user.get_gifts()
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2026
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
import pytest
from telegram import BotCommand, UserRating
from tests.auxil.slots import mro_slots
@pytest.fixture(scope="module")
def user_rating():
return UserRating(
level=UserRatingTestBase.level,
rating=UserRatingTestBase.rating,
current_level_rating=UserRatingTestBase.current_level_rating,
next_level_rating=UserRatingTestBase.next_level_rating,
)
class UserRatingTestBase:
level = 2
rating = 120
current_level_rating = 100
next_level_rating = 180
class TestUserRatingWithoutRequest(UserRatingTestBase):
def test_slot_behaviour(self, user_rating):
for attr in user_rating.__slots__:
assert getattr(user_rating, attr, "err") != "err", f"got extra slot '{attr}'"
assert len(mro_slots(user_rating)) == len(set(mro_slots(user_rating))), "duplicate slot"
def test_de_json_with_next(self, offline_bot):
json_dict = {
"level": self.level,
"rating": self.rating,
"current_level_rating": self.current_level_rating,
"next_level_rating": self.next_level_rating,
}
ur = UserRating.de_json(json_dict, offline_bot)
assert ur.api_kwargs == {}
assert ur.level == self.level
assert ur.rating == self.rating
assert ur.current_level_rating == self.current_level_rating
assert ur.next_level_rating == self.next_level_rating
def test_de_json_no_optional(self, offline_bot):
json_dict = {
"level": self.level,
"rating": self.rating,
"current_level_rating": self.current_level_rating,
}
ur = UserRating.de_json(json_dict, offline_bot)
assert ur.api_kwargs == {}
assert ur.level == self.level
assert ur.rating == self.rating
assert ur.current_level_rating == self.current_level_rating
assert ur.next_level_rating is None
def test_to_dict(self, user_rating):
ur_dict = user_rating.to_dict()
assert isinstance(ur_dict, dict)
assert ur_dict["level"] == user_rating.level
assert ur_dict["rating"] == user_rating.rating
assert ur_dict["current_level_rating"] == user_rating.current_level_rating
assert ur_dict["next_level_rating"] == user_rating.next_level_rating
def test_equality(self):
a = UserRating(3, 200, 150, 300)
b = UserRating(3, 200, 100, None)
c = UserRating(3, 201, 150, 300)
d = UserRating(4, 200, 150, 300)
e = BotCommand("start", "description")
assert a == b
assert hash(a) == hash(b)
assert a != c
assert hash(a) != hash(c)
assert a != d
assert hash(a) != hash(d)
assert a != e
assert hash(a) != hash(e)