Skip to content

Commit

Permalink
Handled Py11 getdefaultlocale() deprecation warnings (#754)
Browse files Browse the repository at this point in the history
  • Loading branch information
caronc committed Aug 20, 2023
1 parent e46f8fe commit 5fd568f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 22 deletions.
38 changes: 29 additions & 9 deletions apprise/AppriseLocale.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -181,7 +194,7 @@ def lang_at(self, lang):
@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.
Expand All @@ -190,6 +203,17 @@ def detect_language(lang=None, detect_fallback=True):
# 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:
Expand All @@ -203,11 +227,12 @@ def detect_language(lang=None, detect_fallback=True):
# 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
Expand All @@ -217,11 +242,6 @@ def detect_language(lang=None, detect_fallback=True):
'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):
Expand Down
10 changes: 9 additions & 1 deletion apprise/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import contextlib
import os
import hashlib
import locale
from itertools import chain
from os.path import expanduser
from functools import reduce
Expand Down Expand Up @@ -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]
Expand All @@ -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):
Expand Down
29 changes: 17 additions & 12 deletions test/test_locale.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"):
Expand All @@ -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
Expand Down

0 comments on commit 5fd568f

Please sign in to comment.