[Python-checkins] r68454 - in python/branches/py3k: Lib/io.py Lib/test/test_io.py Misc/NEWS

antoine.pitrou python-checkins at python.org
Fri Jan 9 20:54:29 CET 2009


Author: antoine.pitrou
Date: Fri Jan  9 20:54:29 2009
New Revision: 68454

Log:
Issue #4604: Some objects of the I/O library could still be used after 
having been closed (for instance, a read() call could return some
previously buffered data). Patch by Dmitry Vasiliev.



Modified:
   python/branches/py3k/Lib/io.py
   python/branches/py3k/Lib/test/test_io.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Lib/io.py
==============================================================================
--- python/branches/py3k/Lib/io.py	(original)
+++ python/branches/py3k/Lib/io.py	Fri Jan  9 20:54:29 2009
@@ -340,6 +340,7 @@
 
     def tell(self) -> int:
         """Return current stream position."""
+        self._checkClosed()
         return self.seek(0, 1)
 
     def truncate(self, pos: int = None) -> int:
@@ -358,6 +359,8 @@
         This is not implemented for read-only and non-blocking streams.
         """
         # XXX Should this return the number of bytes written???
+        if self.__closed:
+            raise ValueError("I/O operation on closed file.")
 
     __closed = False
 
@@ -530,6 +533,7 @@
         lines will be read if the total size (in bytes/characters) of all
         lines so far exceeds hint.
         """
+        self._checkClosed()
         if hint is None or hint <= 0:
             return list(self)
         n = 0
@@ -567,6 +571,7 @@
         Returns an empty bytes object on EOF, or None if the object is
         set not to block and has no data to read.
         """
+        self._checkClosed()
         if n is None:
             n = -1
         if n < 0:
@@ -578,6 +583,7 @@
 
     def readall(self):
         """Read until EOF, using multiple read() call."""
+        self._checkClosed()
         res = bytearray()
         while True:
             data = self.read(DEFAULT_BUFFER_SIZE)
@@ -673,6 +679,7 @@
         data at the moment.
         """
         # XXX This ought to work with anything that supports the buffer API
+        self._checkClosed()
         data = self.read(len(b))
         n = len(data)
         try:
@@ -787,13 +794,11 @@
     def getvalue(self):
         """Return the bytes value (contents) of the buffer
         """
-        if self.closed:
-            raise ValueError("getvalue on closed file")
+        self._checkClosed()
         return bytes(self._buffer)
 
     def read(self, n=None):
-        if self.closed:
-            raise ValueError("read from closed file")
+        self._checkClosed()
         if n is None:
             n = -1
         if n < 0:
@@ -811,8 +816,7 @@
         return self.read(n)
 
     def write(self, b):
-        if self.closed:
-            raise ValueError("write to closed file")
+        self._checkClosed()
         if isinstance(b, str):
             raise TypeError("can't write str to binary stream")
         n = len(b)
@@ -829,8 +833,7 @@
         return n
 
     def seek(self, pos, whence=0):
-        if self.closed:
-            raise ValueError("seek on closed file")
+        self._checkClosed()
         try:
             pos = pos.__index__()
         except AttributeError as err:
@@ -848,13 +851,11 @@
         return self._pos
 
     def tell(self):
-        if self.closed:
-            raise ValueError("tell on closed file")
+        self._checkClosed()
         return self._pos
 
     def truncate(self, pos=None):
-        if self.closed:
-            raise ValueError("truncate on closed file")
+        self._checkClosed()
         if pos is None:
             pos = self._pos
         elif pos < 0:
@@ -914,6 +915,7 @@
         mode. If n is negative, read until EOF or until read() would
         block.
         """
+        self._checkClosed()
         with self._read_lock:
             return self._read_unlocked(n)
 
@@ -970,6 +972,7 @@
         do at most one raw read to satisfy it.  We never return more
         than self.buffer_size.
         """
+        self._checkClosed()
         with self._read_lock:
             return self._peek_unlocked(n)
 
@@ -988,6 +991,7 @@
         """Reads up to n bytes, with at most one read() system call."""
         # Returns up to n bytes.  If at least one byte is buffered, we
         # only return buffered bytes.  Otherwise, we do one raw read.
