Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c98eeed

Browse files
committed
Patch #1215184: FileInput now can be given an opening hook which can
be used to control how files are opened.
1 parent c029f87 commit c98eeed

4 files changed

Lines changed: 105 additions & 12 deletions

File tree

Doc/lib/libfileinput.tex

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,23 @@ \section{\module{fileinput} ---
4343
character; lines are returned including the trailing newline when it
4444
is present.
4545

46+
You can control how files are opened by providing an opening hook via the
47+
\var{openhook} parameter to \function{input()} or \class{FileInput()}.
48+
The hook must be a function that takes two arguments, \var{filename}
49+
and \var{mode}, and returns an accordingly opened file-like object.
50+
Two useful hooks are already provided by this module.
51+
4652
The following function is the primary interface of this module:
4753

48-
\begin{funcdesc}{input}{\optional{files\optional{,
49-
inplace\optional{, backup\optional{, mode}}}}}
54+
\begin{funcdesc}{input}{\optional{files\optional{, inplace\optional{,
55+
backup\optional{, mode\optional{, openhook}}}}}}
5056
Create an instance of the \class{FileInput} class. The instance
5157
will be used as global state for the functions of this module, and
5258
is also returned to use during iteration. The parameters to this
5359
function will be passed along to the constructor of the
5460
\class{FileInput} class.
5561

56-
\versionchanged[Added the \var{mode} parameter]{2.5}
62+
\versionchanged[Added the \var{mode} and \var{openhook} parameters]{2.5}
5763
\end{funcdesc}
5864

5965

@@ -115,7 +121,8 @@ \section{\module{fileinput} ---
115121
module is available for subclassing as well:
116122

117123
\begin{classdesc}{FileInput}{\optional{files\optional{,
118-
inplace\optional{, backup\optional{, mode}}}}}
124+
inplace\optional{, backup\optional{,
125+
mode\optional{, openhook}}}}}}
119126
Class \class{FileInput} is the implementation; its methods
120127
\method{filename()}, \method{fileno()}, \method{lineno()},
121128
\method{fileline()}, \method{isfirstline()}, \method{isstdin()},
@@ -131,7 +138,12 @@ \section{\module{fileinput} ---
131138
\function{open()}. It must be one of \code{'r'}, \code{'rU'},
132139
\code{'U'} and \code{'rb'}.
133140

134-
\versionchanged[Added the \var{mode} parameter]{2.5}
141+
The \var{openhook}, when given, must be a function that takes two arguments,
142+
\var{filename} and \var{mode}, and returns an accordingly opened
143+
file-like object.
144+
You cannot use \var{inplace} and \var{openhook} together.
145+
146+
\versionchanged[Added the \var{mode} and \var{openhook} parameters]{2.5}
135147
\end{classdesc}
136148

137149
\strong{Optional in-place filtering:} if the keyword argument
@@ -148,3 +160,29 @@ \section{\module{fileinput} ---
148160

149161
\strong{Caveat:} The current implementation does not work for MS-DOS
150162
8+3 filesystems.
163+
164+
165+
The two following opening hooks are provided by this module:
166+
167+
\begin{funcdesc}{hook_compressed}{filename, mode}
168+
Transparently opens files compressed with gzip and bzip2 using
169+
the \module{gzip} and \module{bz2} modules.
170+
171+
Usage example:
172+
\samp{fi = fileinput.FileInput(openhook=fileinput.hook_compressed)}
173+
174+
\versionadded{2.5}
175+
\end{funcdesc}
176+
177+
\begin{funcdesc}{hook_encoded}{encoding}
178+
Returns a hook which opens each file with \function{codecs.open()},
179+
using the given \var{encoding} to read the file.
180+
181+
Usage example:
182+
\samp{fi = fileinput.FileInput(openhook=fileinput.hook_encoded("iso-8859-1"))}
183+
184+
\note{With this hook, \class{FileInput} might return Unicode strings
185+
depending on the specified \var{encoding}.}
186+
\versionadded{2.5}
187+
\end{funcdesc}
188+

Lib/fileinput.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@
8888

8989
DEFAULT_BUFSIZE = 8*1024
9090

91-
def input(files=None, inplace=0, backup="", bufsize=0, mode="r"):
92-
"""input([files[, inplace[, backup[, mode]]]])
91+
def input(files=None, inplace=0, backup="", bufsize=0,
92+
mode="r", openhook=None):
93+
"""input([files[, inplace[, backup[, mode[, openhook]]]]])
9394
9495
Create an instance of the FileInput class. The instance will be used
9596
as global state for the functions of this module, and is also returned
@@ -99,7 +100,7 @@ def input(files=None, inplace=0, backup="", bufsize=0, mode="r"):
99100
global _state
100101
if _state and _state._file:
101102
raise RuntimeError, "input() already active"
102-
_state = FileInput(files, inplace, backup, bufsize, mode)
103+
_state = FileInput(files, inplace, backup, bufsize, mode, openhook)
103104
return _state
104105

105106
def close():
@@ -181,7 +182,7 @@ def isstdin():
181182
return _state.isstdin()
182183

183184
class FileInput:
184-
"""class FileInput([files[, inplace[, backup[, mode]]]])
185+
"""class FileInput([files[, inplace[, backup[, mode[, openhook]]]]])
185186
186187
Class FileInput is the implementation of the module; its methods
187188
filename(), lineno(), fileline(), isfirstline(), isstdin(), fileno(),
@@ -193,7 +194,8 @@ class FileInput:
193194
sequential order; random access and readline() cannot be mixed.
194195
"""
195196

196-
def __init__(self, files=None, inplace=0, backup="", bufsize=0, mode="r"):
197+
def __init__(self, files=None, inplace=0, backup="", bufsize=0,
198+
mode="r", openhook=None):
197199
if isinstance(files, basestring):
198200
files = (files,)
199201
else:
@@ -222,6 +224,11 @@ def __init__(self, files=None, inplace=0, backup="", bufsize=0, mode="r"):
222224
raise ValueError("FileInput opening mode must be one of "
223225
"'r', 'rU', 'U' and 'rb'")
224226
self._mode = mode
227+
if inplace and openhook:
228+
raise ValueError("FileInput cannot use an opening hook in inplace mode")
229+
elif openhook and not callable(openhook):
230+
raise ValueError("FileInput openhook must be callable")
231+
self._openhook = openhook
225232

226233
def __del__(self):
227234
self.close()
@@ -332,7 +339,10 @@ def readline(self):
332339
sys.stdout = self._output
333340
else:
334341
# This may raise IOError
335-
self._file = open(self._filename, self._mode)
342+
if self._openhook:
343+
self._file = self._openhook(self._filename, self._mode)
344+
else:
345+
self._file = open(self._filename, self._mode)
336346
self._buffer = self._file.readlines(self._bufsize)
337347
self._bufindex = 0
338348
if not self._buffer:
@@ -364,6 +374,26 @@ def isfirstline(self):
364374
def isstdin(self):
365375
return self._isstdin
366376

377+
378+
def hook_compressed(filename, mode):
379+
ext = os.path.splitext(filename)[1]
380+
if ext == '.gz':
381+
import gzip
382+
return gzip.open(filename, mode)
383+
elif ext == '.bz2':
384+
import bz2
385+
return bz2.BZ2File(filename, mode)
386+
else:
387+
return open(filename, mode)
388+
389+
390+
def hook_encoded(encoding):
391+
import codecs
392+
def openhook(filename, mode):
393+
return codecs.open(filename, mode, encoding)
394+
return openhook
395+
396+
367397
def _test():
368398
import getopt
369399
inplace = 0

Lib/test/test_fileinput.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from test.test_support import verify, verbose, TESTFN, TestFailed
77
import sys, os, re
88
from StringIO import StringIO
9-
from fileinput import FileInput
9+
from fileinput import FileInput, hook_encoded
1010

1111
# The fileinput module has 2 interfaces: the FileInput class which does
1212
# all the work, and a few functions (input, etc.) that use a global _state
@@ -200,3 +200,25 @@ def writeFiles():
200200
verify(lines == ["A\n", "B\n", "C\n", "D"])
201201
finally:
202202
remove_tempfiles(t1)
203+
204+
if verbose:
205+
print "18. Test file opening hook"
206+
try:
207+
# cannot use openhook and inplace mode
208+
fi = FileInput(inplace=1, openhook=lambda f,m: None)
209+
raise TestFailed("FileInput should raise if both inplace "
210+
"and openhook arguments are given")
211+
except ValueError:
212+
pass
213+
try:
214+
fi = FileInput(openhook=1)
215+
raise TestFailed("FileInput should check openhook for being callable")
216+
except ValueError:
217+
pass
218+
try:
219+
t1 = writeTmp(1, ["A\nB"])
220+
fi = FileInput(files=t1, openhook=hook_encoded("rot13"))
221+
lines = list(fi)
222+
verify(lines == ["N\n", "O"])
223+
finally:
224+
remove_tempfiles(t1)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ Extension Modules
366366
Library
367367
-------
368368

369+
- Patch #1215184: FileInput now can be given an opening hook which can
370+
be used to control how files are opened.
371+
369372
- Patch #1212287: fileinput.input() now has a mode parameter for
370373
specifying the file mode input files should be opened with.
371374

0 commit comments

Comments
 (0)