Patch #1212287: fileinput.input() now has a mode parameter for
authorGeorg Brandl <georg@python.org>
Sun, 19 Feb 2006 14:12:34 +0000 (14:12 +0000)
committerGeorg Brandl <georg@python.org>
Sun, 19 Feb 2006 14:12:34 +0000 (14:12 +0000)
specifying the file mode input files should be opened with.

Doc/lib/libfileinput.tex
Lib/fileinput.py
Lib/test/test_fileinput.py
Misc/NEWS

index b6186dcf7a77bd8565903757f4921269fe14ea44..9e16f44fe5c1fc640e0cccf1f5dd052cabdfe3fa 100644 (file)
@@ -26,8 +26,10 @@ empty.  If a filename is \code{'-'}, it is also replaced by
 it as the first argument to \function{input()}.  A single file name is
 also allowed.
 
-All files are opened in text mode.  If an I/O error occurs during
-opening or reading a file, \exception{IOError} is raised.
+All files are opened in text mode by default, but you can override this by
+specifying the \var{mode} parameter in the call to \function{input()}
+or \class{FileInput()}.  If an I/O error occurs during opening or reading
+a file, \exception{IOError} is raised.
 
 If \code{sys.stdin} is used more than once, the second and further use
 will return no lines, except perhaps for interactive use, or if it has
@@ -44,12 +46,14 @@ is present.
 The following function is the primary interface of this module:
 
 \begin{funcdesc}{input}{\optional{files\optional{,
-                       inplace\optional{, backup}}}}
+                       inplace\optional{, backup\optional{, mode}}}}}
   Create an instance of the \class{FileInput} class.  The instance
   will be used as global state for the functions of this module, and
   is also returned to use during iteration.  The parameters to this
   function will be passed along to the constructor of the
   \class{FileInput} class.
+
+  \versionchanged[Added the \var{mode} parameter]{2.5}
 \end{funcdesc}
 
 
@@ -111,7 +115,7 @@ The class which implements the sequence behavior provided by the
 module is available for subclassing as well:
 
 \begin{classdesc}{FileInput}{\optional{files\optional{,
-                             inplace\optional{, backup}}}}
+                             inplace\optional{, backup\optional{, mode}}}}}
   Class \class{FileInput} is the implementation; its methods
   \method{filename()}, \method{fileno()}, \method{lineno()},
   \method{fileline()}, \method{isfirstline()}, \method{isstdin()},
@@ -122,6 +126,12 @@ module is available for subclassing as well:
   which implements the sequence behavior.  The sequence must be
   accessed in strictly sequential order; random access and
   \method{readline()} cannot be mixed.
+
+  With \var{mode} you can specify which file mode will be passed to
+  \function{open()}. It must be one of \code{'r'}, \code{'rU'},
+  \code{'U'} and \code{'rb'}.
+
+  \versionchanged[Added the \var{mode} parameter]{2.5}
 \end{classdesc}
 
 \strong{Optional in-place filtering:} if the keyword argument
index 692eeea0c79d84d00bb63ed34ba23d18e03c33da..004cf09b32429a27c1dde22a9567e408c4e6e3a4 100644 (file)
@@ -28,8 +28,10 @@ numbers are zero; nextfile() has no effect.  After all lines have been
 read, filename() and the line number functions return the values
 pertaining to the last line read; nextfile() has no effect.
 
-All files are opened in text mode.  If an I/O error occurs during
-opening or reading a file, the IOError exception is raised.
+All files are opened in text mode by default, you can override this by
+setting the mode parameter to input() or FileInput.__init__().
+If an I/O error occurs during opening or reading a file, the IOError
+exception is raised.
 
 If sys.stdin is used more than once, the second and further use will
 return no lines, except perhaps for interactive use, or if it has been
@@ -72,7 +74,6 @@ buffer size.
 XXX Possible additions:
 
 - optional getopt argument processing
-- specify open mode ('r' or 'rb')
 - isatty()
 - read(), read(size), even readlines()
 
@@ -87,8 +88,8 @@ _state = None
 
 DEFAULT_BUFSIZE = 8*1024
 
