Kaydet (Commit) 01a255ad authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Merged revisions 80720 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r80720 | antoine.pitrou | 2010-05-03 18:25:33 +0200 (lun., 03 mai 2010) | 5 lines

  Issue #7865: The close() method of :mod:`io` objects should not swallow
  exceptions raised by the implicit flush().  Also ensure that calling
  close() several times is supported.  Patch by Pascal Chambon.
........
üst 2f49f4eb
...@@ -368,6 +368,9 @@ class IOBase(object): ...@@ -368,6 +368,9 @@ class IOBase(object):
This is not implemented for read-only and non-blocking streams. This is not implemented for read-only and non-blocking streams.
""" """
if self.__closed:
raise ValueError("flush of closed file")
#self._checkClosed()
# XXX Should this return the number of bytes written??? # XXX Should this return the number of bytes written???
__closed = False __closed = False
...@@ -378,10 +381,7 @@ class IOBase(object): ...@@ -378,10 +381,7 @@ class IOBase(object):
This method has no effect if the file is already closed. This method has no effect if the file is already closed.
""" """
if not self.__closed: if not self.__closed:
try: self.flush()
self.flush()
except IOError:
pass # If flush() fails, just give up
self.__closed = True self.__closed = True
def __del__(self): def __del__(self):
...@@ -751,10 +751,7 @@ class _BufferedIOMixin(BufferedIOBase): ...@@ -751,10 +751,7 @@ class _BufferedIOMixin(BufferedIOBase):
def close(self): def close(self):
if not self.closed: if not self.closed:
try: self.flush()
self.flush()
except IOError:
pass # If flush() fails, just give up
self.raw.close() self.raw.close()
### Inquiries ### ### Inquiries ###
...@@ -1087,6 +1084,8 @@ class BufferedWriter(_BufferedIOMixin): ...@@ -1087,6 +1084,8 @@ class BufferedWriter(_BufferedIOMixin):
return self.raw.truncate(pos) return self.raw.truncate(pos)
def flush(self): def flush(self):
if self.closed:
raise ValueError("flush of closed file")
with self._write_lock: with self._write_lock:
self._flush_unlocked() self._flush_unlocked()
...@@ -1472,11 +1471,9 @@ class TextIOWrapper(TextIOBase): ...@@ -1472,11 +1471,9 @@ class TextIOWrapper(TextIOBase):
self._telling = self._seekable self._telling = self._seekable
def close(self): def close(self):
try: if not self.closed:
self.flush() self.flush()
except: self.buffer.close()
pass # If flush() fails, just give up
self.buffer.close()
@property @property
def closed(self): def closed(self):
......
...@@ -313,6 +313,20 @@ class IOTest(unittest.TestCase): ...@@ -313,6 +313,20 @@ class IOTest(unittest.TestCase):
file = io.open(f.fileno(), "r", closefd=False) file = io.open(f.fileno(), "r", closefd=False)
self.assertEqual(file.buffer.raw.closefd, False) self.assertEqual(file.buffer.raw.closefd, False)
def test_flush_error_on_close(self):
f = io.open(test_support.TESTFN, "wb", buffering=0)
def bad_flush():
raise IOError()
f.flush = bad_flush
self.assertRaises(IOError, f.close) # exception not swallowed
def test_multi_close(self):
f = io.open(test_support.TESTFN, "wb", buffering=0)
f.close()
f.close()
f.close()
self.assertRaises(ValueError, f.flush)
class MemorySeekTestMixin: class MemorySeekTestMixin:
...@@ -565,6 +579,22 @@ class BufferedWriterTest(unittest.TestCase): ...@@ -565,6 +579,22 @@ class BufferedWriterTest(unittest.TestCase):
finally: finally:
test_support.unlink(test_support.TESTFN) test_support.unlink(test_support.TESTFN)
def test_flush_error_on_close(self):
raw = MockRawIO()
def bad_flush():
raise IOError()
raw.flush = bad_flush
b = io.BufferedWriter(raw)
self.assertRaises(IOError, b.close) # exception not swallowed
def test_multi_close(self):
raw = MockRawIO()
b = io.BufferedWriter(raw)
b.close()
b.close()
b.close()
self.assertRaises(ValueError, b.flush)
class BufferedRWPairTest(unittest.TestCase): class BufferedRWPairTest(unittest.TestCase):
...@@ -1295,6 +1325,20 @@ class TextIOWrapperTest(unittest.TestCase): ...@@ -1295,6 +1325,20 @@ class TextIOWrapperTest(unittest.TestCase):
decoder = io.IncrementalNewlineDecoder(decoder, translate=True) decoder = io.IncrementalNewlineDecoder(decoder, translate=True)
self.check_newline_decoder_utf8(decoder) self.check_newline_decoder_utf8(decoder)
def test_flush_error_on_close(self):
txt = io.TextIOWrapper(io.BytesIO(self.testdata), encoding="ascii")
def bad_flush():
raise IOError()
txt.flush = bad_flush
self.assertRaises(IOError, txt.close) # exception not swallowed
def test_multi_close(self):
txt = io.TextIOWrapper(io.BytesIO(self.testdata), encoding="ascii")
txt.close()
txt.close()
txt.close()
self.assertRaises(ValueError, txt.flush)
# XXX Tests for open() # XXX Tests for open()
......
...@@ -33,6 +33,10 @@ Core and Builtins ...@@ -33,6 +33,10 @@ Core and Builtins
Library Library
------- -------
- Issue #7865: The close() method of :mod:`io` objects should not swallow
exceptions raised by the implicit flush(). Also ensure that calling
close() several times is supported. Initial patch by Pascal Chambon.
- Issue #8581: logging: removed errors raised when closing handlers twice. - Issue #8581: logging: removed errors raised when closing handlers twice.
- Issue #4687: Fix accuracy of garbage collection runtimes displayed with - Issue #4687: Fix accuracy of garbage collection runtimes displayed with
......
...@@ -163,6 +163,7 @@ PyDoc_STRVAR(flush_doc, ...@@ -163,6 +163,7 @@ PyDoc_STRVAR(flush_doc,
static PyObject * static PyObject *
bytesio_flush(BytesIOObject *self) bytesio_flush(BytesIOObject *self)
{ {
CHECK_CLOSED(self);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment