Issue #5761: Add the name of the underlying file to the repr() of various IO objects.

This commit is contained in:
Antoine Pitrou 2009-05-23 19:04:03 +00:00
parent 744af44064
commit 716c444edc
7 changed files with 107 additions and 14 deletions

View File

@ -736,6 +736,15 @@ class _BufferedIOMixin(BufferedIOBase):
def mode(self):
return self.raw.mode
def __repr__(self):
clsname = self.__class__.__name__
try:
name = self.name
except AttributeError:
return "<_pyio.{0}>".format(clsname)
else:
return "<_pyio.{0} name={1!r}>".format(clsname, name)
### Lower-level APIs ###
def fileno(self):
@ -1455,7 +1464,13 @@ class TextIOWrapper(TextIOBase):
# - "chars_..." for integer variables that count decoded characters
def __repr__(self):
return "<TextIOWrapper encoding={0}>".format(self.encoding)
try:
name = self.name
except AttributeError:
return "<_pyio.TextIOWrapper encoding={0!r}>".format(self.encoding)
else:
return "<_pyio.TextIOWrapper name={0!r} encoding={1!r}>".format(
name, self.encoding)
@property
def encoding(self):

View File

@ -70,9 +70,13 @@ class AutoFileTests(unittest.TestCase):
self.assertEquals(array('b', [1, 2]), a[:n])
def testRepr(self):
self.assertEquals(repr(self.f),
"io.FileIO(%d, %s)" % (self.f.fileno(),
repr(self.f.mode)))
self.assertEquals(repr(self.f), "<_io.FileIO name=%r mode=%r>"
% (self.f.name, self.f.mode))
del self.f.name
self.assertEquals(repr(self.f), "<_io.FileIO fd=%r mode=%r>"
% (self.f.fileno(), self.f.mode))
self.f.close()
self.assertEquals(repr(self.f), "<_io.FileIO [closed]>")
def testErrors(self):
f = self.f

View File

@ -618,6 +618,16 @@ class CommonBufferedTests:
self.assert_(s.startswith("Exception IOError: "), s)
self.assert_(s.endswith(" ignored"), s)
def test_repr(self):
raw = self.MockRawIO()
b = self.tp(raw)
clsname = "%s.%s" % (self.tp.__module__, self.tp.__name__)
self.assertEqual(repr(b), "<%s>" % clsname)
raw.name = "dummy"
self.assertEqual(repr(b), "<%s name='dummy'>" % clsname)
raw.name = b"dummy"
self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname)
class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
read_mode = "rb"
@ -1528,7 +1538,15 @@ class TextIOWrapperTest(unittest.TestCase):
raw = self.BytesIO("hello".encode("utf-8"))
b = self.BufferedReader(raw)
t = self.TextIOWrapper(b, encoding="utf-8")
self.assertEqual(repr(t), "<TextIOWrapper encoding=utf-8>")
modname = self.TextIOWrapper.__module__
self.assertEqual(repr(t),
"<%s.TextIOWrapper encoding='utf-8'>" % modname)
raw.name = "dummy"
self.assertEqual(repr(t),
"<%s.TextIOWrapper name='dummy' encoding='utf-8'>" % modname)
raw.name = b"dummy"
self.assertEqual(repr(t),
"<%s.TextIOWrapper name=b'dummy' encoding='utf-8'>" % modname)
def test_line_buffering(self):
r = self.BytesIO()

View File

@ -32,6 +32,9 @@ Core and Builtins
Library
-------
- Issue #5761: Add the name of the underlying file to the repr() of various
IO objects.
- Issue #5259: smtplib plain auth login no longer gives a traceback. Fix
by Musashi Tamura, tests by Marcin Bachry.

View File

@ -1123,6 +1123,27 @@ Buffered_iternext(BufferedObject *self)
return line;
}
static PyObject *
Buffered_repr(BufferedObject *self)
{
PyObject *nameobj, *res;
nameobj = PyObject_GetAttrString((PyObject *) self, "name");
if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
else
return NULL;
res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
}
else {
res = PyUnicode_FromFormat("<%s name=%R>",
Py_TYPE(self)->tp_name, nameobj);
Py_DECREF(nameobj);
}
return res;
}
/*
* class BufferedReader
*/
@ -1472,7 +1493,7 @@ PyTypeObject PyBufferedReader_Type = {
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
(reprfunc)Buffered_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
@ -1828,7 +1849,7 @@ PyTypeObject PyBufferedWriter_Type = {
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
(reprfunc)Buffered_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
@ -2219,7 +2240,7 @@ PyTypeObject PyBufferedRandom_Type = {
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
(reprfunc)Buffered_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/

View File

@ -846,11 +846,26 @@ mode_string(PyFileIOObject *self)
static PyObject *
fileio_repr(PyFileIOObject *self)
{
if (self->fd < 0)
return PyUnicode_FromFormat("io.FileIO(-1)");
PyObject *nameobj, *res;
return PyUnicode_FromFormat("io.FileIO(%d, '%s')",
self->fd, mode_string(self));
if (self->fd < 0)
return PyUnicode_FromFormat("<_io.FileIO [closed]>");
nameobj = PyObject_GetAttrString((PyObject *) self, "name");
if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
else
return NULL;
res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>",
self->fd, mode_string(self));
}
else {
res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>",
nameobj, mode_string(self));
Py_DECREF(nameobj);
}
return res;
}
static PyObject *

View File

@ -2308,8 +2308,25 @@ TextIOWrapper_truncate(PyTextIOWrapperObject *self, PyObject *args)
static PyObject *
TextIOWrapper_repr(PyTextIOWrapperObject *self)
{
CHECK_INITIALIZED(self);
return PyUnicode_FromFormat("<TextIOWrapper encoding=%S>", self->encoding);
PyObject *nameobj, *res;
CHECK_INITIALIZED(self);
nameobj = PyObject_GetAttrString((PyObject *) self, "name");
if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
else
return NULL;
res = PyUnicode_FromFormat("<_io.TextIOWrapper encoding=%R>",
self->encoding);
}
else {
res = PyUnicode_FromFormat("<_io.TextIOWrapper name=%R encoding=%R>",
nameobj, self->encoding);
Py_DECREF(nameobj);
}
return res;
}