Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7665be6

Browse files
Issue #21802: The reader in BufferedRWPair now is closed even when closing
writer failed in BufferedRWPair.close().
1 parent 8ffe917 commit 7665be6

4 files changed

Lines changed: 64 additions & 6 deletions

File tree

Lib/_pyio.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,8 +1230,10 @@ def flush(self):
12301230
return self.writer.flush()
12311231

12321232
def close(self):
1233-
self.writer.close()
1234-
self.reader.close()
1233+
try:
1234+
self.writer.close()
1235+
finally:
1236+
self.reader.close()
12351237

12361238
def isatty(self):
12371239
return self.reader.isatty() or self.writer.isatty()

Lib/test/test_io.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,53 @@ def test_close_and_closed(self):
15881588
pair.close()
15891589
self.assertTrue(pair.closed)
15901590

1591+
def test_reader_close_error_on_close(self):
1592+
def reader_close():
1593+
reader_non_existing
1594+
reader = self.MockRawIO()
1595+
reader.close = reader_close
1596+
writer = self.MockRawIO()
1597+
pair = self.tp(reader, writer)
1598+
with self.assertRaises(NameError) as err:
1599+
pair.close()
1600+
self.assertIn('reader_non_existing', str(err.exception))
1601+
self.assertTrue(pair.closed)
1602+
self.assertFalse(reader.closed)
1603+
self.assertTrue(writer.closed)
1604+
1605+
def test_writer_close_error_on_close(self):
1606+
def writer_close():
1607+
writer_non_existing
1608+
reader = self.MockRawIO()
1609+
writer = self.MockRawIO()
1610+
writer.close = writer_close
1611+
pair = self.tp(reader, writer)
1612+
with self.assertRaises(NameError) as err:
1613+
pair.close()
1614+
self.assertIn('writer_non_existing', str(err.exception))
1615+
self.assertFalse(pair.closed)
1616+
self.assertTrue(reader.closed)
1617+
self.assertFalse(writer.closed)
1618+
1619+
def test_reader_writer_close_error_on_close(self):
1620+
def reader_close():
1621+
reader_non_existing
1622+
def writer_close():
1623+
writer_non_existing
1624+
reader = self.MockRawIO()
1625+
reader.close = reader_close
1626+
writer = self.MockRawIO()
1627+
writer.close = writer_close
1628+
pair = self.tp(reader, writer)
1629+
with self.assertRaises(NameError) as err:
1630+
pair.close()
1631+
self.assertIn('reader_non_existing', str(err.exception))
1632+
self.assertIsInstance(err.exception.__context__, NameError)
1633+
self.assertIn('writer_non_existing', str(err.exception.__context__))
1634+
self.assertFalse(pair.closed)
1635+
self.assertFalse(reader.closed)
1636+
self.assertFalse(writer.closed)
1637+
15911638
def test_isatty(self):
15921639
class SelectableIsAtty(MockRawIO):
15931640
def __init__(self, isatty):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Core and Builtins
1818
Library
1919
-------
2020

21+
- Issue #21802: The reader in BufferedRWPair now is closed even when closing
22+
writer failed in BufferedRWPair.close().
23+
2124
- Issue #23671: string.Template now allows to specify the "self" parameter as
2225
keyword argument. string.Formatter now allows to specify the "self" and
2326
the "format_string" parameters as keyword arguments.

Modules/_io/bufferedio.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,12 +2365,18 @@ bufferedrwpair_writable(rwpair *self, PyObject *args)
23652365
static PyObject *
23662366
bufferedrwpair_close(rwpair *self, PyObject *args)
23672367
{
2368+
PyObject *exc = NULL, *val, *tb;
23682369
PyObject *ret = _forward_call(self->writer, &PyId_close, args);
23692370
if (ret == NULL)
2370-
return NULL;
2371-
Py_DECREF(ret);
2372-
2373-
return _forward_call(self->reader, &PyId_close, args);
2371+
PyErr_Fetch(&exc, &val, &tb);
2372+
else
2373+
Py_DECREF(ret);
2374+
ret = _forward_call(self->reader, &PyId_close, args);
2375+
if (exc != NULL) {
2376+
_PyErr_ChainExceptions(exc, val, tb);
2377+
Py_CLEAR(ret);
2378+
}
2379+
return ret;
23742380
}
23752381

23762382
static PyObject *

0 commit comments

Comments
 (0)