+        self._checkClosed()
         if n <= 0:
             return b""
         with self._read_lock:
@@ -996,9 +1000,11 @@
                 min(n, len(self._read_buf) - self._read_pos))
 
     def tell(self):
+        self._checkClosed()
         return self.raw.tell() - len(self._read_buf) + self._read_pos
 
     def seek(self, pos, whence=0):
+        self._checkClosed()
         with self._read_lock:
             if whence == 1:
                 pos -= len(self._read_buf) - self._read_pos
@@ -1029,8 +1035,7 @@
         self._write_lock = Lock()
 
     def write(self, b):
-        if self.closed:
-            raise ValueError("write to closed file")
+        self._checkClosed()
         if isinstance(b, str):
             raise TypeError("can't write str to binary stream")
         with self._write_lock:
@@ -1060,6 +1065,7 @@
             return written
 
     def truncate(self, pos=None):
+        self._checkClosed()
         with self._write_lock:
             self._flush_unlocked()
             if pos is None:
@@ -1067,12 +1073,11 @@
             return self.raw.truncate(pos)
 
     def flush(self):
+        self._checkClosed()
         with self._write_lock:
             self._flush_unlocked()
 
     def _flush_unlocked(self):
-        if self.closed:
-            raise ValueError("flush of closed file")
         written = 0
         try:
             while self._write_buf:
@@ -1086,9 +1091,11 @@
             raise BlockingIOError(e.errno, e.strerror, written)
 
     def tell(self):
+        self._checkClosed()
         return self.raw.tell() + len(self._write_buf)
 
     def seek(self, pos, whence=0):
+        self._checkClosed()
         with self._write_lock:
             self._flush_unlocked()
             return self.raw.seek(pos, whence)
@@ -1186,6 +1193,7 @@
         return pos
 
     def tell(self):
+        self._checkClosed()
         if self._write_buf:
             return self.raw.tell() + len(self._write_buf)
         else:
@@ -1217,6 +1225,7 @@
         return BufferedReader.read1(self, n)
 
     def write(self, b):
+        self._checkClosed()
         if self._read_buf:
             # Undo readahead
             with self._read_lock:
@@ -1474,8 +1483,7 @@
         return self.buffer.isatty()
 
     def write(self, s: str):
-        if self.closed:
-            raise ValueError("write to closed file")
+        self._checkClosed()
         if not isinstance(s, str):
             raise TypeError("can't write %s to text stream" %
                             s.__class__.__name__)
@@ -1583,6 +1591,7 @@
         return position, dec_flags, bytes_to_feed, need_eof, chars_to_skip
 
     def tell(self):
+        self._checkClosed()
         if not self._seekable:
             raise IOError("underlying stream is not seekable")
         if not self._telling:
@@ -1653,8 +1662,7 @@
         return self.buffer.truncate()
 
     def seek(self, cookie, whence=0):
-        if self.closed:
-            raise ValueError("tell on closed file")
+        self._checkClosed()
         if not self._seekable:
             raise IOError("underlying stream is not seekable")
         if whence == 1: # seek relative to current position
@@ -1712,6 +1720,7 @@
         return cookie
 
     def read(self, n=None):
+        self._checkClosed()
         if n is None:
             n = -1
         decoder = self._decoder or self._get_decoder()
@@ -1732,6 +1741,7 @@
             return result
 
     def __next__(self):
+        self._checkClosed()
         self._telling = False
         line = self.readline()
         if not line:
@@ -1741,8 +1751,7 @@
         return line
 
     def readline(self, limit=None):
-        if self.closed:
-            raise ValueError("read from closed file")
+        self._checkClosed()
         if limit is None:
             limit = -1
 
@@ -1963,8 +1972,7 @@
 
         def getvalue(self) -> str:
             """Retrieve the entire contents of the object."""
-            if self.closed:
-                raise ValueError("read on closed file")
+            self._checkClosed()
             return self._getvalue()
 
         def write(self, s: str) -> int:
@@ -1972,8 +1980,7 @@
 
             Returns the number of characters written.
             """
-            if self.closed:
-                raise ValueError("write to closed file")
+            self._checkClosed()
             if not isinstance(s, str):
                 raise TypeError("can't write %s to text stream" %
                                 s.__class__.__name__)
@@ -1990,8 +1997,7 @@
             If the argument is negative or omitted, read until EOF
             is reached. Return an empty string at EOF.
             """
