Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/pandas/_config/localization.py: 23%
48 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Helpers for configuring locale settings.
4Name `localization` is chosen to avoid overlap with builtin `locale` module.
5"""
6from __future__ import annotations
8from contextlib import contextmanager
9import locale
10import re
11import subprocess
12from typing import (
13 Callable,
14 Iterator,
15)
17from pandas._config.config import options
20@contextmanager
21def set_locale(
22 new_locale: str | tuple[str, str], lc_var: int = locale.LC_ALL
23) -> Iterator[str | tuple[str, str]]:
24 """
25 Context manager for temporarily setting a locale.
27 Parameters
28 ----------
29 new_locale : str or tuple
30 A string of the form <language_country>.<encoding>. For example to set
31 the current locale to US English with a UTF8 encoding, you would pass
32 "en_US.UTF-8".
33 lc_var : int, default `locale.LC_ALL`
34 The category of the locale being set.
36 Notes
37 -----
38 This is useful when you want to run a particular block of code under a
39 particular locale, without globally setting the locale. This probably isn't
40 thread-safe.
41 """
42 # getlocale is not always compliant with setlocale, use setlocale. GH#46595
43 current_locale = locale.setlocale(lc_var)
45 try:
46 locale.setlocale(lc_var, new_locale)
47 normalized_code, normalized_encoding = locale.getlocale()
48 if normalized_code is not None and normalized_encoding is not None:
49 yield f"{normalized_code}.{normalized_encoding}"
50 else:
51 yield new_locale
52 finally:
53 locale.setlocale(lc_var, current_locale)
56def can_set_locale(lc: str, lc_var: int = locale.LC_ALL) -> bool:
57 """
58 Check to see if we can set a locale, and subsequently get the locale,
59 without raising an Exception.
61 Parameters
62 ----------
63 lc : str
64 The locale to attempt to set.
65 lc_var : int, default `locale.LC_ALL`
66 The category of the locale being set.
68 Returns
69 -------
70 bool
71 Whether the passed locale can be set
72 """
73 try:
74 with set_locale(lc, lc_var=lc_var):
75 pass
76 except (ValueError, locale.Error):
77 # horrible name for a Exception subclass
78 return False
79 else:
80 return True
83def _valid_locales(locales: list[str] | str, normalize: bool) -> list[str]:
84 """
85 Return a list of normalized locales that do not throw an ``Exception``
86 when set.
88 Parameters
89 ----------
90 locales : str
91 A string where each locale is separated by a newline.
92 normalize : bool
93 Whether to call ``locale.normalize`` on each locale.
95 Returns
96 -------
97 valid_locales : list
98 A list of valid locales.
99 """
100 return [
101 loc
102 for loc in (
103 locale.normalize(loc.strip()) if normalize else loc.strip()
104 for loc in locales
105 )
106 if can_set_locale(loc)
107 ]
110def _default_locale_getter() -> bytes:
111 return subprocess.check_output(["locale -a"], shell=True)
114def get_locales(
115 prefix: str | None = None,
116 normalize: bool = True,
117 locale_getter: Callable[[], bytes] = _default_locale_getter,
118) -> list[str] | None:
119 """
120 Get all the locales that are available on the system.
122 Parameters
123 ----------
124 prefix : str
125 If not ``None`` then return only those locales with the prefix
126 provided. For example to get all English language locales (those that
127 start with ``"en"``), pass ``prefix="en"``.
128 normalize : bool
129 Call ``locale.normalize`` on the resulting list of available locales.
130 If ``True``, only locales that can be set without throwing an
131 ``Exception`` are returned.
132 locale_getter : callable
133 The function to use to retrieve the current locales. This should return
134 a string with each locale separated by a newline character.
136 Returns
137 -------
138 locales : list of strings
139 A list of locale strings that can be set with ``locale.setlocale()``.
140 For example::
142 locale.setlocale(locale.LC_ALL, locale_string)
144 On error will return None (no locale available, e.g. Windows)
146 """
147 try:
148 raw_locales = locale_getter()
149 except subprocess.CalledProcessError:
150 # Raised on (some? all?) Windows platforms because Note: "locale -a"
151 # is not defined
152 return None
154 try:
155 # raw_locales is "\n" separated list of locales
156 # it may contain non-decodable parts, so split
157 # extract what we can and then rejoin.
158 split_raw_locales = raw_locales.split(b"\n")
159 out_locales = []
160 for x in split_raw_locales:
161 try:
162 out_locales.append(str(x, encoding=options.display.encoding))
163 except UnicodeError:
164 # 'locale -a' is used to populated 'raw_locales' and on
165 # Redhat 7 Linux (and maybe others) prints locale names
166 # using windows-1252 encoding. Bug only triggered by
167 # a few special characters and when there is an
168 # extensive list of installed locales.
169 out_locales.append(str(x, encoding="windows-1252"))
171 except TypeError:
172 pass
174 if prefix is None:
175 return _valid_locales(out_locales, normalize)
177 pattern = re.compile(f"{prefix}.*")
178 found = pattern.findall("\n".join(out_locales))
179 return _valid_locales(found, normalize)