Commit c029f873 authored by Georg Brandl's avatar Georg Brandl

Patch #1212287: fileinput.input() now has a mode parameter for

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