mirror of https://github.com/caronc/apprise
Handled Py11 getdefaultlocale() deprecation warnings (#754)
parent
e46f8fec1d
commit
5fd568fa35
|
@ -33,6 +33,8 @@
|
||||||
import ctypes
|
import ctypes
|
||||||
import locale
|
import locale
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import os
|
||||||
|
import re
|
||||||
from os.path import join
|
from os.path import join
|
||||||
from os.path import dirname
|
from os.path import dirname
|
||||||
from os.path import abspath
|
from os.path import abspath
|
||||||
|
@ -95,6 +97,17 @@ class AppriseLocale:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Locale regular expression
|
||||||
|
_local_re = re.compile(
|
||||||
|
r'^\s*(?P<lang>[a-z]{2})([_:]((?P<country>[a-z]{2}))?'
|
||||||
|
r'(\.(?P<enc>[a-z0-9]+))?|.+)?', re.IGNORECASE)
|
||||||
|
|
||||||
|
# Define our default encoding
|
||||||
|
_default_encoding = 'utf-8'
|
||||||
|
|
||||||
|
# Define our default language
|
||||||
|
_default_language = 'en'
|
||||||
|
|
||||||
def __init__(self, language=None):
|
def __init__(self, language=None):
|
||||||
"""
|
"""
|
||||||
Initializes our object, if a language is specified, then we
|
Initializes our object, if a language is specified, then we
|
||||||
|
@ -181,7 +194,7 @@ class AppriseLocale:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def detect_language(lang=None, detect_fallback=True):
|
def detect_language(lang=None, detect_fallback=True):
|
||||||
"""
|
"""
|
||||||
returns the language (if it's retrievable)
|
Returns the language (if it's retrievable)
|
||||||
"""
|
"""
|
||||||
# We want to only use the 2 character version of this language
|
# We want to only use the 2 character version of this language
|
||||||
# hence en_CA becomes en, en_US becomes en.
|
# hence en_CA becomes en, en_US becomes en.
|
||||||
|
@ -190,6 +203,17 @@ class AppriseLocale:
|
||||||
# no detection enabled; we're done
|
# no detection enabled; we're done
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Posix lookup
|
||||||
|
lookup = os.environ.get
|
||||||
|
localename = None
|
||||||
|
for variable in ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'):
|
||||||
|
localename = lookup(variable, None)
|
||||||
|
if localename:
|
||||||
|
result = AppriseLocale._local_re.match(localename)
|
||||||
|
if result and result.group('lang'):
|
||||||
|
return result.group('lang').lower()
|
||||||
|
|
||||||
|
# Windows handling
|
||||||
if hasattr(ctypes, 'windll'):
|
if hasattr(ctypes, 'windll'):
|
||||||
windll = ctypes.windll.kernel32
|
windll = ctypes.windll.kernel32
|
||||||
try:
|
try:
|
||||||
|
@ -203,11 +227,12 @@ class AppriseLocale:
|
||||||
# Fallback to posix detection
|
# Fallback to posix detection
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Linux Handling
|
||||||
try:
|
try:
|
||||||
# Detect language
|
# Acquire our locale
|
||||||
lang = locale.getdefaultlocale()[0]
|
lang = locale.getlocale()[0]
|
||||||
|
|
||||||
except ValueError as e:
|
except TypeError as e:
|
||||||
# This occurs when an invalid locale was parsed from the
|
# This occurs when an invalid locale was parsed from the
|
||||||
# environment variable. While we still return None in this
|
# environment variable. While we still return None in this
|
||||||
# case, we want to better notify the end user of this. Users
|
# case, we want to better notify the end user of this. Users
|
||||||
|
@ -217,11 +242,6 @@ class AppriseLocale:
|
||||||
'Language detection failure / {}'.format(str(e)))
|
'Language detection failure / {}'.format(str(e)))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except TypeError:
|
|
||||||
# None is returned if the default can't be determined
|
|
||||||
# we're done in this case
|
|
||||||
return None
|
|
||||||
|
|
||||||
return None if not lang else lang[0:2].lower()
|
return None if not lang else lang[0:2].lower()
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
|
|
|
@ -36,6 +36,7 @@ import json
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import locale
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
@ -1488,7 +1489,7 @@ def environ(*remove, **update):
|
||||||
|
|
||||||
# Create a backup of our environment for restoration purposes
|
# Create a backup of our environment for restoration purposes
|
||||||
env_orig = os.environ.copy()
|
env_orig = os.environ.copy()
|
||||||
|
loc_orig = locale.getlocale()
|
||||||
try:
|
try:
|
||||||
os.environ.update(update)
|
os.environ.update(update)
|
||||||
[os.environ.pop(k, None) for k in remove]
|
[os.environ.pop(k, None) for k in remove]
|
||||||
|
@ -1497,6 +1498,13 @@ def environ(*remove, **update):
|
||||||
finally:
|
finally:
|
||||||
# Restore our snapshot
|
# Restore our snapshot
|
||||||
os.environ = env_orig.copy()
|
os.environ = env_orig.copy()
|
||||||
|
try:
|
||||||
|
# Restore locale
|
||||||
|
locale.setlocale(locale.LC_ALL, loc_orig)
|
||||||
|
|
||||||
|
except locale.Error:
|
||||||
|
# Thrown in py3.6
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def apply_template(template, app_mode=TemplateType.RAW, **kwargs):
|
def apply_template(template, app_mode=TemplateType.RAW, **kwargs):
|
||||||
|
|
|
@ -144,6 +144,7 @@ def test_detect_language_windows_users():
|
||||||
|
|
||||||
if hasattr(ctypes, 'windll'):
|
if hasattr(ctypes, 'windll'):
|
||||||
from ctypes import windll
|
from ctypes import windll
|
||||||
|
|
||||||
else:
|
else:
|
||||||
windll = mock.Mock()
|
windll = mock.Mock()
|
||||||
# 4105 = en_CA
|
# 4105 = en_CA
|
||||||
|
@ -164,18 +165,17 @@ def test_detect_language_windows_users():
|
||||||
assert AppriseLocale.AppriseLocale.detect_language() == 'en'
|
assert AppriseLocale.AppriseLocale.detect_language() == 'en'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform == "win32", reason="Does not work on Windows")
|
def test_detect_language_using_env():
|
||||||
def test_detect_language_windows_users_croaks_please_review():
|
|
||||||
"""
|
"""
|
||||||
When enabling CI testing on Windows, those tests did not produce the
|
Test the reading of information from an environment variable
|
||||||
correct results. They may want to be reviewed.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The below accesses the windows fallback code and fail
|
# The below accesses the windows fallback code and fail
|
||||||
# then it will resort to the environment variables.
|
# then it will resort to the environment variables.
|
||||||
with environ('LANG', 'LANGUAGE', 'LC_ALL', 'LC_CTYPE'):
|
with environ('LANG', 'LANGUAGE', 'LC_ALL', 'LC_CTYPE'):
|
||||||
# Language can't be detected
|
# Language can now be detected in this case
|
||||||
assert AppriseLocale.AppriseLocale.detect_language() is None
|
assert isinstance(
|
||||||
|
AppriseLocale.AppriseLocale.detect_language(), str)
|
||||||
|
|
||||||
# Detect French language.
|
# Detect French language.
|
||||||
with environ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', LANG="fr_CA"):
|
with environ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', LANG="fr_CA"):
|
||||||
|
@ -187,23 +187,28 @@ def test_detect_language_windows_users_croaks_please_review():
|
||||||
# dropped, but just to ensure this issue does not come back, we keep
|
# dropped, but just to ensure this issue does not come back, we keep
|
||||||
# this test:
|
# this test:
|
||||||
with environ(*list(os.environ.keys()), LC_CTYPE="UTF-8"):
|
with environ(*list(os.environ.keys()), LC_CTYPE="UTF-8"):
|
||||||
assert AppriseLocale.AppriseLocale.detect_language() is None
|
assert isinstance(AppriseLocale.AppriseLocale.detect_language(), str)
|
||||||
|
|
||||||
# Test with absolutely no environment variables what-so-ever
|
# Test with absolutely no environment variables what-so-ever
|
||||||
with environ(*list(os.environ.keys())):
|
with environ(*list(os.environ.keys())):
|
||||||
assert AppriseLocale.AppriseLocale.detect_language() is None
|
assert isinstance(AppriseLocale.AppriseLocale.detect_language(), str)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform == "win32", reason="Does not work on Windows")
|
@pytest.mark.skipif(sys.platform == "win32", reason="Does not work on Windows")
|
||||||
@mock.patch('locale.getdefaultlocale')
|
@mock.patch('locale.getlocale')
|
||||||
def test_detect_language_defaultlocale(mock_getlocale):
|
def test_detect_language_locale(mock_getlocale):
|
||||||
"""
|
"""
|
||||||
API: Apprise() Default locale detection
|
API: Apprise() Default locale detection
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Handle case where getdefaultlocale() can't be detected
|
# Handle case where getlocale() can't be detected
|
||||||
mock_getlocale.return_value = None
|
mock_getlocale.return_value = None
|
||||||
assert AppriseLocale.AppriseLocale.detect_language() is None
|
with environ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'):
|
||||||
|
assert AppriseLocale.AppriseLocale.detect_language() is None
|
||||||
|
|
||||||
|
mock_getlocale.return_value = (None, None)
|
||||||
|
with environ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'):
|
||||||
|
assert AppriseLocale.AppriseLocale.detect_language() is None
|
||||||
|
|
||||||
# if detect_language and windows env fail us, then we don't
|
# if detect_language and windows env fail us, then we don't
|
||||||
# set up a default language on first load
|
# set up a default language on first load
|
||||||
|
|
Loading…
Reference in New Issue