-def input(files=None, inplace=0, backup="", bufsize=0):
-    """input([files[, inplace[, backup]]])
+def input(files=None, inplace=0, backup="", bufsize=0, mode="r"):
+    """input([files[, inplace[, backup[, mode]]]])
 
     Create an instance of the FileInput class. The instance will be used
     as global state for the functions of this module, and is also returned
@@ -98,7 +99,7 @@ def input(files=None, inplace=0, backup="", bufsize=0):
     global _state
     if _state and _state._file:
         raise RuntimeError, "input() already active"
-    _state = FileInput(files, inplace, backup, bufsize)
+    _state = FileInput(files, inplace, backup, bufsize, mode)
     return _state
 
 def close():
@@ -180,7 +181,7 @@ def isstdin():
     return _state.isstdin()
 
 class FileInput:
-    """class FileInput([files[, inplace[, backup]]])
+    """class FileInput([files[, inplace[, backup[, mode]]]])
 
     Class FileInput is the implementation of the module; its methods
     filename(), lineno(), fileline(), isfirstline(), isstdin(), fileno(),
@@ -192,7 +193,7 @@ class FileInput:
     sequential order; random access and readline() cannot be mixed.
     """
 
-    def __init__(self, files=None, inplace=0, backup="", bufsize=0):
+    def __init__(self, files=None, inplace=0, backup="", bufsize=0, mode="r"):
         if isinstance(files, basestring):
             files = (files,)
         else:
@@ -216,6 +217,11 @@ class FileInput:
         self._backupfilename = None
         self._buffer = []
         self._bufindex = 0
+        # restrict mode argument to reading modes
+        if mode not in ('r', 'rU', 'U', 'rb'):
+            raise ValueError("FileInput opening mode must be one of "
+                             "'r', 'rU', 'U' and 'rb'")
+        self._mode = mode
 
     def __del__(self):
         self.close()
@@ -307,7 +313,7 @@ class FileInput:
                     except os.error: pass
                     # The next few lines may raise IOError
                     os.rename(self._filename, self._backupfilename)
-                    self._file = open(self._backupfilename, "r")
+                    self._file = open(self._backupfilename, self._mode)
                     try:
                         perm = os.fstat(self._file.fileno()).st_mode
                     except OSError:
@@ -326,7 +332,7 @@ class FileInput:
                     sys.stdout = self._output
                 else:
                     # This may raise IOError
-                    self._file = open(self._filename, "r")
+                    self._file = open(self._filename, self._mode)
         self._buffer = self._file.readlines(self._bufsize)
         self._bufindex = 0
         if not self._buffer:
index be4cb8e87b28d0630b498389dcfc85074920d462..4080a25da5c5ff321f5439171390c8daf16b05de 100644 (file)
@@ -3,7 +3,7 @@ Tests for fileinput module.
 Nick Mathewson
 '''
 
-from test.test_support import verify, verbose, TESTFN
+from test.test_support import verify, verbose, TESTFN, TestFailed
 import sys, os, re
 from StringIO import StringIO
 from fileinput import FileInput
@@ -183,3 +183,20 @@ try:
     verify(fi.fileno() == -1)
 finally:
     remove_tempfiles(t1, t2)
+
+if verbose:
+    print "17. Specify opening mode"
+try:
+    # invalid mode, should raise ValueError
+    fi = FileInput(mode="w")
+    raise TestFailed("FileInput should reject invalid mode argument")
+except ValueError:
+    pass
+try:
+    # try opening in universal newline mode
+    t1 = writeTmp(1, ["A\nB\r\nC\rD"])
+    fi = FileInput(files=t1, mode="U")
+    lines = list(fi)
+    verify(lines == ["A\n", "B\n", "C\n", "D"])
+finally:
+    remove_tempfiles(t1)
index 2ef34245739b94eeb256c505d0200ef9783e7047..ae0f2d92da5214c73ee6e6a8c5d720c2cee21849 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -366,6 +366,9 @@ Extension Modules
 Library
 -------
 
+- Patch #1212287: fileinput.input() now has a mode parameter for
+  specifying the file mode input files should be opened with.
+
 - Patch #1215184: fileinput now has a fileno() function for getting the
   current file number.