mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
Warnings Overhaul (#2662)
This commit is contained in:
parent
7528503794
commit
f6497093ce
16 changed files with 207 additions and 124 deletions
|
@ -182,3 +182,4 @@ utils
|
||||||
telegram.utils.promise
|
telegram.utils.promise
|
||||||
telegram.utils.request
|
telegram.utils.request
|
||||||
telegram.utils.types
|
telegram.utils.types
|
||||||
|
telegram.utils.warnings
|
||||||
|
|
8
docs/source/telegram.utils.warnings.rst
Normal file
8
docs/source/telegram.utils.warnings.rst
Normal file
|
@ -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:
|
|
@ -22,10 +22,10 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import json # type: ignore[no-redef]
|
import json # type: ignore[no-redef]
|
||||||
|
|
||||||
import warnings
|
|
||||||
from typing import TYPE_CHECKING, List, Optional, Type, TypeVar, Tuple
|
from typing import TYPE_CHECKING, List, Optional, Type, TypeVar, Tuple
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
|
from telegram.utils.warnings import warn
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
@ -140,14 +140,16 @@ class TelegramObject:
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
if self._id_attrs == ():
|
if self._id_attrs == ():
|
||||||
warnings.warn(
|
warn(
|
||||||
f"Objects of type {self.__class__.__name__} can not be meaningfully tested for"
|
f"Objects of type {self.__class__.__name__} can not be meaningfully tested for"
|
||||||
" equivalence."
|
" equivalence.",
|
||||||
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
if other._id_attrs == ():
|
if other._id_attrs == ():
|
||||||
warnings.warn(
|
warn(
|
||||||
f"Objects of type {other.__class__.__name__} can not be meaningfully tested"
|
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 self._id_attrs == other._id_attrs
|
||||||
return super().__eq__(other)
|
return super().__eq__(other)
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import warnings
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from typing import (
|
from typing import (
|
||||||
|
@ -91,7 +90,7 @@ from telegram import (
|
||||||
)
|
)
|
||||||
from telegram.constants import MAX_INLINE_QUERY_RESULTS
|
from telegram.constants import MAX_INLINE_QUERY_RESULTS
|
||||||
from telegram.error import InvalidToken, TelegramError
|
from telegram.error import InvalidToken, TelegramError
|
||||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
from telegram.utils.warnings import PTBDeprecationWarning, warn
|
||||||
from telegram.utils.helpers import (
|
from telegram.utils.helpers import (
|
||||||
DEFAULT_NONE,
|
DEFAULT_NONE,
|
||||||
DefaultValue,
|
DefaultValue,
|
||||||
|
@ -198,10 +197,10 @@ class Bot(TelegramObject):
|
||||||
self.defaults = defaults
|
self.defaults = defaults
|
||||||
|
|
||||||
if self.defaults:
|
if self.defaults:
|
||||||
warnings.warn(
|
warn(
|
||||||
'Passing Defaults to telegram.Bot is deprecated. Use telegram.ext.ExtBot instead.',
|
'Passing Defaults to telegram.Bot is deprecated. Use telegram.ext.ExtBot instead.',
|
||||||
TelegramDeprecationWarning,
|
PTBDeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
if base_url is None:
|
if base_url is None:
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
"""This module contains the BasePersistence class."""
|
"""This module contains the BasePersistence class."""
|
||||||
import warnings
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict, NamedTuple
|
from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict, NamedTuple
|
||||||
|
@ -26,6 +25,7 @@ from telegram import Bot
|
||||||
import telegram.ext.extbot
|
import telegram.ext.extbot
|
||||||
|
|
||||||
from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData
|
from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData
|
||||||
|
from telegram.utils.warnings import warn, PTBRuntimeWarning
|
||||||
|
|
||||||
|
|
||||||
class PersistenceInput(NamedTuple):
|
class PersistenceInput(NamedTuple):
|
||||||
|
@ -230,10 +230,10 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||||
return new_immutable
|
return new_immutable
|
||||||
if isinstance(obj, type):
|
if isinstance(obj, type):
|
||||||
# classes usually do have a __dict__, but it's not writable
|
# classes usually do have a __dict__, but it's not writable
|
||||||
warnings.warn(
|
warn(
|
||||||
'BasePersistence.replace_bot does not handle classes. See '
|
f'BasePersistence.replace_bot does not handle classes such as {obj.__name__!r}. '
|
||||||
'the docs of BasePersistence.replace_bot for more information.',
|
'See the docs of BasePersistence.replace_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@ -241,10 +241,10 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||||
new_obj = copy(obj)
|
new_obj = copy(obj)
|
||||||
memo[obj_id] = new_obj
|
memo[obj_id] = new_obj
|
||||||
except Exception:
|
except Exception:
|
||||||
warnings.warn(
|
warn(
|
||||||
'BasePersistence.replace_bot does not handle objects that can not be copied. See '
|
'BasePersistence.replace_bot does not handle objects that can not be copied. See '
|
||||||
'the docs of BasePersistence.replace_bot for more information.',
|
'the docs of BasePersistence.replace_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
memo[obj_id] = obj
|
memo[obj_id] = obj
|
||||||
return obj
|
return obj
|
||||||
|
@ -282,10 +282,10 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||||
memo[obj_id] = new_obj
|
memo[obj_id] = new_obj
|
||||||
return new_obj
|
return new_obj
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
warnings.warn(
|
warn(
|
||||||
f'Parsing of an object failed with the following exception: {exception}. '
|
f'Parsing of an object failed with the following exception: {exception}. '
|
||||||
f'See the docs of BasePersistence.replace_bot for more information.',
|
f'See the docs of BasePersistence.replace_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
|
|
||||||
memo[obj_id] = obj
|
memo[obj_id] = obj
|
||||||
|
@ -333,20 +333,20 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||||
return new_immutable
|
return new_immutable
|
||||||
if isinstance(obj, type):
|
if isinstance(obj, type):
|
||||||
# classes usually do have a __dict__, but it's not writable
|
# classes usually do have a __dict__, but it's not writable
|
||||||
warnings.warn(
|
warn(
|
||||||
'BasePersistence.insert_bot does not handle classes. See '
|
f'BasePersistence.insert_bot does not handle classes such as {obj.__name__!r}. '
|
||||||
'the docs of BasePersistence.insert_bot for more information.',
|
'See the docs of BasePersistence.insert_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_obj = copy(obj)
|
new_obj = copy(obj)
|
||||||
except Exception:
|
except Exception:
|
||||||
warnings.warn(
|
warn(
|
||||||
'BasePersistence.insert_bot does not handle objects that can not be copied. See '
|
'BasePersistence.insert_bot does not handle objects that can not be copied. See '
|
||||||
'the docs of BasePersistence.insert_bot for more information.',
|
'the docs of BasePersistence.insert_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
memo[obj_id] = obj
|
memo[obj_id] = obj
|
||||||
return obj
|
return obj
|
||||||
|
@ -384,10 +384,10 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
|
||||||
memo[obj_id] = new_obj
|
memo[obj_id] = new_obj
|
||||||
return new_obj
|
return new_obj
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
warnings.warn(
|
warn(
|
||||||
f'Parsing of an object failed with the following exception: {exception}. '
|
f'Parsing of an object failed with the following exception: {exception}. '
|
||||||
f'See the docs of BasePersistence.insert_bot for more information.',
|
f'See the docs of BasePersistence.insert_bot for more information.',
|
||||||
RuntimeWarning,
|
PTBRuntimeWarning,
|
||||||
)
|
)
|
||||||
|
|
||||||
memo[obj_id] = obj
|
memo[obj_id] = obj
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
"""This module contains the ConversationHandler."""
|
"""This module contains the ConversationHandler."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import warnings
|
|
||||||
import functools
|
import functools
|
||||||
import datetime
|
import datetime
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
@ -39,6 +38,7 @@ from telegram.ext import (
|
||||||
from telegram.ext.utils.promise import Promise
|
from telegram.ext.utils.promise import Promise
|
||||||
from telegram.ext.utils.types import ConversationDict
|
from telegram.ext.utils.types import ConversationDict
|
||||||
from telegram.ext.utils.types import CCT
|
from telegram.ext.utils.types import CCT
|
||||||
|
from telegram.utils.warnings import warn
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import Dispatcher, Job
|
from telegram.ext import Dispatcher, Job
|
||||||
|
@ -259,9 +259,10 @@ class ConversationHandler(Handler[Update, CCT]):
|
||||||
raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'")
|
raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'")
|
||||||
|
|
||||||
if self.per_message and not self.per_chat:
|
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, "
|
"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] = []
|
all_handlers: List[Handler] = []
|
||||||
|
@ -274,37 +275,41 @@ class ConversationHandler(Handler[Update, CCT]):
|
||||||
if self.per_message:
|
if self.per_message:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if not isinstance(handler, CallbackQueryHandler):
|
if not isinstance(handler, CallbackQueryHandler):
|
||||||
warnings.warn(
|
warn(
|
||||||
"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 "
|
" must be 'CallbackQueryHandler', since no other handlers "
|
||||||
"have a message context."
|
"have a message context.",
|
||||||
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if isinstance(handler, CallbackQueryHandler):
|
if isinstance(handler, CallbackQueryHandler):
|
||||||
warnings.warn(
|
warn(
|
||||||
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
||||||
"tracked for every message."
|
"tracked for every message.",
|
||||||
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.per_chat:
|
if self.per_chat:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
|
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
|
||||||
warnings.warn(
|
warn(
|
||||||
"If 'per_chat=True', 'InlineQueryHandler' can not be used, "
|
"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
|
break
|
||||||
|
|
||||||
if self.conversation_timeout:
|
if self.conversation_timeout:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if isinstance(handler, self.__class__):
|
if isinstance(handler, self.__class__):
|
||||||
warnings.warn(
|
warn(
|
||||||
"Using `conversation_timeout` with nested conversations is currently not "
|
"Using `conversation_timeout` with nested conversations is currently not "
|
||||||
"supported. You can still try to use it, but it will likely behave "
|
"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
|
break
|
||||||
|
|
||||||
|
@ -644,8 +649,8 @@ class ConversationHandler(Handler[Update, CCT]):
|
||||||
new_state, dispatcher, update, context, conversation_key
|
new_state, dispatcher, update, context, conversation_key
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.logger.warning(
|
warn(
|
||||||
"Ignoring `conversation_timeout` because the Dispatcher has no JobQueue."
|
"Ignoring `conversation_timeout` because the Dispatcher has no JobQueue.",
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
||||||
|
@ -680,9 +685,9 @@ class ConversationHandler(Handler[Update, CCT]):
|
||||||
|
|
||||||
elif new_state is not None:
|
elif new_state is not None:
|
||||||
if new_state not in self.states:
|
if new_state not in self.states:
|
||||||
warnings.warn(
|
warn(
|
||||||
f"Handler returned state {new_state} which is unknown to the "
|
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:
|
with self._conversations_lock:
|
||||||
self.conversations[key] = new_state
|
self.conversations[key] = new_state
|
||||||
|
@ -711,9 +716,9 @@ class ConversationHandler(Handler[Update, CCT]):
|
||||||
try:
|
try:
|
||||||
handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context)
|
handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context)
|
||||||
except DispatcherHandlerStop:
|
except DispatcherHandlerStop:
|
||||||
self.logger.warning(
|
warn(
|
||||||
'DispatcherHandlerStop in TIMEOUT state of '
|
'DispatcherHandlerStop in TIMEOUT state of '
|
||||||
'ConversationHandler has no effect. Ignoring.'
|
'ConversationHandler has no effect. Ignoring.',
|
||||||
)
|
)
|
||||||
|
|
||||||
self._update_state(self.END, ctxt.conversation_key)
|
self._update_state(self.END, ctxt.conversation_key)
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
"""This module contains the Dispatcher class."""
|
"""This module contains the Dispatcher class."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import warnings
|
|
||||||
import weakref
|
import weakref
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from queue import Empty, Queue
|
from queue import Empty, Queue
|
||||||
|
@ -47,6 +46,7 @@ from telegram.ext.handler import Handler
|
||||||
import telegram.ext.extbot
|
import telegram.ext.extbot
|
||||||
from telegram.ext.callbackdatacache import CallbackDataCache
|
from telegram.ext.callbackdatacache import CallbackDataCache
|
||||||
from telegram.ext.utils.promise import Promise
|
from telegram.ext.utils.promise import Promise
|
||||||
|
from telegram.utils.warnings import warn
|
||||||
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
|
||||||
from telegram.ext.utils.types import CCT, UD, CD, BD
|
from telegram.ext.utils.types import CCT, UD, CD, BD
|
||||||
|
|
||||||
|
@ -199,8 +199,9 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
|
||||||
self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes())
|
self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes())
|
||||||
|
|
||||||
if self.workers < 1:
|
if self.workers < 1:
|
||||||
warnings.warn(
|
warn(
|
||||||
'Asynchronous callbacks can not be processed without at least one worker thread.'
|
'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)
|
self.user_data: DefaultDict[int, UD] = defaultdict(self.context_types.user_data)
|
||||||
|
@ -315,9 +316,9 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(promise.exception, DispatcherHandlerStop):
|
if isinstance(promise.exception, DispatcherHandlerStop):
|
||||||
self.logger.warning(
|
warn(
|
||||||
'DispatcherHandlerStop is not supported with async functions; func: %s',
|
'DispatcherHandlerStop is not supported with async functions; '
|
||||||
promise.pooled_function.__name__,
|
f'func: {promise.pooled_function.__name__}',
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import ssl
|
import ssl
|
||||||
import warnings
|
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from signal import SIGABRT, SIGINT, SIGTERM, signal
|
from signal import SIGABRT, SIGINT, SIGTERM, signal
|
||||||
from threading import Event, Lock, Thread, current_thread
|
from threading import Event, Lock, Thread, current_thread
|
||||||
|
@ -42,7 +41,7 @@ from typing import (
|
||||||
from telegram import Bot, TelegramError
|
from telegram import Bot, TelegramError
|
||||||
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized
|
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized
|
||||||
from telegram.ext import Dispatcher, JobQueue, ContextTypes, ExtBot
|
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.helpers import get_signal_name, DEFAULT_FALSE, DefaultValue
|
||||||
from telegram.utils.request import Request
|
from telegram.utils.request import Request
|
||||||
from telegram.ext.utils.types import CCT, UD, CD, BD
|
from telegram.ext.utils.types import CCT, UD, CD, BD
|
||||||
|
@ -211,14 +210,14 @@ class Updater(Generic[CCT, UD, CD, BD]):
|
||||||
):
|
):
|
||||||
|
|
||||||
if defaults and bot:
|
if defaults and bot:
|
||||||
warnings.warn(
|
warn(
|
||||||
'Passing defaults to an Updater has no effect when a Bot is passed '
|
'Passing defaults to an Updater has no effect when a Bot is passed '
|
||||||
'as well. Pass them to the Bot instead.',
|
'as well. Pass them to the Bot instead.',
|
||||||
TelegramDeprecationWarning,
|
PTBDeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
if arbitrary_callback_data is not DEFAULT_FALSE and bot:
|
if arbitrary_callback_data is not DEFAULT_FALSE and bot:
|
||||||
warnings.warn(
|
warn(
|
||||||
'Passing arbitrary_callback_data to an Updater has no '
|
'Passing arbitrary_callback_data to an Updater has no '
|
||||||
'effect when a Bot is passed as well. Pass them to the Bot instead.',
|
'effect when a Bot is passed as well. Pass them to the Bot instead.',
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
|
@ -250,9 +249,10 @@ class Updater(Generic[CCT, UD, CD, BD]):
|
||||||
if bot is not None:
|
if bot is not None:
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
if bot.request.con_pool_size < con_pool_size:
|
if bot.request.con_pool_size < con_pool_size:
|
||||||
self.logger.warning(
|
warn(
|
||||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
f'Connection pool of Request object is smaller than optimal value '
|
||||||
con_pool_size,
|
f'{con_pool_size}',
|
||||||
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# we need a connection pool the size of:
|
# we need a connection pool the size of:
|
||||||
|
@ -299,9 +299,10 @@ class Updater(Generic[CCT, UD, CD, BD]):
|
||||||
|
|
||||||
self.bot = dispatcher.bot
|
self.bot = dispatcher.bot
|
||||||
if self.bot.request.con_pool_size < con_pool_size:
|
if self.bot.request.con_pool_size < con_pool_size:
|
||||||
self.logger.warning(
|
warn(
|
||||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
f'Connection pool of Request object is smaller than optimal value '
|
||||||
con_pool_size,
|
f'{con_pool_size}',
|
||||||
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
self.update_queue = dispatcher.update_queue
|
self.update_queue = dispatcher.update_queue
|
||||||
self.__exception_event = dispatcher.exception_event
|
self.__exception_event = dispatcher.exception_event
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
|
||||||
# Copyright (C) 2015-2022
|
|
||||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
|
||||||
"""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__ = ()
|
|
68
telegram/utils/warnings.py
Normal file
68
telegram/utils/warnings.py
Normal file
|
@ -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 <devs@python-telegram-bot.org>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
|
"""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)
|
|
@ -64,7 +64,7 @@ from tests.bots import get_bot
|
||||||
# This is here instead of in setup.cfg due to https://github.com/pytest-dev/pytest/issues/8343
|
# This is here instead of in setup.cfg due to https://github.com/pytest-dev/pytest/issues/8343
|
||||||
def pytest_runtestloop(session):
|
def pytest_runtestloop(session):
|
||||||
session.add_marker(
|
session.add_marker(
|
||||||
pytest.mark.filterwarnings('ignore::telegram.utils.deprecate.TelegramDeprecationWarning')
|
pytest.mark.filterwarnings('ignore::telegram.utils.warnings.PTBDeprecationWarning')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class DictDispatcher(Dispatcher):
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def bot(bot_info):
|
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 = {}
|
DEFAULT_BOTS = {}
|
||||||
|
|
|
@ -788,7 +788,7 @@ class TestConversationHandler:
|
||||||
assert not handler.check_update(Update(0, pre_checkout_query=pre_checkout_query))
|
assert not handler.check_update(Update(0, pre_checkout_query=pre_checkout_query))
|
||||||
assert not handler.check_update(Update(0, shipping_query=shipping_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(
|
handler = ConversationHandler(
|
||||||
entry_points=self.entry_points,
|
entry_points=self.entry_points,
|
||||||
states=self.states,
|
states=self.states,
|
||||||
|
@ -813,12 +813,11 @@ class TestConversationHandler:
|
||||||
bot=bot,
|
bot=bot,
|
||||||
)
|
)
|
||||||
|
|
||||||
with caplog.at_level(logging.WARNING):
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
sleep(0.5)
|
||||||
sleep(0.5)
|
assert len(recwarn) == 1
|
||||||
assert len(caplog.records) == 1
|
|
||||||
assert (
|
assert (
|
||||||
caplog.records[0].message
|
str(recwarn[0].message)
|
||||||
== "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue."
|
== "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue."
|
||||||
)
|
)
|
||||||
# now set dp.job_queue back to it's original value
|
# now set dp.job_queue back to it's original value
|
||||||
|
@ -990,7 +989,7 @@ class TestConversationHandler:
|
||||||
# assert timeout handler didn't got called
|
# assert timeout handler didn't got called
|
||||||
assert self.test_flag is False
|
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(
|
handler = ConversationHandler(
|
||||||
entry_points=self.entry_points,
|
entry_points=self.entry_points,
|
||||||
states=self.states,
|
states=self.states,
|
||||||
|
@ -1017,14 +1016,12 @@ class TestConversationHandler:
|
||||||
bot=bot,
|
bot=bot,
|
||||||
)
|
)
|
||||||
|
|
||||||
with caplog.at_level(logging.WARNING):
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
sleep(0.9)
|
||||||
sleep(0.9)
|
assert handler.conversations.get((self.group.id, user1.id)) is None
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) is None
|
assert len(recwarn) == 1
|
||||||
assert len(caplog.records) == 1
|
assert str(recwarn[0].message).startswith('DispatcherHandlerStop in TIMEOUT')
|
||||||
rec = caplog.records[-1]
|
|
||||||
assert rec.getMessage().startswith('DispatcherHandlerStop in TIMEOUT')
|
|
||||||
|
|
||||||
def test_conversation_handler_timeout_update_and_context(self, dp, bot, user1):
|
def test_conversation_handler_timeout_update_and_context(self, dp, bot, user1):
|
||||||
context = None
|
context = None
|
||||||
|
@ -1360,6 +1357,7 @@ class TestConversationHandler:
|
||||||
"supported. You can still try to use it, but it will likely behave "
|
"supported. You can still try to use it, but it will likely behave "
|
||||||
"differently from what you expect."
|
"differently from what you expect."
|
||||||
)
|
)
|
||||||
|
assert recwarn[0].filename == __file__, "incorrect stacklevel!"
|
||||||
|
|
||||||
def test_per_message_warning_is_only_shown_once(self, recwarn):
|
def test_per_message_warning_is_only_shown_once(self, recwarn):
|
||||||
ConversationHandler(
|
ConversationHandler(
|
||||||
|
@ -1373,10 +1371,28 @@ class TestConversationHandler:
|
||||||
)
|
)
|
||||||
assert len(recwarn) == 1
|
assert len(recwarn) == 1
|
||||||
assert str(recwarn[0].message) == (
|
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"
|
" must be 'CallbackQueryHandler', since no other handlers"
|
||||||
" have a message context."
|
" 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):
|
def test_per_message_false_warning_is_only_shown_once(self, recwarn):
|
||||||
ConversationHandler(
|
ConversationHandler(
|
||||||
|
@ -1393,6 +1409,7 @@ class TestConversationHandler:
|
||||||
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
||||||
"tracked for every message."
|
"tracked for every message."
|
||||||
)
|
)
|
||||||
|
assert recwarn[0].filename == __file__, "incorrect stacklevel!"
|
||||||
|
|
||||||
def test_warnings_per_chat_is_only_shown_once(self, recwarn):
|
def test_warnings_per_chat_is_only_shown_once(self, recwarn):
|
||||||
def hello(update, context):
|
def hello(update, context):
|
||||||
|
@ -1415,6 +1432,7 @@ class TestConversationHandler:
|
||||||
"If 'per_chat=True', 'InlineQueryHandler' can not be used,"
|
"If 'per_chat=True', 'InlineQueryHandler' can not be used,"
|
||||||
" since inline queries have no chat context."
|
" since inline queries have no chat context."
|
||||||
)
|
)
|
||||||
|
assert recwarn[0].filename == __file__, "incorrect stacklevel!"
|
||||||
|
|
||||||
def test_nested_conversation_handler(self, dp, bot, user1, user2):
|
def test_nested_conversation_handler(self, dp, bot, user1, user2):
|
||||||
self.nested_states[self.DRINKING] = [
|
self.nested_states[self.DRINKING] = [
|
||||||
|
|
|
@ -110,6 +110,7 @@ class TestDispatcher:
|
||||||
str(recwarn[0].message)
|
str(recwarn[0].message)
|
||||||
== 'Asynchronous callbacks can not be processed without at least one worker thread.'
|
== '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 test_one_context_per_update(self, dp):
|
||||||
def one(update, context):
|
def one(update, context):
|
||||||
|
@ -243,21 +244,18 @@ class TestDispatcher:
|
||||||
|
|
||||||
assert name1 != name2
|
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):
|
def callback(update, context):
|
||||||
raise DispatcherHandlerStop()
|
raise DispatcherHandlerStop()
|
||||||
|
|
||||||
dp.add_handler(MessageHandler(Filters.all, callback, run_async=True))
|
dp.add_handler(MessageHandler(Filters.all, callback, run_async=True))
|
||||||
|
|
||||||
with caplog.at_level(logging.WARNING):
|
dp.update_queue.put(self.message_update)
|
||||||
dp.update_queue.put(self.message_update)
|
sleep(0.1)
|
||||||
sleep(0.1)
|
assert len(recwarn) == 1
|
||||||
assert len(caplog.records) == 1
|
assert str(recwarn[-1].message).startswith(
|
||||||
assert (
|
'DispatcherHandlerStop is not supported with async functions'
|
||||||
caplog.records[-1]
|
)
|
||||||
.getMessage()
|
|
||||||
.startswith('DispatcherHandlerStop is not supported with async functions')
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_add_async_handler(self, dp):
|
def test_add_async_handler(self, dp):
|
||||||
dp.add_handler(
|
dp.add_handler(
|
||||||
|
|
|
@ -774,10 +774,10 @@ class TestBasePersistence:
|
||||||
|
|
||||||
assert len(recwarn) == 2
|
assert len(recwarn) == 2
|
||||||
assert str(recwarn[0].message).startswith(
|
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(
|
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):
|
def test_bot_replace_insert_bot_objects_with_faulty_equality(self, bot, bot_persistence):
|
||||||
|
|
|
@ -101,9 +101,9 @@ class TestTelegramObject:
|
||||||
a = TGO()
|
a = TGO()
|
||||||
b = TGO()
|
b = TGO()
|
||||||
assert a == b
|
assert a == b
|
||||||
assert len(recwarn) == 2
|
assert len(recwarn) == 1
|
||||||
assert str(recwarn[0].message) == expected_warning
|
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):
|
def test_meaningful_comparison(self, recwarn):
|
||||||
class TGO(TelegramObject):
|
class TGO(TelegramObject):
|
||||||
|
|
|
@ -56,7 +56,7 @@ from telegram.ext import (
|
||||||
InvalidCallbackData,
|
InvalidCallbackData,
|
||||||
ExtBot,
|
ExtBot,
|
||||||
)
|
)
|
||||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
from telegram.utils.warnings import PTBDeprecationWarning
|
||||||
from telegram.ext.utils.webhookhandler import WebhookServer
|
from telegram.ext.utils.webhookhandler import WebhookServer
|
||||||
|
|
||||||
signalskip = pytest.mark.skipif(
|
signalskip = pytest.mark.skipif(
|
||||||
|
@ -119,6 +119,16 @@ class TestUpdater:
|
||||||
assert len(recwarn) == 1
|
assert len(recwarn) == 1
|
||||||
assert 'Passing arbitrary_callback_data to an Updater' in str(recwarn[0].message)
|
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(
|
@pytest.mark.parametrize(
|
||||||
('error',),
|
('error',),
|
||||||
argvalues=[(TelegramError('Test Error 2'),), (Unauthorized('Test Unauthorized'),)],
|
argvalues=[(TelegramError('Test Error 2'),), (Unauthorized('Test Unauthorized'),)],
|
||||||
|
@ -647,5 +657,5 @@ class TestUpdater:
|
||||||
Updater(dispatcher=dispatcher, context_types=True)
|
Updater(dispatcher=dispatcher, context_types=True)
|
||||||
|
|
||||||
def test_defaults_warning(self, bot):
|
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())
|
Updater(bot=bot, defaults=Defaults())
|
||||||
|
|
Loading…
Reference in a new issue