From 58b8ef4ce498472980daec4958709b96b4dd2872 Mon Sep 17 00:00:00 2001 From: marinelay Date: Sun, 14 Apr 2024 03:27:29 +0900 Subject: [PATCH 1/4] Fix Annotation of `EncryptedCredentials.decrypted_secret` (#4199) Co-authored-by: marinelay --- AUTHORS.rst | 1 + telegram/_passport/credentials.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index e01a2a13ec9..fe69dba625d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -123,6 +123,7 @@ The following wonderful people contributed directly or indirectly to this projec - `Vorobjev Simon `_ - `Wagner Macedo `_ - `wjt `_ +- `Wonseok Oh `_ - `Yaw Danso `_ - `Yao Kuan `_ - `zeroone2numeral2 `_ diff --git a/telegram/_passport/credentials.py b/telegram/_passport/credentials.py index bc48077b516..525dd473e17 100644 --- a/telegram/_passport/credentials.py +++ b/telegram/_passport/credentials.py @@ -153,15 +153,15 @@ def __init__( self._id_attrs = (self.data, self.hash, self.secret) - self._decrypted_secret: Optional[str] = None + self._decrypted_secret: Optional[bytes] = None self._decrypted_data: Optional[Credentials] = None self._freeze() @property - def decrypted_secret(self) -> str: + def decrypted_secret(self) -> bytes: """ - :obj:`str`: Lazily decrypt and return secret. + :obj:`bytes`: Lazily decrypt and return secret. Raises: telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad From 42b68f1a708250f7c495ca968a0196f5cca999ea Mon Sep 17 00:00:00 2001 From: Nano Date: Sun, 14 Apr 2024 20:14:45 +0800 Subject: [PATCH 2/4] Remove Deprecation Warning in `JobQueue.run_daily` (#4206) --- telegram/ext/_jobqueue.py | 8 -------- tests/ext/test_jobqueue.py | 24 +----------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/telegram/ext/_jobqueue.py b/telegram/ext/_jobqueue.py index 940a80bb462..1229659f6f9 100644 --- a/telegram/ext/_jobqueue.py +++ b/telegram/ext/_jobqueue.py @@ -33,7 +33,6 @@ from telegram._utils.repr import build_repr_with_selected_attrs from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn from telegram.ext._extbot import ExtBot from telegram.ext._utils.types import CCT, JobCallback @@ -587,13 +586,6 @@ async def callback(context: CallbackContext) queue. """ - # TODO: After v20.0, we should remove this warning. - if days != tuple(range(7)): # checks if user passed a custom value - warn( - "Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday " - "scheme. We recommend double checking if the passed value is correct.", - stacklevel=2, - ) if not job_kwargs: job_kwargs = {} diff --git a/tests/ext/test_jobqueue.py b/tests/ext/test_jobqueue.py index 458fc4cc4f9..0a3723763d9 100644 --- a/tests/ext/test_jobqueue.py +++ b/tests/ext/test_jobqueue.py @@ -26,7 +26,6 @@ import pytest from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Defaults, Job, JobQueue -from telegram.warnings import PTBUserWarning from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS from tests.auxil.pytest_classes import make_bot from tests.auxil.slots import mro_slots @@ -80,11 +79,6 @@ class TestJobQueue: job_time = 0 received_error = None - expected_warning = ( - "Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday scheme." - " We recommend double checking if the passed value is correct." - ) - async def test_repr(self, app): jq = JobQueue() jq.set_application(app) @@ -375,20 +369,8 @@ async def test_run_daily(self, job_queue): scheduled_time = job_queue.jobs()[0].next_t.timestamp() assert scheduled_time == pytest.approx(expected_reschedule_time) - async def test_run_daily_warning(self, job_queue, recwarn): - delta, now = 1, dtm.datetime.now(UTC) - time_of_day = (now + dtm.timedelta(seconds=delta)).time() - - job_queue.run_daily(self.job_run_once, time_of_day) - assert len(recwarn) == 0 - job_queue.run_daily(self.job_run_once, time_of_day, days=(0, 1, 2, 3)) - assert len(recwarn) == 1 - assert str(recwarn[0].message) == self.expected_warning - assert recwarn[0].category is PTBUserWarning - assert recwarn[0].filename == __file__, "wrong stacklevel" - @pytest.mark.parametrize("weekday", [0, 1, 2, 3, 4, 5, 6]) - async def test_run_daily_days_of_week(self, job_queue, recwarn, weekday): + async def test_run_daily_days_of_week(self, job_queue, weekday): delta, now = 1, dtm.datetime.now(UTC) time_of_day = (now + dtm.timedelta(seconds=delta)).time() # offset in days until next weekday @@ -400,10 +382,6 @@ async def test_run_daily_days_of_week(self, job_queue, recwarn, weekday): await asyncio.sleep(delta + 0.1) scheduled_time = job_queue.jobs()[0].next_t.timestamp() assert scheduled_time == pytest.approx(expected_reschedule_time) - assert len(recwarn) == 1 - assert str(recwarn[0].message) == self.expected_warning - assert recwarn[0].category is PTBUserWarning - assert recwarn[0].filename == __file__, "wrong stacklevel" async def test_run_monthly(self, job_queue, timezone): delta, now = 1, dtm.datetime.now(timezone) From fed8d8875e4ef5a235888a1ab12459f09db40dea Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:49:36 +0200 Subject: [PATCH 3/4] Fix Bug With Parameter `message_thread_id` of `Message.reply_*` (#4207) --- telegram/_message.py | 65 +++++++----- tests/auxil/bot_method_checks.py | 29 +++++- tests/test_message.py | 163 ++++++++++++++++++++++--------- 3 files changed, 183 insertions(+), 74 deletions(-) diff --git a/telegram/_message.py b/telegram/_message.py index 502b193a8d5..87ecdd300f3 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -1462,7 +1462,7 @@ def build_reply_arguments( quote_index: Optional[int] = None, target_chat_id: Optional[Union[int, str]] = None, allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, ) -> _ReplyKwargs: """ Builds a dictionary with the keys ``chat_id`` and ``reply_parameters``. This dictionary can @@ -1587,11 +1587,22 @@ async def _parse_quote_arguments( def _parse_message_thread_id( self, chat_id: Union[str, int], - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, ) -> Optional[int]: - return message_thread_id or ( - self.message_thread_id if chat_id in {self.chat_id, self.chat.username} else None - ) + # values set by user have the highest priority + if not isinstance(message_thread_id, DefaultValue): + return message_thread_id + + # self.message_thread_id can be used for send_*.param.message_thread_id only if the + # thread is a forum topic. It does not work if the thread is a chain of replies to a + # message in a normal group. In that case, self.message_thread_id is just the message_id + # of the first message in the chain. + if not self.is_topic_message: + return None + + # Setting message_thread_id=self.message_thread_id only makes sense if we're replying in + # the same chat. + return self.message_thread_id if chat_id in {self.chat_id, self.chat.username} else None async def reply_text( self, @@ -1601,7 +1612,7 @@ async def reply_text( reply_markup: Optional[ReplyMarkup] = None, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -1677,7 +1688,7 @@ async def reply_markdown( reply_markup: Optional[ReplyMarkup] = None, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -1759,7 +1770,7 @@ async def reply_markdown_v2( reply_markup: Optional[ReplyMarkup] = None, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -1837,7 +1848,7 @@ async def reply_html( reply_markup: Optional[ReplyMarkup] = None, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -1915,7 +1926,7 @@ async def reply_media_group( ], disable_notification: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -1994,7 +2005,7 @@ async def reply_photo( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -2076,7 +2087,7 @@ async def reply_audio( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -2159,7 +2170,7 @@ async def reply_document( disable_content_type_detection: Optional[bool] = None, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -2242,7 +2253,7 @@ async def reply_animation( reply_markup: Optional[ReplyMarkup] = None, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, has_spoiler: Optional[bool] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, @@ -2323,7 +2334,7 @@ async def reply_sticker( disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -2401,7 +2412,7 @@ async def reply_video( supports_streaming: Optional[bool] = None, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, has_spoiler: Optional[bool] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, @@ -2485,7 +2496,7 @@ async def reply_video_note( disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, @@ -2564,7 +2575,7 @@ async def reply_voice( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -2644,7 +2655,7 @@ async def reply_location( heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -2727,7 +2738,7 @@ async def reply_venue( google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -2808,7 +2819,7 @@ async def reply_contact( reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -2893,7 +2904,7 @@ async def reply_poll( close_date: Optional[Union[int, datetime.datetime]] = None, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -2973,7 +2984,7 @@ async def reply_dice( reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -3039,7 +3050,7 @@ async def reply_dice( async def reply_chat_action( self, action: str, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3086,7 +3097,7 @@ async def reply_game( disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -3177,7 +3188,7 @@ async def reply_invoice( max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, @@ -3387,7 +3398,7 @@ async def reply_copy( disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, - message_thread_id: Optional[int] = None, + message_thread_id: ODVInput[int] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, reply_to_message_id: Optional[int] = None, diff --git a/tests/auxil/bot_method_checks.py b/tests/auxil/bot_method_checks.py index 1e85af1baca..9c71190bd6b 100644 --- a/tests/auxil/bot_method_checks.py +++ b/tests/auxil/bot_method_checks.py @@ -21,7 +21,7 @@ import functools import inspect import re -from typing import Any, Callable, Dict, Iterable, List, Optional +from typing import Any, Callable, Collection, Dict, Iterable, List, Optional, Tuple import pytest @@ -59,6 +59,7 @@ def check_shortcut_signature( bot_method: Callable, shortcut_kwargs: List[str], additional_kwargs: List[str], + annotation_overrides: Optional[Dict[str, Tuple[Any, Any]]] = None, ) -> bool: """ Checks that the signature of a shortcut matches the signature of the underlying bot method. @@ -69,10 +70,14 @@ def check_shortcut_signature( shortcut_kwargs: The kwargs passed by the shortcut directly, e.g. ``chat_id`` additional_kwargs: Additional kwargs of the shortcut that the bot method doesn't have, e.g. ``quote``. + annotation_overrides: A dictionary of exceptions for the annotation comparison. The key is + the name of the argument, the value is a tuple of the expected annotation and + the default value. E.g. ``{'parse_mode': (str, 'None')}``. Returns: :obj:`bool`: Whether or not the signature matches. """ + annotation_overrides = annotation_overrides or {} def resolve_class(class_name: str) -> Optional[type]: """Attempts to resolve a PTB class (telegram module only) from a ForwardRef. @@ -117,6 +122,14 @@ def resolve_class(class_name: str) -> Optional[type]: if shortcut_sig.parameters[kwarg].kind != expected_kind: raise Exception(f"Argument {kwarg} must be of kind {expected_kind}.") + if kwarg in annotation_overrides: + if shortcut_sig.parameters[kwarg].annotation != annotation_overrides[kwarg][0]: + raise Exception( + f"For argument {kwarg} I expected {annotation_overrides[kwarg]}, " + f"but got {shortcut_sig.parameters[kwarg].annotation}" + ) + continue + if bot_sig.parameters[kwarg].annotation != shortcut_sig.parameters[kwarg].annotation: if FORWARD_REF_PATTERN.search(str(shortcut_sig.parameters[kwarg])): # If a shortcut signature contains a ForwardRef, the simple comparison of @@ -155,6 +168,13 @@ def resolve_class(class_name: str) -> Optional[type]: bot_method_sig = inspect.signature(bot_method) shortcut_sig = inspect.signature(shortcut) for arg in expected_args: + if arg in annotation_overrides: + if shortcut_sig.parameters[arg].default == annotation_overrides[arg][1]: + continue + raise Exception( + f"For argument {arg} I expected default {annotation_overrides[arg][1]}, " + f"but got {shortcut_sig.parameters[arg].default}" + ) if not shortcut_sig.parameters[arg].default == bot_method_sig.parameters[arg].default: raise Exception( f"Default for argument {arg} does not match the default of the Bot method." @@ -525,6 +545,7 @@ async def check_defaults_handling( method: Callable, bot: Bot, return_value=None, + no_default_kwargs: Collection[str] = frozenset(), ) -> bool: """ Checks that tg.ext.Defaults are handled correctly. @@ -536,6 +557,8 @@ async def check_defaults_handling( return_value: Optional. The return value of Bot._post that the method expects. Defaults to None. get_file is automatically handled. If this is a `TelegramObject`, Bot._post will return the `to_dict` representation of it. + no_default_kwargs: Optional. A collection of keyword arguments that should not have default + values. Defaults to an empty frozenset. """ raw_bot = not isinstance(bot, ExtBot) @@ -545,7 +568,9 @@ async def check_defaults_handling( kwargs_need_default = { kwarg for kwarg, value in shortcut_signature.parameters.items() - if isinstance(value.default, DefaultValue) and not kwarg.endswith("_timeout") + if isinstance(value.default, DefaultValue) + and not kwarg.endswith("_timeout") + and kwarg not in no_default_kwargs } # We tested this for a long time, but Bot API 7.0 deprecated it in favor of # reply_parameters. In the transition phase, both exist in a mutually exclusive diff --git a/tests/test_message.py b/tests/test_message.py index 7f04dffbeb1..e70b8f0668f 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -69,6 +69,8 @@ WebAppData, ) from telegram._utils.datetime import UTC +from telegram._utils.defaultvalue import DEFAULT_NONE +from telegram._utils.types import ODVInput from telegram.constants import ChatAction, ParseMode from telegram.ext import Defaults from telegram.warnings import PTBDeprecationWarning @@ -502,35 +504,42 @@ async def extract_message_thread_id(*args, **kwargs): monkeypatch.setattr(message.get_bot(), bot_method_name, extract_message_thread_id) - message.message_thread_id = None - message_thread_id = await method(*args) - assert message_thread_id is None + for is_topic_message in (True, False): + message.is_topic_message = is_topic_message - message.message_thread_id = 99 - message_thread_id = await method(*args) - assert message_thread_id == 99 + message.message_thread_id = None + message_thread_id = await method(*args) + assert message_thread_id is None - message_thread_id = await method(*args, message_thread_id=50) - assert message_thread_id == 50 + message.message_thread_id = 99 + message_thread_id = await method(*args) + assert message_thread_id == (99 if is_topic_message else None) - if bot_method_name == "send_chat_action": - return + message_thread_id = await method(*args, message_thread_id=50) + assert message_thread_id == 50 - message_thread_id = await method( - *args, - do_quote=message.build_reply_arguments( - target_chat_id=123, - ), - ) - assert message_thread_id is None + message_thread_id = await method(*args, message_thread_id=None) + assert message_thread_id is None - message_thread_id = await method( - *args, - do_quote=message.build_reply_arguments( - target_chat_id=message.chat_id, - ), - ) - assert message_thread_id == message.message_thread_id + if bot_method_name == "send_chat_action": + return + + message_thread_id = await method( + *args, + do_quote=message.build_reply_arguments( + target_chat_id=123, + ), + ) + assert message_thread_id is None + + for target_chat_id in (message.chat_id, message.chat.username): + message_thread_id = await method( + *args, + do_quote=message.build_reply_arguments( + target_chat_id=target_chat_id, + ), + ) + assert message_thread_id == (message.message_thread_id if is_topic_message else None) def test_slot_behaviour(self): message = Message( @@ -1396,6 +1405,7 @@ async def make_assertion(*_, **kwargs): Bot.send_message, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_text, @@ -1404,7 +1414,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_text, message.get_bot()) + assert await check_defaults_handling( + message.reply_text, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_message", make_assertion) assert await message.reply_text("test") @@ -1435,6 +1447,7 @@ async def make_assertion(*_, **kwargs): Bot.send_message, ["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_text, @@ -1443,7 +1456,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_text, message.get_bot()) + assert await check_defaults_handling( + message.reply_text, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) text_markdown = self.test_message.text_markdown assert text_markdown == test_md_string @@ -1478,6 +1493,7 @@ async def make_assertion(*_, **kwargs): Bot.send_message, ["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_text, @@ -1486,7 +1502,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_text, message.get_bot()) + assert await check_defaults_handling( + message.reply_text, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) text_markdown = self.test_message_v2.text_markdown_v2 assert text_markdown == test_md_string @@ -1526,6 +1544,7 @@ async def make_assertion(*_, **kwargs): Bot.send_message, ["chat_id", "parse_mode", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_text, @@ -1534,7 +1553,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_text, message.get_bot()) + assert await check_defaults_handling( + message.reply_text, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) text_html = self.test_message_v2.text_html assert text_html == test_html_string @@ -1560,6 +1581,7 @@ async def make_assertion(*_, **kwargs): Bot.send_media_group, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_media_group, @@ -1568,7 +1590,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_media_group, message.get_bot()) + assert await check_defaults_handling( + message.reply_media_group, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_media_group", make_assertion) assert await message.reply_media_group(media="reply_media_group") @@ -1599,6 +1623,7 @@ async def make_assertion(*_, **kwargs): Bot.send_photo, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_photo, @@ -1607,7 +1632,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_photo, message.get_bot()) + assert await check_defaults_handling( + message.reply_photo, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_photo", make_assertion) assert await message.reply_photo(photo="test_photo") @@ -1630,6 +1657,7 @@ async def make_assertion(*_, **kwargs): Bot.send_audio, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_audio, @@ -1638,7 +1666,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_audio, message.get_bot()) + assert await check_defaults_handling( + message.reply_audio, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_audio", make_assertion) assert await message.reply_audio(audio="test_audio") @@ -1661,6 +1691,7 @@ async def make_assertion(*_, **kwargs): Bot.send_document, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_document, @@ -1669,7 +1700,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_document, message.get_bot()) + assert await check_defaults_handling( + message.reply_document, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_document", make_assertion) assert await message.reply_document(document="test_document") @@ -1692,6 +1725,7 @@ async def make_assertion(*_, **kwargs): Bot.send_animation, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_animation, @@ -1700,7 +1734,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_animation, message.get_bot()) + assert await check_defaults_handling( + message.reply_animation, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_animation", make_assertion) assert await message.reply_animation(animation="test_animation") @@ -1723,6 +1759,7 @@ async def make_assertion(*_, **kwargs): Bot.send_sticker, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_sticker, @@ -1731,7 +1768,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_sticker, message.get_bot()) + assert await check_defaults_handling( + message.reply_sticker, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_sticker", make_assertion) assert await message.reply_sticker(sticker="test_sticker") @@ -1754,6 +1793,7 @@ async def make_assertion(*_, **kwargs): Bot.send_video, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_video, @@ -1762,7 +1802,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_video, message.get_bot()) + assert await check_defaults_handling( + message.reply_video, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_video", make_assertion) assert await message.reply_video(video="test_video") @@ -1785,6 +1827,7 @@ async def make_assertion(*_, **kwargs): Bot.send_video_note, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_video_note, @@ -1793,7 +1836,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_video_note, message.get_bot()) + assert await check_defaults_handling( + message.reply_video_note, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_video_note", make_assertion) assert await message.reply_video_note(video_note="test_video_note") @@ -1816,6 +1861,7 @@ async def make_assertion(*_, **kwargs): Bot.send_voice, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_voice, @@ -1824,7 +1870,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_voice, message.get_bot()) + assert await check_defaults_handling( + message.reply_voice, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_voice", make_assertion) assert await message.reply_voice(voice="test_voice") @@ -1847,6 +1895,7 @@ async def make_assertion(*_, **kwargs): Bot.send_location, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_location, @@ -1855,7 +1904,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_location, message.get_bot()) + assert await check_defaults_handling( + message.reply_location, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_location", make_assertion) assert await message.reply_location(location="test_location") @@ -1878,6 +1929,7 @@ async def make_assertion(*_, **kwargs): Bot.send_venue, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_venue, @@ -1886,7 +1938,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_venue, message.get_bot()) + assert await check_defaults_handling( + message.reply_venue, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_venue", make_assertion) assert await message.reply_venue(venue="test_venue") @@ -1909,6 +1963,7 @@ async def make_assertion(*_, **kwargs): Bot.send_contact, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_contact, @@ -1917,7 +1972,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_contact, message.get_bot()) + assert await check_defaults_handling( + message.reply_contact, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_contact", make_assertion) assert await message.reply_contact(contact="test_contact") @@ -1941,6 +1998,7 @@ async def make_assertion(*_, **kwargs): Bot.send_poll, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_poll, @@ -1949,7 +2007,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_poll, message.get_bot()) + assert await check_defaults_handling( + message.reply_poll, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_poll", make_assertion) assert await message.reply_poll(question="test_poll", options=["1", "2", "3"]) @@ -1972,6 +2032,7 @@ async def make_assertion(*_, **kwargs): Bot.send_dice, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_dice, @@ -1980,7 +2041,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_dice, message.get_bot()) + assert await check_defaults_handling( + message.reply_dice, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_dice", make_assertion) assert await message.reply_dice(disable_notification=True) @@ -2007,6 +2070,7 @@ async def make_assertion(*_, **kwargs): Bot.send_chat_action, ["chat_id", "reply_to_message_id", "business_connection_id"], [], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_chat_action, @@ -2014,7 +2078,9 @@ async def make_assertion(*_, **kwargs): "send_chat_action", shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_chat_action, message.get_bot()) + assert await check_defaults_handling( + message.reply_chat_action, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_chat_action", make_assertion) assert await message.reply_chat_action(action=ChatAction.TYPING) @@ -2038,6 +2104,7 @@ async def make_assertion(*_, **kwargs): Bot.send_game, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_game, @@ -2046,7 +2113,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_game, message.get_bot()) + assert await check_defaults_handling( + message.reply_game, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_game", make_assertion) assert await message.reply_game(game_short_name="test_game") @@ -2078,6 +2147,7 @@ async def make_assertion(*_, **kwargs): Bot.send_invoice, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call( message.reply_invoice, @@ -2086,7 +2156,9 @@ async def make_assertion(*_, **kwargs): skip_params=["reply_to_message_id"], shortcut_kwargs=["business_connection_id"], ) - assert await check_defaults_handling(message.reply_invoice, message.get_bot()) + assert await check_defaults_handling( + message.reply_invoice, message.get_bot(), no_default_kwargs={"message_thread_id"} + ) monkeypatch.setattr(message.get_bot(), "send_invoice", make_assertion) assert await message.reply_invoice( @@ -2204,6 +2276,7 @@ async def make_assertion(*_, **kwargs): Bot.copy_message, ["chat_id", "reply_to_message_id", "business_connection_id"], ["quote", "do_quote", "reply_to_message_id"], + annotation_overrides={"message_thread_id": (ODVInput[int], DEFAULT_NONE)}, ) assert await check_shortcut_call(message.copy, message.get_bot(), "copy_message") assert await check_defaults_handling(message.copy, message.get_bot()) From 75d946e4be493316a98a638adedf537d1000889e Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:00:17 +0200 Subject: [PATCH 4/4] Bump version to v21.1.1 --- CHANGES.rst | 19 +++++++++++++++++++ docs/source/conf.py | 4 ++-- telegram/_version.py | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 1a7f3c0466c..91e0eb8f00e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,25 @@ Changelog ========= +Version 21.1.1 +============== + +*Released 2024-04-15* + +This is the technical changelog for version 21.1.1. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel `__. + +Bug Fixes +--------- + +- Fix Bug With Parameter ``message_thread_id`` of ``Message.reply_*`` (:pr:`4207` closes :issue:`4205`) + +Minor Changes +------------- + +- Remove Deprecation Warning in ``JobQueue.run_daily`` (:pr:`4206` by `@Konano `__) +- Fix Annotation of ``EncryptedCredentials.decrypted_secret`` (:pr:`4199` by `@marinelay `__ closes :issue:`4198`) + + Version 21.1 ============== diff --git a/docs/source/conf.py b/docs/source/conf.py index 372d0c81581..92388805993 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,9 +20,9 @@ # built documents. # # The short X.Y version. -version = "21.1" # telegram.__version__[:3] +version = "21.1.1" # telegram.__version__[:3] # The full version, including alpha/beta/rc tags. -release = "21.1" # telegram.__version__ +release = "21.1.1" # telegram.__version__ # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = "6.1.3" diff --git a/telegram/_version.py b/telegram/_version.py index fd81c535668..bc75598cc1a 100644 --- a/telegram/_version.py +++ b/telegram/_version.py @@ -51,7 +51,7 @@ def __str__(self) -> str: __version_info__: Final[Version] = Version( - major=21, minor=1, micro=0, releaselevel="final", serial=0 + major=21, minor=1, micro=1, releaselevel="final", serial=0 ) __version__: Final[str] = str(__version_info__)