A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/ncoghlan/cpython/commit/476a78133c94d82e19b89f50036cecd9b4214e7a below:

Change locale coercion to always respect LC_ALL · ncoghlan/cpython@476a781 · GitHub

17 17

# In order to get the warning messages to match up as expected, the candidate

18 18

# order here must much the target locale order in Python/pylifecycle.c

19 19

_C_UTF8_LOCALES = (

20 -

# Entries: (Target locale, target category, expected env var updates)

21 -

("C.UTF-8", "LC_ALL", "LC_ALL & LANG"),

22 -

("C.utf8", "LC_ALL", "LC_ALL & LANG"),

23 -

("UTF-8", "LC_CTYPE", "LC_CTYPE"),

20 +

# Entries: (Target locale, expected env var updates)

21 +

("C.UTF-8", "LC_CTYPE & LANG"),

22 +

("C.utf8", "LC_CTYPE & LANG"),

23 +

("UTF-8", "LC_CTYPE"),

24 24

)

25 25 26 26

# There's no reliable cross-platform way of checking locale alias

27 27

# lists, so the only way of knowing which of these locales will work

28 28

# is to try them with locale.setlocale(). We do that in a subprocess

29 29

# to avoid altering the locale of the test runner.

30 -

def _set_locale_in_subprocess(locale_name, category):

31 -

cmd_fmt = "import locale; print(locale.setlocale(locale.{}, '{}'))"

32 -

cmd = cmd_fmt.format(category, locale_name)

30 +

def _set_locale_in_subprocess(locale_name):

31 +

cmd_fmt = "import locale; print(locale.setlocale(locale.LC_CTYPE, '{}'))"

32 +

cmd = cmd_fmt.format(locale_name)

33 33

result, py_cmd = run_python_until_end("-c", cmd, __isolated=True)

34 34

return result.rc == 0

35 35 36 -

# Details of the CLI warning emitted at runtime

37 -

CLI_COERCION_WARNING_FMT = (

38 -

"Python detected LC_CTYPE=C: {} coerced to {} (set another locale "

39 -

"or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior)."

40 -

)

41 - 42 36

_EncodingDetails = namedtuple("EncodingDetails",

43 37

"fsencoding stdin_info stdout_info stderr_info")

44 38

@@ -67,9 +61,13 @@ def _handle_output_variations(data):

67 61

"""Adjust the output to handle platform specific idiosyncrasies

68 62 69 63

* Some platforms report ASCII as ANSI_X3.4-1968

64 +

* Some platforms report ASCII as US-ASCII

70 65

* Some platforms report UTF-8 instead of utf-8

71 66

"""

72 -

return data.replace(b"ANSI_X3.4-1968", b"ascii").lower()

67 +

data = data.replace(b"ANSI_X3.4-1968", b"ascii")

68 +

data = data.replace(b"US-ASCII", b"ascii")

69 +

data = data.lower()

70 +

return data

73 71 74 72

@classmethod

75 73

def get_child_details(cls, env_vars):

@@ -98,50 +96,116 @@ def get_child_details(cls, env_vars):

98 96

return child_encoding_details, stderr_lines

99 97 100 98 101 -

@test.support.cpython_only

102 -

@unittest.skipUnless(sysconfig.get_config_var("PY_COERCE_C_LOCALE"),

103 -

"C locale coercion disabled at build time")

104 -

class LocaleOverrideTests(unittest.TestCase):

99 +

class _ChildProcessEncodingTestCase(unittest.TestCase):

100 +

# Base class to check for expected encoding details in a child process

101 + 102 +

def _check_child_encoding_details(self,

103 +

env_vars,

104 +

expected_fsencoding,

105 +

expected_warning):

106 +

"""Check the C locale handling for the given process environment

107 + 108 +

Parameters:

109 +

expected_fsencoding: the encoding the child is expected to report

110 +

allow_c_locale: setting to use for PYTHONALLOWCLOCALE

111 +

None: don't set the variable at all

112 +

str: the value set in the child's environment

113 +

"""

114 +

result = EncodingDetails.get_child_details(env_vars)

115 +

encoding_details, stderr_lines = result

116 +

self.assertEqual(encoding_details,

117 +

EncodingDetails.get_expected_details(

118 +

expected_fsencoding))

119 +

self.assertEqual(stderr_lines, expected_warning)

120 + 121 +

# Details of the shared library warning emitted at runtime

122 +

LIBRARY_C_LOCALE_WARNING = (

123 +

"Python runtime initialized with LC_CTYPE=C (a locale with default ASCII "

124 +

"encoding), which may cause Unicode compatibility problems. Using C.UTF-8, "

125 +

"C.utf8, or UTF-8 (if available) as alternative Unicode-compatible "

126 +

"locales is recommended."

127 +

)

