cpython: f2cfa8a348dd (original) (raw)
--- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -812,7 +812,7 @@ class _BufferedIOMixin(BufferedIOBase): clsname = self.class.qualname try: name = self.name
except AttributeError:[](#l1.7)
except Exception:[](#l1.8) return "<{}.{}>".format(modname, clsname)[](#l1.9) else:[](#l1.10) return "<{}.{} name={!r}>".format(modname, clsname, name)[](#l1.11)
@@ -1640,13 +1640,13 @@ class TextIOWrapper(TextIOBase): self.class.qualname) try: name = self.name
except AttributeError:[](#l1.16)
except Exception:[](#l1.17) pass[](#l1.18) else:[](#l1.19) result += " name={0!r}".format(name)[](#l1.20) try:[](#l1.21) mode = self.mode[](#l1.22)
except AttributeError:[](#l1.23)
except Exception:[](#l1.24) pass[](#l1.25) else:[](#l1.26) result += " mode={0!r}".format(mode)[](#l1.27)
--- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -697,6 +697,8 @@ class CommonBufferedTests: self.assertIs(buf.detach(), raw) self.assertRaises(ValueError, buf.detach)
repr(buf) # Should still work[](#l2.7)
+ def test_fileno(self): rawio = self.MockRawIO() bufio = self.tp(rawio) @@ -2087,6 +2089,12 @@ class TextIOWrapperTest(unittest.TestCas self.assertEqual(r.getvalue(), b"howdy") self.assertRaises(ValueError, t.detach)
# Operations independent of the detached stream should still work[](#l2.16)
repr(t)[](#l2.17)
self.assertEqual(t.encoding, "ascii")[](#l2.18)
self.assertEqual(t.errors, "strict")[](#l2.19)
self.assertFalse(t.line_buffering)[](#l2.20)
+ def test_repr(self): raw = self.BytesIO("hello".encode("utf-8")) b = self.BufferedReader(raw) @@ -2104,6 +2112,9 @@ class TextIOWrapperTest(unittest.TestCas self.assertEqual(repr(t), "<%s.TextIOWrapper name=b'dummy' mode='r' encoding='utf-8'>" % modname)
t.buffer.detach()[](#l2.29)
repr(t) # Should not raise an exception[](#l2.30)
+ def test_line_buffering(self): r = self.BytesIO() b = self.BufferedWriter(r, 1000) @@ -2904,6 +2915,9 @@ class CTextIOWrapperTest(TextIOWrapperTe self.assertRaises(ValueError, t.init, b, newline='xyzzy') self.assertRaises(ValueError, t.read)
t = self.TextIOWrapper.__new__(self.TextIOWrapper)[](#l2.39)
self.assertRaises(Exception, repr, t)[](#l2.40)
+ def test_garbage_collection(self): # C TextIOWrapper objects are collected, and collecting them flushes # all data to disk.
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -196,6 +196,9 @@ Core and Builtins Library ------- +- Issue #23093: In the io, module allow more operations to work on detached
- Issue #22585: On OpenBSD 5.6 and newer, os.urandom() now calls getentropy(), instead of reading /dev/urandom, to get pseudo-random bytes.
--- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1404,7 +1404,7 @@ buffered_repr(buffered *self) nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name); if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))[](#l4.7)
if (PyErr_ExceptionMatches(PyExc_Exception))[](#l4.8) PyErr_Clear();[](#l4.9) else[](#l4.10) return NULL;[](#l4.11)
--- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1219,25 +1219,27 @@ textiowrapper_closed_get(textio *self, v #define CHECK_INITIALIZED(self) [](#l5.5) if (self->ok <= 0) { [](#l5.6)
if (self->detached) { \[](#l5.7)
PyErr_SetString(PyExc_ValueError, \[](#l5.8)
"underlying buffer has been detached"); \[](#l5.9)
} else { \[](#l5.10)
PyErr_SetString(PyExc_ValueError, \[](#l5.11)
"I/O operation on uninitialized object"); \[](#l5.12)
} \[](#l5.13)
PyErr_SetString(PyExc_ValueError, \[](#l5.14)
} -#define CHECK_INITIALIZED_INT(self) [](#l5.19) +#define CHECK_ATTACHED(self) [](#l5.20)"I/O operation on uninitialized object"); \[](#l5.15) return NULL; \[](#l5.16)
- CHECK_INITIALIZED(self); [](#l5.21)
- if (self->detached) { [](#l5.22)
PyErr_SetString(PyExc_ValueError, \[](#l5.23)
"underlying buffer has been detached"); \[](#l5.24)
return NULL; \[](#l5.25)
- }
+ +#define CHECK_ATTACHED_INT(self) [](#l5.28) if (self->ok <= 0) { [](#l5.29)
if (self->detached) { \[](#l5.30)
PyErr_SetString(PyExc_ValueError, \[](#l5.31)
"underlying buffer has been detached"); \[](#l5.32)
} else { \[](#l5.33)
PyErr_SetString(PyExc_ValueError, \[](#l5.34)
"I/O operation on uninitialized object"); \[](#l5.35)
} \[](#l5.36)
PyErr_SetString(PyExc_ValueError, \[](#l5.37)
"I/O operation on uninitialized object"); \[](#l5.38)
return -1; \[](#l5.39)
- } else if (self->detached) { [](#l5.40)
PyErr_SetString(PyExc_ValueError, \[](#l5.41)
} @@ -1246,7 +1248,7 @@ static PyObject * textiowrapper_detach(textio *self) { PyObject *buffer, *res;"underlying buffer has been detached"); \[](#l5.42) return -1; \[](#l5.43)
- CHECK_ATTACHED(self); res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); if (res == NULL) return NULL;
@@ -1254,7 +1256,6 @@ textiowrapper_detach(textio *self) buffer = self->buffer; self->buffer = NULL; self->detached = 1;
@@ -1299,7 +1300,7 @@ textiowrapper_write(textio *self, PyObje int haslf = 0; int needflush = 0, text_needflush = 0;
if (!PyArg_ParseTuple(args, "U:write", &text)) { return NULL; @@ -1562,7 +1563,7 @@ textiowrapper_read(textio *self, PyObjec Py_ssize_t n = -1; PyObject *result = NULL, *chunks = NULL;
if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) return NULL; @@ -1937,7 +1938,7 @@ textiowrapper_readline(textio *self, PyO { Py_ssize_t limit = -1;
- CHECK_ATTACHED(self); if (!PyArg_ParseTuple(args, "|n:readline", &limit)) { return NULL; } @@ -2075,7 +2076,7 @@ textiowrapper_seek(textio *self, PyObjec PyObject *res; int cmp;
if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence)) return NULL; @@ -2255,7 +2256,7 @@ textiowrapper_tell(textio *self, PyObjec Py_ssize_t dec_buffer_len; int dec_flags;
- CHECK_ATTACHED(self); CHECK_CLOSED(self); if (!self->seekable) { @@ -2458,7 +2459,7 @@ textiowrapper_truncate(textio *self, PyO PyObject *pos = Py_None; PyObject *res;
- CHECK_ATTACHED(self) if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) { return NULL; } @@ -2481,9 +2482,10 @@ textiowrapper_repr(textio *self) 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))[](#l5.124)
if (PyErr_ExceptionMatches(PyExc_Exception))[](#l5.125) PyErr_Clear();[](#l5.126) else[](#l5.127) goto error;[](#l5.128)
@@ -2499,7 +2501,7 @@ textiowrapper_repr(textio *self) } modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode); if (modeobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))[](#l5.133)
if (PyErr_ExceptionMatches(PyExc_Exception))[](#l5.134) PyErr_Clear();[](#l5.135) else[](#l5.136) goto error;[](#l5.137)
@@ -2528,35 +2530,35 @@ error: static PyObject * textiowrapper_fileno(textio *self, PyObject *args) {
static PyObject * textiowrapper_seekable(textio *self, PyObject *args) {
static PyObject * textiowrapper_readable(textio *self, PyObject *args) {
static PyObject * textiowrapper_writable(textio *self, PyObject *args) {
static PyObject * textiowrapper_isatty(textio *self, PyObject *args) {
@@ -2571,7 +2573,7 @@ textiowrapper_getstate(textio *self, PyO static PyObject * textiowrapper_flush(textio *self, PyObject *args) {
- CHECK_ATTACHED(self); CHECK_CLOSED(self); self->telling = self->seekable; if (_textiowrapper_writeflush(self) < 0) @@ -2584,7 +2586,7 @@ textiowrapper_close(textio *self, PyObje { PyObject *res; int r;
res = textiowrapper_closed_get(self, NULL); if (res == NULL) @@ -2626,7 +2628,7 @@ textiowrapper_iternext(textio *self) { PyObject *line;
self->telling = 0; if (Py_TYPE(self) == &PyTextIOWrapper_Type) { @@ -2662,14 +2664,14 @@ textiowrapper_iternext(textio *self) static PyObject * textiowrapper_name_get(textio *self, void *context) {
static PyObject * textiowrapper_closed_get(textio *self, void *context) {
@@ -2677,7 +2679,7 @@ static PyObject * textiowrapper_newlines_get(textio *self, void *context) { PyObject *res;
- CHECK_ATTACHED(self); if (self->decoder == NULL) Py_RETURN_NONE; res = PyObject_GetAttr(self->decoder, _PyIO_str_newlines); @@ -2703,7 +2705,7 @@ textiowrapper_errors_get(textio *self, v static PyObject * textiowrapper_chunk_size_get(textio *self, void *context) {
@@ -2711,7 +2713,7 @@ static int textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) { Py_ssize_t n;