Skip to content

Commit 6fdb62b

Browse files
authored
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.
1 parent 39a54ba commit 6fdb62b

File tree

4 files changed

+9
-70
lines changed

4 files changed

+9
-70
lines changed

Lib/_pyio.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,14 +2021,6 @@ def __init__(self, buffer, encoding=None, errors=None, newline=None,
20212021
self._check_newline(newline)
20222022
encoding = text_encoding(encoding)
20232023

2024-
if encoding == "locale" and sys.platform == "win32":
2025-
# On Unix, os.device_encoding() returns "utf-8" instead of locale encoding
2026-
# in the UTF-8 mode. So we use os.device_encoding() only on Windows.
2027-
try:
2028-
encoding = os.device_encoding(buffer.fileno()) or "locale"
2029-
except (AttributeError, UnsupportedOperation):
2030-
pass
2031-
20322024
if encoding == "locale":
20332025
try:
20342026
import locale

Lib/test/test_io.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2736,18 +2736,6 @@ def test_default_encoding(self):
27362736
os.environ.clear()
27372737
os.environ.update(old_environ)
27382738

2739-
@support.cpython_only
2740-
@unittest.skipIf(sys.platform != "win32", "Windows-only test")
2741-
@unittest.skipIf(sys.flags.utf8_mode, "utf-8 mode is enabled")
2742-
def test_device_encoding(self):
2743-
# Issue 15989
2744-
import _testcapi
2745-
b = self.BytesIO()
2746-
b.fileno = lambda: _testcapi.INT_MAX + 1
2747-
self.assertRaises(OverflowError, self.TextIOWrapper, b, encoding="locale")
2748-
b.fileno = lambda: _testcapi.UINT_MAX + 1
2749-
self.assertRaises(OverflowError, self.TextIOWrapper, b, encoding="locale")
2750-
27512739
def test_encoding(self):
27522740
# Check the encoding attribute is always set, and valid
27532741
b = self.BytesIO()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Stop calling ``os.device_encoding(file.fileno())`` in
2+
:class:`TextIOWrapper`. It was complex, never documented, and didn't work
3+
for most cases. (Patch by Inada Naoki.)

Modules/_io/textio.c

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
10601060
PyObject *raw, *codec_info = NULL;
10611061
PyObject *res;
10621062
int r;
1063-
int use_locale_encoding = 0; // Use locale encoding even in UTF-8 mode.
10641063

10651064
self->ok = 0;
10661065
self->detached = 0;
@@ -1074,10 +1073,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
10741073
}
10751074
}
10761075
}
1077-
else if (strcmp(encoding, "locale") == 0) {
1078-
encoding = NULL;
1079-
use_locale_encoding = 1;
1080-
}
10811076

10821077
if (errors == Py_None) {
10831078
errors = &_Py_ID(strict);
@@ -1114,57 +1109,18 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
11141109
self->encodefunc = NULL;
11151110
self->b2cratio = 0.0;
11161111

1117-
#ifdef MS_WINDOWS
1118-
// os.device_encoding() on Unix is the locale encoding or UTF-8
1119-
// according to UTF-8 Mode.
1120-
// Since UTF-8 mode shouldn't affect `encoding="locale"`, we call
1121-
// os.device_encoding() only on Windows.
1122-
if (encoding == NULL) {
1123-
/* Try os.device_encoding(fileno) */
1124-
PyObject *fileno;
1125-
_PyIO_State *state = IO_STATE();
1126-
if (state == NULL)
1127-
goto error;
1128-
fileno = PyObject_CallMethodNoArgs(buffer, &_Py_ID(fileno));
1129-
/* Ignore only AttributeError and UnsupportedOperation */
1130-
if (fileno == NULL) {
1131-
if (PyErr_ExceptionMatches(PyExc_AttributeError) ||
1132-
PyErr_ExceptionMatches(state->unsupported_operation)) {
1133-
PyErr_Clear();
1134-
}
1135-
else {
1136-
goto error;
1137-
}
1138-
}
1139-
else {
1140-
int fd = _PyLong_AsInt(fileno);
1141-
Py_DECREF(fileno);
1142-
if (fd == -1 && PyErr_Occurred()) {
1143-
goto error;
1144-
}
1145-
1146-
self->encoding = _Py_device_encoding(fd);
1147-
if (self->encoding == NULL)
1148-
goto error;
1149-
else if (!PyUnicode_Check(self->encoding))
1150-
Py_CLEAR(self->encoding);
1151-
}
1112+
if (encoding == NULL && _PyRuntime.preconfig.utf8_mode) {
1113+
_Py_DECLARE_STR(utf_8, "utf-8");
1114+
self->encoding = Py_NewRef(&_Py_STR(utf_8));
11521115
}
1153-
#endif
1154-
1155-
if (encoding == NULL && self->encoding == NULL) {
1156-
if (_PyRuntime.preconfig.utf8_mode && !use_locale_encoding) {
1157-
_Py_DECLARE_STR(utf_8, "utf-8");
1158-
self->encoding = Py_NewRef(&_Py_STR(utf_8));
1159-
}
1160-
else {
1161-
self->encoding = _Py_GetLocaleEncodingObject();
1162-
}
1116+
else if (encoding == NULL || (strcmp(encoding, "locale") == 0)) {
1117+
self->encoding = _Py_GetLocaleEncodingObject();
11631118
if (self->encoding == NULL) {
11641119
goto error;
11651120
}
11661121
assert(PyUnicode_Check(self->encoding));
11671122
}
1123+
11681124
if (self->encoding != NULL) {
11691125
encoding = PyUnicode_AsUTF8(self->encoding);
11701126
if (encoding == NULL)

0 commit comments

Comments
 (0)