Skip to content

[3.7] Revert "[3.7] bpo-34589: Add -X coerce_c_locale option; C locale coercion off by default (GH-9379)" #9416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -438,19 +438,10 @@ Miscellaneous options
* Set the :attr:`~sys.flags.dev_mode` attribute of :attr:`sys.flags` to
``True``

* ``-X utf8`` enables UTF-8 mode (:pep:`540`) for operating system interfaces, overriding
* ``-X utf8`` enables UTF-8 mode for operating system interfaces, overriding
the default locale-aware mode. ``-X utf8=0`` explicitly disables UTF-8
mode (even when it would otherwise activate automatically).
See :envvar:`PYTHONUTF8` for more details.
* ``-X coerce_c_locale`` or ``-X coerce_c_locale=1`` tries to coerce the C
locale (:pep:`538`).
``-X coerce_c_locale=0`` skips coercing the legacy ASCII-based C and POSIX
locales to a more capable UTF-8 based alternative.
``-X coerce_c_locale=warn`` will cause Python to emit warning messages on
``stderr`` if either the locale coercion activates, or else if a locale
that *would* have triggered coercion is still active when the Python
runtime is initialized.
See :envvar:`PYTHONCOERCECLOCALE` for more details.

It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary.
Expand All @@ -470,9 +461,6 @@ Miscellaneous options
.. versionadded:: 3.7
The ``-X importtime``, ``-X dev`` and ``-X utf8`` options.

.. versionadded:: 3.7.1
The ``-X coerce_c_locale`` option.


Options you shouldn't use
~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -846,8 +834,6 @@ conflict.
order to force the interpreter to use ``ASCII`` instead of ``UTF-8`` for
system interfaces.

Also available as the :option:`-X` ``coerce_c_locale`` option.

Availability: \*nix

.. versionadded:: 3.7
Expand Down
7 changes: 0 additions & 7 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2494,10 +2494,3 @@ versions, it respected an ill-defined subset of those environment variables,
while in Python 3.7.0 it didn't read any of them due to :issue:`34247`). If
this behavior is unwanted, set :c:data:`Py_IgnoreEnvironmentFlag` to 1 before
calling :c:func:`Py_Initialize`.

:c:func:`Py_Initialize` and :c:func:`Py_Main` cannot enable the C locale
coercion (:pep:`538`) anymore: it is always disabled. It can now only be
enabled by the Python program ("python3).

New :option:`-X` ``coerce_c_locale`` command line option to control C locale
coercion (:pep:`538`).
4 changes: 0 additions & 4 deletions Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,7 @@ PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *);
/* Bootstrap __main__ (defined in Modules/main.c) */
PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
#ifdef Py_BUILD_CORE
# ifdef MS_WINDOWS
PyAPI_FUNC(int) _Py_WindowsMain(int argc, wchar_t **argv);
# else
PyAPI_FUNC(int) _Py_UnixMain(int argc, char **argv);
# endif
#endif

