]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-66060: Use actual class name in _io type's __repr__ (#30824)
authorAN Long <aisk@users.noreply.github.com>
Tue, 9 Jan 2024 20:39:36 +0000 (04:39 +0800)
committerGitHub <noreply@github.com>
Tue, 9 Jan 2024 20:39:36 +0000 (21:39 +0100)
Use the object's actual class name in the following _io type's __repr__:
- FileIO
- TextIOWrapper
- _WindowsConsoleIO

Lib/test/test_fileio.py
Lib/test/test_io.py
Lib/test/test_winconsoleio.py
Misc/NEWS.d/next/Core and Builtins/2022-01-23-18-00-10.bpo-21861.N8E1zw.rst [new file with mode: 0644]
Modules/_io/fileio.c
Modules/_io/textio.c
Modules/_io/winconsoleio.c

index f490485cdaf3ebd0c468f70042700351b30cf908..06d9b454add34cd380e45e5af32caae8f0b889c4 100644 (file)
@@ -174,6 +174,16 @@ class AutoFileTests:
         self.assertEqual(repr(self.f),
                          "<%s.FileIO [closed]>" % (self.modulename,))
 
+    def test_subclass_repr(self):
+        class TestSubclass(self.FileIO):
+            pass
+
+        f = TestSubclass(TESTFN)
+        with f:
+            self.assertIn(TestSubclass.__name__, repr(f))
+
+        self.assertIn(TestSubclass.__name__, repr(f))
+
     def testReprNoCloseFD(self):
         fd = os.open(TESTFN, os.O_RDONLY)
         try:
index ca31b9dad2631a266bba460f7fb4d10e1011b67a..936edea3cad70c6df7e7bd0dce3b826fc9194b47 100644 (file)
@@ -2806,6 +2806,13 @@ class TextIOWrapperTest(unittest.TestCase):
             with self.assertRaises(RuntimeError):
                 repr(t)  # Should not crash
 
+    def test_subclass_repr(self):
+        class TestSubclass(self.TextIOWrapper):
+            pass
+
+        f = TestSubclass(self.StringIO())
+        self.assertIn(TestSubclass.__name__, repr(f))
+
     def test_line_buffering(self):
         r = self.BytesIO()
         b = self.BufferedWriter(r, 1000)
index 70a85552cc03b01ab37bce4defa964e7ceb7ee5a..72ff9606908ed5ac7cd66c70a238864da67e0688 100644 (file)
@@ -98,6 +98,16 @@ class WindowsConsoleIOTests(unittest.TestCase):
             self.assertIsInstance(f, ConIO)
             f.close()
 
