diff --git a/telegram/ext/basepersistence.py b/telegram/ext/basepersistence.py index 834d6543ffd..28643ac52c5 100644 --- a/telegram/ext/basepersistence.py +++ b/telegram/ext/basepersistence.py @@ -25,6 +25,8 @@ class BasePersistence(object): All relevant methods must be overwritten. This means: + * If :attr:`store_bot_data` is ``True`` you must overwrite :meth:`get_bot_data` and + :meth:`update_bot_data`. * If :attr:`store_chat_data` is ``True`` you must overwrite :meth:`get_chat_data` and :meth:`update_chat_data`. * If :attr:`store_user_data` is ``True`` you must overwrite :meth:`get_user_data` and @@ -38,17 +40,22 @@ class BasePersistence(object): persistence class. store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this persistence class. + store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this + persistence class. Args: store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this persistence class. Default is ``True``. store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this persistence class. Default is ``True`` . + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is ``True`` . """ - def __init__(self, store_user_data=True, store_chat_data=True): + def __init__(self, store_user_data=True, store_chat_data=True, store_bot_data=True): self.store_user_data = store_user_data self.store_chat_data = store_chat_data + self.store_bot_data = store_bot_data def get_user_data(self): """"Will be called by :class:`telegram.ext.Dispatcher` upon creation with a @@ -70,6 +77,16 @@ def get_chat_data(self): """ raise NotImplementedError + def get_bot_data(self): + """"Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + persistence object. It should return the bot_data if stored, or an empty + ``dict``. + + Returns: + :obj:`defaultdict`: The restored bot data. + """ + raise NotImplementedError + def get_conversations(self, name): """"Will be called by :class:`telegram.ext.Dispatcher` when a :class:`telegram.ext.ConversationHandler` is added if @@ -111,7 +128,16 @@ def update_chat_data(self, chat_id, data): Args: chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [user_id]. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id]. + """ + raise NotImplementedError + + def update_bot_data(self, data): + """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has + handled an update. + + Args: + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data` . """ raise NotImplementedError diff --git a/telegram/ext/callbackcontext.py b/telegram/ext/callbackcontext.py index 83dd3912aad..5f40fba7f37 100644 --- a/telegram/ext/callbackcontext.py +++ b/telegram/ext/callbackcontext.py @@ -43,6 +43,8 @@ class CallbackContext(object): that you think you added will not be present. Attributes: + bot_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each + update it will be the same ``dict``. chat_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each update from the same chat id it will be the same ``dict``. @@ -80,6 +82,7 @@ def __init__(self, dispatcher): raise ValueError('CallbackContext should not be used with a non context aware ' 'dispatcher!') self._dispatcher = dispatcher + self._bot_data = dispatcher.bot_data self._chat_data = None self._user_data = None self.args = None @@ -92,6 +95,15 @@ def dispatcher(self): """:class:`telegram.ext.Dispatcher`: The dispatcher associated with this context.""" return self._dispatcher + @property + def bot_data(self): + return self._bot_data + + @bot_data.setter + def bot_data(self, value): + raise AttributeError("You can not assign a new value to bot_data, see " + "https://git.io/fjxKe") + @property def chat_data(self): return self._chat_data @@ -119,6 +131,7 @@ def from_error(cls, update, error, dispatcher): @classmethod def from_update(cls, update, dispatcher): self = cls(dispatcher) + if update is not None and isinstance(update, Update): chat = update.effective_chat user = update.effective_user diff --git a/telegram/ext/dictpersistence.py b/telegram/ext/dictpersistence.py index 431fb82f665..98c58ac5533 100644 --- a/telegram/ext/dictpersistence.py +++ b/telegram/ext/dictpersistence.py @@ -31,36 +31,51 @@ class DictPersistence(BasePersistence): - """Using python's dicts and json for making you bot persistent. + """Using python's dicts and json for making your bot persistent. Attributes: store_user_data (:obj:`bool`): Whether user_data should be saved by this persistence class. store_chat_data (:obj:`bool`): Whether chat_data should be saved by this persistence class. + store_bot_data (:obj:`bool`): Whether bot_data should be saved by this + persistence class. Args: store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this persistence class. Default is ``True``. store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this persistence class. Default is ``True``. + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is ``True`` . user_data_json (:obj:`str`, optional): Json string that will be used to reconstruct user_data on creating this persistence. Default is ``""``. chat_data_json (:obj:`str`, optional): Json string that will be used to reconstruct chat_data on creating this persistence. Default is ``""``. + bot_data_json (:obj:`str`, optional): Json string that will be used to reconstruct + bot_data on creating this persistence. Default is ``""``. conversations_json (:obj:`str`, optional): Json string that will be used to reconstruct conversation on creating this persistence. Default is ``""``. """ - def __init__(self, store_user_data=True, store_chat_data=True, user_data_json='', - chat_data_json='', conversations_json=''): - self.store_user_data = store_user_data - self.store_chat_data = store_chat_data + def __init__(self, + store_user_data=True, + store_chat_data=True, + store_bot_data=True, + user_data_json='', + chat_data_json='', + bot_data_json='', + conversations_json=''): + super(DictPersistence, self).__init__(store_user_data=store_user_data, + store_chat_data=store_chat_data, + store_bot_data=store_bot_data) self._user_data = None self._chat_data = None + self._bot_data = None self._conversations = None self._user_data_json = None self._chat_data_json = None + self._bot_data_json = None self._conversations_json = None if user_data_json: try: @@ -74,6 +89,14 @@ def __init__(self, store_user_data=True, store_chat_data=True, user_data_json='' self._chat_data_json = chat_data_json except (ValueError, AttributeError): raise TypeError("Unable to deserialize chat_data_json. Not valid JSON") + if bot_data_json: + try: + self._bot_data = json.loads(bot_data_json) + self._bot_data_json = bot_data_json + except (ValueError, AttributeError): + raise TypeError("Unable to deserialize bot_data_json. Not valid JSON") + if not isinstance(self._bot_data, dict): + raise TypeError("bot_data_json must be serialized dict") if conversations_json: try: @@ -108,6 +131,19 @@ def chat_data_json(self): else: return json.dumps(self.chat_data) + @property + def bot_data(self): + """:obj:`dict`: The bot_data as a dict""" + return self._bot_data + + @property + def bot_data_json(self): + """:obj:`str`: The bot_data serialized as a JSON-string.""" + if self._bot_data_json: + return self._bot_data_json + else: + return json.dumps(self.bot_data) + @property def conversations(self): """:obj:`dict`: The conversations as a dict""" @@ -145,6 +181,18 @@ def get_chat_data(self): self._chat_data = defaultdict(dict) return deepcopy(self.chat_data) + def get_bot_data(self): + """Returns the bot_data created from the ``bot_data_json`` or an empty dict. + + Returns: + :obj:`defaultdict`: The restored user data. + """ + if self.bot_data: + pass + else: + self._bot_data = {} + return deepcopy(self.bot_data) + def get_conversations(self, name): """Returns the conversations created from the ``conversations_json`` or an empty defaultdict. @@ -194,3 +242,14 @@ def update_chat_data(self, chat_id, data): return self._chat_data[chat_id] = data self._chat_data_json = None + + def update_bot_data(self, data): + """Will update the bot_data (if changed). + + Args: + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`. + """ + if self._bot_data == data: + return + self._bot_data = data.copy() + self._bot_data_json = None diff --git a/telegram/ext/dispatcher.py b/telegram/ext/dispatcher.py index 1c64c4b5a6a..bc4a9180a3e 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -79,6 +79,7 @@ class Dispatcher(object): decorator. user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user. chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat. + bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot. persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to store data that should be persistent over restarts @@ -121,8 +122,8 @@ def __init__(self, TelegramDeprecationWarning, stacklevel=3) self.user_data = defaultdict(dict) - """:obj:`dict`: A dictionary handlers can use to store data for the user.""" self.chat_data = defaultdict(dict) + self.bot_data = {} if persistence: if not isinstance(persistence, BasePersistence): raise TypeError("persistence should be based on telegram.ext.BasePersistence") @@ -135,6 +136,10 @@ def __init__(self, self.chat_data = self.persistence.get_chat_data() if not isinstance(self.chat_data, defaultdict): raise ValueError("chat_data must be of type defaultdict") + if self.persistence.store_bot_data: + self.bot_data = self.persistence.get_bot_data() + if not isinstance(self.bot_data, dict): + raise ValueError("bot_data must be of type dict") else: self.persistence = None @@ -327,6 +332,17 @@ def persist_update(update): """ if self.persistence and isinstance(update, Update): + if self.persistence.store_bot_data: + try: + self.persistence.update_bot_data(self.bot_data) + except Exception as e: + try: + self.dispatch_error(update, e) + except Exception: + message = 'Saving bot data raised an error and an ' \ + 'uncaught error was raised while handling ' \ + 'the error with an error_handler' + self.logger.exception(message) if self.persistence.store_chat_data and update.effective_chat: chat_id = update.effective_chat.id try: @@ -455,9 +471,11 @@ def remove_handler(self, handler, group=DEFAULT_GROUP): self.groups.remove(group) def update_persistence(self): - """Update :attr:`user_data` and :attr:`chat_data` in :attr:`persistence`. + """Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`. """ if self.persistence: + if self.persistence.store_bot_data: + self.persistence.update_bot_data(self.bot_data) if self.persistence.store_chat_data: for chat_id in self.chat_data: self.persistence.update_chat_data(chat_id, self.chat_data[chat_id]) diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index 1684b685aba..432dd4ec583 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -34,6 +34,8 @@ class PicklePersistence(BasePersistence): persistence class. store_chat_data (:obj:`bool`): Optional. Whether user_data should be saved by this persistence class. + store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this + persistence class. single_file (:obj:`bool`): Optional. When ``False`` will store 3 sperate files of `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is ``True``. @@ -48,6 +50,8 @@ class PicklePersistence(BasePersistence): persistence class. Default is ``True``. store_chat_data (:obj:`bool`, optional): Whether user_data should be saved by this persistence class. Default is ``True``. + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is ``True`` . single_file (:obj:`bool`, optional): When ``False`` will store 3 sperate files of `filename_user_data`, `filename_chat_data` and `filename_conversations`. Default is ``True``. @@ -56,15 +60,21 @@ class PicklePersistence(BasePersistence): on any transaction *and* on call fo :meth:`flush`. Default is ``False``. """ - def __init__(self, filename, store_user_data=True, store_chat_data=True, single_file=True, + def __init__(self, filename, + store_user_data=True, + store_chat_data=True, + store_bot_data=True, + single_file=True, on_flush=False): + super(PicklePersistence, self).__init__(store_user_data=store_user_data, + store_chat_data=store_chat_data, + store_bot_data=store_bot_data) self.filename = filename - self.store_user_data = store_user_data - self.store_chat_data = store_chat_data self.single_file = single_file self.on_flush = on_flush self.user_data = None self.chat_data = None + self.bot_data = None self.conversations = None def load_singlefile(self): @@ -74,11 +84,13 @@ def load_singlefile(self): all = pickle.load(f) self.user_data = defaultdict(dict, all['user_data']) self.chat_data = defaultdict(dict, all['chat_data']) + self.bot_data = all['bot_data'] self.conversations = all['conversations'] except IOError: self.conversations = {} self.user_data = defaultdict(dict) self.chat_data = defaultdict(dict) + self.bot_data = {} except pickle.UnpicklingError: raise TypeError("File {} does not contain valid pickle data".format(filename)) except Exception: @@ -98,7 +110,7 @@ def load_file(self, filename): def dump_singlefile(self): with open(self.filename, "wb") as f: all = {'conversations': self.conversations, 'user_data': self.user_data, - 'chat_data': self.chat_data} + 'chat_data': self.chat_data, 'bot_data': self.bot_data} pickle.dump(all, f) def dump_file(self, filename, data): @@ -145,6 +157,24 @@ def get_chat_data(self): self.load_singlefile() return deepcopy(self.chat_data) + def get_bot_data(self): + """Returns the bot_data from the pickle file if it exsists or an empty dict. + + Returns: + :obj:`defaultdict`: The restored bot data. + """ + if self.bot_data: + pass + elif not self.single_file: + filename = "{}_bot_data".format(self.filename) + data = self.load_file(filename) + if not data: + data = {} + self.bot_data = data + else: + self.load_singlefile() + return deepcopy(self.bot_data) + def get_conversations(self, name): """Returns the conversations from the pickle file if it exsists or an empty defaultdict. @@ -221,6 +251,23 @@ def update_chat_data(self, chat_id, data): else: self.dump_singlefile() + def update_bot_data(self, data): + """Will update the bot_data (if changed) and depending on :attr:`on_flush` save the + pickle file. + + Args: + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`. + """ + if self.bot_data == data: + return + self.bot_data = data.copy() + if not self.on_flush: + if not self.single_file: + filename = "{}_bot_data".format(self.filename) + self.dump_file(filename, self.bot_data) + else: + self.dump_singlefile() + def flush(self): """ Will save all data in memory to pickle file(s). """ @@ -232,5 +279,7 @@ def flush(self): self.dump_file("{}_user_data".format(self.filename), self.user_data) if self.chat_data: self.dump_file("{}_chat_data".format(self.filename), self.chat_data) + if self.bot_data: + self.dump_file("{}_bot_data".format(self.filename), self.bot_data) if self.conversations: self.dump_file("{}_conversations".format(self.filename), self.conversations) diff --git a/telegram/vendor/ptb_urllib3 b/telegram/vendor/ptb_urllib3 index 1954df03958..d2403a79fc3 160000 --- a/telegram/vendor/ptb_urllib3 +++ b/telegram/vendor/ptb_urllib3 @@ -1 +1 @@ -Subproject commit 1954df03958b164483282330b3a58092c070bc7a +Subproject commit d2403a79fc38afbdd9aba8a05d274a83dc8bb412 diff --git a/tests/conftest.py b/tests/conftest.py index 314f6a142ca..4ee1667d7ab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -107,6 +107,7 @@ def dp(_dp): _dp.update_queue.get(False) _dp.chat_data = defaultdict(dict) _dp.user_data = defaultdict(dict) + _dp.bot_data = {} _dp.persistence = None _dp.handlers = {} _dp.groups = [] diff --git a/tests/test_callbackcontext.py b/tests/test_callbackcontext.py index 5607fda0d59..28e5ca2b3ab 100644 --- a/tests/test_callbackcontext.py +++ b/tests/test_callbackcontext.py @@ -35,6 +35,7 @@ def test_from_job(self, cdp): assert callback_context.job is job assert callback_context.chat_data is None assert callback_context.user_data is None + assert callback_context.bot_data is cdp.bot_data assert callback_context.bot is cdp.bot assert callback_context.job_queue is cdp.job_queue assert callback_context.update_queue is cdp.update_queue @@ -46,15 +47,18 @@ def test_from_update(self, cdp): assert callback_context.chat_data == {} assert callback_context.user_data == {} + assert callback_context.bot_data is cdp.bot_data assert callback_context.bot is cdp.bot assert callback_context.job_queue is cdp.job_queue assert callback_context.update_queue is cdp.update_queue callback_context_same_user_chat = CallbackContext.from_update(update, cdp) + callback_context.bot_data['test'] = 'bot' callback_context.chat_data['test'] = 'chat' callback_context.user_data['test'] = 'user' + assert callback_context_same_user_chat.bot_data is callback_context.bot_data assert callback_context_same_user_chat.chat_data is callback_context.chat_data assert callback_context_same_user_chat.user_data is callback_context.user_data @@ -63,6 +67,7 @@ def test_from_update(self, cdp): callback_context_other_user_chat = CallbackContext.from_update(update_other_user_chat, cdp) + assert callback_context_other_user_chat.bot_data is callback_context.bot_data assert callback_context_other_user_chat.chat_data is not callback_context.chat_data assert callback_context_other_user_chat.user_data is not callback_context.user_data @@ -71,6 +76,7 @@ def test_from_update_not_update(self, cdp): assert callback_context.chat_data is None assert callback_context.user_data is None + assert callback_context.bot_data is cdp.bot_data assert callback_context.bot is cdp.bot assert callback_context.job_queue is cdp.job_queue assert callback_context.update_queue is cdp.update_queue @@ -79,6 +85,7 @@ def test_from_update_not_update(self, cdp): assert callback_context.chat_data is None assert callback_context.user_data is None + assert callback_context.bot_data is cdp.bot_data assert callback_context.bot is cdp.bot assert callback_context.job_queue is cdp.job_queue assert callback_context.update_queue is cdp.update_queue @@ -93,6 +100,7 @@ def test_from_error(self, cdp): assert callback_context.error is error assert callback_context.chat_data == {} assert callback_context.user_data == {} + assert callback_context.bot_data is cdp.bot_data assert callback_context.bot is cdp.bot assert callback_context.job_queue is cdp.job_queue assert callback_context.update_queue is cdp.update_queue diff --git a/tests/test_callbackqueryhandler.py b/tests/test_callbackqueryhandler.py index 8631b43e296..05ade13aa38 100644 --- a/tests/test_callbackqueryhandler.py +++ b/tests/test_callbackqueryhandler.py @@ -90,6 +90,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and context.chat_data is None + and isinstance(context.bot_data, dict) and isinstance(update.callback_query, CallbackQuery)) def callback_context_pattern(self, update, context): diff --git a/tests/test_choseninlineresulthandler.py b/tests/test_choseninlineresulthandler.py index 79fc35bb09b..4278b35358a 100644 --- a/tests/test_choseninlineresulthandler.py +++ b/tests/test_choseninlineresulthandler.py @@ -87,6 +87,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and context.chat_data is None + and isinstance(context.bot_data, dict) and isinstance(update.chosen_inline_result, ChosenInlineResult)) def test_basic(self, dp, chosen_inline_result): diff --git a/tests/test_commandhandler.py b/tests/test_commandhandler.py index f3c5297d7a1..11222878252 100644 --- a/tests/test_commandhandler.py +++ b/tests/test_commandhandler.py @@ -88,6 +88,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and isinstance(context.chat_data, dict) + and isinstance(context.bot_data, dict) and isinstance(update.message, Message)) def callback_context_args(self, update, context): diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 90960f92f5b..2ab26783d1a 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -122,6 +122,7 @@ class my_per: def __init__(self): self.store_user_data = False self.store_chat_data = False + self.store_bot_data = False with pytest.raises(TypeError, match='persistence should be based on telegram.ext.BasePersistence'): @@ -352,6 +353,13 @@ def __init__(self): super(BasePersistence, self).__init__() self.store_user_data = True self.store_chat_data = True + self.store_bot_data = True + + def get_bot_data(self): + return dict() + + def update_bot_data(self, data): + raise Exception def get_chat_data(self): return defaultdict(dict) @@ -385,7 +393,7 @@ def error(b, u, e): dp.add_handler(CommandHandler('start', start1)) dp.add_error_handler(error) dp.process_update(update) - assert increment == ["error", "error"] + assert increment == ["error", "error", "error"] def test_flow_stop_in_error_handler(self, dp, bot): passed = [] diff --git a/tests/test_inlinequeryhandler.py b/tests/test_inlinequeryhandler.py index 506130d7cd5..3591497b167 100644 --- a/tests/test_inlinequeryhandler.py +++ b/tests/test_inlinequeryhandler.py @@ -94,6 +94,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and context.chat_data is None + and isinstance(context.bot_data, dict) and isinstance(update.inline_query, InlineQuery)) def callback_context_pattern(self, update, context): diff --git a/tests/test_jobqueue.py b/tests/test_jobqueue.py index 664254f4bc3..1cad3a8feb1 100644 --- a/tests/test_jobqueue.py +++ b/tests/test_jobqueue.py @@ -76,6 +76,7 @@ def job_context_based_callback(self, context): and context.job.context == 2 and context.chat_data is None and context.user_data is None + and isinstance(context.bot_data, dict) and context.job_queue is context.job.job_queue): self.result += 1 diff --git a/tests/test_messagehandler.py b/tests/test_messagehandler.py index bf8cdf93cbc..d8ce813ec55 100644 --- a/tests/test_messagehandler.py +++ b/tests/test_messagehandler.py @@ -83,6 +83,7 @@ def callback_context(self, update, context): and isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and isinstance(context.chat_data, dict) + and isinstance(context.bot_data, dict) and ((isinstance(context.user_data, dict) and (isinstance(update.message, Message) or isinstance(update.edited_message, Message))) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index c9b01d10998..a253a9b8eac 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -38,7 +38,12 @@ @pytest.fixture(scope="function") def base_persistence(): - return BasePersistence(store_chat_data=True, store_user_data=True) + return BasePersistence(store_chat_data=True, store_user_data=True, store_bot_data=True) + + +@pytest.fixture(scope="function") +def bot_data(): + return {'test1': 'test2', 'test3': {'test4': 'test5'}} @pytest.fixture(scope="function") @@ -60,8 +65,10 @@ def conversations(): @pytest.fixture(scope="function") def updater(bot, base_persistence): base_persistence.store_chat_data = False + base_persistence.store_bot_data = False base_persistence.store_user_data = False u = Updater(bot=bot, persistence=base_persistence) + base_persistence.store_bot_data = True base_persistence.store_chat_data = True base_persistence.store_user_data = True return u @@ -72,12 +79,16 @@ class TestBasePersistence(object): def test_creation(self, base_persistence): assert base_persistence.store_chat_data assert base_persistence.store_user_data + with pytest.raises(NotImplementedError): + base_persistence.get_bot_data() with pytest.raises(NotImplementedError): base_persistence.get_chat_data() with pytest.raises(NotImplementedError): base_persistence.get_user_data() with pytest.raises(NotImplementedError): base_persistence.get_conversations("test") + with pytest.raises(NotImplementedError): + base_persistence.update_bot_data(None) with pytest.raises(NotImplementedError): base_persistence.update_chat_data(None, None) with pytest.raises(NotImplementedError): @@ -98,15 +109,21 @@ def test_conversationhandler_addition(self, dp, base_persistence): with pytest.raises(NotImplementedError): dp.add_handler(ConversationHandler([], {}, [], persistent=True, name="My Handler")) - def test_dispatcher_integration_init(self, bot, base_persistence, chat_data, user_data): + def test_dispatcher_integration_init(self, bot, base_persistence, chat_data, user_data, + bot_data): def get_user_data(): return "test" def get_chat_data(): return "test" + def get_bot_data(): + return "test" + base_persistence.get_user_data = get_user_data base_persistence.get_chat_data = get_chat_data + base_persistence.get_bot_data = get_bot_data + with pytest.raises(ValueError, match="user_data must be of type defaultdict"): u = Updater(bot=bot, persistence=base_persistence) @@ -121,22 +138,34 @@ def get_chat_data(): return chat_data base_persistence.get_chat_data = get_chat_data + with pytest.raises(ValueError, match="bot_data must be of type dict"): + u = Updater(bot=bot, persistence=base_persistence) + + def get_bot_data(): + return bot_data + + base_persistence.get_bot_data = get_bot_data u = Updater(bot=bot, persistence=base_persistence) + assert u.dispatcher.bot_data == bot_data assert u.dispatcher.chat_data == chat_data assert u.dispatcher.user_data == user_data u.dispatcher.chat_data[442233]['test5'] = 'test6' assert u.dispatcher.chat_data[442233]['test5'] == 'test6' def test_dispatcher_integration_handlers(self, caplog, bot, base_persistence, - chat_data, user_data): + chat_data, user_data, bot_data): def get_user_data(): return user_data def get_chat_data(): return chat_data + def get_bot_data(): + return bot_data + base_persistence.get_user_data = get_user_data base_persistence.get_chat_data = get_chat_data + base_persistence.get_bot_data = get_bot_data # base_persistence.update_chat_data = lambda x: x # base_persistence.update_user_data = lambda x: x updater = Updater(bot=bot, persistence=base_persistence, use_context=True) @@ -145,18 +174,25 @@ def get_chat_data(): def callback_known_user(update, context): if not context.user_data['test1'] == 'test2': pytest.fail('user_data corrupt') + if not context.bot_data == bot_data: + pytest.fail('bot_data corrupt') def callback_known_chat(update, context): if not context.chat_data['test3'] == 'test4': pytest.fail('chat_data corrupt') + if not context.bot_data == bot_data: + pytest.fail('bot_data corrupt') def callback_unknown_user_or_chat(update, context): if not context.user_data == {}: pytest.fail('user_data corrupt') if not context.chat_data == {}: pytest.fail('chat_data corrupt') + if not context.bot_data == bot_data: + pytest.fail('bot_data corrupt') context.user_data[1] = 'test7' context.chat_data[2] = 'test8' + context.bot_data['test0'] = 'test0' known_user = MessageHandler(Filters.user(user_id=12345), callback_known_user, pass_chat_data=True, pass_user_data=True) @@ -188,6 +224,10 @@ def callback_unknown_user_or_chat(update, context): m.chat = chat2 u = Update(2, m) + def save_bot_data(data): + if 'test0' not in data: + pytest.fail() + def save_chat_data(data): if -987654 not in data: pytest.fail() @@ -198,10 +238,12 @@ def save_user_data(data): base_persistence.update_chat_data = save_chat_data base_persistence.update_user_data = save_user_data + base_persistence.update_bot_data = save_bot_data dp.process_update(u) assert dp.user_data[54321][1] == 'test7' assert dp.chat_data[-987654][2] == 'test8' + assert dp.bot_data['test0'] == 'test0' def test_persistence_dispatcher_arbitrary_update_types(self, dp, base_persistence, caplog): # Updates used with TypeHandler doesn't necessarily have the proper attributes for @@ -224,6 +266,17 @@ def pickle_persistence(): return PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=True, + store_bot_data=True, + single_file=False, + on_flush=False) + + +@pytest.fixture(scope='function') +def pickle_persistence_only_bot(): + return PicklePersistence(filename='pickletest', + store_user_data=False, + store_chat_data=False, + store_bot_data=True, single_file=False, on_flush=False) @@ -233,6 +286,7 @@ def pickle_persistence_only_chat(): return PicklePersistence(filename='pickletest', store_user_data=False, store_chat_data=True, + store_bot_data=False, single_file=False, on_flush=False) @@ -242,36 +296,40 @@ def pickle_persistence_only_user(): return PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=False, + store_bot_data=False, single_file=False, on_flush=False) @pytest.fixture(scope='function') def bad_pickle_files(): - for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_conversations', - 'pickletest']: + for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_bot_data', + 'pickletest_conversations', 'pickletest']: with open(name, 'w') as f: f.write('(())') yield True - for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_conversations', - 'pickletest']: + for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_bot_data', + 'pickletest_conversations', 'pickletest']: os.remove(name) @pytest.fixture(scope='function') -def good_pickle_files(user_data, chat_data, conversations): - all = {'user_data': user_data, 'chat_data': chat_data, 'conversations': conversations} +def good_pickle_files(user_data, chat_data, bot_data, conversations): + all = {'user_data': user_data, 'chat_data': chat_data, + 'bot_data': bot_data, 'conversations': conversations} with open('pickletest_user_data', 'wb') as f: pickle.dump(user_data, f) with open('pickletest_chat_data', 'wb') as f: pickle.dump(chat_data, f) + with open('pickletest_bot_data', 'wb') as f: + pickle.dump(bot_data, f) with open('pickletest_conversations', 'wb') as f: pickle.dump(conversations, f) with open('pickletest', 'wb') as f: pickle.dump(all, f) yield True - for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_conversations', - 'pickletest']: + for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_bot_data', + 'pickletest_conversations', 'pickletest']: os.remove(name) @@ -289,6 +347,8 @@ def test_no_files_present_multi_file(self, pickle_persistence): assert pickle_persistence.get_user_data() == defaultdict(dict) assert pickle_persistence.get_chat_data() == defaultdict(dict) assert pickle_persistence.get_chat_data() == defaultdict(dict) + assert pickle_persistence.get_bot_data() == {} + assert pickle_persistence.get_bot_data() == {} assert pickle_persistence.get_conversations('noname') == {} assert pickle_persistence.get_conversations('noname') == {} @@ -296,6 +356,7 @@ def test_no_files_present_single_file(self, pickle_persistence): pickle_persistence.single_file = True assert pickle_persistence.get_user_data() == defaultdict(dict) assert pickle_persistence.get_chat_data() == defaultdict(dict) + assert pickle_persistence.get_chat_data() == {} assert pickle_persistence.get_conversations('noname') == {} def test_with_bad_multi_file(self, pickle_persistence, bad_pickle_files): @@ -303,6 +364,8 @@ def test_with_bad_multi_file(self, pickle_persistence, bad_pickle_files): pickle_persistence.get_user_data() with pytest.raises(TypeError, match='pickletest_chat_data'): pickle_persistence.get_chat_data() + with pytest.raises(TypeError, match='pickletest_bot_data'): + pickle_persistence.get_bot_data() with pytest.raises(TypeError, match='pickletest_conversations'): pickle_persistence.get_conversations('name') @@ -312,6 +375,8 @@ def test_with_bad_single_file(self, pickle_persistence, bad_pickle_files): pickle_persistence.get_user_data() with pytest.raises(TypeError, match='pickletest'): pickle_persistence.get_chat_data() + with pytest.raises(TypeError, match='pickletest'): + pickle_persistence.get_bot_data() with pytest.raises(TypeError, match='pickletest'): pickle_persistence.get_conversations('name') @@ -328,6 +393,12 @@ def test_with_good_multi_file(self, pickle_persistence, good_pickle_files): assert chat_data[-67890][3] == 'test4' assert chat_data[-54321] == {} + bot_data = pickle_persistence.get_bot_data() + assert isinstance(bot_data, dict) + assert bot_data['test1'] == 'test2' + assert bot_data['test3']['test4'] == 'test5' + assert 'test0' not in bot_data + conversation1 = pickle_persistence.get_conversations('name1') assert isinstance(conversation1, dict) assert conversation1[(123, 123)] == 3 @@ -355,6 +426,12 @@ def test_with_good_single_file(self, pickle_persistence, good_pickle_files): assert chat_data[-67890][3] == 'test4' assert chat_data[-54321] == {} + bot_data = pickle_persistence.get_bot_data() + assert isinstance(bot_data, dict) + assert bot_data['test1'] == 'test2' + assert bot_data['test3']['test4'] == 'test5' + assert 'test0' not in bot_data + conversation1 = pickle_persistence.get_conversations('name1') assert isinstance(conversation1, dict) assert conversation1[(123, 123)] == 3 @@ -387,6 +464,15 @@ def test_updating_multi_file(self, pickle_persistence, good_pickle_files): chat_data_test = defaultdict(dict, pickle.load(f)) assert chat_data_test == chat_data + bot_data = pickle_persistence.get_bot_data() + bot_data['test6'] = 'test 7' + assert not pickle_persistence.bot_data == bot_data + pickle_persistence.update_bot_data(bot_data) + assert pickle_persistence.bot_data == bot_data + with open('pickletest_bot_data', 'rb') as f: + bot_data_test = pickle.load(f) + assert bot_data_test == bot_data + conversation1 = pickle_persistence.get_conversations('name1') conversation1[(123, 123)] = 5 assert not pickle_persistence.conversations['name1'] == conversation1 @@ -417,6 +503,15 @@ def test_updating_single_file(self, pickle_persistence, good_pickle_files): chat_data_test = defaultdict(dict, pickle.load(f)['chat_data']) assert chat_data_test == chat_data + bot_data = pickle_persistence.get_bot_data() + bot_data['test6'] = 'test 7' + assert not pickle_persistence.bot_data == bot_data + pickle_persistence.update_bot_data(bot_data) + assert pickle_persistence.bot_data == bot_data + with open('pickletest', 'rb') as f: + bot_data_test = pickle.load(f)['bot_data'] + assert bot_data_test == bot_data + conversation1 = pickle_persistence.get_conversations('name1') conversation1[(123, 123)] = 5 assert not pickle_persistence.conversations['name1'] == conversation1 @@ -453,6 +548,17 @@ def test_save_on_flush_multi_files(self, pickle_persistence, good_pickle_files): chat_data_test = defaultdict(dict, pickle.load(f)) assert not chat_data_test == chat_data + bot_data = pickle_persistence.get_bot_data() + bot_data['test6'] = 'test 7' + assert not pickle_persistence.bot_data == bot_data + + pickle_persistence.update_bot_data(bot_data) + assert pickle_persistence.bot_data == bot_data + + with open('pickletest_bot_data', 'rb') as f: + bot_data_test = pickle.load(f) + assert not bot_data_test == bot_data + conversation1 = pickle_persistence.get_conversations('name1') conversation1[(123, 123)] = 5 assert not pickle_persistence.conversations['name1'] == conversation1 @@ -473,6 +579,10 @@ def test_save_on_flush_multi_files(self, pickle_persistence, good_pickle_files): chat_data_test = defaultdict(dict, pickle.load(f)) assert chat_data_test == chat_data + with open('pickletest_bot_data', 'rb') as f: + bot_data_test = pickle.load(f) + assert bot_data_test == bot_data + with open('pickletest_conversations', 'rb') as f: conversations_test = defaultdict(dict, pickle.load(f)) assert conversations_test['name1'] == conversation1 @@ -502,6 +612,15 @@ def test_save_on_flush_single_files(self, pickle_persistence, good_pickle_files) chat_data_test = defaultdict(dict, pickle.load(f)['chat_data']) assert not chat_data_test == chat_data + bot_data = pickle_persistence.get_bot_data() + bot_data['test6'] = 'test 7' + assert not pickle_persistence.bot_data == bot_data + pickle_persistence.update_bot_data(bot_data) + assert pickle_persistence.bot_data == bot_data + with open('pickletest', 'rb') as f: + bot_data_test = pickle.load(f)['bot_data'] + assert not bot_data_test == bot_data + conversation1 = pickle_persistence.get_conversations('name1') conversation1[(123, 123)] = 5 assert not pickle_persistence.conversations['name1'] == conversation1 @@ -520,11 +639,15 @@ def test_save_on_flush_single_files(self, pickle_persistence, good_pickle_files) chat_data_test = defaultdict(dict, pickle.load(f)['chat_data']) assert chat_data_test == chat_data + with open('pickletest', 'rb') as f: + bot_data_test = pickle.load(f)['bot_data'] + assert bot_data_test == bot_data + with open('pickletest', 'rb') as f: conversations_test = defaultdict(dict, pickle.load(f)['conversations']) assert conversations_test['name1'] == conversation1 - def test_with_handler(self, bot, update, pickle_persistence, good_pickle_files): + def test_with_handler(self, bot, update, bot_data, pickle_persistence, good_pickle_files): u = Updater(bot=bot, persistence=pickle_persistence, use_context=True) dp = u.dispatcher @@ -533,14 +656,19 @@ def first(update, context): pytest.fail() if not context.chat_data == {}: pytest.fail() + if not context.bot_data == bot_data: + pytest.failt() context.user_data['test1'] = 'test2' context.chat_data['test3'] = 'test4' + context.bot_data['test1'] = 'test0' def second(update, context): if not context.user_data['test1'] == 'test2': pytest.fail() if not context.chat_data['test3'] == 'test4': pytest.fail() + if not context.bot_data['test1'] == 'test0': + pytest.fail() h1 = MessageHandler(None, first, pass_user_data=True, pass_chat_data=True) h2 = MessageHandler(None, second, pass_user_data=True, pass_chat_data=True) @@ -552,6 +680,7 @@ def second(update, context): pickle_persistence_2 = PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=True, + store_bot_data=True, single_file=False, on_flush=False) u = Updater(bot=bot, persistence=pickle_persistence_2) @@ -565,6 +694,7 @@ def test_flush_on_stop(self, bot, update, pickle_persistence): u.running = True dp.user_data[4242424242]['my_test'] = 'Working!' dp.chat_data[-4242424242]['my_test2'] = 'Working2!' + dp.bot_data['test'] = 'Working3!' u.signal_handler(signal.SIGINT, None) del (dp) del (u) @@ -576,10 +706,34 @@ def test_flush_on_stop(self, bot, update, pickle_persistence): on_flush=False) assert pickle_persistence_2.get_user_data()[4242424242]['my_test'] == 'Working!' assert pickle_persistence_2.get_chat_data()[-4242424242]['my_test2'] == 'Working2!' + assert pickle_persistence_2.get_bot_data()['test'] == 'Working3!' - def test_flush_on_stop_only_chat(self, bot, update, pickle_persistence_only_chat): + def test_flush_on_stop_only_bot(self, bot, update, pickle_persistence_only_bot): os.remove('pickletest_user_data') os.remove('pickletest_chat_data') + os.remove('pickletest_bot_data') + u = Updater(bot=bot, persistence=pickle_persistence_only_bot) + dp = u.dispatcher + u.running = True + dp.user_data[4242424242]['my_test'] = 'Working!' + dp.chat_data[-4242424242]['my_test2'] = 'Working2!' + dp.bot_data['my_test3'] = 'Working3!' + u.signal_handler(signal.SIGINT, None) + del (dp) + del (u) + del (pickle_persistence_only_bot) + pickle_persistence_2 = PicklePersistence(filename='pickletest', + store_user_data=False, + store_chat_data=False, + store_bot_data=True, + single_file=False, + on_flush=False) + assert pickle_persistence_2.get_user_data() == {} + assert pickle_persistence_2.get_chat_data() == {} + assert pickle_persistence_2.get_bot_data()['my_test3'] == 'Working3!' + + def test_flush_on_stop_only_chat(self, bot, update, pickle_persistence_only_chat): + os.remove('pickletest_bot_data') u = Updater(bot=bot, persistence=pickle_persistence_only_chat) dp = u.dispatcher u.running = True @@ -592,10 +746,12 @@ def test_flush_on_stop_only_chat(self, bot, update, pickle_persistence_only_chat pickle_persistence_2 = PicklePersistence(filename='pickletest', store_user_data=False, store_chat_data=True, + store_bot_data=False, single_file=False, on_flush=False) assert pickle_persistence_2.get_user_data() == {} assert pickle_persistence_2.get_chat_data()[-4242424242]['my_test2'] == 'Working2!' + assert pickle_persistence_2.get_bot_data() == {} def test_flush_on_stop_only_user(self, bot, update, pickle_persistence_only_user): os.remove('pickletest_chat_data') @@ -611,10 +767,12 @@ def test_flush_on_stop_only_user(self, bot, update, pickle_persistence_only_user pickle_persistence_2 = PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=False, + store_bot_data=False, single_file=False, on_flush=False) assert pickle_persistence_2.get_user_data()[4242424242]['my_test'] == 'Working!' assert pickle_persistence_2.get_chat_data()[-4242424242] == {} + assert pickle_persistence_2.get_bot_data() == {} def test_with_conversationHandler(self, dp, update, good_pickle_files, pickle_persistence): dp.persistence = pickle_persistence @@ -652,6 +810,7 @@ def next2(update, context): def teardown_class(cls): try: for name in ['pickletest_user_data', 'pickletest_chat_data', + 'pickletest_bot_data', 'pickletest_conversations', 'pickletest']: os.remove(name) @@ -669,6 +828,11 @@ def chat_data_json(chat_data): return json.dumps(chat_data) +@pytest.fixture(scope='function') +def bot_data_json(bot_data): + return json.dumps(bot_data) + + @pytest.fixture(scope='function') def conversations_json(conversations): return """{"name1": {"[123, 123]": 3, "[456, 654]": 4}, "name2": @@ -680,33 +844,42 @@ def test_no_json_given(self): dict_persistence = DictPersistence() assert dict_persistence.get_user_data() == defaultdict(dict) assert dict_persistence.get_chat_data() == defaultdict(dict) + assert dict_persistence.get_bot_data() == {} assert dict_persistence.get_conversations('noname') == {} def test_bad_json_string_given(self): bad_user_data = 'thisisnojson99900()))(' bad_chat_data = 'thisisnojson99900()))(' + bad_bot_data = 'thisisnojson99900()))(' bad_conversations = 'thisisnojson99900()))(' with pytest.raises(TypeError, match='user_data'): DictPersistence(user_data_json=bad_user_data) with pytest.raises(TypeError, match='chat_data'): DictPersistence(chat_data_json=bad_chat_data) + with pytest.raises(TypeError, match='bot_data'): + DictPersistence(bot_data_json=bad_bot_data) with pytest.raises(TypeError, match='conversations'): DictPersistence(conversations_json=bad_conversations) def test_invalid_json_string_given(self, pickle_persistence, bad_pickle_files): bad_user_data = '["this", "is", "json"]' bad_chat_data = '["this", "is", "json"]' + bad_bot_data = '["this", "is", "json"]' bad_conversations = '["this", "is", "json"]' with pytest.raises(TypeError, match='user_data'): DictPersistence(user_data_json=bad_user_data) with pytest.raises(TypeError, match='chat_data'): DictPersistence(chat_data_json=bad_chat_data) + with pytest.raises(TypeError, match='bot_data'): + DictPersistence(bot_data_json=bad_bot_data) with pytest.raises(TypeError, match='conversations'): DictPersistence(conversations_json=bad_conversations) - def test_good_json_input(self, user_data_json, chat_data_json, conversations_json): + def test_good_json_input(self, user_data_json, chat_data_json, bot_data_json, + conversations_json): dict_persistence = DictPersistence(user_data_json=user_data_json, chat_data_json=chat_data_json, + bot_data_json=bot_data_json, conversations_json=conversations_json) user_data = dict_persistence.get_user_data() assert isinstance(user_data, defaultdict) @@ -720,6 +893,12 @@ def test_good_json_input(self, user_data_json, chat_data_json, conversations_jso assert chat_data[-67890][3] == 'test4' assert chat_data[-54321] == {} + bot_data = dict_persistence.get_bot_data() + assert isinstance(bot_data, dict) + assert bot_data['test1'] == 'test2' + assert bot_data['test3']['test4'] == 'test5' + assert 'test6' not in bot_data + conversation1 = dict_persistence.get_conversations('name1') assert isinstance(conversation1, dict) assert conversation1[(123, 123)] == 3 @@ -734,26 +913,33 @@ def test_good_json_input(self, user_data_json, chat_data_json, conversations_jso conversation2[(123, 123)] def test_dict_outputs(self, user_data, user_data_json, chat_data, chat_data_json, + bot_data, bot_data_json, conversations, conversations_json): dict_persistence = DictPersistence(user_data_json=user_data_json, chat_data_json=chat_data_json, + bot_data_json=bot_data_json, conversations_json=conversations_json) assert dict_persistence.user_data == user_data assert dict_persistence.chat_data == chat_data + assert dict_persistence.bot_data == bot_data assert dict_persistence.conversations == conversations - def test_json_outputs(self, user_data_json, chat_data_json, conversations_json): + def test_json_outputs(self, user_data_json, chat_data_json, bot_data_json, conversations_json): dict_persistence = DictPersistence(user_data_json=user_data_json, chat_data_json=chat_data_json, + bot_data_json=bot_data_json, conversations_json=conversations_json) assert dict_persistence.user_data_json == user_data_json assert dict_persistence.chat_data_json == chat_data_json + assert dict_persistence.bot_data_json == bot_data_json assert dict_persistence.conversations_json == conversations_json def test_json_changes(self, user_data, user_data_json, chat_data, chat_data_json, + bot_data, bot_data_json, conversations, conversations_json): dict_persistence = DictPersistence(user_data_json=user_data_json, chat_data_json=chat_data_json, + bot_data_json=bot_data_json, conversations_json=conversations_json) user_data_two = user_data.copy() user_data_two.update({4: {5: 6}}) @@ -769,6 +955,14 @@ def test_json_changes(self, user_data, user_data_json, chat_data, chat_data_json assert dict_persistence.chat_data_json != chat_data_json assert dict_persistence.chat_data_json == json.dumps(chat_data_two) + bot_data_two = bot_data.copy() + bot_data_two.update({'7': {'8': '9'}}) + bot_data['7'] = {'8': '9'} + dict_persistence.update_bot_data(bot_data) + assert dict_persistence.bot_data == bot_data_two + assert dict_persistence.bot_data_json != bot_data_json + assert dict_persistence.bot_data_json == json.dumps(bot_data_two) + conversations_two = conversations.copy() conversations_two.update({'name3': {(1, 2): 3}}) dict_persistence.update_conversation('name3', (1, 2), 3) @@ -787,14 +981,19 @@ def first(update, context): pytest.fail() if not context.chat_data == {}: pytest.fail() + if not context.bot_data == {}: + pytest.fail() context.user_data['test1'] = 'test2' context.chat_data[3] = 'test4' + context.bot_data['test1'] = 'test2' def second(update, context): if not context.user_data['test1'] == 'test2': pytest.fail() if not context.chat_data[3] == 'test4': pytest.fail() + if not context.bot_data['test1'] == 'test2': + pytest.fail() h1 = MessageHandler(None, first, pass_user_data=True, pass_chat_data=True) h2 = MessageHandler(None, second, pass_user_data=True, pass_chat_data=True) @@ -804,9 +1003,11 @@ def second(update, context): del (u) user_data = dict_persistence.user_data_json chat_data = dict_persistence.chat_data_json + bot_data = dict_persistence.bot_data_json del (dict_persistence) dict_persistence_2 = DictPersistence(user_data_json=user_data, - chat_data_json=chat_data) + chat_data_json=chat_data, + bot_data_json=bot_data) u = Updater(bot=bot, persistence=dict_persistence_2) dp = u.dispatcher diff --git a/tests/test_precheckoutqueryhandler.py b/tests/test_precheckoutqueryhandler.py index 1f0580b789b..2b05f2f4096 100644 --- a/tests/test_precheckoutqueryhandler.py +++ b/tests/test_precheckoutqueryhandler.py @@ -87,6 +87,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and context.chat_data is None + and isinstance(context.bot_data, dict) and isinstance(update.pre_checkout_query, PreCheckoutQuery)) def test_basic(self, dp, pre_checkout_query): diff --git a/tests/test_regexhandler.py b/tests/test_regexhandler.py index c3adccdfb3a..4481649547e 100644 --- a/tests/test_regexhandler.py +++ b/tests/test_regexhandler.py @@ -88,6 +88,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and isinstance(context.chat_data, dict) + and isinstance(context.bot_data, dict) and isinstance(update.message, Message)) def callback_context_pattern(self, update, context): diff --git a/tests/test_shippingqueryhandler.py b/tests/test_shippingqueryhandler.py index fbad3c33095..395c09f3e51 100644 --- a/tests/test_shippingqueryhandler.py +++ b/tests/test_shippingqueryhandler.py @@ -88,6 +88,7 @@ def callback_context(self, update, context): and isinstance(context.job_queue, JobQueue) and isinstance(context.user_data, dict) and context.chat_data is None + and isinstance(context.bot_data, dict) and isinstance(update.shipping_query, ShippingQuery)) def test_basic(self, dp, shiping_query): diff --git a/tests/test_stringcommandhandler.py b/tests/test_stringcommandhandler.py index e512522f6ee..cc1bbf29cc2 100644 --- a/tests/test_stringcommandhandler.py +++ b/tests/test_stringcommandhandler.py @@ -80,7 +80,8 @@ def callback_context(self, update, context): and isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and context.user_data is None - and context.chat_data is None) + and context.chat_data is None + and isinstance(context.bot_data, dict)) def callback_context_args(self, update, context): self.test_flag = context.args == ['one', 'two'] diff --git a/tests/test_typehandler.py b/tests/test_typehandler.py index 56c33f055ce..08fc9cbfd13 100644 --- a/tests/test_typehandler.py +++ b/tests/test_typehandler.py @@ -50,7 +50,8 @@ def callback_context(self, update, context): and isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and context.user_data is None - and context.chat_data is None) + and context.chat_data is None + and isinstance(context.bot_data, dict)) def test_basic(self, dp): handler = TypeHandler(dict, self.callback_basic)