# HG changeset patch # Parent 4e84e45e191b3b063387fdd68075f47f4576e215 Operations independent of the detached stream should continue to work diff -r 4e84e45e191b Lib/test/test_io.py --- a/Lib/test/test_io.py Fri Dec 19 11:21:56 2014 -0500 +++ b/Lib/test/test_io.py Sat Dec 20 13:52:34 2014 +0000 @@ -697,6 +697,8 @@ self.assertIs(buf.detach(), raw) self.assertRaises(ValueError, buf.detach) + repr(buf) # Should still work + def test_fileno(self): rawio = self.MockRawIO() bufio = self.tp(rawio) @@ -2087,6 +2089,12 @@ self.assertEqual(r.getvalue(), b"howdy") self.assertRaises(ValueError, t.detach) + # Operations independent of the detached stream should still work + repr(t) + self.assertEqual(t.encoding, "ascii") + self.assertEqual(t.errors, "strict") + self.assertFalse(t.line_buffering) + def test_repr(self): raw = self.BytesIO("hello".encode("utf-8")) b = self.BufferedReader(raw) @@ -2904,6 +2912,9 @@ self.assertRaises(ValueError, t.__init__, b, newline='xyzzy') self.assertRaises(ValueError, t.read) + t = self.TextIOWrapper.__new__(self.TextIOWrapper) + self.assertRaises(Exception, repr, t) + def test_garbage_collection(self): # C TextIOWrapper objects are collected, and collecting them flushes # all data to disk. diff -r 4e84e45e191b Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Fri Dec 19 11:21:56 2014 -0500 +++ b/Modules/_io/bufferedio.c Sat Dec 20 13:52:34 2014 +0000 @@ -1400,14 +1400,18 @@ static PyObject * buffered_repr(buffered *self) { - PyObject *nameobj, *res; + PyObject *nameobj = NULL, *res; - nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); + if (self->ok) { + nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); + if (nameobj == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + return NULL; + } + } if (nameobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_Clear(); - else - return NULL; res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name); } else { diff -r 4e84e45e191b Modules/_io/textio.c --- a/Modules/_io/textio.c Fri Dec 19 11:21:56 2014 -0500 +++ b/Modules/_io/textio.c Sat Dec 20 13:52:34 2014 +0000 @@ -1219,25 +1219,27 @@ #define CHECK_INITIALIZED(self) \ if (self->ok <= 0) { \ - if (self->detached) { \ - PyErr_SetString(PyExc_ValueError, \ - "underlying buffer has been detached"); \ - } else { \ - PyErr_SetString(PyExc_ValueError, \ - "I/O operation on uninitialized object"); \ - } \ + PyErr_SetString(PyExc_ValueError, \ + "I/O operation on uninitialized object"); \ return NULL; \ } -#define CHECK_INITIALIZED_INT(self) \ +#define CHECK_ATTACHED(self) \ + CHECK_INITIALIZED(self); \ + if (self->detached) { \ + PyErr_SetString(PyExc_ValueError, \ + "underlying buffer has been detached"); \ + return NULL; \ + } + +#define CHECK_ATTACHED_INT(self) \ if (self->ok <= 0) { \ - if (self->detached) { \ - PyErr_SetString(PyExc_ValueError, \ - "underlying buffer has been detached"); \ - } else { \ - PyErr_SetString(PyExc_ValueError, \ - "I/O operation on uninitialized object"); \ - } \ + PyErr_SetString(PyExc_ValueError, \ + "I/O operation on uninitialized object"); \ + return -1; \ + } else if (self->detached) { \ + PyErr_SetString(PyExc_ValueError, \ + "underlying buffer has been detached"); \ return -1; \ } @@ -1246,7 +1248,7 @@ textiowrapper_detach(textio *self) { PyObject *buffer, *res; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); if (res == NULL) return NULL; @@ -1254,7 +1256,6 @@ buffer = self->buffer; self->buffer = NULL; self->detached = 1; - self->ok = 0; return buffer; } @@ -1299,7 +1300,7 @@ int haslf = 0; int needflush = 0, text_needflush = 0; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); if (!PyArg_ParseTuple(args, "U:write", &text)) { return NULL; @@ -1562,7 +1563,7 @@ Py_ssize_t n = -1; PyObject *result = NULL, *chunks = NULL; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) return NULL; @@ -1937,7 +1938,7 @@ { Py_ssize_t limit = -1; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); if (!PyArg_ParseTuple(args, "|n:readline", &limit)) { return NULL; } @@ -2075,7 +2076,7 @@ PyObject *res; int cmp; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence)) return NULL; @@ -2255,7 +2256,7 @@ Py_ssize_t dec_buffer_len; int dec_flags; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); CHECK_CLOSED(self); if (!self->seekable) { @@ -2458,7 +2459,7 @@ PyObject *pos = Py_None; PyObject *res; - CHECK_INITIALIZED(self) + CHECK_ATTACHED(self) if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) { return NULL; } @@ -2481,37 +2482,40 @@ res = PyUnicode_FromString("<_io.TextIOWrapper"); if (res == NULL) return NULL; - nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); - if (nameobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_Clear(); - else - goto error; - } - else { - s = PyUnicode_FromFormat(" name=%R", nameobj); - Py_DECREF(nameobj); - if (s == NULL) - goto error; - PyUnicode_AppendAndDel(&res, s); - if (res == NULL) - return NULL; - } - modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode); - if (modeobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_Clear(); - else - goto error; - } - else { - s = PyUnicode_FromFormat(" mode=%R", modeobj); - Py_DECREF(modeobj); - if (s == NULL) - goto error; - PyUnicode_AppendAndDel(&res, s); - if (res == NULL) - return NULL; + + if (!self->detached) { + nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); + if (nameobj == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto error; + } + else { + s = PyUnicode_FromFormat(" name=%R", nameobj); + Py_DECREF(nameobj); + if (s == NULL) + goto error; + PyUnicode_AppendAndDel(&res, s); + if (res == NULL) + return NULL; + } + modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode); + if (modeobj == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto error; + } + else { + s = PyUnicode_FromFormat(" mode=%R", modeobj); + Py_DECREF(modeobj); + if (s == NULL) + goto error; + PyUnicode_AppendAndDel(&res, s); + if (res == NULL) + return NULL; + } } s = PyUnicode_FromFormat("%U encoding=%R>", res, self->encoding); @@ -2528,35 +2532,35 @@ static PyObject * textiowrapper_fileno(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_fileno, NULL); } static PyObject * textiowrapper_seekable(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_seekable, NULL); } static PyObject * textiowrapper_readable(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_readable, NULL); } static PyObject * textiowrapper_writable(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_writable, NULL); } static PyObject * textiowrapper_isatty(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_isatty, NULL); } @@ -2571,7 +2575,7 @@ static PyObject * textiowrapper_flush(textio *self, PyObject *args) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); CHECK_CLOSED(self); self->telling = self->seekable; if (_textiowrapper_writeflush(self) < 0) @@ -2584,7 +2588,7 @@ { PyObject *res; int r; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); res = textiowrapper_closed_get(self, NULL); if (res == NULL) @@ -2626,7 +2630,7 @@ { PyObject *line; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); self->telling = 0; if (Py_TYPE(self) == &PyTextIOWrapper_Type) { @@ -2662,14 +2666,14 @@ static PyObject * textiowrapper_name_get(textio *self, void *context) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return _PyObject_GetAttrId(self->buffer, &PyId_name); } static PyObject * textiowrapper_closed_get(textio *self, void *context) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return PyObject_GetAttr(self->buffer, _PyIO_str_closed); } @@ -2677,7 +2681,7 @@ textiowrapper_newlines_get(textio *self, void *context) { PyObject *res; - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); if (self->decoder == NULL) Py_RETURN_NONE; res = PyObject_GetAttr(self->decoder, _PyIO_str_newlines); @@ -2703,7 +2707,7 @@ static PyObject * textiowrapper_chunk_size_get(textio *self, void *context) { - CHECK_INITIALIZED(self); + CHECK_ATTACHED(self); return PyLong_FromSsize_t(self->chunk_size); } @@ -2711,7 +2715,7 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) { Py_ssize_t n; - CHECK_INITIALIZED_INT(self); + CHECK_ATTACHED_INT(self); n = PyNumber_AsSsize_t(arg, PyExc_ValueError); if (n == -1 && PyErr_Occurred()) return -1;