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

Skip to content

Commit 6cb7b65

Browse files
committed
#1286: allow using fileinput.FileInput as context manager.
1 parent e42a59d commit 6cb7b65

4 files changed

Lines changed: 59 additions & 7 deletions

File tree

Doc/library/fileinput.rst

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ as the first argument to :func:`.input`. A single file name is also allowed.
2424

2525
All files are opened in text mode by default, but you can override this by
2626
specifying the *mode* parameter in the call to :func:`.input` or
27-
:class:`FileInput()`. If an I/O error occurs during opening or reading a file,
27+
:class:`FileInput`. If an I/O error occurs during opening or reading a file,
2828
:exc:`IOError` is raised.
2929

3030
If ``sys.stdin`` is used more than once, the second and further use will return
@@ -54,6 +54,16 @@ The following function is the primary interface of this module:
5454
during iteration. The parameters to this function will be passed along to the
5555
constructor of the :class:`FileInput` class.
5656

57+
The :class:`FileInput` instance can be used as a context manager in the
58+
:keyword:`with` statement. In this example, *input* is closed after the
59+
:keyword:`with` statement is exited, even if an exception occurs::
60+
61+
with fileinput.input(files=('spam.txt', 'eggs.txt')) as input:
62+
process(input)
63+
64+
.. versionchanged:: 3.2
65+
Can be used as a context manager.
66+
5767

5868
The following functions use the global state created by :func:`fileinput.input`;
5969
if there is no active state, :exc:`RuntimeError` is raised.
@@ -132,13 +142,23 @@ available for subclassing as well:
132142
*filename* and *mode*, and returns an accordingly opened file-like object. You
133143
cannot use *inplace* and *openhook* together.
134144

145+
A :class:`FileInput` instance can be used as a context manager in the
146+
:keyword:`with` statement. In this example, *input* is closed after the
147+
:keyword:`with` statement is exited, even if an exception occurs::
148+
149+
with FileInput(files=('spam.txt', 'eggs.txt')) as input:
150+
process(input)
151+
152+
.. versionchanged:: 3.2
153+
Can be used as a context manager.
154+
135155

136-
**Optional in-place filtering:** if the keyword argument ``inplace=1`` is passed
137-
to :func:`fileinput.input` or to the :class:`FileInput` constructor, the file is
138-
moved to a backup file and standard output is directed to the input file (if a
139-
file of the same name as the backup file already exists, it will be replaced
140-
silently). This makes it possible to write a filter that rewrites its input
141-
file in place. If the *backup* parameter is given (typically as
156+
**Optional in-place filtering:** if the keyword argument ``inplace=True`` is
157+
passed to :func:`fileinput.input` or to the :class:`FileInput` constructor, the
158+
file is moved to a backup file and standard output is directed to the input file
159+
(if a file of the same name as the backup file already exists, it will be
160+
replaced silently). This makes it possible to write a filter that rewrites its
161+
input file in place. If the *backup* parameter is given (typically as
142162
``backup='.<some extension>'``), it specifies the extension for the backup file,
143163
and the backup file remains around; by default, the extension is ``'.bak'`` and
144164
it is deleted when the output file is closed. In-place filtering is disabled

Lib/fileinput.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ def close(self):
238238
self.nextfile()
239239
self._files = ()
240240

241+
def __enter__(self):
242+
return self
243+
244+
def __exit__(self, type, value, traceback):
245+
self.close()
246+
241247
def __iter__(self):
242248
return self
243249

Lib/test/test_fileinput.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,30 @@ def test_file_opening_hook(self):
231231
## finally:
232232
## remove_tempfiles(t1)
233233

234+
def test_context_manager(self):
235+
try:
236+
t1 = writeTmp(1, ["A\nB\nC"])
237+
t2 = writeTmp(2, ["D\nE\nF"])
238+
with FileInput(files=(t1, t2)) as fi:
239+
lines = list(fi)
240+
self.assertEqual(lines, ["A\n", "B\n", "C", "D\n", "E\n", "F"])
241+
self.assertEqual(fi.filelineno(), 3)
242+
self.assertEqual(fi.lineno(), 6)
243+
self.assertEqual(fi._files, ())
244+
finally:
245+
remove_tempfiles(t1, t2)
246+
247+
def test_close_on_exception(self):
248+
try:
249+
t1 = writeTmp(1, [""])
250+
with FileInput(files=t1) as fi:
251+
raise IOError
252+
except IOError:
253+
self.assertEqual(fi._files, ())
254+
finally:
255+
remove_tempfiles(t1)
256+
257+
234258
def test_main():
235259
run_unittest(BufferSizesTests, FileInputTests)
236260

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Core and Builtins
1515
Library
1616
-------
1717

18+
- Issue #1286: Allow using fileinput.FileInput as a context manager.
19+
1820
- Add lfu_cache() and lru_cache() decorators to the functools module.
1921

2022

0 commit comments

Comments
 (0)