]> granicus.if.org Git - python/commitdiff
bpo-37223: test_io: silence destructor errors (GH-14031)
authorVictor Stinner <vstinner@redhat.com>
Wed, 12 Jun 2019 22:23:49 +0000 (00:23 +0200)
committerGitHub <noreply@github.com>
Wed, 12 Jun 2019 22:23:49 +0000 (00:23 +0200)
* 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)

* bpo-37223: test_io: silence destructor errors (GH-13954)

Implement also MockNonBlockWriterIO.seek() method.

(cherry picked from commit b589cef9c4dada2fb84ce0fae5040ecf16d9d5ef)

* 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/_pyio.py
Lib/test/test_io.py
Misc/NEWS.d/next/Library/2019-06-11-01-54-19.bpo-18748.ADqCkq.rst [new file with mode: 0644]

index 43c24342ad6162ce97bc93a20fd105a3500c5f1e..0b6493bc8dc926281803f955c4eb99c358512ce7 100644 (file)
@@ -405,6 +405,16 @@ class IOBase(metaclass=abc.ABCMeta):
 
     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:
index 3a1f5ba5b6663d5cea385179dc46ad3fb0336dba..55686d743983556a48e3fe29abe301a6bd06d0d8 100644 (file)
@@ -277,6 +277,10 @@ class MockNonBlockWriterIO:
     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 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
         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 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
         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)
@@ -2060,6 +2070,11 @@ class BufferedRWPairTest(unittest.TestCase):
 
         # 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():
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 (file)
index 0000000..295ddeb
--- /dev/null
@@ -0,0 +1,2 @@
+:class:`_pyio.IOBase` destructor now does nothing if getting the ``closed``
+attribute fails to better mimick :class:`_io.IOBase` finalizer.