From 2cf079a304b6bd9c7971c345af6aa420f2e40709 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Thu, 10 Jan 2019 13:01:48 +0100 Subject: [PATCH 01/12] Update AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1223422fc36..d7854e70f64 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -19,6 +19,7 @@ The following wonderful people contributed directly or indirectly to this projec - `Anton Tagunov `_ - `Avanatiker `_ - `Balduro `_ +- `Bibo-Joshi `_ - `bimmlerd `_ - `d-qoi `_ - `daimajia `_ From 9865e0e2e1674006d2f343671dbaa72b8b7eed91 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Thu, 10 Jan 2019 13:18:48 +0100 Subject: [PATCH 02/12] Update AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1223422fc36..d7854e70f64 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -19,6 +19,7 @@ The following wonderful people contributed directly or indirectly to this projec - `Anton Tagunov `_ - `Avanatiker `_ - `Balduro `_ +- `Bibo-Joshi `_ - `bimmlerd `_ - `d-qoi `_ - `daimajia `_ From 81803e1642bc7acd75b1d7be1f914ba1c6888aca Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Sat, 12 Jan 2019 17:32:30 +0100 Subject: [PATCH 03/12] Add bot_data to CallbackContext as global memory --- telegram/ext/basepersistence.py | 32 +++- telegram/ext/callbackcontext.py | 6 + telegram/ext/dictpersistence.py | 65 +++++++- telegram/ext/dispatcher.py | 37 +++-- telegram/ext/picklepersistence.py | 56 ++++++- tests/conftest.py | 1 + tests/test_callbackcontext.py | 8 + tests/test_callbackqueryhandler.py | 1 + tests/test_choseninlineresulthandler.py | 1 + tests/test_commandhandler.py | 2 + tests/test_dispatcher.py | 1 + tests/test_inlinequeryhandler.py | 1 + tests/test_jobqueue.py | 1 + tests/test_messagehandler.py | 1 + tests/test_persistence.py | 190 ++++++++++++++++++++++-- tests/test_precheckoutqueryhandler.py | 1 + tests/test_regexhandler.py | 1 + tests/test_shippingqueryhandler.py | 1 + tests/test_stringcommandhandler.py | 3 +- tests/test_typehandler.py | 3 +- 20 files changed, 372 insertions(+), 40 deletions(-) diff --git a/telegram/ext/basepersistence.py b/telegram/ext/basepersistence.py index f62491ee903..c7d5e249e31 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 + ``defaultdict(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 @@ -101,7 +118,7 @@ def update_user_data(self, user_id, data): Args: user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data`[user_id]. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` [user_id]. """ raise NotImplementedError @@ -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 bf502dc5414..2071afa465f 100644 --- a/telegram/ext/callbackcontext.py +++ b/telegram/ext/callbackcontext.py @@ -29,6 +29,8 @@ class CallbackContext(object): :class:`telegram.ext.Job`. 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 it will be the same ``dict``. user_data (:obj:`dict`, optional): A dict that can be used to keep any data in. For each @@ -57,6 +59,7 @@ def __init__(self, dispatcher): raise ValueError('CallbackContext should not be used with a non context aware ' 'dispatcher!') self._dispatcher = dispatcher + self.bot_data = None self.chat_data = None self.user_data = None self.args = None @@ -73,6 +76,8 @@ def from_error(cls, update, error, dispatcher): @classmethod def from_update(cls, update, dispatcher): self = cls(dispatcher) + self.bot_data = dispatcher.bot_data + if update is not None and isinstance(update, Update): chat = update.effective_chat user = update.effective_user @@ -86,6 +91,7 @@ def from_update(cls, update, dispatcher): @classmethod def from_job(cls, job, dispatcher): self = cls(dispatcher) + self.bot_data = dispatcher.bot_data self.job = job return self diff --git a/telegram/ext/dictpersistence.py b/telegram/ext/dictpersistence.py index 28ca4727331..a9a373d57df 100644 --- a/telegram/ext/dictpersistence.py +++ b/telegram/ext/dictpersistence.py @@ -29,36 +29,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`): 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 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=''): + 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=''): self.store_user_data = store_user_data self.store_chat_data = store_chat_data + self.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: @@ -72,6 +87,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: @@ -106,6 +129,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""" @@ -143,6 +179,18 @@ def get_chat_data(self): self._chat_data = defaultdict(dict) return self.chat_data.copy() + def get_bot_data(self): + """Returns the bot_data created from the ``bot_data_json`` or an empty defaultdict. + + Returns: + :obj:`defaultdict`: The restored user data. + """ + if self.bot_data: + pass + else: + self._bot_data = {} + return self.bot_data.copy() + def get_conversations(self, name): """Returns the conversations created from the ``conversations_json`` or an empty defaultdict. @@ -192,3 +240,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 69a259f7943..3cb01bde845 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -77,6 +77,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 @@ -119,8 +120,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") @@ -133,6 +134,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 @@ -322,20 +327,26 @@ def process_update(self, update): if check is not None and check is not False: handler.handle_update(update, self, check) if self.persistence: - if self.persistence.store_chat_data and update.effective_chat: - chat_id = update.effective_chat.id + if self.persistence.store_bot_data: try: - self.persistence.update_chat_data(chat_id, - self.chat_data[chat_id]) + self.persistence.update_bot_data(self.bot_data) except Exception: - self.logger.exception('Saving chat data raised an error') - if self.persistence.store_user_data and update.effective_user: - user_id = update.effective_user.id - try: - self.persistence.update_user_data(user_id, - self.user_data[user_id]) - except Exception: - self.logger.exception('Saving user data raised an error') + self.logger.exception('Saving bot data raised an error') + + if self.persistence.store_chat_data and update.effective_chat: + chat_id = update.effective_chat.id + try: + self.persistence.update_chat_data(chat_id, + self.chat_data[chat_id]) + except Exception: + self.logger.exception('Saving chat data raised an error') + if self.persistence.store_user_data and update.effective_user: + user_id = update.effective_user.id + try: + self.persistence.update_user_data(user_id, + self.user_data[user_id]) + except Exception: + self.logger.exception('Saving user data raised an error') break # Stop processing with any other handler. diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index ed3c06cf900..9fbbea73279 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -33,6 +33,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``. @@ -47,6 +49,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``. @@ -55,15 +59,21 @@ class PicklePersistence(BasePersistence): transaction. Default is ``False``. """ - def __init__(self, filename, store_user_data=True, store_chat_data=True, singe_file=True, + def __init__(self, filename, + store_user_data=True, + store_chat_data=True, + store_bot_data=True, + singe_file=True, on_flush=False): self.filename = filename self.store_user_data = store_user_data self.store_chat_data = store_chat_data + self.store_bot_data = store_bot_data self.single_file = singe_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): @@ -73,11 +83,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: @@ -97,7 +109,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): @@ -144,6 +156,24 @@ def get_chat_data(self): self.load_singlefile() return self.chat_data.copy() + def get_bot_data(self): + """Returns the bot_data from the pickle file if it exsists or an empty defaultdict. + + 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 self.bot_data.copy() + def get_conversations(self, name): """Returns the conversations from the pickle file if it exsists or an empty defaultdict. @@ -190,7 +220,7 @@ def update_user_data(self, user_id, data): Args: user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data`[user_id]. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` [user_id]. """ if self.user_data.get(user_id) == data: return @@ -208,7 +238,7 @@ 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`[chat_id]. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` [chat_id]. """ if self.chat_data.get(chat_id) == data: return @@ -220,6 +250,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): """If :attr:`on_flush` is set to ``True``. Will save all data in memory to pickle file(s). If it's ``False`` will just pass. @@ -232,4 +279,5 @@ def flush(self): else: self.dump_file("{}_user_data".format(self.filename), self.user_data) self.dump_file("{}_chat_data".format(self.filename), self.chat_data) + self.dump_file("{}_bot_data".format(self.filename), self.bot_data) self.dump_file("{}_conversations".format(self.filename), self.conversations) diff --git a/tests/conftest.py b/tests/conftest.py index e38e8f570d4..3902c6281c5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -97,6 +97,7 @@ def dp(_dp): _dp.update_queue.get(False) _dp.chat_data = defaultdict(dict) _dp.user_data = defaultdict(dict) + _dp.bot_data = {} _dp.handlers = {} _dp.groups = [] _dp.error_handlers = [] diff --git a/tests/test_callbackcontext.py b/tests/test_callbackcontext.py index 70eb9bcbcf3..aa55cec288b 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 ca6a81a47b4..cebd2f6d09b 100644 --- a/tests/test_callbackqueryhandler.py +++ b/tests/test_callbackqueryhandler.py @@ -90,6 +90,7 @@ def callback_context(self, update, context): 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 06d8dac438b..02f86e2da25 100644 --- a/tests/test_choseninlineresulthandler.py +++ b/tests/test_choseninlineresulthandler.py @@ -87,6 +87,7 @@ def callback_context(self, update, context): 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 beeb3587839..d681f0919f9 100644 --- a/tests/test_commandhandler.py +++ b/tests/test_commandhandler.py @@ -102,6 +102,7 @@ def callback_context(self, update, context): 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): @@ -385,6 +386,7 @@ def callback_context(self, update, context): 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 7e42b05f89b..8c563e332e2 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -97,6 +97,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'): diff --git a/tests/test_inlinequeryhandler.py b/tests/test_inlinequeryhandler.py index 689f1ad10db..58376aa3c2b 100644 --- a/tests/test_inlinequeryhandler.py +++ b/tests/test_inlinequeryhandler.py @@ -94,6 +94,7 @@ def callback_context(self, update, context): 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 e3ed8e6995d..a00557e9c43 100644 --- a/tests/test_jobqueue.py +++ b/tests/test_jobqueue.py @@ -73,6 +73,7 @@ def job_context_based_callback(self, context): context.job.context == 2 and context.chat_data is None and context.user_data is None and + context.bot_data is not None 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 1d1d6c8354f..7e96b450b23 100644 --- a/tests/test_messagehandler.py +++ b/tests/test_messagehandler.py @@ -81,6 +81,7 @@ def callback_context(self, update, context): 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 diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 9f4c1d30d0f..1f06b44357b 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -36,7 +36,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") @@ -58,8 +63,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 @@ -70,12 +77,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): @@ -96,15 +107,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) @@ -119,22 +136,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) @@ -143,18 +172,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) @@ -186,6 +222,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() @@ -196,10 +236,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' @pytest.fixture(scope='function') @@ -207,36 +249,40 @@ def pickle_persistence(): return PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=True, + store_bot_data=True, singe_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) @@ -254,6 +300,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') == {} @@ -261,6 +309,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): @@ -268,6 +317,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') @@ -277,6 +328,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') @@ -293,6 +346,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 @@ -320,6 +379,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 @@ -352,6 +417,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 @@ -382,6 +456,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 @@ -418,6 +501,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 @@ -438,6 +532,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 @@ -467,6 +565,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 @@ -485,11 +592,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 @@ -498,14 +609,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) @@ -517,6 +633,7 @@ def second(update, context): pickle_persistence_2 = PicklePersistence(filename='pickletest', store_user_data=True, store_chat_data=True, + store_bot_data=True, singe_file=False, on_flush=False) u = Updater(bot=bot, persistence=pickle_persistence_2) @@ -560,6 +677,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) @@ -577,6 +695,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": @@ -588,33 +711,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) @@ -628,6 +760,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 @@ -642,26 +780,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}}) @@ -677,6 +822,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) @@ -695,14 +848,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) @@ -712,9 +870,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 a5cfba99d9f..2d9314a7292 100644 --- a/tests/test_precheckoutqueryhandler.py +++ b/tests/test_precheckoutqueryhandler.py @@ -87,6 +87,7 @@ def callback_context(self, update, context): 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 6e3af9766b0..a0bc3a332bf 100644 --- a/tests/test_regexhandler.py +++ b/tests/test_regexhandler.py @@ -87,6 +87,7 @@ def callback_context(self, update, context): 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 64e70b69697..94339301f30 100644 --- a/tests/test_shippingqueryhandler.py +++ b/tests/test_shippingqueryhandler.py @@ -88,6 +88,7 @@ def callback_context(self, update, context): 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 52aa1ae23d4..1f8302fcf05 100644 --- a/tests/test_stringcommandhandler.py +++ b/tests/test_stringcommandhandler.py @@ -80,7 +80,8 @@ def callback_context(self, update, context): isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and context.user_data is None and - context.chat_data is None) + 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 f0fc362a06b..c1bb1a5e5ff 100644 --- a/tests/test_typehandler.py +++ b/tests/test_typehandler.py @@ -50,7 +50,8 @@ def callback_context(self, update, context): isinstance(context.update_queue, Queue) and isinstance(context.job_queue, JobQueue) and context.user_data is None and - context.chat_data is None) + context.chat_data is None and + context.bot_data is not None) def test_basic(self, dp): handler = TypeHandler(dict, self.callback_basic) From 767e914e2d24da8153ca69920550a9aa20e7f849 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Sat, 12 Jan 2019 17:52:22 +0100 Subject: [PATCH 04/12] Minor fixes in docstrings --- telegram/ext/basepersistence.py | 2 +- telegram/ext/dictpersistence.py | 4 ++-- telegram/ext/picklepersistence.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/telegram/ext/basepersistence.py b/telegram/ext/basepersistence.py index c7d5e249e31..28643ac52c5 100644 --- a/telegram/ext/basepersistence.py +++ b/telegram/ext/basepersistence.py @@ -80,7 +80,7 @@ def get_chat_data(self): 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 - ``defaultdict(dict)``. + ``dict``. Returns: :obj:`defaultdict`: The restored bot data. diff --git a/telegram/ext/dictpersistence.py b/telegram/ext/dictpersistence.py index a9a373d57df..f9aa1526e66 100644 --- a/telegram/ext/dictpersistence.py +++ b/telegram/ext/dictpersistence.py @@ -36,7 +36,7 @@ class DictPersistence(BasePersistence): persistence class. store_chat_data (:obj:`bool`): Whether chat_data should be saved by this persistence class. - store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this + store_bot_data (:obj:`bool`): Whether bot_data should be saved by this persistence class. Args: @@ -180,7 +180,7 @@ def get_chat_data(self): return self.chat_data.copy() def get_bot_data(self): - """Returns the bot_data created from the ``bot_data_json`` or an empty defaultdict. + """Returns the bot_data created from the ``bot_data_json`` or an empty dict. Returns: :obj:`defaultdict`: The restored user data. diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index 9fbbea73279..e26b51de857 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -157,7 +157,7 @@ def get_chat_data(self): return self.chat_data.copy() def get_bot_data(self): - """Returns the bot_data from the pickle file if it exsists or an empty defaultdict. + """Returns the bot_data from the pickle file if it exsists or an empty dict. Returns: :obj:`defaultdict`: The restored bot data. From 4582cc4198d2c6b565ecfb3a30559fe8e471f956 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Sun, 13 Jan 2019 11:46:46 +0100 Subject: [PATCH 05/12] Incorp. req. changes, Flake8 Fixes --- telegram/ext/callbackcontext.py | 4 +-- telegram/ext/commandhandler.py | 16 +++++------ telegram/ext/dictpersistence.py | 6 ++--- telegram/ext/dispatcher.py | 28 +++++++++---------- telegram/ext/picklepersistence.py | 6 ++--- tests/test_callbackqueryhandler.py | 18 ++++++------- tests/test_choseninlineresulthandler.py | 18 ++++++------- tests/test_commandhandler.py | 36 ++++++++++++------------- tests/test_dispatcher.py | 10 +++---- tests/test_inlinequeryhandler.py | 18 ++++++------- tests/test_jobqueue.py | 16 +++++------ tests/test_messagehandler.py | 29 ++++++++++---------- tests/test_precheckoutqueryhandler.py | 18 ++++++------- tests/test_regexhandler.py | 18 ++++++------- tests/test_shippingqueryhandler.py | 18 ++++++------- tests/test_stringcommandhandler.py | 16 +++++------ tests/test_stringregexhandler.py | 10 +++---- tests/test_typehandler.py | 16 +++++------ 18 files changed, 149 insertions(+), 152 deletions(-) diff --git a/telegram/ext/callbackcontext.py b/telegram/ext/callbackcontext.py index 2071afa465f..deb67956d93 100644 --- a/telegram/ext/callbackcontext.py +++ b/telegram/ext/callbackcontext.py @@ -59,7 +59,7 @@ def __init__(self, dispatcher): raise ValueError('CallbackContext should not be used with a non context aware ' 'dispatcher!') self._dispatcher = dispatcher - self.bot_data = None + self.bot_data = dispatcher.bot_data self.chat_data = None self.user_data = None self.args = None @@ -76,7 +76,6 @@ def from_error(cls, update, error, dispatcher): @classmethod def from_update(cls, update, dispatcher): self = cls(dispatcher) - self.bot_data = dispatcher.bot_data if update is not None and isinstance(update, Update): chat = update.effective_chat @@ -91,7 +90,6 @@ def from_update(cls, update, dispatcher): @classmethod def from_job(cls, job, dispatcher): self = cls(dispatcher) - self.bot_data = dispatcher.bot_data self.job = job return self diff --git a/telegram/ext/commandhandler.py b/telegram/ext/commandhandler.py index 508661730eb..faac8a954ea 100644 --- a/telegram/ext/commandhandler.py +++ b/telegram/ext/commandhandler.py @@ -145,19 +145,19 @@ def check_update(self, update): :obj:`bool` """ - if (isinstance(update, Update) and - (update.message or update.edited_message and self.allow_edited)): + if (isinstance(update, Update) + and (update.message or update.edited_message and self.allow_edited)): message = update.effective_message - if (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND and - message.entities[0].offset == 0): + if (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND + and message.entities[0].offset == 0): command = message.text[1:message.entities[0].length] args = message.text.split()[1:] command = command.split('@') command.append(message.bot.username) - if not (command[0].lower() in self.command and - command[1].lower() == message.bot.username.lower()): + if not (command[0].lower() in self.command + and command[1].lower() == message.bot.username.lower()): return None if self.filters is None or self.filters(message): @@ -308,8 +308,8 @@ def check_update(self, update): :obj:`bool` """ - if (isinstance(update, Update) and - (update.message or update.edited_message and self.allow_edited)): + if (isinstance(update, Update) + and (update.message or update.edited_message and self.allow_edited)): message = update.effective_message text_list = message.text.split() diff --git a/telegram/ext/dictpersistence.py b/telegram/ext/dictpersistence.py index f9aa1526e66..e4b0216cb7d 100644 --- a/telegram/ext/dictpersistence.py +++ b/telegram/ext/dictpersistence.py @@ -64,9 +64,9 @@ def __init__(self, chat_data_json='', bot_data_json='', conversations_json=''): - self.store_user_data = store_user_data - self.store_chat_data = store_chat_data - self.store_bot_data = store_bot_data + 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 diff --git a/telegram/ext/dispatcher.py b/telegram/ext/dispatcher.py index 3cb01bde845..29b750abae8 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -333,20 +333,20 @@ def process_update(self, update): except Exception: self.logger.exception('Saving bot data raised an error') - if self.persistence.store_chat_data and update.effective_chat: - chat_id = update.effective_chat.id - try: - self.persistence.update_chat_data(chat_id, - self.chat_data[chat_id]) - except Exception: - self.logger.exception('Saving chat data raised an error') - if self.persistence.store_user_data and update.effective_user: - user_id = update.effective_user.id - try: - self.persistence.update_user_data(user_id, - self.user_data[user_id]) - except Exception: - self.logger.exception('Saving user data raised an error') + if self.persistence.store_chat_data and update.effective_chat: + chat_id = update.effective_chat.id + try: + self.persistence.update_chat_data(chat_id, + self.chat_data[chat_id]) + except Exception: + self.logger.exception('Saving chat data raised an error') + if self.persistence.store_user_data and update.effective_user: + user_id = update.effective_user.id + try: + self.persistence.update_user_data(user_id, + self.user_data[user_id]) + except Exception: + self.logger.exception('Saving user data raised an error') break # Stop processing with any other handler. diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index e26b51de857..41ff284e1af 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -65,10 +65,10 @@ def __init__(self, filename, store_bot_data=True, singe_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.store_bot_data = store_bot_data self.single_file = singe_file self.on_flush = on_flush self.user_data = None diff --git a/tests/test_callbackqueryhandler.py b/tests/test_callbackqueryhandler.py index cebd2f6d09b..3a374ef006b 100644 --- a/tests/test_callbackqueryhandler.py +++ b/tests/test_callbackqueryhandler.py @@ -83,15 +83,15 @@ def callback_group(self, bot, update, groups=None, groupdict=None): self.test_flag = groupdict == {'begin': 't', 'end': ' data'} def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): if context.match.groups(): diff --git a/tests/test_choseninlineresulthandler.py b/tests/test_choseninlineresulthandler.py index 02f86e2da25..4278b35358a 100644 --- a/tests/test_choseninlineresulthandler.py +++ b/tests/test_choseninlineresulthandler.py @@ -80,15 +80,15 @@ def callback_queue_2(self, bot, update, job_queue=None, update_queue=None): self.test_flag = (job_queue is not None) and (update_queue is not None) def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): handler = ChosenInlineResultHandler(self.callback_basic) diff --git a/tests/test_commandhandler.py b/tests/test_commandhandler.py index d681f0919f9..2d51521020f 100644 --- a/tests/test_commandhandler.py +++ b/tests/test_commandhandler.py @@ -95,15 +95,15 @@ def ch_callback_args(self, bot, update, args): self.test_flag = args == ['one', 'two'] def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): self.test_flag = context.args == ['one', 'two'] @@ -379,15 +379,15 @@ def ch_callback_args(self, bot, update, args): self.test_flag = args == ['one', 'two'] def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): self.test_flag = context.args == ['one', 'two'] diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 8c563e332e2..45e15843758 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -70,11 +70,11 @@ def callback_if_not_update_queue(self, bot, update, update_queue=None): self.received = update.message def callback_context(self, update, context): - if (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(context.update_queue, Queue) and - isinstance(context.job_queue, JobQueue) and - isinstance(context.error, TelegramError)): + if (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(context.update_queue, Queue) + and isinstance(context.job_queue, JobQueue) + and isinstance(context.error, TelegramError)): self.received = context.error.message def test_error_handler(self, dp): diff --git a/tests/test_inlinequeryhandler.py b/tests/test_inlinequeryhandler.py index 58376aa3c2b..827d081a100 100644 --- a/tests/test_inlinequeryhandler.py +++ b/tests/test_inlinequeryhandler.py @@ -87,15 +87,15 @@ def callback_group(self, bot, update, groups=None, groupdict=None): self.test_flag = groupdict == {'begin': 't', 'end': ' query'} def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): if context.match.groups(): diff --git a/tests/test_jobqueue.py b/tests/test_jobqueue.py index a00557e9c43..2eda32f16d2 100644 --- a/tests/test_jobqueue.py +++ b/tests/test_jobqueue.py @@ -67,14 +67,14 @@ def job_datetime_tests(self, bot, job): self.job_time = time.time() def job_context_based_callback(self, context): - if (isinstance(context, CallbackContext) and - isinstance(context.job, Job) and - isinstance(context.update_queue, Queue) and - context.job.context == 2 and - context.chat_data is None and - context.user_data is None and - context.bot_data is not None and - context.job_queue is context.job.job_queue): + if (isinstance(context, CallbackContext) + and isinstance(context.job, Job) + and isinstance(context.update_queue, Queue) + 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 def test_run_once(self, job_queue): diff --git a/tests/test_messagehandler.py b/tests/test_messagehandler.py index 7e96b450b23..2911f5553f8 100644 --- a/tests/test_messagehandler.py +++ b/tests/test_messagehandler.py @@ -75,21 +75,20 @@ def callback_queue_2(self, bot, update, job_queue=None, update_queue=None): def callback_context(self, update, context): self.test_flag = ( - isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) 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))) - or - (context.user_data is None and - (isinstance(update.channel_post, Message) or - isinstance(update.edited_channel_post, Message))) + isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + 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))) + or (context.user_data is None + and (isinstance(update.channel_post, Message) + or isinstance(update.edited_channel_post, Message))) ) ) diff --git a/tests/test_precheckoutqueryhandler.py b/tests/test_precheckoutqueryhandler.py index 2d9314a7292..2b05f2f4096 100644 --- a/tests/test_precheckoutqueryhandler.py +++ b/tests/test_precheckoutqueryhandler.py @@ -80,15 +80,15 @@ def callback_queue_2(self, bot, update, job_queue=None, update_queue=None): self.test_flag = (job_queue is not None) and (update_queue is not None) def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): handler = PreCheckoutQueryHandler(self.callback_basic) diff --git a/tests/test_regexhandler.py b/tests/test_regexhandler.py index a0bc3a332bf..81c65c5acc7 100644 --- a/tests/test_regexhandler.py +++ b/tests/test_regexhandler.py @@ -80,15 +80,15 @@ def callback_group(self, bot, update, groups=None, groupdict=None): self.test_flag = groupdict == {'begin': 't', 'end': ' message'} def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): if context.match.groups(): diff --git a/tests/test_shippingqueryhandler.py b/tests/test_shippingqueryhandler.py index 94339301f30..395c09f3e51 100644 --- a/tests/test_shippingqueryhandler.py +++ b/tests/test_shippingqueryhandler.py @@ -81,15 +81,15 @@ def callback_queue_2(self, bot, update, job_queue=None, update_queue=None): self.test_flag = (job_queue is not None) and (update_queue is not None) def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, Update) and - isinstance(context.update_queue, Queue) 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)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, Update) + and isinstance(context.update_queue, Queue) + 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): handler = ShippingQueryHandler(self.callback_basic) diff --git a/tests/test_stringcommandhandler.py b/tests/test_stringcommandhandler.py index 1f8302fcf05..cc1bbf29cc2 100644 --- a/tests/test_stringcommandhandler.py +++ b/tests/test_stringcommandhandler.py @@ -74,14 +74,14 @@ def sch_callback_args(self, bot, update, args): self.test_flag = args == ['one', 'two'] def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, str) 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 - isinstance(context.bot_data, dict)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, str) + 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 isinstance(context.bot_data, dict)) def callback_context_args(self, update, context): self.test_flag = context.args == ['one', 'two'] diff --git a/tests/test_stringregexhandler.py b/tests/test_stringregexhandler.py index cc09350e37c..339e1311f52 100644 --- a/tests/test_stringregexhandler.py +++ b/tests/test_stringregexhandler.py @@ -74,11 +74,11 @@ def callback_group(self, bot, update, groups=None, groupdict=None): self.test_flag = groupdict == {'begin': 't', 'end': ' message'} def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, str) and - isinstance(context.update_queue, Queue) and - isinstance(context.job_queue, JobQueue)) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, str) + and isinstance(context.update_queue, Queue) + and isinstance(context.job_queue, JobQueue)) def callback_context_pattern(self, update, context): if context.match.groups(): diff --git a/tests/test_typehandler.py b/tests/test_typehandler.py index c1bb1a5e5ff..08fc9cbfd13 100644 --- a/tests/test_typehandler.py +++ b/tests/test_typehandler.py @@ -44,14 +44,14 @@ def callback_queue_2(self, bot, update, job_queue=None, update_queue=None): self.test_flag = (job_queue is not None) and (update_queue is not None) def callback_context(self, update, context): - self.test_flag = (isinstance(context, CallbackContext) and - isinstance(context.bot, Bot) and - isinstance(update, dict) 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.bot_data is not None) + self.test_flag = (isinstance(context, CallbackContext) + and isinstance(context.bot, Bot) + and isinstance(update, dict) + 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 isinstance(context.bot_data, dict)) def test_basic(self, dp): handler = TypeHandler(dict, self.callback_basic) From 28124221789afb84f71c1394f11834197582370f Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Sun, 4 Aug 2019 14:26:39 +0200 Subject: [PATCH 06/12] Persist before stop --- telegram/ext/dispatcher.py | 3 ++- tests/test_persistence.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/telegram/ext/dispatcher.py b/telegram/ext/dispatcher.py index fd0c8c2f969..22e6bb3facd 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -440,9 +440,10 @@ 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: + self.persistence.update_bot_data(self.bot_data) for chat_id in self.chat_data: self.persistence.update_chat_data(chat_id, self.chat_data[chat_id]) for user_id in self.user_data: diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 7327e6c7deb..afb3b4850c4 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -271,6 +271,16 @@ def pickle_persistence(): 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, + singe_file=False, + on_flush=False) + + @pytest.fixture(scope='function') def bad_pickle_files(): for name in ['pickletest_user_data', 'pickletest_chat_data', 'pickletest_bot_data', @@ -664,6 +674,7 @@ def test_flush_on_stop(self, bot, update, pickle_persistence, good_pickle_files) 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) @@ -675,6 +686,7 @@ def test_flush_on_stop(self, bot, update, pickle_persistence, good_pickle_files) 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_with_conversationHandler(self, dp, update, good_pickle_files, pickle_persistence): dp.persistence = pickle_persistence From 6ce699d38774c087425835957228e2e8cf812554 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Fri, 30 Aug 2019 10:20:58 +0000 Subject: [PATCH 07/12] Fix CI errors --- telegram/ext/picklepersistence.py | 5 +++-- tests/test_dispatcher.py | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index da31c57383c..267b2b9379e 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -66,9 +66,10 @@ def __init__(self, filename, 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 diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 0c76ad384c7..79aed684a9a 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -353,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) From 336c55651c2001de6a1d23398b6eb513dc36f4dc Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Fri, 18 Oct 2019 09:51:25 +0000 Subject: [PATCH 08/12] Implement #1342 for bot_data --- telegram/ext/dictpersistence.py | 2 +- telegram/ext/picklepersistence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram/ext/dictpersistence.py b/telegram/ext/dictpersistence.py index cb7e4681ab7..5af44270942 100644 --- a/telegram/ext/dictpersistence.py +++ b/telegram/ext/dictpersistence.py @@ -191,7 +191,7 @@ def get_bot_data(self): pass else: self._bot_data = {} - return self.bot_data.copy() + return deepcopy(self.bot_data) def get_conversations(self, name): """Returns the conversations created from the ``conversations_json`` or an empty diff --git a/telegram/ext/picklepersistence.py b/telegram/ext/picklepersistence.py index 267b2b9379e..432dd4ec583 100644 --- a/telegram/ext/picklepersistence.py +++ b/telegram/ext/picklepersistence.py @@ -173,7 +173,7 @@ def get_bot_data(self): self.bot_data = data else: self.load_singlefile() - return self.bot_data.copy() + return deepcopy(self.bot_data) def get_conversations(self, name): """Returns the conversations from the pickle file if it exsists or an empty defaultdict. From c547ec97bc2e20b007ccfc94272556fab6829e42 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Fri, 18 Oct 2019 10:10:07 +0000 Subject: [PATCH 09/12] Add check pickle_persistence_only_bot similar to #1462 --- tests/test_persistence.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 8b809e1d523..09e9d9fc5ba 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -279,7 +279,8 @@ def pickle_persistence_only_bot(): store_bot_data=True, single_file=False, on_flush=False) - + + @pytest.fixture(scope='function') def pickle_persistence_only_chat(): return PicklePersistence(filename='pickletest', @@ -707,9 +708,34 @@ def test_flush_on_stop(self, bot, update, pickle_persistence): 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_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_datae()['my_test3'] == 'Working3!' + def test_flush_on_stop_only_chat(self, bot, update, pickle_persistence_only_chat): os.remove('pickletest_user_data') os.remove('pickletest_chat_data') + os.remove('pickletest_bot_data') u = Updater(bot=bot, persistence=pickle_persistence_only_chat) dp = u.dispatcher u.running = True @@ -722,13 +748,17 @@ 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_user_data') os.remove('pickletest_chat_data') + os.remove('pickletest_bot_data') u = Updater(bot=bot, persistence=pickle_persistence_only_user) dp = u.dispatcher u.running = True @@ -741,10 +771,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 From 4ecc0314bc766a817e9ef6d0ea4a25d1c3135912 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler Date: Fri, 18 Oct 2019 10:18:46 +0000 Subject: [PATCH 10/12] Fix test_persistence --- tests/test_persistence.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 09e9d9fc5ba..a96cc511d35 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -730,11 +730,9 @@ def test_flush_on_stop_only_bot(self, bot, update, pickle_persistence_only_bot): on_flush=False) assert pickle_persistence_2.get_user_data() == {} assert pickle_persistence_2.get_chat_data() == {} - assert pickle_persistence_2.get_bot_datae()['my_test3'] == 'Working3!' + 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_user_data') - os.remove('pickletest_chat_data') os.remove('pickletest_bot_data') u = Updater(bot=bot, persistence=pickle_persistence_only_chat) dp = u.dispatcher @@ -756,9 +754,7 @@ def test_flush_on_stop_only_chat(self, bot, update, pickle_persistence_only_chat assert pickle_persistence_2.get_bot_data() == {} def test_flush_on_stop_only_user(self, bot, update, pickle_persistence_only_user): - os.remove('pickletest_user_data') os.remove('pickletest_chat_data') - os.remove('pickletest_bot_data') u = Updater(bot=bot, persistence=pickle_persistence_only_user) dp = u.dispatcher u.running = True From 169e42f69a31cef5efb04c3d0a7a8203187960d0 Mon Sep 17 00:00:00 2001 From: Pieter Schutz Date: Sun, 2 Feb 2020 21:46:41 +0100 Subject: [PATCH 11/12] Try dispatching error before logging it --- telegram/ext/dispatcher.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/telegram/ext/dispatcher.py b/telegram/ext/dispatcher.py index 52f2ddae737..bc4a9180a3e 100644 --- a/telegram/ext/dispatcher.py +++ b/telegram/ext/dispatcher.py @@ -335,11 +335,14 @@ def persist_update(update): if self.persistence.store_bot_data: try: self.persistence.update_bot_data(self.bot_data) - 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) + 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: From ea5aa187069d7ab19bb921d088cc30f1b76821ba Mon Sep 17 00:00:00 2001 From: Pieter Schutz Date: Sun, 2 Feb 2020 22:03:49 +0100 Subject: [PATCH 12/12] Fix test --- tests/test_dispatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 79aed684a9a..2ab26783d1a 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -393,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 = []