diff --git a/docs/source/telegram.rst b/docs/source/telegram.rst index 39d8a6b1321..e5d101e3176 100644 --- a/docs/source/telegram.rst +++ b/docs/source/telegram.rst @@ -181,3 +181,4 @@ utils telegram.utils.promise telegram.utils.request telegram.utils.types + telegram.utils.warnings diff --git a/docs/source/telegram.utils.warnings.rst b/docs/source/telegram.utils.warnings.rst new file mode 100644 index 00000000000..1be54181097 --- /dev/null +++ b/docs/source/telegram.utils.warnings.rst @@ -0,0 +1,8 @@ +:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/utils/warnings.py + +telegram.utils.warnings Module +=============================== + +.. automodule:: telegram.utils.warnings + :members: + :show-inheritance: diff --git a/telegram/base.py b/telegram/base.py index e8fc3a98096..21abade3853 100644 --- a/telegram/base.py +++ b/telegram/base.py @@ -22,10 +22,10 @@ except ImportError: import json # type: ignore[no-redef] -import warnings from typing import TYPE_CHECKING, List, Optional, Type, TypeVar, Tuple from telegram.utils.types import JSONDict +from telegram.utils.warnings import warn if TYPE_CHECKING: from telegram import Bot @@ -140,14 +140,16 @@ def __eq__(self, other: object) -> bool: # pylint: disable=no-member if isinstance(other, self.__class__): if self._id_attrs == (): - warnings.warn( + warn( f"Objects of type {self.__class__.__name__} can not be meaningfully tested for" - " equivalence." + " equivalence.", + stacklevel=2, ) if other._id_attrs == (): - warnings.warn( + warn( f"Objects of type {other.__class__.__name__} can not be meaningfully tested" - " for equivalence." + " for equivalence.", + stacklevel=2, ) return self._id_attrs == other._id_attrs return super().__eq__(other) diff --git a/telegram/bot.py b/telegram/bot.py index ffc3bce6f37..a02e36272e6 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -21,7 +21,6 @@ import functools import logging -import warnings from datetime import datetime from typing import ( @@ -91,7 +90,7 @@ ) from telegram.constants import MAX_INLINE_QUERY_RESULTS from telegram.error import InvalidToken, TelegramError -from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.warnings import PTBDeprecationWarning, warn from telegram.utils.helpers import ( DEFAULT_NONE, DefaultValue, @@ -198,10 +197,10 @@ def __init__( self.defaults = defaults if self.defaults: - warnings.warn( + warn( 'Passing Defaults to telegram.Bot is deprecated. Use telegram.ext.ExtBot instead.', - TelegramDeprecationWarning, - stacklevel=3, + PTBDeprecationWarning, + stacklevel=4, ) if base_url is None: diff --git a/telegram/ext/basepersistence.py b/telegram/ext/basepersistence.py index 98d0515556e..39f35208c79 100644 --- a/telegram/ext/basepersistence.py +++ b/telegram/ext/basepersistence.py @@ -17,7 +17,6 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains the BasePersistence class.""" -import warnings from abc import ABC, abstractmethod from copy import copy from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict, NamedTuple @@ -26,6 +25,7 @@ import telegram.ext.extbot from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData +from telegram.utils.warnings import warn, PTBRuntimeWarning class PersistenceInput(NamedTuple): @@ -230,10 +230,10 @@ def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint return new_immutable if isinstance(obj, type): # classes usually do have a __dict__, but it's not writable - warnings.warn( - 'BasePersistence.replace_bot does not handle classes. See ' - 'the docs of BasePersistence.replace_bot for more information.', - RuntimeWarning, + warn( + f'BasePersistence.replace_bot does not handle classes such as {obj.__name__!r}. ' + 'See the docs of BasePersistence.replace_bot for more information.', + PTBRuntimeWarning, ) return obj @@ -241,10 +241,10 @@ def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint new_obj = copy(obj) memo[obj_id] = new_obj except Exception: - warnings.warn( + warn( 'BasePersistence.replace_bot does not handle objects that can not be copied. See ' 'the docs of BasePersistence.replace_bot for more information.', - RuntimeWarning, + PTBRuntimeWarning, ) memo[obj_id] = obj return obj @@ -282,10 +282,10 @@ def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint memo[obj_id] = new_obj return new_obj except Exception as exception: - warnings.warn( + warn( f'Parsing of an object failed with the following exception: {exception}. ' f'See the docs of BasePersistence.replace_bot for more information.', - RuntimeWarning, + PTBRuntimeWarning, ) memo[obj_id] = obj @@ -333,20 +333,20 @@ def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint return new_immutable if isinstance(obj, type): # classes usually do have a __dict__, but it's not writable - warnings.warn( - 'BasePersistence.insert_bot does not handle classes. See ' - 'the docs of BasePersistence.insert_bot for more information.', - RuntimeWarning, + warn( + f'BasePersistence.insert_bot does not handle classes such as {obj.__name__!r}. ' + 'See the docs of BasePersistence.insert_bot for more information.', + PTBRuntimeWarning, ) return obj try: new_obj = copy(obj) except Exception: - warnings.warn( + warn( 'BasePersistence.insert_bot does not handle objects that can not be copied. See ' 'the docs of BasePersistence.insert_bot for more information.', - RuntimeWarning, + PTBRuntimeWarning, ) memo[obj_id] = obj return obj @@ -384,10 +384,10 @@ def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint memo[obj_id] = new_obj return new_obj except Exception as exception: - warnings.warn( + warn( f'Parsing of an object failed with the following exception: {exception}. ' f'See the docs of BasePersistence.insert_bot for more information.', - RuntimeWarning, + PTBRuntimeWarning, ) memo[obj_id] = obj diff --git a/telegram/ext/conversationhandler.py b/telegram/ext/conversationhandler.py index 91ed42a61e2..794afca19f9 100644 --- a/telegram/ext/conversationhandler.py +++ b/telegram/ext/conversationhandler.py @@ -20,7 +20,6 @@ """This module contains the ConversationHandler.""" import logging -import warnings import functools import datetime from threading import Lock @@ -39,6 +38,7 @@ from telegram.ext.utils.promise import Promise from telegram.ext.utils.types import ConversationDict from telegram.ext.utils.types import CCT +from telegram.utils.warnings import warn if TYPE_CHECKING: from telegram.ext import Dispatcher, Job @@ -259,9 +259,10 @@ def __init__( raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'") if self.per_message and not self.per_chat: - warnings.warn( + warn( "If 'per_message=True' is used, 'per_chat=True' should also be used, " - "since message IDs are not globally unique." + "since message IDs are not globally unique.", + stacklevel=2, ) all_handlers: List[Handler] = [] @@ -274,37 +275,41 @@ def __init__( if self.per_message: for handler in all_handlers: if not isinstance(handler, CallbackQueryHandler): - warnings.warn( - "If 'per_message=True', all entry points and state handlers" + warn( + "If 'per_message=True', all entry points, state handlers, and fallbacks" " must be 'CallbackQueryHandler', since no other handlers " - "have a message context." + "have a message context.", + stacklevel=2, ) break else: for handler in all_handlers: if isinstance(handler, CallbackQueryHandler): - warnings.warn( + warn( "If 'per_message=False', 'CallbackQueryHandler' will not be " - "tracked for every message." + "tracked for every message.", + stacklevel=2, ) break if self.per_chat: for handler in all_handlers: if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)): - warnings.warn( + warn( "If 'per_chat=True', 'InlineQueryHandler' can not be used, " - "since inline queries have no chat context." + "since inline queries have no chat context.", + stacklevel=2, ) break if self.conversation_timeout: for handler in all_handlers: if isinstance(handler, self.__class__): - warnings.warn( + warn( "Using `conversation_timeout` with nested conversations is currently not " "supported. You can still try to use it, but it will likely behave " - "differently from what you expect." + "differently from what you expect.", + stacklevel=2, ) break @@ -644,8 +649,8 @@ def handle_update( # type: ignore[override] new_state, dispatcher, update, context, conversation_key ) else: - self.logger.warning( - "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue." + warn( + "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue.", ) if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent: @@ -680,9 +685,9 @@ def _update_state(self, new_state: object, key: Tuple[int, ...]) -> None: elif new_state is not None: if new_state not in self.states: - warnings.warn( + warn( f"Handler returned state {new_state} which is unknown to the " - f"ConversationHandler{' ' + self.name if self.name is not None else ''}." + f"ConversationHandler{' ' + self.name if self.name is not None else ''}.", ) with self._conversations_lock: self.conversations[key] = new_state @@ -711,9 +716,9 @@ def _trigger_timeout(self, context: CallbackContext) -> None: try: handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context) except DispatcherHandlerStop: - self.logger.warning( + warn( 'DispatcherHandlerStop in TIMEOUT state of ' - 'ConversationHandler has no effect. Ignoring.' + 'ConversationHandler has no effect. Ignoring.', ) self._update_state(self.END, ctxt.conversation_key) diff --git a/telegram/ext/dispatcher.py b/telegram/ext/dispatcher.py index 55c1485202b..7fec7f30ff4 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -19,7 +19,6 @@ """This module contains the Dispatcher class.""" import logging -import warnings import weakref from collections import defaultdict from queue import Empty, Queue @@ -47,6 +46,7 @@ import telegram.ext.extbot from telegram.ext.callbackdatacache import CallbackDataCache from telegram.ext.utils.promise import Promise +from telegram.utils.warnings import warn from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.ext.utils.types import CCT, UD, CD, BD @@ -196,8 +196,9 @@ def __init__( self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes()) if self.workers < 1: - warnings.warn( - 'Asynchronous callbacks can not be processed without at least one worker thread.' + warn( + 'Asynchronous callbacks can not be processed without at least one worker thread.', + stacklevel=2, ) self.user_data: DefaultDict[int, UD] = defaultdict(self.context_types.user_data) @@ -312,9 +313,9 @@ def _pooled(self) -> None: continue if isinstance(promise.exception, DispatcherHandlerStop): - self.logger.warning( - 'DispatcherHandlerStop is not supported with async functions; func: %s', - promise.pooled_function.__name__, + warn( + 'DispatcherHandlerStop is not supported with async functions; ' + f'func: {promise.pooled_function.__name__}', ) continue diff --git a/telegram/ext/updater.py b/telegram/ext/updater.py index 15ae9276b56..05e9274c736 100644 --- a/telegram/ext/updater.py +++ b/telegram/ext/updater.py @@ -20,7 +20,6 @@ import logging import ssl -import warnings from queue import Queue from signal import SIGABRT, SIGINT, SIGTERM, signal from threading import Event, Lock, Thread, current_thread @@ -42,7 +41,7 @@ from telegram import Bot, TelegramError from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized from telegram.ext import Dispatcher, JobQueue, ContextTypes, ExtBot -from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.warnings import PTBDeprecationWarning, warn from telegram.utils.helpers import get_signal_name, DEFAULT_FALSE, DefaultValue from telegram.utils.request import Request from telegram.ext.utils.types import CCT, UD, CD, BD @@ -211,14 +210,14 @@ def __init__( # type: ignore[no-untyped-def,misc] ): if defaults and bot: - warnings.warn( + warn( 'Passing defaults to an Updater has no effect when a Bot is passed ' 'as well. Pass them to the Bot instead.', - TelegramDeprecationWarning, + PTBDeprecationWarning, stacklevel=2, ) if arbitrary_callback_data is not DEFAULT_FALSE and bot: - warnings.warn( + warn( 'Passing arbitrary_callback_data to an Updater has no ' 'effect when a Bot is passed as well. Pass them to the Bot instead.', stacklevel=2, @@ -250,9 +249,10 @@ def __init__( # type: ignore[no-untyped-def,misc] if bot is not None: self.bot = bot if bot.request.con_pool_size < con_pool_size: - self.logger.warning( - 'Connection pool of Request object is smaller than optimal value (%s)', - con_pool_size, + warn( + f'Connection pool of Request object is smaller than optimal value ' + f'{con_pool_size}', + stacklevel=2, ) else: # we need a connection pool the size of: @@ -299,9 +299,10 @@ def __init__( # type: ignore[no-untyped-def,misc] self.bot = dispatcher.bot if self.bot.request.con_pool_size < con_pool_size: - self.logger.warning( - 'Connection pool of Request object is smaller than optimal value (%s)', - con_pool_size, + warn( + f'Connection pool of Request object is smaller than optimal value ' + f'{con_pool_size}', + stacklevel=2, ) self.update_queue = dispatcher.update_queue self.__exception_event = dispatcher.exception_event diff --git a/telegram/utils/deprecate.py b/telegram/utils/deprecate.py deleted file mode 100644 index 7945695937b..00000000000 --- a/telegram/utils/deprecate.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza -# -# 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/]. -"""This module contains a class which is used for deprecation warnings.""" - - -# We use our own DeprecationWarning since they are muted by default and "UserWarning" makes it -# seem like it's the user that issued the warning -# We name it something else so that you don't get confused when you attempt to suppress it -class TelegramDeprecationWarning(Warning): - """Custom warning class for deprecations in this library.""" - - __slots__ = () diff --git a/telegram/utils/warnings.py b/telegram/utils/warnings.py new file mode 100644 index 00000000000..fe709c83bb7 --- /dev/null +++ b/telegram/utils/warnings.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza +# +# 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/]. +"""This module contains classes used for warnings.""" +import warnings +from typing import Type + + +class PTBUserWarning(UserWarning): + """ + Custom user warning class used for warnings in this library. + + .. versionadded:: 14.0 + """ + + __slots__ = () + + +class PTBRuntimeWarning(PTBUserWarning, RuntimeWarning): + """ + Custom runtime warning class used for warnings in this library. + + .. versionadded:: 14.0 + """ + + __slots__ = () + + +# https://www.python.org/dev/peps/pep-0565/ recommends to use a custom warning class derived from +# DeprecationWarning. We also subclass from TGUserWarning so users can easily 'switch off' warnings +class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning): + """ + Custom warning class for deprecations in this library. + + .. versionchanged:: 14.0 + Renamed TelegramDeprecationWarning to PTBDeprecationWarning. + """ + + __slots__ = () + + +def warn(message: str, category: Type[Warning] = PTBUserWarning, stacklevel: int = 0) -> None: + """ + Helper function used as a shortcut for warning with default values. + + .. versionadded:: 14.0 + + Args: + category (:obj:`Type[Warning]`): Specify the Warning class to pass to ``warnings.warn()``. + stacklevel (:obj:`int`): Specify the stacklevel to pass to ``warnings.warn()``. Pass the + same value as you'd pass directly to ``warnings.warn()``. + """ + warnings.warn(message, category=category, stacklevel=stacklevel + 1) diff --git a/tests/conftest.py b/tests/conftest.py index 9dad5246c10..404fe5ab0db 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -64,7 +64,7 @@ # This is here instead of in setup.cfg due to https://github.com/pytest-dev/pytest/issues/8343 def pytest_runtestloop(session): session.add_marker( - pytest.mark.filterwarnings('ignore::telegram.utils.deprecate.TelegramDeprecationWarning') + pytest.mark.filterwarnings('ignore::telegram.utils.warnings.PTBDeprecationWarning') ) @@ -106,7 +106,7 @@ class DictBot(Bot): @pytest.fixture(scope='session') def bot(bot_info): - return DictExtBot(bot_info['token'], private_key=PRIVATE_KEY, request=DictRequest()) + return DictExtBot(bot_info['token'], private_key=PRIVATE_KEY, request=DictRequest(8)) DEFAULT_BOTS = {} diff --git a/tests/test_conversationhandler.py b/tests/test_conversationhandler.py index 5b1aa49a775..8e69a821c1e 100644 --- a/tests/test_conversationhandler.py +++ b/tests/test_conversationhandler.py @@ -788,7 +788,7 @@ def test_all_update_types(self, dp, bot, user1): assert not handler.check_update(Update(0, pre_checkout_query=pre_checkout_query)) assert not handler.check_update(Update(0, shipping_query=shipping_query)) - def test_no_jobqueue_warning(self, dp, bot, user1, caplog): + def test_no_jobqueue_warning(self, dp, bot, user1, recwarn): handler = ConversationHandler( entry_points=self.entry_points, states=self.states, @@ -813,12 +813,11 @@ def test_no_jobqueue_warning(self, dp, bot, user1, caplog): bot=bot, ) - with caplog.at_level(logging.WARNING): - dp.process_update(Update(update_id=0, message=message)) - sleep(0.5) - assert len(caplog.records) == 1 + dp.process_update(Update(update_id=0, message=message)) + sleep(0.5) + assert len(recwarn) == 1 assert ( - caplog.records[0].message + str(recwarn[0].message) == "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue." ) # now set dp.job_queue back to it's original value @@ -990,7 +989,7 @@ def timeout(*a, **kw): # assert timeout handler didn't got called assert self.test_flag is False - def test_conversation_timeout_dispatcher_handler_stop(self, dp, bot, user1, caplog): + def test_conversation_timeout_dispatcher_handler_stop(self, dp, bot, user1, recwarn): handler = ConversationHandler( entry_points=self.entry_points, states=self.states, @@ -1017,14 +1016,12 @@ def timeout(*args, **kwargs): bot=bot, ) - with caplog.at_level(logging.WARNING): - dp.process_update(Update(update_id=0, message=message)) - assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY - sleep(0.9) - assert handler.conversations.get((self.group.id, user1.id)) is None - assert len(caplog.records) == 1 - rec = caplog.records[-1] - assert rec.getMessage().startswith('DispatcherHandlerStop in TIMEOUT') + dp.process_update(Update(update_id=0, message=message)) + assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY + sleep(0.9) + assert handler.conversations.get((self.group.id, user1.id)) is None + assert len(recwarn) == 1 + assert str(recwarn[0].message).startswith('DispatcherHandlerStop in TIMEOUT') def test_conversation_handler_timeout_update_and_context(self, dp, bot, user1): context = None @@ -1360,6 +1357,7 @@ def test_conversation_timeout_warning_only_shown_once(self, recwarn): "supported. You can still try to use it, but it will likely behave " "differently from what you expect." ) + assert recwarn[0].filename == __file__, "incorrect stacklevel!" def test_per_message_warning_is_only_shown_once(self, recwarn): ConversationHandler( @@ -1373,10 +1371,28 @@ def test_per_message_warning_is_only_shown_once(self, recwarn): ) assert len(recwarn) == 1 assert str(recwarn[0].message) == ( - "If 'per_message=True', all entry points and state handlers" + "If 'per_message=True', all entry points, state handlers, and fallbacks" " must be 'CallbackQueryHandler', since no other handlers" " have a message context." ) + assert recwarn[0].filename == __file__, "incorrect stacklevel!" + + def test_per_message_but_not_per_chat_warning(self, recwarn): + ConversationHandler( + entry_points=[CallbackQueryHandler(self.code, "code")], + states={ + self.BREWING: [CallbackQueryHandler(self.code, "code")], + }, + fallbacks=[CallbackQueryHandler(self.code, "code")], + per_message=True, + per_chat=False, + ) + assert len(recwarn) == 1 + assert str(recwarn[0].message) == ( + "If 'per_message=True' is used, 'per_chat=True' should also be used, " + "since message IDs are not globally unique." + ) + assert recwarn[0].filename == __file__, "incorrect stacklevel!" def test_per_message_false_warning_is_only_shown_once(self, recwarn): ConversationHandler( @@ -1393,6 +1409,7 @@ def test_per_message_false_warning_is_only_shown_once(self, recwarn): "If 'per_message=False', 'CallbackQueryHandler' will not be " "tracked for every message." ) + assert recwarn[0].filename == __file__, "incorrect stacklevel!" def test_warnings_per_chat_is_only_shown_once(self, recwarn): def hello(update, context): @@ -1415,6 +1432,7 @@ def bye(update, context): "If 'per_chat=True', 'InlineQueryHandler' can not be used," " since inline queries have no chat context." ) + assert recwarn[0].filename == __file__, "incorrect stacklevel!" def test_nested_conversation_handler(self, dp, bot, user1, user2): self.nested_states[self.DRINKING] = [ diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 11e766f60ce..f4772898ae9 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -109,6 +109,7 @@ def test_less_than_one_worker_warning(self, dp, recwarn): str(recwarn[0].message) == 'Asynchronous callbacks can not be processed without at least one worker thread.' ) + assert recwarn[0].filename == __file__, "stacklevel is incorrect!" def test_one_context_per_update(self, dp): def one(update, context): @@ -242,21 +243,18 @@ def get_dispatcher_name(q): assert name1 != name2 - def test_async_raises_dispatcher_handler_stop(self, dp, caplog): + def test_async_raises_dispatcher_handler_stop(self, dp, recwarn): def callback(update, context): raise DispatcherHandlerStop() dp.add_handler(MessageHandler(Filters.all, callback, run_async=True)) - with caplog.at_level(logging.WARNING): - dp.update_queue.put(self.message_update) - sleep(0.1) - assert len(caplog.records) == 1 - assert ( - caplog.records[-1] - .getMessage() - .startswith('DispatcherHandlerStop is not supported with async functions') - ) + dp.update_queue.put(self.message_update) + sleep(0.1) + assert len(recwarn) == 1 + assert str(recwarn[-1].message).startswith( + 'DispatcherHandlerStop is not supported with async functions' + ) def test_add_async_handler(self, dp): dp.add_handler( diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 21645143508..436a69fa083 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -774,10 +774,10 @@ class CustomClass: assert len(recwarn) == 2 assert str(recwarn[0].message).startswith( - "BasePersistence.replace_bot does not handle classes." + "BasePersistence.replace_bot does not handle classes such as 'CustomClass'" ) assert str(recwarn[1].message).startswith( - "BasePersistence.insert_bot does not handle classes." + "BasePersistence.insert_bot does not handle classes such as 'CustomClass'" ) def test_bot_replace_insert_bot_objects_with_faulty_equality(self, bot, bot_persistence): diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index 70142093e8c..9606cfcda2b 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -101,9 +101,9 @@ class TGO(TelegramObject): a = TGO() b = TGO() assert a == b - assert len(recwarn) == 2 + assert len(recwarn) == 1 assert str(recwarn[0].message) == expected_warning - assert str(recwarn[1].message) == expected_warning + assert recwarn[0].filename == __file__, "wrong stacklevel" def test_meaningful_comparison(self, recwarn): class TGO(TelegramObject): diff --git a/tests/test_updater.py b/tests/test_updater.py index c31351a64e3..66ceddc1418 100644 --- a/tests/test_updater.py +++ b/tests/test_updater.py @@ -56,7 +56,7 @@ InvalidCallbackData, ExtBot, ) -from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.warnings import PTBDeprecationWarning from telegram.ext.utils.webhookhandler import WebhookServer signalskip = pytest.mark.skipif( @@ -119,6 +119,16 @@ def test_warn_arbitrary_callback_data(self, bot, recwarn): assert len(recwarn) == 1 assert 'Passing arbitrary_callback_data to an Updater' in str(recwarn[0].message) + def test_warn_con_pool(self, bot, recwarn, dp): + dp = Dispatcher(bot, Queue(), workers=5) + Updater(bot=bot, workers=8) + Updater(dispatcher=dp, workers=None) + assert len(recwarn) == 2 + for idx, value in enumerate((12, 9)): + warning = f'Connection pool of Request object is smaller than optimal value {value}' + assert str(recwarn[idx].message) == warning + assert recwarn[idx].filename == __file__, "wrong stacklevel!" + @pytest.mark.parametrize( ('error',), argvalues=[(TelegramError('Test Error 2'),), (Unauthorized('Test Unauthorized'),)], @@ -647,5 +657,5 @@ def test_mutual_exclude_custom_context_dispatcher(self): Updater(dispatcher=dispatcher, context_types=True) def test_defaults_warning(self, bot): - with pytest.warns(TelegramDeprecationWarning, match='no effect when a Bot is passed'): + with pytest.warns(PTBDeprecationWarning, match='no effect when a Bot is passed'): Updater(bot=bot, defaults=Defaults())