From c76992632bad5bfefb59150197ac374fa4bda8a1 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sun, 20 Aug 2023 13:02:13 -0400 Subject: [PATCH] improvements added --- .gitignore | 1 + apprise/AppriseLocale.py | 27 +- apprise/i18n/en/LC_MESSAGES/apprise.po | 369 +++++++++--------- setup.cfg | 4 +- setup.py | 4 +- ...{test_locale.py => test_apprise_locale.py} | 45 ++- 6 files changed, 243 insertions(+), 207 deletions(-) rename test/{test_locale.py => test_apprise_locale.py} (85%) diff --git a/.gitignore b/.gitignore index 174d28b3bb..4ae5f5880c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ sdist/ *.egg-info/ .installed.cfg *.egg +.local # Generated from Docker Instance .bash_history diff --git a/apprise/AppriseLocale.py b/apprise/AppriseLocale.py index 2295de3a98..dd88958d77 100644 --- a/apprise/AppriseLocale.py +++ b/apprise/AppriseLocale.py @@ -107,14 +107,13 @@ def __init__(self, language=None): return # Add language - if not (self.lang and self.add(self.lang)): - # Fall back to our default - self.add(self._default_language) + self.add(self.lang) - def add(self, lang, set_default=True): + def add(self, lang=None, set_default=True): """ Add a language to our list """ + lang = lang if lang else self._default_language if lang not in self._gtobjs: # Load our gettext object and install our language try: @@ -132,19 +131,18 @@ def add(self, lang, set_default=True): 'Could not load translation path: %s', join(self._locale_dir, lang)) - # Fallback - if None not in self._gtobjs: - self._gtobjs[None] = gettext - self.__fn_map = getattr(self._gtobjs[None], self._fn) - if set_default: - self.lang = None + # Fallback (handle case where self.lang does not exist) + if self.lang not in self._gtobjs: + self._gtobjs[self.lang] = gettext + self.__fn_map = getattr(self._gtobjs[self.lang], self._fn) + return False logger.trace('Loaded language %s', lang) if set_default: - logger.debug('Language set to %s', self.lang) - self.lang = self._default_language + logger.debug('Language set to %s', lang) + self.lang = lang return True @@ -249,8 +247,10 @@ def __getstate__(self): Pickle Support dumps() """ state = self.__dict__.copy() + # Remove the unpicklable entries. del state['_gtobjs'] + del state['_AppriseLocale__fn_map'] return state def __setstate__(self, state): @@ -258,7 +258,10 @@ def __setstate__(self, state): Pickle Support loads() """ self.__dict__.update(state) + # Our mapping to our _fn + self.__fn_map = None self._gtobjs = {} + self.add(state['lang'], set_default=True) # diff --git a/apprise/i18n/en/LC_MESSAGES/apprise.po b/apprise/i18n/en/LC_MESSAGES/apprise.po index 44451262cf..65deb7775d 100644 --- a/apprise/i18n/en/LC_MESSAGES/apprise.po +++ b/apprise/i18n/en/LC_MESSAGES/apprise.po @@ -3,9 +3,10 @@ # This file is distributed under the same license as the apprise project. # Chris Caron , 2019. # -msgid "" +msgid "" msgstr "" -"Project-Id-Version: apprise 0.7.6\n" + +"Project-Id-Version: apprise 1.4.5\n" "Report-Msgid-Bugs-To: lead2gold@gmail.com\n" "POT-Creation-Date: 2019-05-28 16:56-0400\n" "PO-Revision-Date: 2019-05-24 20:00-0400\n" @@ -18,276 +19,272 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.6.0\n" -msgid "API Key" -msgstr "" +msgid "API Key" +msgstr "API Key" -msgid "Access Key" -msgstr "" +msgid "Access Key" +msgstr "Access Key" -msgid "Access Key ID" -msgstr "" +msgid "Access Key ID" +msgstr "Access Key ID" -msgid "Access Secret" -msgstr "" +msgid "Access Secret" +msgstr "Access Secret" -msgid "Access Token" -msgstr "" +msgid "Access Token" +msgstr "Access Token" -msgid "Account SID" -msgstr "" +msgid "Account SID" +msgstr "Account SID" -msgid "Add Tokens" -msgstr "" +msgid "Add Tokens" +msgstr "Add Tokens" -msgid "Application Key" -msgstr "" +msgid "Application Key" +msgstr "Application Key" -msgid "Application Secret" -msgstr "" +msgid "Application Secret" +msgstr "Application Secret" -msgid "Auth Token" -msgstr "" +msgid "Auth Token" +msgstr "Auth Token" -msgid "Authorization Token" -msgstr "" +msgid "Authorization Token" +msgstr "Authorization Token" -msgid "Avatar Image" -msgstr "" +msgid "Avatar Image" +msgstr "Avatar Image" -msgid "Bot Name" -msgstr "" +msgid "Bot Name" +msgstr "Bot Name" -msgid "Bot Token" -msgstr "" +msgid "Bot Token" +msgstr "Bot Token" -msgid "Channels" -msgstr "" +msgid "Channels" +msgstr "Channels" -msgid "Consumer Key" -msgstr "" +msgid "Consumer Key" +msgstr "Consumer Key" -msgid "Consumer Secret" -msgstr "" +msgid "Consumer Secret" +msgstr "Consumer Secret" -msgid "Detect Bot Owner" -msgstr "" +msgid "Detect Bot Owner" +msgstr "Detect Bot Owner" -msgid "Device ID" -msgstr "" +msgid "Device ID" +msgstr "Device ID" -msgid "Display Footer" -msgstr "" +msgid "Display Footer" +msgstr "Display Footer" -msgid "Domain" -msgstr "" +msgid "Domain" +msgstr "Domain" -msgid "Duration" -msgstr "" +msgid "Duration" +msgstr "Duration" -msgid "Events" -msgstr "" +msgid "Events" +msgstr "Events" -msgid "Footer Logo" -msgstr "" +msgid "Footer Logo" +msgstr "Footer Logo" -msgid "From Email" -msgstr "" +msgid "From Email" +msgstr "From Email" -msgid "From Name" -msgstr "" +msgid "From Name" +msgstr "From Name" -msgid "From Phone No" -msgstr "" +msgid "From Phone No" +msgstr "From Phone No" -msgid "Group" -msgstr "" +msgid "Group" +msgstr "Group" -msgid "HTTP Header" -msgstr "" +msgid "HTTP Header" +msgstr "HTTP Header" -msgid "Hostname" -msgstr "" +msgid "Hostname" +msgstr "Hostname" -msgid "Include Image" -msgstr "" +msgid "Include Image" +msgstr "Include Image" -msgid "Modal" -msgstr "" +msgid "Modal" +msgstr "Modal" -msgid "Notify Format" -msgstr "" +msgid "Notify Format" +msgstr "Notify Format" -msgid "Organization" -msgstr "" +msgid "Organization" +msgstr "Organization" -msgid "Overflow Mode" -msgstr "" +msgid "Overflow Mode" +msgstr "Overflow Mode" -msgid "Password" -msgstr "" +msgid "Password" +msgstr "Password" -msgid "Port" -msgstr "" +msgid "Port" +msgstr "Port" -msgid "Priority" -msgstr "" +msgid "Priority" +msgstr "Priority" -msgid "Provider Key" -msgstr "" +msgid "Provider Key" +msgstr "Provider Key" -msgid "Region" -msgstr "" +msgid "Region" +msgstr "Region" -msgid "Region Name" -msgstr "" +msgid "Region Name" +msgstr "Region Name" -msgid "Remove Tokens" -msgstr "" +msgid "Remove Tokens" +msgstr "Remove Tokens" -msgid "Rooms" -msgstr "" +msgid "Rooms" +msgstr "Rooms" -msgid "SMTP Server" -msgstr "" +msgid "SMTP Server" +msgstr "SMTP Server" -msgid "Schema" -msgstr "" +msgid "Schema" +msgstr "Schema" -msgid "Secret Access Key" -msgstr "" +msgid "Secret Access Key" +msgstr "Secret Access Key" -msgid "Secret Key" -msgstr "" +msgid "Secret Key" +msgstr "Secret Key" -msgid "Secure Mode" -msgstr "" +msgid "Secure Mode" +msgstr "Secure Mode" -msgid "Server Timeout" -msgstr "" +msgid "Server Timeout" +msgstr "Server Timeout" -msgid "Sound" -msgstr "" +msgid "Sound" +msgstr "Sound" -msgid "Source JID" -msgstr "" +msgid "Source JID" +msgstr "Source JID" -msgid "Target Channel" -msgstr "" +msgid "Target Channel" +msgstr "Target Channel" -msgid "Target Chat ID" -msgstr "" +msgid "Target Chat ID" +msgstr "Target Chat ID" -msgid "Target Device" -msgstr "" +msgid "Target Device" +msgstr "Target Device" -msgid "Target Device ID" -msgstr "" +msgid "Target Device ID" +msgstr "Target Device ID" -msgid "Target Email" -msgstr "" +msgid "Target Email" +msgstr "Target Email" -msgid "Target Emails" -msgstr "" +msgid "Target Emails" +msgstr "Target Emails" -msgid "Target Encoded ID" -msgstr "" +msgid "Target Encoded ID" +msgstr "Target Encoded ID" -msgid "Target JID" -msgstr "" +msgid "Target JID" +msgstr "Target JID" -msgid "Target Phone No" -msgstr "" +msgid "Target Phone No" +msgstr "Target Phone No" -msgid "Target Room Alias" -msgstr "" +msgid "Target Room Alias" +msgstr "Target Room Alias" -msgid "Target Room ID" -msgstr "" +msgid "Target Room ID" +msgstr "Target Room ID" -msgid "Target Short Code" -msgstr "" +msgid "Target Short Code" +msgstr "Target Short Code" -msgid "Target Tag ID" -msgstr "" +msgid "Target Tag ID" +msgstr "Target Tag ID" -msgid "Target Topic" -msgstr "" - -msgid "Target User" -msgstr "" - -msgid "Targets" -msgstr "" +msgid "Target Topic" +msgstr "Target Topic" -msgid "Text To Speech" -msgstr "" +msgid "Target User" +msgstr "Target User" -msgid "To Channel ID" -msgstr "" +msgid "Targets" +msgstr "Targets" -msgid "To Email" -msgstr "" +msgid "Text To Speech" +msgstr "Text To Speech" -msgid "To User ID" -msgstr "" +msgid "To Channel ID" +msgstr "To Channel ID" -msgid "Token" -msgstr "" +msgid "To Email" +msgstr "To Email" -msgid "Token A" -msgstr "" +msgid "To User ID" +msgstr "To User ID" -msgid "Token B" -msgstr "" +msgid "Token" +msgstr "Token" -msgid "Token C" -msgstr "" +msgid "Token A" +msgstr "Token A" -msgid "Urgency" -msgstr "" +msgid "Token B" +msgstr "Token B" -msgid "Use Avatar" -msgstr "" +msgid "Token C" +msgstr "Token C" -msgid "User" -msgstr "" +msgid "Urgency" +msgstr "Urgency" -msgid "User Key" -msgstr "" +msgid "Use Avatar" +msgstr "Use Avatar" -msgid "User Name" -msgstr "" +msgid "User" +msgstr "User" -msgid "Username" -msgstr "" +msgid "User Key" +msgstr "User Key" -msgid "Verify SSL" -msgstr "" +msgid "User Name" +msgstr "User Name" -msgid "Version" -msgstr "" +msgid "Username" +msgstr "Username" -msgid "Webhook" -msgstr "" +msgid "Verify SSL" +msgstr "Verify SSL" -msgid "Webhook ID" -msgstr "" +msgid "Version" +msgstr "Version" -msgid "Webhook Mode" -msgstr "" +msgid "Webhook" +msgstr "Webhook" -msgid "Webhook Token" -msgstr "" +msgid "Webhook ID" +msgstr "Webhook ID" -msgid "X-Axis" -msgstr "" +msgid "Webhook Mode" +msgstr "Webhook Mode" -msgid "XEP" -msgstr "" +msgid "Webhook Token" +msgstr "Webhook Token" -msgid "Y-Axis" -msgstr "" +msgid "X-Axis" +msgstr "X-Axis" -#~ msgid "Access Key Secret" -#~ msgstr "" +msgid "XEP" +msgstr "XEP" +msgid "Y-Axis" +msgstr "Y-Axis" diff --git a/setup.cfg b/setup.cfg index 830db59158..c4861b4e35 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,11 +3,11 @@ universal = 0 [metadata] # ensure LICENSE is included in wheel metadata -license_file = LICENSE +license_files = LICENSE [flake8] # We exclude packages we don't maintain -exclude = .eggs,.tox +exclude = .eggs,.tox,.local ignore = E741,E722,W503,W504,W605 statistics = true builtins = _ diff --git a/setup.py b/setup.py index ed3d1e8a62..128f9ff7e8 100755 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ ], }, install_requires=install_requires, - classifiers=( + classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', @@ -109,7 +109,7 @@ 'License :: OSI Approved :: BSD License', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries :: Application Frameworks', - ), + ], entry_points={'console_scripts': console_scripts}, python_requires='>=3.6', setup_requires=['babel', ], diff --git a/test/test_locale.py b/test/test_apprise_locale.py similarity index 85% rename from test/test_locale.py rename to test/test_apprise_locale.py index 192fef5f1b..d1039e0a9f 100644 --- a/test/test_locale.py +++ b/test/test_apprise_locale.py @@ -77,12 +77,17 @@ def test_apprise_locale_gettext_init(): @pytest.mark.skipif( 'gettext' not in sys.modules, reason="Requires gettext") @mock.patch('gettext.translation') -def test_apprise_locale_gettext_translations(mock_gettext_trans): +@mock.patch('locale.getlocale') +def test_apprise_locale_gettext_translations( + mock_getlocale, mock_gettext_trans): """ API: Apprise() Gettext translations """ + # Set- our gettext.locale() return value + mock_getlocale.return_value = ('en_US', 'UTF-8') + mock_gettext_trans.side_effect = FileNotFoundError() # This throws internally but we handle it gracefully @@ -98,12 +103,16 @@ def test_apprise_locale_gettext_translations(mock_gettext_trans): @pytest.mark.skipif( 'gettext' not in sys.modules, reason="Requires gettext") -def test_apprise_locale_gettext_lang_at(): +@mock.patch('locale.getlocale') +def test_apprise_locale_gettext_lang_at(mock_getlocale): """ API: Apprise() Gettext lang_at """ + # Set- our gettext.locale() return value + mock_getlocale.return_value = ('en_CA', 'UTF-8') + # This throws internally but we handle it gracefully al = AppriseLocale.AppriseLocale() @@ -135,12 +144,34 @@ def test_apprise_locale_gettext_lang_at(): # reason the person who set up apprise does not have the languages # installed. fallback = AppriseLocale.AppriseLocale._default_language - with environ('LANG', 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', LANG="en_CA"): + mock_getlocale.return_value = None + + with environ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG'): + # Our default language AppriseLocale.AppriseLocale._default_language = 'zz' + + # We will detect the zz since there were no environment variables to + # help us otherwise + assert AppriseLocale.AppriseLocale.detect_language() is None al = AppriseLocale.AppriseLocale() + + # No Language could be set becuause no locale directory exists for this + assert al.lang is None + + # We can still perform simple lookups; they access a dummy wrapper: + assert al.gettext('test') == 'test' + + with environ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', LANG="en_CA"): + AppriseLocale.AppriseLocale._default_language = 'fr' + + # We will detect the english language (found in the LANG= environment + # variable which over-rides the _default + assert AppriseLocale.AppriseLocale.detect_language() == "en" + al = AppriseLocale.AppriseLocale() + assert al.lang == "en" assert al.gettext('test') == 'test' - # Test case with set_default set to False (so we're still set to 'zz') + # Test case with set_default set to False (so we're still set to 'fr') assert al.add('zy', set_default=False) is False assert al.gettext('test') == 'test' @@ -202,11 +233,15 @@ def test_apprise_locale_detect_language_windows_users(): assert AppriseLocale.AppriseLocale.detect_language() == 'en' -def test_detect_language_using_env(): +@mock.patch('locale.getlocale') +def test_detect_language_using_env(mock_getlocale): """ Test the reading of information from an environment variable """ + # Set- our gettext.locale() return value + mock_getlocale.return_value = ('en_CA', 'UTF-8') + # The below accesses the windows fallback code and fail # then it will resort to the environment variables. with environ('LANG', 'LANGUAGE', 'LC_ALL', 'LC_CTYPE'):