Handled Py11 getdefaultlocale() deprecation warnings (#754)

pull/928/head
Chris Caron 2023-08-20 00:20:46 -04:00 committed by GitHub
parent e46f8fec1d
commit 5fd568fa35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 22 deletions

View File

@ -33,6 +33,8 @@
import ctypes
import locale
import contextlib
import os
import re
from os.path import join
from os.path import dirname
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):
"""
Initializes our object, if a language is specified, then we
@ -181,7 +194,7 @@ class AppriseLocale:
@staticmethod
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
# hence en_CA becomes en, en_US becomes en.
@ -190,6 +203,17 @@ class AppriseLocale:
# no detection enabled; we're done
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'):
windll = ctypes.windll.kernel32
try:
@ -203,11 +227,12 @@ class AppriseLocale:
# Fallback to posix detection
pass
# Linux Handling
try:
# Detect language
lang = locale.getdefaultlocale()[0]
# Acquire our locale
lang = locale.getlocale()[0]
except ValueError as e:
except TypeError as e:
# This occurs when an invalid locale was parsed from the
# environment variable. While we still return None in this
# case, we want to better notify the end user of this. Users
@ -217,11 +242,6 @@ class AppriseLocale:
'Language detection failure / {}'.format(str(e)))
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()
def __getstate__(self):

View File

@ -36,6 +36,7 @@ import json
import contextlib
import os
import hashlib
import locale
from itertools import chain
from os.path import expanduser
from functools import reduce
@ -1488,7 +1489,7 @@ def environ(*remove, **update):
# Create a backup of our environment for restoration purposes
env_orig = os.environ.copy()
loc_orig = locale.getlocale()
try:
os.environ.update(update)
[os.environ.pop(k, None) for k in remove]
@ -1497,6 +1498,13 @@ def environ(*remove, **update):
finally:
# Restore our snapshot
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):

View File

@ -144,6 +144,7 @@ def test_detect_language_windows_users():
if hasattr(ctypes, 'windll'):
from ctypes import windll
else:
windll = mock.Mock()
# 4105 = en_CA
@ -164,18 +165,17 @@ def test_detect_language_windows_users():
assert AppriseLocale.AppriseLocale.detect_language() == 'en'
@pytest.mark.skipif(sys.platform == "win32", reason="Does not work on Windows")
def test_detect_language_windows_users_croaks_please_review():
def test_detect_language_using_env():
"""
When enabling CI testing on Windows, those tests did not produce the
correct results. They may want to be reviewed.
Test the reading of information from an environment variable
"""
# 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'):
# Language can't be detected
assert AppriseLocale.AppriseLocale.detect_language() is None
# Language can now be detected in this case
assert isinstance(
AppriseLocale.AppriseLocale.detect_language(), str)
# Detect French language.
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
# this test:
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
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")
@mock.patch('locale.getdefaultlocale')
def test_detect_language_defaultlocale(mock_getlocale):
@mock.patch('locale.getlocale')
def test_detect_language_locale(mock_getlocale):
"""
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
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
# set up a default language on first load