-            if self.closed:
-                raise ValueError("read to closed file")
+            self._checkClosed()
             if n is None:
                 n = -1
             res = self._pending
@@ -2006,8 +2012,7 @@
 
         def tell(self) -> int:
             """Tell the current file position."""
-            if self.closed:
-                raise ValueError("tell from closed file")
+            self._checkClosed()
             if self._pending:
                 return self._tell() - len(self._pending)
             else:
@@ -2022,8 +2027,7 @@
                 2  End of stream - pos must be 0.
             Returns the new absolute position.
             """
-            if self.closed:
-                raise ValueError("seek from closed file")
+            self._checkClosed()
             self._pending = ""
             return self._seek(pos, whence)
 
@@ -2034,14 +2038,12 @@
             returned by tell().  Imply an absolute seek to pos.
             Returns the new absolute position.
             """
-            if self.closed:
-                raise ValueError("truncate from closed file")
+            self._checkClosed()
             self._pending = ""
             return self._truncate(pos)
 
         def readline(self, limit: int = None) -> str:
-            if self.closed:
-                raise ValueError("read from closed file")
+            self._checkClosed()
             if limit is None:
                 limit = -1
             if limit >= 0:

Modified: python/branches/py3k/Lib/test/test_io.py
==============================================================================
--- python/branches/py3k/Lib/test/test_io.py	(original)
+++ python/branches/py3k/Lib/test/test_io.py	Fri Jan  9 20:54:29 2009
@@ -1324,6 +1324,45 @@
         f.close()
         g.close()
 
+    def test_io_after_close(self):
+        for kwargs in [
+                {"mode": "w"},
+                {"mode": "wb"},
+                {"mode": "w", "buffering": 1},
+                {"mode": "w", "buffering": 2},
+                {"mode": "wb", "buffering": 0},
+                {"mode": "r"},
+                {"mode": "rb"},
+                {"mode": "r", "buffering": 1},
+                {"mode": "r", "buffering": 2},
+                {"mode": "rb", "buffering": 0},
+                {"mode": "w+"},
+                {"mode": "w+b"},
+                {"mode": "w+", "buffering": 1},
+                {"mode": "w+", "buffering": 2},
+                {"mode": "w+b", "buffering": 0},
+            ]:
+            f = io.open(support.TESTFN, **kwargs)
+            f.close()
+            self.assertRaises(ValueError, f.flush)
+            self.assertRaises(ValueError, f.fileno)
+            self.assertRaises(ValueError, f.isatty)
+            self.assertRaises(ValueError, f.__iter__)
+            if hasattr(f, "peek"):
+                self.assertRaises(ValueError, f.peek, 1)
+            self.assertRaises(ValueError, f.read)
+            if hasattr(f, "read1"):
+                self.assertRaises(ValueError, f.read1, 1024)
+            if hasattr(f, "readinto"):
+                self.assertRaises(ValueError, f.readinto, bytearray(1024))
+            self.assertRaises(ValueError, f.readline)
+            self.assertRaises(ValueError, f.readlines)
+            self.assertRaises(ValueError, f.seek, 0)
+            self.assertRaises(ValueError, f.tell)
+            self.assertRaises(ValueError, f.truncate)
+            self.assertRaises(ValueError, f.write, "")
+            self.assertRaises(ValueError, f.writelines, [])
+
 
 def test_main():
     support.run_unittest(IOTest, BytesIOTest, StringIOTest,

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Fri Jan  9 20:54:29 2009
@@ -12,6 +12,10 @@
 Core and Builtins
 -----------------
 
+- Issue #4604: Some objects of the I/O library could still be used after 
+  having been closed (for instance, a read() call could return some
+  previously buffered data). Patch by Dmitry Vasiliev.
+
 - Issue #4705: Fix the -u ("unbuffered binary stdout and stderr") command-line
   flag to work properly. Furthermore, when specifying -u, the text stdout
   and stderr streams have line-by-line buffering enabled (the default being


More information about the Python-checkins mailing list