summaryrefslogtreecommitdiffstats
path: root/test/lib/ansible_test/_internal/locale_util.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/ansible_test/_internal/locale_util.py')
-rw-r--r--test/lib/ansible_test/_internal/locale_util.py61
1 files changed, 61 insertions, 0 deletions
diff --git a/test/lib/ansible_test/_internal/locale_util.py b/test/lib/ansible_test/_internal/locale_util.py
new file mode 100644
index 0000000..3fb74ad
--- /dev/null
+++ b/test/lib/ansible_test/_internal/locale_util.py
@@ -0,0 +1,61 @@
+"""Initialize locale settings. This must be imported very early in ansible-test startup."""
+
+from __future__ import annotations
+
+import locale
+import sys
+import typing as t
+
+STANDARD_LOCALE = 'en_US.UTF-8'
+"""
+The standard locale used by ansible-test and its subprocesses and delegated instances.
+"""
+
+FALLBACK_LOCALE = 'C.UTF-8'
+"""
+The fallback locale to use when the standard locale is not available.
+This was added in ansible-core 2.14 to allow testing in environments without the standard locale.
+It was not needed in previous ansible-core releases since they do not verify the locale during startup.
+"""
+
+
+class LocaleError(SystemExit):
+ """Exception to raise when locale related errors occur."""
+ def __init__(self, message: str) -> None:
+ super().__init__(f'ERROR: {message}')
+
+
+def configure_locale() -> tuple[str, t.Optional[str]]:
+ """Configure the locale, returning the selected locale and an optional warning."""
+
+ if (fs_encoding := sys.getfilesystemencoding()).lower() != 'utf-8':
+ raise LocaleError(f'ansible-test requires the filesystem encoding to be UTF-8, but "{fs_encoding}" was detected.')
+
+ candidate_locales = STANDARD_LOCALE, FALLBACK_LOCALE
+
+ errors: dict[str, str] = {}
+ warning: t.Optional[str] = None
+ configured_locale: t.Optional[str] = None
+
+ for candidate_locale in candidate_locales:
+ try:
+ locale.setlocale(locale.LC_ALL, candidate_locale)
+ locale.getlocale()
+ except (locale.Error, ValueError) as ex:
+ errors[candidate_locale] = str(ex)
+ else:
+ configured_locale = candidate_locale
+ break
+
+ if not configured_locale:
+ raise LocaleError('ansible-test could not initialize a supported locale:\n' +
+ '\n'.join(f'{key}: {value}' for key, value in errors.items()))
+
+ if configured_locale != STANDARD_LOCALE:
+ warning = (f'Using locale "{configured_locale}" instead of "{STANDARD_LOCALE}". '
+ 'Tests which depend on the locale may behave unexpectedly.')
+
+ return configured_locale, warning
+
+
+CONFIGURED_LOCALE, LOCALE_WARNING = configure_locale()