[Python-3000-checkins] r57564 - in python/branches/py3k/Lib: io.py socket.py test/test_io.py

guido.van.rossum python-3000-checkins at python.org
Mon Aug 27 19:39:33 CEST 2007


Author: guido.van.rossum
Date: Mon Aug 27 19:39:33 2007
New Revision: 57564

Modified:
   python/branches/py3k/Lib/io.py
   python/branches/py3k/Lib/socket.py
   python/branches/py3k/Lib/test/test_io.py
Log:
Changes to io.py and socket.py by Christian Heimes.
- Replace all asserts by ValuleErrors or TypeErrors as appropriate.
- Add _checkReadable, _checkWritable methods; these check self.closed too.
- Add a test that everything exported by io.py exists, and is either
  an exception or an IOBase instance (except for the open function).
- Default buffering to 1 if isatty() (I had to tweak this to enforce
  the *default* bit -- GvR).


Modified: python/branches/py3k/Lib/io.py
==============================================================================
--- python/branches/py3k/Lib/io.py	(original)
+++ python/branches/py3k/Lib/io.py	Mon Aug 27 19:39:33 2007
@@ -12,13 +12,12 @@
 variable are part of the specification.
 
 XXX edge cases when switching between reading/writing
-XXX need to default buffer size to 1 if isatty()
 XXX need to support 1 meaning line-buffered
-XXX don't use assert to validate input requirements
 XXX whenever an argument is None, use the default value
 XXX read/write ops should check readable/writable
 XXX buffered readinto should work with arbitrary buffer objects
 XXX use incremental encoder for text output, at least for UTF-16 and UTF-8-SIG
+XXX check writable, readable and seekable in appropriate places
 """
 
 __author__ = ("Guido van Rossum <guido at python.org>, "
@@ -26,7 +25,7 @@
               "Mark Russell <mark.russell at zen.co.uk>")
 
 __all__ = ["BlockingIOError", "open", "IOBase", "RawIOBase", "FileIO",
-           "SocketIO", "BytesIO", "StringIO", "BufferedIOBase",
+           "BytesIO", "StringIO", "BufferedIOBase",
            "BufferedReader", "BufferedWriter", "BufferedRWPair",
            "BufferedRandom", "TextIOBase", "TextIOWrapper"]
 
@@ -38,7 +37,7 @@
 import io
 import warnings
 
-# XXX Shouldn't we use st_blksize whenever we can?
+# open() uses st_blksize whenever we can
 DEFAULT_BUFFER_SIZE = 8 * 1024  # bytes
 
 
@@ -105,11 +104,14 @@
       binary stream, a buffered binary stream, or a buffered text
       stream, open for reading and/or writing.
     """
-    # XXX Don't use asserts for these checks; raise TypeError or ValueError
-    assert isinstance(file, (basestring, int)), repr(file)
-    assert isinstance(mode, basestring), repr(mode)
-    assert buffering is None or isinstance(buffering, int), repr(buffering)
-    assert encoding is None or isinstance(encoding, basestring), repr(encoding)
+    if not isinstance(file, (basestring, int)):
+        raise TypeError("invalid file: %r" % file)
+    if not isinstance(mode, basestring):
+        raise TypeError("invalid mode: %r" % mode)
+    if buffering is not None and not isinstance(buffering, int):
+        raise TypeError("invalid buffering: %r" % buffering)
+    if encoding is not None and not isinstance(encoding, basestring):
+        raise TypeError("invalid encoding: %r" % encoding)
     modes = set(mode)
     if modes - set("arwb+tU") or len(mode) > len(modes):
         raise ValueError("invalid mode: %r" % mode)
@@ -140,9 +142,10 @@
                  (updating and "+" or ""))
     if buffering is None:
         buffering = -1
+    if buffering < 0 and raw.isatty():
+        buffering = 1
     if buffering < 0:
         buffering = DEFAULT_BUFFER_SIZE
-        # XXX Should default to line buffering if os.isatty(raw.fileno())
         try:
             bs = os.fstat(raw.fileno()).st_blksize
         except (os.error, AttributeError):
@@ -162,9 +165,10 @@
         buffer = BufferedRandom(raw, buffering)
     elif writing or appending:
         buffer = BufferedWriter(raw, buffering)
-    else:
-        assert reading
+    elif reading:
         buffer = BufferedReader(raw, buffering)
+    else:
+        raise ValueError("unknown mode: %r" % mode)
     if binary:
         buffer.name = file
         buffer.mode = mode
@@ -273,6 +277,14 @@
         """
         return False
 
+    def _checkSeekable(self, msg=None):
+        """Internal: raise an IOError if file is not seekable
+        """
+        if not self.seekable():
+            raise IOError("File or stream is not seekable."
+                          if msg is None else msg)
+
+
     def readable(self) -> bool:
         """readable() -> bool.  Return whether object was opened for reading.
 
@@ -280,6 +292,13 @@
         """
         return False
 
+    def _checkReadable(self, msg=None):
+        """Internal: raise an IOError if file is not readable
+        """
+        if not self.readable():
+            raise IOError("File or stream is not readable."
+                          if msg is None else msg)
+
     def writable(self) -> bool:
         """writable() -> bool.  Return whether object was opened for writing.
 
