diff options
author | Alexey Stepanov <penguinolog@users.noreply.github.com> | 2023-04-03 12:04:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-03 12:04:37 +0200 |
commit | 2d27ffc2bebc6436fc38ee3f1b3828635dc976a3 (patch) | |
tree | f8a040f1275a29732df3b32511fa39f646e41cb1 | |
parent | e9080d282869392835ee579af18965aa4c633526 (diff) | |
download | urwid-2d27ffc2bebc6436fc38ee3f1b3828635dc976a3.tar.gz |
Use `locale.getpreferredencoding(False)` if possible (most systems) Fix #436 Fix #479 (#528)
* Handle impossibility to set locale in tests
(docker container scenario)
* `detect_encoding` start from non-destructive behavior
(do not change locale)
and restore exact locale in destructive
Co-authored-by: Aleksei Stepanov <alekseis@nvidia.com>
-rw-r--r-- | urwid/tests/test_util.py | 25 | ||||
-rw-r--r-- | urwid/util.py | 27 |
2 files changed, 39 insertions, 13 deletions
diff --git a/urwid/tests/test_util.py b/urwid/tests/test_util.py index abe7aa5..eeae2f9 100644 --- a/urwid/tests/test_util.py +++ b/urwid/tests/test_util.py @@ -193,6 +193,7 @@ class RleTest(unittest.TestCase): self.assertListEqual(rle3, [('A', 10), ('B', 20)]) self.assertListEqual(rle4, [('A', 10), ('B', 15), ('K', 1)]) + class PortabilityTest(unittest.TestCase): def test_locale(self): initial = locale.getlocale() @@ -201,8 +202,28 @@ class PortabilityTest(unittest.TestCase): util.detect_encoding() self.assertEqual(locale.getlocale(), (None, None)) - locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8')) + try: + locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8')) + except locale.Error as exc: + if "unsupported locale setting" not in str(exc): + raise + + print( + f"Locale change impossible, probably locale not supported by system (libc ignores this error).\n" + f"{exc}" + ) + return + util.detect_encoding() self.assertEqual(locale.getlocale(), ('en_US', 'UTF-8')) - locale.setlocale(locale.LC_ALL, initial) + try: + locale.setlocale(locale.LC_ALL, initial) + except locale.Error as exc: + if "unsupported locale setting" not in str(exc): + raise + + print( + f"Locale restore impossible, probably locale not supported by system (libc ignores this error).\n" + f"{exc}" + ) diff --git a/urwid/util.py b/urwid/util.py index 3ac4657..9def762 100644 --- a/urwid/util.py +++ b/urwid/util.py @@ -37,28 +37,33 @@ move_prev_char = str_util.move_prev_char within_double_byte = str_util.within_double_byte -def detect_encoding(): +def detect_encoding() -> str: # Try to determine if using a supported double-byte encoding import locale - initial = locale.getlocale() + + no_set_locale = locale.getpreferredencoding(False) + + if no_set_locale != "ascii": + # ascii is fallback locale in case of detect failed + + return no_set_locale + + # Use actual `getpreferredencoding` with public API only + old_loc = locale.setlocale(locale.LC_CTYPE) # == getlocale, but not mangle data try: try: - locale.setlocale(locale.LC_ALL, "") + locale.setlocale(locale.LC_CTYPE, "") except locale.Error: pass - return locale.getlocale()[1] or "" - except ValueError as e: - # with invalid LANG value python will throw ValueError - if e.args and e.args[0].startswith("unknown locale"): - return "" - else: - raise + # internally call private `_get_locale_encoding` + return locale.getpreferredencoding(False) finally: try: - locale.setlocale(locale.LC_ALL, initial) + locale.setlocale(locale.LC_CTYPE, old_loc) except locale.Error: pass + if 'detected_encoding' not in locals(): detected_encoding = detect_encoding() else: |