From 6fdb62b1fa344b9cdf1f221eac83404fb1980822 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 19 Apr 2022 11:44:36 +0900 Subject: [PATCH] gh-91526: io: Remove device encoding support from TextIOWrapper (GH-91529) `TextIOWrapper.__init__()` called `os.device_encoding(file.fileno())` if fileno is 0-2 and encoding=None. But it is very rarely works, and never documented behavior. --- Lib/_pyio.py | 8 --- Lib/test/test_io.py | 12 ---- ...2-04-14-18-06-00.gh-issue-91526.cwfhSB.rst | 3 + Modules/_io/textio.c | 56 ++----------------- 4 files changed, 9 insertions(+), 70 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-04-14-18-06-00.gh-issue-91526.cwfhSB.rst diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 0f33ed59492..380a7a736c6 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -2021,14 +2021,6 @@ class TextIOWrapper(TextIOBase): self._check_newline(newline) encoding = text_encoding(encoding) - if encoding == "locale" and sys.platform == "win32": - # On Unix, os.device_encoding() returns "utf-8" instead of locale encoding - # in the UTF-8 mode. So we use os.device_encoding() only on Windows. - try: - encoding = os.device_encoding(buffer.fileno()) or "locale" - except (AttributeError, UnsupportedOperation): - pass - if encoding == "locale": try: import locale diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index c86251dfe57..45bf81b61f4 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2736,18 +2736,6 @@ class TextIOWrapperTest(unittest.TestCase): os.environ.clear() os.environ.update(old_environ) - @support.cpython_only - @unittest.skipIf(sys.platform != "win32", "Windows-only test") - @unittest.skipIf(sys.flags.utf8_mode, "utf-8 mode is enabled") - def test_device_encoding(self): - # Issue 15989 - import _testcapi - b = self.BytesIO() - b.fileno = lambda: _testcapi.INT_MAX + 1 - self.assertRaises(OverflowError, self.TextIOWrapper, b, encoding="locale") - b.fileno = lambda: _testcapi.UINT_MAX + 1 - self.assertRaises(OverflowError, self.TextIOWrapper, b, encoding="locale") - def test_encoding(self): # Check the encoding attribute is always set, and valid b = self.BytesIO() diff --git a/Misc/NEWS.d/next/Library/2022-04-14-18-06-00.gh-issue-91526.cwfhSB.rst b/Misc/NEWS.d/next/Library/2022-04-14-18-06-00.gh-issue-91526.cwfhSB.rst new file mode 100644 index 00000000000..a6633421e2b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-14-18-06-00.gh-issue-91526.cwfhSB.rst @@ -0,0 +1,3 @@ +Stop calling ``os.device_encoding(file.fileno())`` in +:class:`TextIOWrapper`. It was complex, never documented, and didn't work +for most cases. (Patch by Inada Naoki.) diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 6ba7393c3a6..f45a6978738 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1060,7 +1060,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, PyObject *raw, *codec_info = NULL; PyObject *res; int r; - int use_locale_encoding = 0; // Use locale encoding even in UTF-8 mode. self->ok = 0; self->detached = 0; @@ -1074,10 +1073,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, } } } - else if (strcmp(encoding, "locale") == 0) { - encoding = NULL; - use_locale_encoding = 1; - } if (errors == Py_None) { errors = &_Py_ID(strict); @@ -1114,57 +1109,18 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, self->encodefunc = NULL; self->b2cratio = 0.0; -#ifdef MS_WINDOWS - // os.device_encoding() on Unix is the locale encoding or UTF-8 - // according to UTF-8 Mode. - // Since UTF-8 mode shouldn't affect `encoding="locale"`, we call - // os.device_encoding() only on Windows. - if (encoding == NULL) { - /* Try os.device_encoding(fileno) */ - PyObject *fileno; - _PyIO_State *state = IO_STATE(); - if (state == NULL) - goto error; - fileno = PyObject_CallMethodNoArgs(buffer, &_Py_ID(fileno)); - /* Ignore only AttributeError and UnsupportedOperation */ - if (fileno == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError) || - PyErr_ExceptionMatches(state->unsupported_operation)) { - PyErr_Clear(); - } - else { - goto error; - } - } - else { - int fd = _PyLong_AsInt(fileno); - Py_DECREF(fileno); - if (fd == -1 && PyErr_Occurred()) { - goto error; - } - - self->encoding = _Py_device_encoding(fd); - if (self->encoding == NULL) - goto error; - else if (!PyUnicode_Check(self->encoding)) - Py_CLEAR(self->encoding); - } + if (encoding == NULL && _PyRuntime.preconfig.utf8_mode) { + _Py_DECLARE_STR(utf_8, "utf-8"); + self->encoding = Py_NewRef(&_Py_STR(utf_8)); } -#endif - - if (encoding == NULL && self->encoding == NULL) { - if (_PyRuntime.preconfig.utf8_mode && !use_locale_encoding) { - _Py_DECLARE_STR(utf_8, "utf-8"); - self->encoding = Py_NewRef(&_Py_STR(utf_8)); - } - else { - self->encoding = _Py_GetLocaleEncodingObject(); - } + else if (encoding == NULL || (strcmp(encoding, "locale") == 0)) { + self->encoding = _Py_GetLocaleEncodingObject(); if (self->encoding == NULL) { goto error; } assert(PyUnicode_Check(self->encoding)); } + if (self->encoding != NULL) { encoding = PyUnicode_AsUTF8(self->encoding); if (encoding == NULL)