Skip to content

Commit c15a682

Browse files
authored
bpo-37223: test_io: silence destructor errors (GH-14031)
* bpo-18748: Fix _pyio.IOBase destructor (closed case) (GH-13952) _pyio.IOBase destructor now does nothing if getting the closed attribute fails to better mimick _io.IOBase finalizer. (cherry picked from commit 4f6f7c5) * bpo-37223: test_io: silence destructor errors (GH-13954) Implement also MockNonBlockWriterIO.seek() method. (cherry picked from commit b589cef) * bpo-37223, test_io: silence last 'Exception ignored in:' (GH-14029) Use catch_unraisable_exception() to ignore 'Exception ignored in:' error when the internal BufferedWriter of the BufferedRWPair is destroyed. The C implementation doesn't give access to the internal BufferedWriter, so just ignore the warning instead. (cherry picked from commit 913fa1c)
1 parent 3955dff commit c15a682

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

Lib/_pyio.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,16 @@ def close(self):
405405

406406
def __del__(self):
407407
"""Destructor. Calls close()."""
408+
try:
409+
closed = self.closed
410+
except Exception:
411+
# If getting closed fails, then the object is probably
412+
# in an unusable state, so ignore.
413+
return
414+
415+
if closed:
416+
return
417+
408418
if _IOBASE_EMITS_UNRAISABLE:
409419
self.close()
410420
else:

Lib/test/test_io.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ def readable(self):
277277
def seekable(self):
278278
return True
279279

280+
def seek(self, pos, whence=0):
281+
# naive implementation, enough for tests
282+
return 0
283+
280284
def writable(self):
281285
return True
282286

@@ -1486,6 +1490,9 @@ def test_misbehaved_io(self):
14861490
self.assertRaises(OSError, bufio.seek, 0)
14871491
self.assertRaises(OSError, bufio.tell)
14881492

1493+
# Silence destructor error
1494+
bufio.close = lambda: None
1495+
14891496
def test_no_extraneous_read(self):
14901497
# Issue #9550; when the raw IO object has satisfied the read request,
14911498
# we should not issue any additional reads, otherwise it may block
@@ -1834,6 +1841,9 @@ def test_misbehaved_io(self):
18341841
self.assertRaises(OSError, bufio.tell)
18351842
self.assertRaises(OSError, bufio.write, b"abcdef")
18361843

1844+
# Silence destructor error
1845+
bufio.close = lambda: None
1846+
18371847
def test_max_buffer_size_removal(self):
18381848
with self.assertRaises(TypeError):
18391849
self.tp(self.MockRawIO(), 8, 12)
@@ -2060,6 +2070,11 @@ def writer_close():
20602070

20612071
# Silence destructor error
20622072
writer.close = lambda: None
2073+
writer = None
2074+
2075+
with support.catch_unraisable_exception():
2076+
pair = None
2077+
support.gc_collect()
20632078

20642079
def test_reader_writer_close_error_on_close(self):
20652080
def reader_close():
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`_pyio.IOBase` destructor now does nothing if getting the ``closed``
2+
attribute fails to better mimick :class:`_io.IOBase` finalizer.

0 commit comments

Comments
 (0)