@@ -287,6 +306,13 @@
         """
         return False
 
+    def _checkWritable(self, msg=None):
+        """Internal: raise an IOError if file is not writable
+        """
+        if not self.writable():
+            raise IOError("File or stream is not writable."
+                          if msg is None else msg)
+
     @property
     def closed(self):
         """closed: bool.  True iff the file has been closed.
@@ -295,6 +321,13 @@
         """
         return self.__closed
 
+    def _checkClosed(self, msg=None):
+        """Internal: raise an ValueError if file is closed
+        """
+        if self.closed:
+            raise ValueError("I/O operation on closed file."
+                             if msg is None else msg)
+
     ### Context manager ###
 
     def __enter__(self) -> "IOBase":  # That's a forward reference
@@ -321,8 +354,7 @@
 
         Returns False if we don't know.
         """
-        if self.closed:
-            raise ValueError("isatty() on closed file")
+        self._checkClosed()
         return False
 
     ### Readline[s] and writelines ###
@@ -354,8 +386,7 @@
         return res
 
     def __iter__(self):
-        if self.closed:
-            raise ValueError("__iter__ on closed file")
+        self._checkClosed()
         return self
 
     def __next__(self):
@@ -377,8 +408,7 @@
         return lines
 
     def writelines(self, lines):
-        if self.closed:
-            raise ValueError("write to closed file")
+        self._checkClosed()
         for line in lines:
             self.write(line)
 
@@ -677,7 +707,7 @@
     def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
         """Create a new buffered reader using the given readable raw IO object.
         """
-        assert raw.readable()
+        raw._checkReadable()
         _BufferedIOMixin.__init__(self, raw)
         self._read_buf = b""
         self.buffer_size = buffer_size
@@ -760,7 +790,7 @@
 
     def __init__(self, raw,
                  buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=None):
-        assert raw.writable()
+        raw._checkWritable()
         _BufferedIOMixin.__init__(self, raw)
         self.buffer_size = buffer_size
         self.max_buffer_size = (2*buffer_size
@@ -842,8 +872,8 @@
 
         The arguments are two RawIO instances.
         """
-        assert reader.readable()
-        assert writer.writable()
+        reader._checkReadable()
+        writer._checkWritable()
         self.reader = BufferedReader(reader, buffer_size)
         self.writer = BufferedWriter(writer, buffer_size, max_buffer_size)
 
@@ -891,7 +921,7 @@
 
     def __init__(self, raw,
                  buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=None):
-        assert raw.seekable()
+        raw._checkSeekable()
         BufferedReader.__init__(self, raw, buffer_size)
         BufferedWriter.__init__(self, raw, buffer_size, max_buffer_size)
 
@@ -1086,7 +1116,8 @@
         return decoder
 
     def _read_chunk(self):
-        assert self._decoder is not None
+        if self._decoder is None:
+            raise ValueError("no decoder")
         if not self._telling:
             readahead = self.buffer.read1(self._CHUNK_SIZE)
             pending = self._decoder.decode(readahead, not readahead)
@@ -1122,7 +1153,8 @@
         position = self.buffer.tell()
         decoder = self._decoder
         if decoder is None or self._snapshot is None:
-            assert self._pending == ""
+            if self._pending:
+                raise ValueError("pending data")
             return position
         decoder_state, readahead, pending = self._snapshot
         position -= len(readahead)

Modified: python/branches/py3k/Lib/socket.py
==============================================================================
--- python/branches/py3k/Lib/socket.py	(original)
+++ python/branches/py3k/Lib/socket.py	Mon Aug 27 19:39:33 2007
@@ -253,24 +253,31 @@
     # XXX More docs
 
     def __init__(self, sock, mode, closer):
-        assert mode in ("r", "w", "rw")
+        if mode not in ("r", "w", "rw"):
+            raise ValueError("invalid mode: %r" % mode)
         io.RawIOBase.__init__(self)
         self._sock = sock
         self._mode = mode
         self._closer = closer
+        self._reading = "r" in mode
+        self._writing = "w" in mode
         closer.makefile_open()
 
     def readinto(self, b):
+        self._checkClosed()
+        self._checkReadable()
         return self._sock.recv_into(b)
 
     def write(self, b):
+        self._checkClosed()
+        self._checkWritable()
         return self._sock.send(b)
 
     def readable(self):
-        return "r" in self._mode
+        return self._reading and not self.closed
 
     def writable(self):
-        return "w" in self._mode
+        return self._writing and not self.closed
 
     def fileno(self):
         return self._sock.fileno()

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	Mon Aug 27 19:39:33 2007
@@ -740,11 +740,26 @@
 
 # XXX Tests for open()
 
+class MiscIOTest(unittest.TestCase):
+
+    def testImport__all__(self):
+        for name in io.__all__:
+            obj = getattr(io, name, None)
+            self.assert_(obj is not None, name)
+            if name == "open":
+                continue
+            elif "error" in name.lower():
+                self.assert_(issubclass(obj, Exception), name)
+            else:
+                self.assert_(issubclass(obj, io.IOBase))
+
+
 def test_main():
     test_support.run_unittest(IOTest, BytesIOTest, StringIOTest,
                               BufferedReaderTest,
                               BufferedWriterTest, BufferedRWPairTest,
-                              BufferedRandomTest, TextIOWrapperTest)
+                              BufferedRandomTest, TextIOWrapperTest,
+                              MiscIOTest)
 
 if __name__ == "__main__":
     unittest.main()


More information about the Python-3000-checkins mailing list