]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-91526: io: Remove device encoding support from TextIOWrapper (GH-91529)
authorInada Naoki <songofacandy@gmail.com>
Tue, 19 Apr 2022 02:44:36 +0000 (11:44 +0900)
committerGitHub <noreply@github.com>
Tue, 19 Apr 2022 02:44:36 +0000 (11:44 +0900)
`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
Lib/test/test_io.py
Misc/NEWS.d/next/Library/2022-04-14-18-06-00.gh-issue-91526.cwfhSB.rst [new file with mode: 0644]
Modules/_io/textio.c

index 0f33ed59492e71181e1f701e9e1de2bdf6cf546f..380a7a736c64e94491d2aaa4b01f46b9466e5a45 100644 (file)
@@ -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
index c86251dfe5734c832c95a81a4df3af288651df49..45bf81b61f4163e5b42c6d890974413602cc9810 100644 (file)
@@ -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 (file)
index 0000000..a663342
--- /dev/null
@@ -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.)
index 6ba7393c3a6a309cea57bcb2910409fa4d4e62fa..f45a69787383f9bee47b6c171f795aaae1a50194 100644 (file)
@@ -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)