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

1""" 

2Helpers for configuring locale settings. 

3 

4Name `localization` is chosen to avoid overlap with builtin `locale` module. 

5""" 

6from __future__ import annotations 

7 

8from contextlib import contextmanager 

9import locale 

10import re 

11import subprocess 

12from typing import ( 

13 Callable, 

14 Iterator, 

15) 

16 

17from pandas._config.config import options 

18 

19 

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. 

26 

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. 

35 

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) 

44 

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) 

54 

55 

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. 

60 

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. 

67 

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 

81 

82 

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. 

87 

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. 

94 

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 ] 

108 

109 

110def _default_locale_getter() -> bytes: 

111 return subprocess.check_output(["locale -a"], shell=True) 

112 

113 

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. 

121 

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. 

135 

136 Returns 

137 ------- 

138 locales : list of strings 

139 A list of locale strings that can be set with ``locale.setlocale()``. 

140 For example:: 

141 

142 locale.setlocale(locale.LC_ALL, locale_string) 

143 

144 On error will return None (no locale available, e.g. Windows) 

145 

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 

153 

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")) 

170 

171 except TypeError: 

172 pass 

173 

174 if prefix is None: 

175 return _valid_locales(out_locales, normalize) 

176 

177 pattern = re.compile(f"{prefix}.*") 

178 found = pattern.findall("\n".join(out_locales)) 

179 return _valid_locales(found, normalize)