Skip to content

Commit 1faece6

Browse files
committed
coerces locale to be C.UTF-8 irrespective to the system locale
Code from gh#python/cpython@6ea4186 (upstream released in 3.7.0) Fixes: bpo#28180 Patch: pep538_coerce_legacy_c_locale.patch
1 parent ebbde33 commit 1faece6

File tree

10 files changed

+708
-34
lines changed

10 files changed

+708
-34
lines changed

Doc/using/cmdline.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,45 @@ conflict.
728728

729729
.. versionadded:: 3.6
730730

731+
732+
.. envvar:: PYTHONCOERCECLOCALE
733+
734+
If set to the value ``0``, causes the main Python command line application
735+
to skip coercing the legacy ASCII-based C locale to a more capable UTF-8
736+
based alternative. Note that this setting is checked even when the
737+
:option:`-E` or :option:`-I` options are used, as it is handled prior to
738+
the processing of command line options.
739+
740+
If this variable is *not* set, or is set to a value other than ``0``, and
741+
the current locale reported for the ``LC_CTYPE`` category is the default
742+
``C`` locale, then the Python CLI will attempt to configure one of the
743+
following locales for the given locale categories before loading the
744+
interpreter runtime:
745+
746+
* ``C.UTF-8`` (``LC_ALL``)
747+
* ``C.utf8`` (``LC_ALL``)
748+
* ``UTF-8`` (``LC_CTYPE``)
749+
750+
If setting one of these locale categories succeeds, then the matching
751+
environment variables will be set (both ``LC_ALL`` and ``LANG`` for the
752+
``LC_ALL`` category, and ``LC_CTYPE`` for the ``LC_CTYPE`` category) in
753+
the current process environment before the Python runtime is initialized.
754+
755+
Configuring one of these locales (either explicitly or via the above
756+
implicit locale coercion) will automatically set the error handler for
757+
:data:`sys.stdin` and :data:`sys.stdout` to ``surrogateescape``. This
758+
behavior can be overridden using :envvar:`PYTHONIOENCODING` as usual.
759+
760+
For debugging purposes, setting ``PYTHONCOERCECLOCALE=warn`` will cause
761+
Python to emit warning messages on ``stderr`` if either the locale coercion
762+
activates, or else if a locale that *would* have triggered coercion is
763+
still active when the Python runtime is initialized.
764+
765+
Availability: \*nix
766+
767+
.. versionadded:: 3.7
768+
See :pep:`538` for more details.
769+
731770
Debug-mode variables
732771
~~~~~~~~~~~~~~~~~~~~
733772

Lib/test/support/script_helper.py

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,35 @@ def interpreter_requires_environment():
5656
return __cached_interp_requires_environment
5757

5858

59-
_PythonRunResult = collections.namedtuple("_PythonRunResult",
60-
("rc", "out", "err"))
59+
class _PythonRunResult(collections.namedtuple("_PythonRunResult",
60+
("rc", "out", "err"))):
61+
"""Helper for reporting Python subprocess run results"""
62+
def fail(self, cmd_line):
63+
"""Provide helpful details about failed subcommand runs"""
64+
# Limit to 80 lines to ASCII characters
65+
maxlen = 80 * 100
66+
out, err = self.out, self.err
67+
if len(out) > maxlen:
68+
out = b'(... truncated stdout ...)' + out[-maxlen:]
69+
if len(err) > maxlen:
70+
err = b'(... truncated stderr ...)' + err[-maxlen:]
71+
out = out.decode('ascii', 'replace').rstrip()
72+
err = err.decode('ascii', 'replace').rstrip()
73+
raise AssertionError("Process return code is %d\n"
74+
"command line: %r\n"
75+
"\n"
76+
"stdout:\n"
77+
"---\n"
78+
"%s\n"
79+
"---\n"
80+
"\n"
81+
"stderr:\n"
82+
"---\n"
83+
"%s\n"
84+
"---"
85+
% (self.rc, cmd_line,
86+
out,
87+
err))
6188

6289

6390
# Executing the interpreter in a subprocess
@@ -115,30 +142,7 @@ def run_python_until_end(*args, **env_vars):
115142
def _assert_python(expected_success, *args, **env_vars):
116143
res, cmd_line = run_python_until_end(*args, **env_vars)
117144
if (res.rc and expected_success) or (not res.rc and not expected_success):
118-
# Limit to 80 lines to ASCII characters
119-
maxlen = 80 * 100
120-
out, err = res.out, res.err
121-
if len(out) > maxlen:
122-
out = b'(... truncated stdout ...)' + out[-maxlen:]
123-
if len(err) > maxlen:
124-
err = b'(... truncated stderr ...)' + err[-maxlen:]
125-
out = out.decode('ascii', 'replace').rstrip()
126-
err = err.decode('ascii', 'replace').rstrip()
127-
raise AssertionError("Process return code is %d\n"
128-
"command line: %r\n"
129-
"\n"
130-
"stdout:\n"
131-
"---\n"
132-
"%s\n"
133-
"---\n"
134-
"\n"
135-
"stderr:\n"
136-
"---\n"
137-
"%s\n"
138-
"---"
139-
% (res.rc, cmd_line,
140-
out,
141-
err))
145+
res.fail(cmd_line)
142146
return res
143147

144148
def assert_python_ok(*args, **env_vars):

0 commit comments

Comments
 (0)