+    def test_subclass_repr(self):
+        class TestSubclass(ConIO):
+            pass
+
+        f = TestSubclass("CON")
+        with f:
+            self.assertIn(TestSubclass.__name__, repr(f))
+
+        self.assertIn(TestSubclass.__name__, repr(f))
+
     @unittest.skipIf(sys.getwindowsversion()[:2] <= (6, 1),
         "test does not work on Windows 7 and earlier")
     def test_conin_conout_names(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-23-18-00-10.bpo-21861.N8E1zw.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-23-18-00-10.bpo-21861.N8E1zw.rst
new file mode 100644 (file)
index 0000000..5d99845
--- /dev/null
@@ -0,0 +1,3 @@
+Use the object's actual class name in :meth:`_io.FileIO.__repr__`,
+:meth:`_io._WindowsConsoleIO` and :meth:`_io.TextIOWrapper.__repr__`, to
+make these methods subclass friendly.
index 8a73ea0365b7a30fa6c9e467fba59707152b82a4..af4375c3640679002f4d88672fa02f623d5d6d33 100644 (file)
@@ -1100,31 +1100,32 @@ static PyObject *
 fileio_repr(fileio *self)
 {
     PyObject *nameobj, *res;
+    const char *type_name = Py_TYPE((PyObject *) self)->tp_name;
 
-    if (self->fd < 0)
-        return PyUnicode_FromFormat("<_io.FileIO [closed]>");
+    if (self->fd < 0) {
+        return PyUnicode_FromFormat("<%.100s [closed]>", type_name);
+    }
 
     if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) {
         return NULL;
     }
     if (nameobj == NULL) {
         res = PyUnicode_FromFormat(
-            "<_io.FileIO fd=%d mode='%s' closefd=%s>",
-            self->fd, mode_string(self), self->closefd ? "True" : "False");
+            "<%.100s fd=%d mode='%s' closefd=%s>",
+            type_name, self->fd, mode_string(self), self->closefd ? "True" : "False");
     }
     else {
         int status = Py_ReprEnter((PyObject *)self);
         res = NULL;
         if (status == 0) {
             res = PyUnicode_FromFormat(
-                "<_io.FileIO name=%R mode='%s' closefd=%s>",
-                nameobj, mode_string(self), self->closefd ? "True" : "False");
+                "<%.100s name=%R mode='%s' closefd=%s>",
+                type_name, nameobj, mode_string(self), self->closefd ? "True" : "False");
             Py_ReprLeave((PyObject *)self);
         }
         else if (status > 0) {
             PyErr_Format(PyExc_RuntimeError,
-                         "reentrant call inside %s.__repr__",
-                         Py_TYPE(self)->tp_name);
+                         "reentrant call inside %.100s.__repr__", type_name);
         }
         Py_DECREF(nameobj);
     }
index e93c3e091549db5f7b73b4b68092c5e8c6ae0068..d794af8de2b8f021a5b9db09dcda7af940a66644 100644 (file)
@@ -2948,10 +2948,11 @@ textiowrapper_repr(textio *self)
 {
     PyObject *nameobj, *modeobj, *res, *s;
     int status;
+    const char *type_name = Py_TYPE(self)->tp_name;
 
     CHECK_INITIALIZED(self);
 
-    res = PyUnicode_FromString("<_io.TextIOWrapper");
+    res = PyUnicode_FromFormat("<%.100s", type_name);
     if (res == NULL)
         return NULL;
 
@@ -2959,8 +2960,8 @@ textiowrapper_repr(textio *self)
     if (status != 0) {
         if (status > 0) {
             PyErr_Format(PyExc_RuntimeError,
-                         "reentrant call inside %s.__repr__",
-                         Py_TYPE(self)->tp_name);
+                         "reentrant call inside %.100s.__repr__",
+                         type_name);
         }
         goto error;
     }
index 6680488b740cfc612c373dfc5989fceeea677879..fecb33895707807241cfb1ef1961b1662bbb6222 100644 (file)
@@ -1070,15 +1070,22 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls,
 static PyObject *
 winconsoleio_repr(winconsoleio *self)
 {
-    if (self->fd == -1)
-        return PyUnicode_FromFormat("<_io._WindowsConsoleIO [closed]>");
-
-    if (self->readable)
-        return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='rb' closefd=%s>",
-            self->closefd ? "True" : "False");
-    if (self->writable)
-        return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='wb' closefd=%s>",
-            self->closefd ? "True" : "False");
+    const char *type_name = (Py_TYPE((PyObject *)self)->tp_name);
+
+    if (self->fd == -1) {
+        return PyUnicode_FromFormat("<%.100s [closed]>", type_name);
+    }
+
+    if (self->readable) {
+        return PyUnicode_FromFormat("<%.100s mode='rb' closefd=%s>",
+                                    type_name,
+                                    self->closefd ? "True" : "False");
+    }
+    if (self->writable) {
+        return PyUnicode_FromFormat("<%.100s mode='wb' closefd=%s>",
+                                    type_name,
+                                    self->closefd ? "True" : "False");
+    }
 
     PyErr_SetString(PyExc_SystemError, "_WindowsConsoleIO has invalid mode");
     return NULL;