128 + 129 +

@unittest.skipUnless(sysconfig.get_config_var("PY_WARN_ON_C_LOCALE"),

130 +

"C locale runtime warning disabled at build time")

131 +

class LocaleWarningTests(_ChildProcessEncodingTestCase):

132 +

# Test warning emitted when running in the C locale

133 + 134 +

def test_library_c_locale_warning(self):

135 +

self.maxDiff = None

136 +

for locale_to_set in ("C", "POSIX", "invalid.ascii"):

137 +

var_dict = {

138 +

"LC_ALL": locale_to_set

139 +

}

140 +

with self.subTest(forced_locale=locale_to_set):

141 +

self._check_child_encoding_details(var_dict,

142 +

"ascii",

143 +

[LIBRARY_C_LOCALE_WARNING])

144 + 145 +

# Details of the CLI locale coercion warning emitted at runtime

146 +

CLI_COERCION_WARNING_FMT = (

147 +

"Python detected LC_CTYPE=C: {} coerced to {} (set another locale "

148 +

"or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior)."

149 +

)

150 + 151 +

class _LocaleCoercionTargetsTestCase(_ChildProcessEncodingTestCase):

152 +

# Base class for test cases that rely on coercion targets being defined

105 153 106 154

available_targets = []

155 +

targets_required = True

107 156 108 157

@classmethod

109 158

def setUpClass(cls):

110 159

first_target_locale = first_env_updates = None

111 160

available_targets = cls.available_targets

112 161

# Find the target locales available in the current system

113 -

for target_locale, target_category, env_updates in _C_UTF8_LOCALES:

114 -

if _set_locale_in_subprocess(target_locale, target_category):

162 +

for target_locale, env_updates in _C_UTF8_LOCALES:

163 +

if _set_locale_in_subprocess(target_locale):

115 164

available_targets.append(target_locale)

116 165

if first_target_locale is None:

117 166

first_target_locale = target_locale

118 167

first_env_updates = env_updates

119 -

if not available_targets:

168 +

if cls.targets_required and not available_targets:

120 169

raise unittest.SkipTest("No C-with-UTF-8 locale available")

121 170

# Expect coercion to use the first available locale

122 171

cls.EXPECTED_COERCION_WARNING = CLI_COERCION_WARNING_FMT.format(

123 172

first_env_updates, first_target_locale

124 173

)

125 174 126 -

def _check_child_encoding_details(self,

127 -

env_vars,

128 -

expected_fsencoding,

129 -

expected_warning):

130 -

"""Check the C locale handling for various configurations

131 175 132 -

Parameters:

133 -

expected_fsencoding: the encoding the child is expected to report

134 -

allow_c_locale: setting to use for PYTHONALLOWCLOCALE

135 -

None: don't set the variable at all

136 -

str: the value set in the child's environment

137 -

"""

138 -

result = EncodingDetails.get_child_details(env_vars)

139 -

encoding_details, stderr_lines = result

140 -

self.assertEqual(encoding_details,

141 -

EncodingDetails.get_expected_details(

142 -

expected_fsencoding))

143 -

self.assertEqual(stderr_lines, expected_warning)

176 +

class LocaleConfigurationTests(_LocaleCoercionTargetsTestCase):

177 +

# Test explicit external configuration via the process environment

144 178 179 +

def test_external_target_locale_configuration(self):

180 +

# Explicitly setting a target locale should give the same behaviour as

181 +

# is seen when implicitly coercing to that target locale

182 +

self.maxDiff = None

183 + 184 +

expected_warning = []

185 +

expected_fsencoding = "utf-8"

186 + 187 +

base_var_dict = {

188 +

"LANG": "",

189 +

"LC_CTYPE": "",

190 +

"LC_ALL": "",

191 +

}

192 +

for env_var in ("LANG", "LC_CTYPE"):

193 +

for locale_to_set in self.available_targets:

194 +

with self.subTest(env_var=env_var,

195 +

configured_locale=locale_to_set):

196 +

var_dict = base_var_dict.copy()

197 +

var_dict[env_var] = locale_to_set

198 +

self._check_child_encoding_details(var_dict,

199 +

expected_fsencoding,

200 +

expected_warning)

201 + 202 + 203 + 204 +

@test.support.cpython_only

205 +

@unittest.skipUnless(sysconfig.get_config_var("PY_COERCE_C_LOCALE"),

206 +

"C locale coercion disabled at build time")

207 +

class LocaleCoercionTests(_LocaleCoercionTargetsTestCase):

208 +

# Test implicit reconfiguration of the environment during CLI startup

145 209 146 210

def _check_c_locale_coercion(self, expected_fsencoding, coerce_c_locale):

147 211