/* In getpath.c */
Expand Down
7 changes: 3 additions & 4 deletions Include/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ typedef struct {
int show_alloc_count; /* -X showalloccount */
int dump_refs; /* PYTHONDUMPREFS */
int malloc_stats; /* PYTHONMALLOCSTATS */
int coerce_c_locale; /* PYTHONCOERCECLOCALE, -1 means unknown */
int coerce_c_locale_warn; /* PYTHONCOERCECLOCALE=warn */
int utf8_mode; /* PYTHONUTF8, -X utf8; -1 means unknown */

wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
Expand Down Expand Up @@ -72,17 +74,14 @@ typedef struct {

/* Private fields */
int _disable_importlib; /* Needed by freeze_importlib */
int _coerce_c_locale; /* PYTHONCOERCECLOCALE, -1 means unknown */
int _coerce_c_locale_warn; /* PYTHONCOERCECLOCALE=warn */
} _PyCoreConfig;

#define _PyCoreConfig_INIT \
(_PyCoreConfig){ \
.install_signal_handlers = -1, \
.ignore_environment = -1, \
.use_hash_seed = -1, \
._coerce_c_locale = 0, \
._coerce_c_locale_warn = 0, \
.coerce_c_locale = -1, \
.faulthandler = -1, \
.tracemalloc = -1, \
.utf8_mode = -1, \
Expand Down
55 changes: 10 additions & 45 deletions Lib/test/test_c_locale_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def _handle_output_variations(data):
return data

@classmethod
def get_child_details(cls, env_vars, xoption=None):
def get_child_details(cls, env_vars):
"""Retrieves fsencoding and standard stream details from a child process

Returns (encoding_details, stderr_lines):
Expand All @@ -150,11 +150,10 @@ def get_child_details(cls, env_vars, xoption=None):
The child is run in isolated mode if the current interpreter supports
that.
"""
args = []
if xoption:
args.extend(("-X", f"coerce_c_locale={xoption}"))
args.extend(("-X", "utf8=0", "-c", cls.CHILD_PROCESS_SCRIPT))
result, py_cmd = run_python_until_end(*args, **env_vars)
result, py_cmd = run_python_until_end(
"-X", "utf8=0", "-c", cls.CHILD_PROCESS_SCRIPT,
**env_vars
)
if not result.rc == 0:
result.fail(py_cmd)
# All subprocess outputs in this test case should be pure ASCII
Expand Down Expand Up @@ -213,16 +212,15 @@ def _check_child_encoding_details(self,
expected_fs_encoding,
expected_stream_encoding,
expected_warnings,
coercion_expected,
xoption=None):
coercion_expected):
"""Check the C locale handling for the given process environment

Parameters:
expected_fs_encoding: expected sys.getfilesystemencoding() result
expected_stream_encoding: expected encoding for standard streams
expected_warning: stderr output to expect (if any)
"""
result = EncodingDetails.get_child_details(env_vars, xoption)
result = EncodingDetails.get_child_details(env_vars)
encoding_details, stderr_lines = result
expected_details = EncodingDetails.get_expected_details(
coercion_expected,
Expand Down Expand Up @@ -292,7 +290,6 @@ def _check_c_locale_coercion(self,
coerce_c_locale,
expected_warnings=None,
coercion_expected=True,
use_xoption=False,
**extra_vars):
"""Check the C locale handling for various configurations

Expand Down Expand Up @@ -322,12 +319,8 @@ def _check_c_locale_coercion(self,
"PYTHONCOERCECLOCALE": "",
}
base_var_dict.update(extra_vars)
xoption = None
if coerce_c_locale is not None:
if use_xoption:
xoption = coerce_c_locale
else:
base_var_dict["PYTHONCOERCECLOCALE"] = coerce_c_locale
base_var_dict["PYTHONCOERCECLOCALE"] = coerce_c_locale

# Check behaviour for the default locale
with self.subTest(default_locale=True,
Expand All @@ -349,8 +342,7 @@ def _check_c_locale_coercion(self,
fs_encoding,
stream_encoding,
_expected_warnings,
_coercion_expected,
xoption=xoption)
_coercion_expected)

# Check behaviour for explicitly configured locales
for locale_to_set in EXPECTED_C_LOCALE_EQUIVALENTS:
Expand All @@ -365,8 +357,7 @@ def _check_c_locale_coercion(self,
fs_encoding,
stream_encoding,
expected_warnings,
coercion_expected,
xoption=xoption)
coercion_expected)

def test_PYTHONCOERCECLOCALE_not_set(self):
# This should coerce to the first available target locale by default
Expand Down Expand Up @@ -413,32 +404,6 @@ def test_LC_ALL_set_to_C(self):
expected_warnings=[LEGACY_LOCALE_WARNING],
coercion_expected=False)

def test_xoption_set_to_1(self):
self._check_c_locale_coercion("utf-8", "utf-8", coerce_c_locale="1",
use_xoption=True)

def test_xoption_set_to_zero(self):
# The setting "0" should result in the locale coercion being disabled
self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
EXPECTED_C_LOCALE_STREAM_ENCODING,
coerce_c_locale="0",
coercion_expected=False,
use_xoption=True)
# Setting LC_ALL=C shouldn't make any difference to the behaviour
self._check_c_locale_coercion(EXPECTED_C_LOCALE_FS_ENCODING,
EXPECTED_C_LOCALE_STREAM_ENCODING,
coerce_c_locale="0",
LC_ALL="C",
coercion_expected=False,
use_xoption=True)

def test_xoption_set_to_warn(self):
# -X coerce_c_locale=warn enables runtime warnings for legacy locales
self._check_c_locale_coercion("utf-8", "utf-8",
coerce_c_locale="warn",
expected_warnings=[CLI_COERCION_WARNING],
use_xoption=True)

def test_main():
test.support.run_unittest(
LocaleConfigurationTests,
Expand Down
7 changes: 2 additions & 5 deletions Lib/test/test_cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,13 @@ def test_undecodable_code(self):
env = os.environ.copy()
# Use C locale to get ascii for the locale encoding
env['LC_ALL'] = 'C'
env['PYTHONCOERCECLOCALE'] = '0'
code = (
b'import locale; '
b'print(ascii("' + undecodable + b'"), '
b'locale.getpreferredencoding())')
p = subprocess.Popen(
[sys.executable,
# Disable C locale coercion and UTF-8 Mode to not use UTF-8
"-X", "coerce_c_locale=0",
"-X", "utf8=0",
"-c", code],
[sys.executable, "-c", code],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
env=env)
stdout, stderr = p.communicate()
Expand Down
5 changes: 3 additions & 2 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'malloc_stats': 0,
'utf8_mode': 0,

'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,

'program_name': './_testembed',
'argc': 0,
'argv': '[]',
Expand All @@ -287,8 +290,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):

'_disable_importlib': 0,
'Py_FrozenFlag': 0,
'_coerce_c_locale': 0,
'_coerce_c_locale_warn': 0,
}

def check_config(self, testname, expected):
Expand Down
8 changes: 3 additions & 5 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,8 +656,9 @@ def test_getfilesystemencoding(self):

def c_locale_get_error_handler(self, locale, isolated=False, encoding=None):
# Force the POSIX locale
env = dict(os.environ)
env = os.environ.copy()
env["LC_ALL"] = locale
env["PYTHONCOERCECLOCALE"] = "0"
code = '\n'.join((
'import sys',
'def dump(name):',
Expand All @@ -667,10 +668,7 @@ def c_locale_get_error_handler(self, locale, isolated=False, encoding=None):
'dump("stdout")',
'dump("stderr")',
))
args = [sys.executable,
"-X", "utf8=0",
"-X", "coerce_c_locale=0",
"-c", code]
args = [sys.executable, "-c", code]
if isolated:
args.append("-I")
if encoding is not None:
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_utf8_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ def posix_locale(self):
return (loc in POSIX_LOCALES)

def get_output(self, *args, failure=False, **kw):
# Always disable the C locale coercion (PEP 538)
args = ('-X', 'coerce_c_locale=0', *args)
kw = dict(self.DEFAULT_ENV, **kw)
if failure:
out = assert_python_failure(*args, **kw)
Expand Down Expand Up @@ -118,6 +116,7 @@ def test_filesystemencoding(self):
# PYTHONLEGACYWINDOWSFSENCODING disables the UTF-8 mode
# and has the priority over -X utf8 and PYTHONUTF8
out = self.get_output('-X', 'utf8', '-c', code,
PYTHONUTF8='strict',
PYTHONLEGACYWINDOWSFSENCODING='1')
self.assertEqual(out, 'mbcs/replace')

Expand Down

This file was deleted.

This file was deleted.

Loading