Skip to content

Commit bf28d2d

Browse files
Issue #18818: The "encodingname" part of PYTHONIOENCODING is now optional.
1 parent 187b063 commit bf28d2d

File tree

4 files changed

+56
-11
lines changed

4 files changed

+56
-11
lines changed

Doc/using/cmdline.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,13 +538,16 @@ conflict.
538538
.. envvar:: PYTHONIOENCODING
539539

540540
If this is set before running the interpreter, it overrides the encoding used
541-
for stdin/stdout/stderr, in the syntax ``encodingname:errorhandler``. The
542-
``:errorhandler`` part is optional and has the same meaning as in
543-
:func:`str.encode`.
541+
for stdin/stdout/stderr, in the syntax ``encodingname:errorhandler``. Both
542+
the ``encodingname`` and the ``:errorhandler`` parts are optional and have
543+
the same meaning as in :func:`str.encode`.
544544

545545
For stderr, the ``:errorhandler`` part is ignored; the handler will always be
546546
``'backslashreplace'``.
547547

548+
.. versionchanged:: 3.4
549+
The ``encodingname`` part is now optional.
550+
548551

549552
.. envvar:: PYTHONNOUSERSITE
550553

Lib/test/test_sys.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,42 @@ def test_ioencoding(self):
544544
out = p.communicate()[0].strip()
545545
self.assertEqual(out, b'?')
546546

547+
env["PYTHONIOENCODING"] = "ascii"
548+
p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
549+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
550+
env=env)
551+
out, err = p.communicate()
552+
self.assertEqual(out, b'')
553+
self.assertIn(b'UnicodeEncodeError:', err)
554+
self.assertIn(rb"'\xa2'", err)
555+
556+
env["PYTHONIOENCODING"] = "ascii:"
557+
p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xa2))'],
558+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
559+
env=env)
560+
out, err = p.communicate()
561+
self.assertEqual(out, b'')
562+
self.assertIn(b'UnicodeEncodeError:', err)
563+
self.assertIn(rb"'\xa2'", err)
564+
565+
env["PYTHONIOENCODING"] = ":surrogateescape"
566+
p = subprocess.Popen([sys.executable, "-c", 'print(chr(0xdcbd))'],
567+
stdout=subprocess.PIPE, env=env)
568+
out = p.communicate()[0].strip()
569+
self.assertEqual(out, b'\xbd')
570+
571+
@unittest.skipUnless(test.support.FS_NONASCII,
572+
'requires OS support of non-ASCII encodings')
573+
def test_ioencoding_nonascii(self):
574+
env = dict(os.environ)
575+
576+
env["PYTHONIOENCODING"] = ""
577+
p = subprocess.Popen([sys.executable, "-c",
578+
'print(%a)' % test.support.FS_NONASCII],
579+
stdout=subprocess.PIPE, env=env)
580+
out = p.communicate()[0].strip()
581+
self.assertEqual(out, os.fsencode(test.support.FS_NONASCII))
582+
547583
@unittest.skipIf(sys.base_prefix != sys.prefix,
548584
'Test is not venv-compatible')
549585
def test_executable(self):

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Projected Release date: 2013-09-29
77
Core and Builtins
88
-----------------
99

10+
- Issue #18818: The "encodingname" part of PYTHONIOENCODING is now optional.
11+
1012
Library
1113
-------
1214

Python/pythonrun.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ initstdio(void)
10561056
PyObject *std = NULL;
10571057
int status = 0, fd;
10581058
PyObject * encoding_attr;
1059-
char *encoding = NULL, *errors;
1059+
char *pythonioencoding = NULL, *encoding, *errors;
10601060

10611061
/* Hack to avoid a nasty recursion issue when Python is invoked
10621062
in verbose mode: pre-import the Latin-1 and UTF-8 codecs */
@@ -1088,19 +1088,23 @@ initstdio(void)
10881088
}
10891089
Py_DECREF(wrapper);
10901090

1091-
encoding = Py_GETENV("PYTHONIOENCODING");
1092-
errors = NULL;
1093-
if (encoding) {
1094-
encoding = _PyMem_Strdup(encoding);
1095-
if (encoding == NULL) {
1091+
pythonioencoding = Py_GETENV("PYTHONIOENCODING");
1092+
encoding = errors = NULL;
1093+
if (pythonioencoding) {
1094+
pythonioencoding = _PyMem_Strdup(pythonioencoding);
1095+
if (pythonioencoding == NULL) {
10961096
PyErr_NoMemory();
10971097
goto error;
10981098
}
1099-
errors = strchr(encoding, ':');
1099+
errors = strchr(pythonioencoding, ':');
11001100
if (errors) {
11011101
*errors = '\0';
11021102
errors++;
1103+
if (!*errors)
1104+
errors = NULL;
11031105
}
1106+
if (*pythonioencoding)
1107+
encoding = pythonioencoding;
11041108
}
11051109

11061110
/* Set sys.stdin */
@@ -1180,7 +1184,7 @@ initstdio(void)
11801184
status = -1;
11811185
}
11821186

1183-
PyMem_Free(encoding);
1187+
PyMem_Free(pythonioencoding);
11841188
Py_XDECREF(bimod);
11851189
Py_XDECREF(iomod);
11861190
return status;

0 commit comments

Comments
 (0)