"""Check the C locale handling for various configurations

@@ -165,7 +229,7 @@ def _check_c_locale_coercion(self, expected_fsencoding, coerce_c_locale):

165 229

"LC_CTYPE": "",

166 230

"LC_ALL": "",

167 231

}

168 -

for env_var in base_var_dict:

232 +

for env_var in ("LANG", "LC_CTYPE"):

169 233

for locale_to_set in ("", "C", "POSIX", "invalid.ascii"):

170 234

with self.subTest(env_var=env_var,

171 235

nominal_locale=locale_to_set,

@@ -178,7 +242,6 @@ def _check_c_locale_coercion(self, expected_fsencoding, coerce_c_locale):

178 242

expected_fsencoding,

179 243

expected_warning)

180 244 181 - 182 245

def test_test_PYTHONCOERCECLOCALE_not_set(self):

183 246

# This should coerce to the first available target locale by default

184 247

self._check_c_locale_coercion("utf-8", coerce_c_locale=None)

@@ -193,79 +256,13 @@ def test_PYTHONCOERCECLOCALE_set_to_zero(self):

193 256

# The setting "0" should result in the locale coercion being disabled

194 257

self._check_c_locale_coercion("ascii", coerce_c_locale="0")

195 258 196 -

def test_external_target_locale_configuration(self):

197 -

# Explicitly setting a target locale should give the same behaviour as

198 -

# is seen when implicitly coercing to that target locale

199 -

self.maxDiff = None

200 - 201 -

expected_warning = []

202 -

expected_fsencoding = "utf-8"

203 - 204 -

base_var_dict = {

205 -

"LANG": "",

206 -

"LC_CTYPE": "",

207 -

"LC_ALL": "",

208 -

}

209 -

for env_var in base_var_dict:

210 -

for locale_to_set in self.available_targets:

211 -

with self.subTest(env_var=env_var,

212 -

configured_locale=locale_to_set):

213 -

var_dict = base_var_dict.copy()

214 -

var_dict[env_var] = locale_to_set

215 -

self._check_child_encoding_details(var_dict,

216 -

expected_fsencoding,

217 -

expected_warning)

218 - 219 - 220 -

# Details of the shared library warning emitted at runtime

221 -

LIBRARY_C_LOCALE_WARNING = (

222 -

"Python runtime initialized with LC_CTYPE=C (a locale with default ASCII "

223 -

"encoding), which may cause Unicode compatibility problems. Using C.UTF-8, "

224 -

"C.utf8, or UTF-8 (if available) as alternative Unicode-compatible "

225 -

"locales is recommended.\n"

226 -

)

227 - 228 -

@unittest.skipUnless(sysconfig.get_config_var("PY_WARN_ON_C_LOCALE"),

229 -

"C locale runtime warning disabled at build time")

230 -

class EmbeddingTests(unittest.TestCase):

231 -

def setUp(self):

232 -

here = os.path.abspath(__file__)

233 -

basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))

234 -

self.test_exe = exe = os.path.join(basepath, "Programs", "_testembed")

235 -

if not os.path.exists(exe):

236 -

self.skipTest("%r doesn't exist" % exe)

237 -

# This is needed otherwise we get a fatal error:

238 -

# "Py_Initialize: Unable to get the locale encoding

239 -

# LookupError: no codec search functions registered: can't find encoding"

240 -

self.addCleanup(os.chdir, os.getcwd())

241 -

os.chdir(basepath)

242 - 243 -

def run_embedded_interpreter(self, *args):

244 -

"""Runs a test in the embedded interpreter"""

245 -

cmd = [self.test_exe]

246 -

cmd.extend(args)

247 -

p = subprocess.Popen(cmd,

248 -

stdout=subprocess.PIPE,

249 -

stderr=subprocess.PIPE,

250 -

universal_newlines=True)

251 -

(out, err) = p.communicate()

252 -

self.assertEqual(p.returncode, 0,

253 -

"bad returncode %d, stderr is %r" %

254 -

(p.returncode, err))

255 -

return out, err

256 - 257 -

def test_library_c_locale_warning(self):

258 -

# Checks forced configuration of embedded interpreter IO streams

259 -

out, err = self.run_embedded_interpreter("c_locale_warning")

260 -

if test.support.verbose > 1:

261 -

print()

262 -

print(out)

263 -

print(err)

264 -

self.assertEqual(out, "")

265 -

self.assertEqual(err, LIBRARY_C_LOCALE_WARNING)

266 259 267 260

def test_main():

268 -

test.support.run_unittest(LocaleOverrideTests, EmbeddingTests)

261 +

test.support.run_unittest(

262 +

LocaleConfigurationTests,

263 +

LocaleCoercionTests,

264 +

LocaleWarningTests

265 +

)

269 266

test.support.reap_children()

270 267 271 268

if __name__ == "__main__":


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4