Warnings Overhaul (#2662)

This commit is contained in:
Harshil 2021-09-20 10:45:42 +04:00 committed by Hinrich Mahler
parent 7528503794
commit f6497093ce
16 changed files with 207 additions and 124 deletions

View file

@ -182,3 +182,4 @@ utils
telegram.utils.promise
telegram.utils.request
telegram.utils.types
telegram.utils.warnings

View 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:

View file

@ -22,10 +22,10 @@ try:
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 @@ class TelegramObject:
# 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)

View file

@ -21,7 +21,6 @@
import functools
import logging
import warnings
from datetime import datetime
from typing import (
@ -91,7 +90,7 @@ from telegram import (
)
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 @@ class Bot(TelegramObject):
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:

View file

@ -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 @@ from telegram import Bot
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 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
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 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
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 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
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 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
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 @@ class BasePersistence(Generic[UD, CD, BD], ABC):
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

View file

@ -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 import (
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 @@ class ConversationHandler(Handler[Update, CCT]):
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 @@ class ConversationHandler(Handler[Update, CCT]):
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 @@ class ConversationHandler(Handler[Update, CCT]):
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 @@ class ConversationHandler(Handler[Update, CCT]):
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 @@ class ConversationHandler(Handler[Update, CCT]):
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)

View file

@ -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 @@ from telegram.ext.handler import Handler
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
@ -199,8 +199,9 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
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)
@ -315,9 +316,9 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
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

View file

@ -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 typing import (
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 @@ class Updater(Generic[CCT, UD, CD, BD]):
):
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 @@ class Updater(Generic[CCT, UD, CD, BD]):
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 @@ class Updater(Generic[CCT, UD, CD, BD]):
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

View file

@ -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__ = ()

View 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)

View file

@ -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
def pytest_runtestloop(session):
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')
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 = {}

View file

@ -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, 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 @@ class TestConversationHandler:
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
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 @@ class TestConversationHandler:
# 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 @@ class TestConversationHandler:
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')
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 @@ class TestConversationHandler:
"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 @@ class TestConversationHandler:
)
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 @@ class TestConversationHandler:
"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 @@ class TestConversationHandler:
"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] = [

View file

@ -110,6 +110,7 @@ class TestDispatcher:
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):
@ -243,20 +244,17 @@ class TestDispatcher:
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')
assert len(recwarn) == 1
assert str(recwarn[-1].message).startswith(
'DispatcherHandlerStop is not supported with async functions'
)
def test_add_async_handler(self, dp):

View file

@ -774,10 +774,10 @@ class TestBasePersistence:
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):

View file

@ -101,9 +101,9 @@ class TestTelegramObject:
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):

View file

@ -56,7 +56,7 @@ from telegram.ext import (
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 @@ class TestUpdater:
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 @@ class TestUpdater:
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())