From c7c65823ad3bf5b6b823b9c7370768ec1c0720ef Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 11 Jun 2019 02:49:06 +0200 Subject: [PATCH 1/3] 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 4f6f7c5a611905fb6b81671547f268c226bc646a) --- Lib/_pyio.py | 10 ++++++++++ .../Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst | 2 ++ 2 files changed, 12 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst diff --git a/Lib/_pyio.py b/Lib/_pyio.py index 43c24342ad6162..0b6493bc8dc926 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -405,6 +405,16 @@ def close(self): def __del__(self): """Destructor. Calls close().""" + try: + closed = self.closed + except Exception: + # If getting closed fails, then the object is probably + # in an unusable state, so ignore. + return + + if closed: + return + if _IOBASE_EMITS_UNRAISABLE: self.close() else: diff --git a/Misc/NEWS.d/next/Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst b/Misc/NEWS.d/next/Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst new file mode 100644 index 00000000000000..295ddebb2a4015 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst @@ -0,0 +1,2 @@ +:class:`_pyio.IOBase` destructor now does nothing if getting the ``closed`` +attribute fails to better mimick :class:`_io.IOBase` finalizer. From 1a2087105f313b2de294e4ce21aa751bbd71cf44 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 11 Jun 2019 03:10:59 +0200 Subject: [PATCH 2/3] bpo-37223: test_io: silence destructor errors (GH-13954) Implement also MockNonBlockWriterIO.seek() method. (cherry picked from commit b589cef9c4dada2fb84ce0fae5040ecf16d9d5ef) --- Lib/test/test_io.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 3a1f5ba5b6663d..102679b1d34243 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -277,6 +277,10 @@ def readable(self): def seekable(self): return True + def seek(self, pos, whence=0): + # naive implementation, enough for tests + return 0 + def writable(self): return True @@ -1486,6 +1490,9 @@ def test_misbehaved_io(self): self.assertRaises(OSError, bufio.seek, 0) self.assertRaises(OSError, bufio.tell) + # Silence destructor error + bufio.close = lambda: None + def test_no_extraneous_read(self): # Issue #9550; when the raw IO object has satisfied the read request, # we should not issue any additional reads, otherwise it may block @@ -1834,6 +1841,9 @@ def test_misbehaved_io(self): self.assertRaises(OSError, bufio.tell) self.assertRaises(OSError, bufio.write, b"abcdef") + # Silence destructor error + bufio.close = lambda: None + def test_max_buffer_size_removal(self): with self.assertRaises(TypeError): self.tp(self.MockRawIO(), 8, 12) From fdc4855815e5cd0366b3da96cc048b57fd316c1f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 12 Jun 2019 23:57:11 +0200 Subject: [PATCH 3/3] 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 913fa1c8245d1cde6edb4254f4fb965cc91786ef) --- Lib/test/test_io.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 102679b1d34243..55686d74398355 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2070,6 +2070,11 @@ def writer_close(): # Silence destructor error writer.close = lambda: None + writer = None + + with support.catch_unraisable_exception(): + pair = None + support.gc_collect() def test_reader_writer_close_error_on_close(self): def reader_close():