From dc2daabffab8fd77fd490806c2112fd83bb42693 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sat, 19 Aug 2023 16:47:24 -0400 Subject: [PATCH] Added Pickle support to Apprise Objects --- apprise/Apprise.py | 24 ++++++++++ apprise/AppriseLocale.py | 16 +++++++ test/test_apprise_pickle.py | 91 +++++++++++++++++++++++++++++++++++++ test/test_apprise_utils.py | 2 +- 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 test/test_apprise_pickle.py diff --git a/apprise/Apprise.py b/apprise/Apprise.py index 67f44b44ca..82d91d7570 100644 --- a/apprise/Apprise.py +++ b/apprise/Apprise.py @@ -819,6 +819,30 @@ def __getitem__(self, index): # If we reach here, then we indexed out of range raise IndexError('list index out of range') + def __getstate__(self): + """ + Pickle Support dumps() + """ + attributes = { + 'asset': self.asset, + 'urls': self.urls(), + 'locale': self.locale, + 'debug': self.debug, + 'location': self.location, + } + + return attributes + + def __setstate__(self, state): + """ + Pickle Support loads() + """ + self.servers = list() + self.asset = state['asset'] + self.locale = state['locale'] + self.location = state['location'] + self.add(state['urls']) + def __bool__(self): """ Allows the Apprise object to be wrapped in an 'if statement'. diff --git a/apprise/AppriseLocale.py b/apprise/AppriseLocale.py index ce61d0c9b3..bf424af8c7 100644 --- a/apprise/AppriseLocale.py +++ b/apprise/AppriseLocale.py @@ -223,3 +223,19 @@ def detect_language(lang=None, detect_fallback=True): return None return None if not lang else lang[0:2].lower() + + def __getstate__(self): + """ + Pickle Support dumps() + """ + state = self.__dict__.copy() + # Remove the unpicklable entries. + del state['_gtobjs'] + return state + + def __setstate__(self, state): + """ + Pickle Support loads() + """ + self.__dict__.update(state) + self._gtobjs = {} diff --git a/test/test_apprise_pickle.py b/test/test_apprise_pickle.py new file mode 100644 index 0000000000..0ad1d5021f --- /dev/null +++ b/test/test_apprise_pickle.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# BSD 3-Clause License +# +# Apprise - Push Notification Library. +# Copyright (c) 2023, Chris Caron +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from __future__ import print_function +import sys +import pickle +from apprise import Apprise, AppriseAsset, AppriseLocale + +# Disable logging for a cleaner testing output +import logging +logging.disable(logging.CRITICAL) + +# Ensure we don't create .pyc files for these tests +sys.dont_write_bytecode = True + + +def test_apprise_pickle_asset(tmpdir): + """pickle: AppriseAsset + """ + asset = AppriseAsset() + encoded = pickle.dumps(asset) + new_asset = pickle.loads(encoded) + + # iterate over some keys to verify they're still the same: + keys = ( + 'app_id', 'app_desc', 'app_url', 'html_notify_map', + 'ascii_notify_map', 'default_html_color', 'default_extension', + 'theme', 'image_url_mask', 'image_url_logo', 'image_path_mask', + 'body_format', 'async_mode', 'interpret_escapes', 'encoding', + 'secure_logging', '_recursion', + ) + + for key in keys: + assert getattr(asset, key) == getattr(new_asset, key) + + +def test_apprise_pickle_locale(tmpdir): + """pickle: AppriseLocale + """ + _locale = AppriseLocale.AppriseLocale() + encoded = pickle.dumps(_locale) + new_locale = pickle.loads(encoded) + + assert _locale.lang == new_locale.lang + + # Ensure internal functions still call in new object + new_locale.detect_language() + + +def test_apprise_pickle_core(tmpdir): + """pickle: Apprise + """ + apobj = Apprise() + + apobj.add("json://localhost") + apobj.add("xml://localhost") + apobj.add("form://localhost") + apobj.add("mailto://user:pass@localhost", tag="email") + encoded = pickle.dumps(apobj) + + new_apobj = pickle.loads(encoded) + assert len(new_apobj) == 4 diff --git a/test/test_apprise_utils.py b/test/test_apprise_utils.py index ad0789cbab..182d19a628 100644 --- a/test/test_apprise_utils.py +++ b/test/test_apprise_utils.py @@ -2016,7 +2016,7 @@ def __str__(self): def test_import_module(tmpdir): - """utils: imort_module testing + """utils: import_module testing """ # Prepare ourselves a file to work with bad_file_base = tmpdir.mkdir('a')