From ac6fb7fe70dbcce74dd819f1fc8c805ad6f4edce Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:00:59 +0530 Subject: [PATCH 1/5] adjust defaults in telegram classes and methods --- telegram/_bot.py | 20 ++++----- telegram/_callbackquery.py | 2 +- telegram/_chat.py | 7 ++- telegram/_forcereply.py | 2 +- telegram/_inline/inlinequery.py | 2 +- telegram/_message.py | 14 +++--- telegram/_replykeyboardmarkup.py | 12 ++--- telegram/_replykeyboardremove.py | 2 +- telegram/_user.py | 10 ++--- telegram/ext/_extbot.py | 4 +- tests/test_official.py | 77 ++++++++++++++++++++++---------- 11 files changed, 89 insertions(+), 63 deletions(-) diff --git a/telegram/_bot.py b/telegram/_bot.py index 23f2659f511..6fde4739e18 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -2658,7 +2658,7 @@ async def answer_inline_query( results: Union[ Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] ], - cache_time: int = 300, + cache_time: int = None, is_personal: bool = None, next_offset: str = None, switch_pm_text: str = None, @@ -2775,7 +2775,7 @@ async def get_user_profile_photos( self, user_id: Union[str, int], offset: int = None, - limit: int = 100, + limit: int = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3177,7 +3177,7 @@ async def answer_callback_query( self, callback_query_id: str, text: str = None, - show_alert: bool = False, + show_alert: bool = None, url: str = None, cache_time: int = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3598,8 +3598,8 @@ async def edit_message_reply_markup( async def get_updates( self, offset: int = None, - limit: int = 100, - timeout: int = 0, + limit: int = None, + timeout: float = None, read_timeout: float = 2, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3678,7 +3678,7 @@ async def get_updates( await self._post( "getUpdates", data, - read_timeout=read_timeout + timeout, + read_timeout=read_timeout + timeout if timeout else read_timeout, write_timeout=write_timeout, connect_timeout=connect_timeout, pool_timeout=pool_timeout, @@ -3702,7 +3702,7 @@ async def set_webhook( write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, pool_timeout: ODVInput[float] = DEFAULT_NONE, - max_connections: int = 40, + max_connections: int = None, allowed_updates: List[str] = None, api_kwargs: JSONDict = None, ip_address: str = None, @@ -6557,9 +6557,9 @@ async def send_poll( chat_id: Union[int, str], question: str, options: List[str], - is_anonymous: bool = True, - type: str = Poll.REGULAR, # pylint: disable=redefined-builtin - allows_multiple_answers: bool = False, + is_anonymous: bool = None, + type: str = None, # pylint: disable=redefined-builtin + allows_multiple_answers: bool = None, correct_option_id: int = None, is_closed: bool = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index 7b960fff747..455616970f7 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -149,7 +149,7 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["CallbackQuer async def answer( self, text: str = None, - show_alert: bool = False, + show_alert: bool = None, url: str = None, cache_time: int = None, read_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_chat.py b/telegram/_chat.py index 216538fd861..dda1066c6c1 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -1701,10 +1701,9 @@ async def send_poll( self, question: str, options: List[str], - is_anonymous: bool = True, - # We use constant.PollType.REGULAR instead of Poll.REGULAR here to avoid circular imports - type: str = constants.PollType.REGULAR, # pylint: disable=redefined-builtin - allows_multiple_answers: bool = False, + is_anonymous: bool = None, + type: str = None, + allows_multiple_answers: bool = None, correct_option_id: int = None, is_closed: bool = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, diff --git a/telegram/_forcereply.py b/telegram/_forcereply.py index 8d14d468b7d..0dcd69c92ab 100644 --- a/telegram/_forcereply.py +++ b/telegram/_forcereply.py @@ -68,7 +68,7 @@ class ForceReply(TelegramObject): def __init__( self, - selective: bool = False, + selective: bool = None, input_field_placeholder: str = None, **_kwargs: Any, ): diff --git a/telegram/_inline/inlinequery.py b/telegram/_inline/inlinequery.py index dab3b388308..dfb6d087eb9 100644 --- a/telegram/_inline/inlinequery.py +++ b/telegram/_inline/inlinequery.py @@ -118,7 +118,7 @@ async def answer( results: Union[ Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]] ], - cache_time: int = 300, + cache_time: int = None, is_personal: bool = None, next_offset: str = None, switch_pm_text: str = None, diff --git a/telegram/_message.py b/telegram/_message.py index 73eae20833d..fda28eb941b 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -460,10 +460,10 @@ def __init__( left_chat_member: User = None, new_chat_title: str = None, new_chat_photo: List[PhotoSize] = None, - delete_chat_photo: bool = False, - group_chat_created: bool = False, - supergroup_chat_created: bool = False, - channel_chat_created: bool = False, + delete_chat_photo: bool = None, + group_chat_created: bool = None, + supergroup_chat_created: bool = None, + channel_chat_created: bool = None, migrate_to_chat_id: int = None, migrate_from_chat_id: int = None, pinned_message: "Message" = None, @@ -1671,9 +1671,9 @@ async def reply_poll( self, question: str, options: List[str], - is_anonymous: bool = True, - type: str = Poll.REGULAR, # pylint: disable=redefined-builtin - allows_multiple_answers: bool = False, + is_anonymous: bool = None, + type: str = None, # pylint: disable=redefined-builtin + allows_multiple_answers: bool = None, correct_option_id: int = None, is_closed: bool = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, diff --git a/telegram/_replykeyboardmarkup.py b/telegram/_replykeyboardmarkup.py index 208151be94e..8b34081b0fa 100644 --- a/telegram/_replykeyboardmarkup.py +++ b/telegram/_replykeyboardmarkup.py @@ -41,12 +41,12 @@ class ReplyKeyboardMarkup(TelegramObject): each represented by an Array of :class:`telegram.KeyboardButton` objects. resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of - buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the + buttons). Defaults to :obj:`None`, in which case the custom keyboard is always of the same height as the app's standard keyboard. one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat - the user can press a special button in - the input field to see the custom keyboard again. Defaults to :obj:`False`. + the input field to see the custom keyboard again. Defaults to :obj:`None`. selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to specific users only. Targets: @@ -55,7 +55,7 @@ class ReplyKeyboardMarkup(TelegramObject): 2) If the bot's message is a reply (has ``reply_to_message_id``), sender of the original message. - Defaults to :obj:`False`. + Defaults to :obj:`None`. input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input field when the keyboard is active; 1-64 characters. @@ -88,9 +88,9 @@ class ReplyKeyboardMarkup(TelegramObject): def __init__( self, keyboard: Sequence[Sequence[Union[str, KeyboardButton]]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, + resize_keyboard: bool = None, + one_time_keyboard: bool = None, + selective: bool = None, input_field_placeholder: str = None, **_kwargs: Any, ): diff --git a/telegram/_replykeyboardremove.py b/telegram/_replykeyboardremove.py index 2ce9260977f..e5c22798f7b 100644 --- a/telegram/_replykeyboardremove.py +++ b/telegram/_replykeyboardremove.py @@ -57,7 +57,7 @@ class ReplyKeyboardRemove(TelegramObject): __slots__ = ("selective", "remove_keyboard") - def __init__(self, selective: bool = False, **_kwargs: Any): + def __init__(self, selective: bool = None, **_kwargs: Any): # Required self.remove_keyboard = True # Optionals diff --git a/telegram/_user.py b/telegram/_user.py index 91095e6e5e8..e0ba8086beb 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -21,7 +21,6 @@ from datetime import datetime from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union -from telegram import constants from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton from telegram._menubutton import MenuButton from telegram._telegramobject import TelegramObject @@ -166,7 +165,7 @@ def link(self) -> Optional[str]: async def get_profile_photos( self, offset: int = None, - limit: int = 100, + limit: int = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1179,10 +1178,9 @@ async def send_poll( self, question: str, options: List[str], - is_anonymous: bool = True, - # We use constant.PollType.REGULAR instead of Poll.REGULAR here to avoid circular imports - type: str = constants.PollType.REGULAR, # pylint: disable=redefined-builtin - allows_multiple_answers: bool = False, + is_anonymous: bool = None, + type: str = None, + allows_multiple_answers: bool = None, correct_option_id: int = None, is_closed: bool = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index a89fdeb6bf0..c768746dac5 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -271,8 +271,8 @@ async def _send_message( async def get_updates( self, offset: int = None, - limit: int = 100, - timeout: int = 0, + limit: int = None, + timeout: float = None, read_timeout: float = 2, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/tests/test_official.py b/tests/test_official.py index 9a4b140ae1a..0ac117d0020 100644 --- a/tests/test_official.py +++ b/tests/test_official.py @@ -25,6 +25,7 @@ from bs4 import BeautifulSoup import telegram +from telegram._utils.defaultvalue import DefaultValue from tests.conftest import env_var_2_bool IGNORED_OBJECTS = ("ResponseParameters", "CallbackGame") @@ -77,15 +78,26 @@ def check_method(h4): sig = inspect.signature(method, follow_wrapped=True) checked = [] - for parameter in table: - param = sig.parameters.get(parameter[0]) - assert param is not None, f"Parameter {parameter[0]} not found in {method.__name__}" + for tg_parameter in table: # Iterates through each row in the table + param = sig.parameters.get( + tg_parameter[0] + ) # parameter[0] is first element (the param name) + assert param is not None, f"Parameter {tg_parameter[0]} not found in {method.__name__}" # TODO: Check type via docstring assert check_required_param( - parameter, param.name, sig, method.__name__ + tg_parameter, param, method.__name__ ), f"Param {param.name!r} of method {method.__name__!r} requirement mismatch!" - checked.append(parameter[0]) + + # Now we will check that we don't pass default values if the parameter is not required. + # parameter[2] can either be Required/Yes or a paragraph where the first word has that info + telegram_param_required = is_parameter_required_by_tg(tg_parameter[2]) + + if not telegram_param_required: + default_arg_none = check_defaults_type(param) + assert default_arg_none, f"Param {param.name!r} of {method.__name__!r} should be None" + + checked.append(tg_parameter[0]) ignored = IGNORED_PARAMETERS.copy() if name == "getUpdates": @@ -124,8 +136,8 @@ def check_object(h4): sig = inspect.signature(obj.__init__, follow_wrapped=True) checked = set() - for parameter in table: - field = parameter[0] + for tg_parameter in table: + field: str = tg_parameter[0] # From telegram docs if field == "from": field = "from_user" elif ( @@ -148,8 +160,15 @@ def check_object(h4): assert param is not None, f"Attribute {field} not found in {obj.__name__}" # TODO: Check type via docstring assert check_required_param( - parameter, field, sig, obj.__name__ + tg_parameter, param, obj.__name__ ), f"{obj.__name__!r} parameter {param.name!r} requirement mismatch" + + telegram_param_required = is_parameter_required_by_tg(tg_parameter[2]) + + if not telegram_param_required: + default_arg_none = check_defaults_type(param) + assert default_arg_none, f"Param {param.name!r} of {obj.__name__!r} should be `None`" + checked.add(field) ignored = IGNORED_PARAMETERS.copy() @@ -175,24 +194,34 @@ def check_object(h4): assert (sig.parameters.keys() ^ checked) - ignored == set() +def is_parameter_required_by_tg(field: str) -> bool: + if field in {"Required", "Yes"}: + return True + if field.split(".", 1)[0] == "Optional": # splits the sentence and extracts first word + return False + else: + return True + + def check_required_param( - param_desc: List[str], param_name: str, sig: inspect.Signature, method_or_obj_name: str + param_desc: List[str], param: inspect.Parameter, method_or_obj_name: str ) -> bool: - """Checks if the method/class parameter is a required/optional param as per Telegram docs.""" - if len(param_desc) == 4: # this means that there is a dedicated 'Required' column present. - # Handle cases where we provide convenience intentionally- - if param_name in ignored_param_requirements.get(method_or_obj_name, {}): - return True - is_required = True if param_desc[2] in {"Required", "Yes"} else False - is_ours_required = sig.parameters[param_name].default is inspect.Signature.empty - return is_required is is_ours_required - - if len(param_desc) == 3: # The docs mention the requirement in the description for classes... - if param_name in ignored_param_requirements.get(method_or_obj_name, {}): - return True - is_required = False if param_desc[2].split(".", 1)[0] == "Optional" else True - is_ours_required = sig.parameters[param_name].default is inspect.Signature.empty - return is_required is is_ours_required + """Checks if the method/class parameter is a required/optional param as per Telegram docs. + + Returns: + :obj:`bool`: The boolean returned represents whether our parameter's requirement (optional + or required) is the same as Telegram's or not. + """ + is_ours_required = param.default is inspect.Signature.empty + telegram_requires = is_parameter_required_by_tg(param_desc[2]) + # Handle cases where we provide convenience intentionally- + if param.name in ignored_param_requirements.get(method_or_obj_name, {}): + return True + return telegram_requires is is_ours_required + + +def check_defaults_type(ptb_param: inspect.Parameter) -> bool: + return True if DefaultValue.get_value(ptb_param.default) is None else False argvalues = [] From 7dc802af0a532b82b51e3e4e28c6d35bf2b75038 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Wed, 27 Apr 2022 20:34:49 +0530 Subject: [PATCH 2/5] defer fetching of telegram web page source if test_official is to be skipped --- tests/test_official.py | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/tests/test_official.py b/tests/test_official.py index 0ac117d0020..a00a65e726f 100644 --- a/tests/test_official.py +++ b/tests/test_official.py @@ -80,8 +80,8 @@ def check_method(h4): checked = [] for tg_parameter in table: # Iterates through each row in the table param = sig.parameters.get( - tg_parameter[0] - ) # parameter[0] is first element (the param name) + tg_parameter[0] # parameter[0] is first element (the param name) + ) assert param is not None, f"Parameter {tg_parameter[0]} not found in {method.__name__}" # TODO: Check type via docstring @@ -224,29 +224,32 @@ def check_defaults_type(ptb_param: inspect.Parameter) -> bool: return True if DefaultValue.get_value(ptb_param.default) is None else False +to_run = env_var_2_bool(os.getenv("TEST_OFFICIAL")) argvalues = [] names = [] -request = httpx.get("https://core.telegram.org/bots/api") -soup = BeautifulSoup(request.text, "html.parser") -for thing in soup.select("h4 > a.anchor"): - # Methods and types don't have spaces in them, luckily all other sections of the docs do - # TODO: don't depend on that - if "-" not in thing["name"]: - h4 = thing.parent +if to_run: + argvalues = [] + names = [] + request = httpx.get("https://core.telegram.org/bots/api") + soup = BeautifulSoup(request.text, "html.parser") - # Is it a method - if h4.text[0].lower() == h4.text[0]: - argvalues.append((check_method, h4)) - names.append(h4.text) - elif h4.text not in IGNORED_OBJECTS: # Or a type/object - argvalues.append((check_object, h4)) - names.append(h4.text) + for thing in soup.select("h4 > a.anchor"): + # Methods and types don't have spaces in them, luckily all other sections of the docs do + # TODO: don't depend on that + if "-" not in thing["name"]: + h4 = thing.parent + # Is it a method + if h4.text[0].lower() == h4.text[0]: + argvalues.append((check_method, h4)) + names.append(h4.text) + elif h4.text not in IGNORED_OBJECTS: # Or a type/object + argvalues.append((check_object, h4)) + names.append(h4.text) + +@pytest.mark.skipif(not to_run, reason="test_official is not enabled") @pytest.mark.parametrize(("method", "data"), argvalues=argvalues, ids=names) -@pytest.mark.skipif( - not env_var_2_bool(os.getenv("TEST_OFFICIAL")), reason="test_official is not enabled" -) def test_official(method, data): method(data) From ad42e7841a9d03356cac1775637cfee035bf125a Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Thu, 5 May 2022 23:21:23 +0530 Subject: [PATCH 3/5] reveiw --- tests/test_official.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/test_official.py b/tests/test_official.py index a00a65e726f..60de720327e 100644 --- a/tests/test_official.py +++ b/tests/test_official.py @@ -90,11 +90,8 @@ def check_method(h4): ), f"Param {param.name!r} of method {method.__name__!r} requirement mismatch!" # Now we will check that we don't pass default values if the parameter is not required. - # parameter[2] can either be Required/Yes or a paragraph where the first word has that info - telegram_param_required = is_parameter_required_by_tg(tg_parameter[2]) - - if not telegram_param_required: - default_arg_none = check_defaults_type(param) + if param.default is not inspect.Parameter.empty: # If there is a default argument... + default_arg_none = check_defaults_type(param) # check if it's None assert default_arg_none, f"Param {param.name!r} of {method.__name__!r} should be None" checked.append(tg_parameter[0]) @@ -163,10 +160,8 @@ def check_object(h4): tg_parameter, param, obj.__name__ ), f"{obj.__name__!r} parameter {param.name!r} requirement mismatch" - telegram_param_required = is_parameter_required_by_tg(tg_parameter[2]) - - if not telegram_param_required: - default_arg_none = check_defaults_type(param) + if param.default is not inspect.Parameter.empty: # If there is a default argument... + default_arg_none = check_defaults_type(param) # check if its None assert default_arg_none, f"Param {param.name!r} of {obj.__name__!r} should be `None`" checked.add(field) @@ -212,7 +207,7 @@ def check_required_param( :obj:`bool`: The boolean returned represents whether our parameter's requirement (optional or required) is the same as Telegram's or not. """ - is_ours_required = param.default is inspect.Signature.empty + is_ours_required = param.default is inspect.Parameter.empty telegram_requires = is_parameter_required_by_tg(param_desc[2]) # Handle cases where we provide convenience intentionally- if param.name in ignored_param_requirements.get(method_or_obj_name, {}): From 16658cbe2db1c6d618973f2bb734315d25d40753 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Fri, 6 May 2022 21:53:45 +0530 Subject: [PATCH 4/5] review 2 --- telegram/_forcereply.py | 2 +- telegram/_replykeyboardmarkup.py | 12 ++++++------ telegram/_replykeyboardremove.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/telegram/_forcereply.py b/telegram/_forcereply.py index 0dcd69c92ab..baecf2c8346 100644 --- a/telegram/_forcereply.py +++ b/telegram/_forcereply.py @@ -73,7 +73,7 @@ def __init__( **_kwargs: Any, ): self.force_reply = True - self.selective = bool(selective) + self.selective = selective self.input_field_placeholder = input_field_placeholder self._id_attrs = (self.selective,) diff --git a/telegram/_replykeyboardmarkup.py b/telegram/_replykeyboardmarkup.py index 8b34081b0fa..23f8405ee80 100644 --- a/telegram/_replykeyboardmarkup.py +++ b/telegram/_replykeyboardmarkup.py @@ -41,12 +41,12 @@ class ReplyKeyboardMarkup(TelegramObject): each represented by an Array of :class:`telegram.KeyboardButton` objects. resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of - buttons). Defaults to :obj:`None`, in which case the custom keyboard is always of the + buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the same height as the app's standard keyboard. one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat - the user can press a special button in - the input field to see the custom keyboard again. Defaults to :obj:`None`. + the input field to see the custom keyboard again. Defaults to :obj:`False`. selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to specific users only. Targets: @@ -55,7 +55,7 @@ class ReplyKeyboardMarkup(TelegramObject): 2) If the bot's message is a reply (has ``reply_to_message_id``), sender of the original message. - Defaults to :obj:`None`. + Defaults to :obj:`False`. input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input field when the keyboard is active; 1-64 characters. @@ -112,9 +112,9 @@ def __init__( self.keyboard.append(button_row) # Optionals - self.resize_keyboard = bool(resize_keyboard) - self.one_time_keyboard = bool(one_time_keyboard) - self.selective = bool(selective) + self.resize_keyboard = resize_keyboard + self.one_time_keyboard = one_time_keyboard + self.selective = selective self.input_field_placeholder = input_field_placeholder self._id_attrs = (self.keyboard,) diff --git a/telegram/_replykeyboardremove.py b/telegram/_replykeyboardremove.py index e5c22798f7b..a98e8b60966 100644 --- a/telegram/_replykeyboardremove.py +++ b/telegram/_replykeyboardremove.py @@ -61,4 +61,4 @@ def __init__(self, selective: bool = None, **_kwargs: Any): # Required self.remove_keyboard = True # Optionals - self.selective = bool(selective) + self.selective = selective From 4bec34733dc1a48ccf68ca928f0b5d24e57fa96e Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sun, 8 May 2022 01:58:08 +0530 Subject: [PATCH 5/5] try stabilizing a test --- tests/test_bot.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_bot.py b/tests/test_bot.py index 2c98d813284..98a067e8351 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -259,6 +259,12 @@ async def test_log_decorator(self, bot, caplog): # Second argument makes sure that we ignore logs from e.g. httpx with caplog.at_level(logging.DEBUG, logger="telegram"): await bot.get_me() + # Only for stabilizing this test- + if len(caplog.records) == 4: + for idx, record in enumerate(caplog.records): + print(record) + if record.getMessage().startswith("Task was destroyed but it is pending"): + caplog.records.pop(idx) assert len(caplog.records) == 3 assert caplog.records[0].getMessage().startswith("Entering: get_me") assert caplog.records[-1].getMessage().startswith("Exiting: get_me")