Commit 6cb7b659 authored by Georg Brandl's avatar Georg Brandl

#1286: allow using fileinput.FileInput as context manager.

parent e42a59da
...@@ -24,7 +24,7 @@ as the first argument to :func:`.input`. A single file name is also allowed. ...@@ -24,7 +24,7 @@ as the first argument to :func:`.input`. A single file name is also allowed.
All files are opened in text mode by default, but you can override this by All files are opened in text mode by default, but you can override this by
specifying the *mode* parameter in the call to :func:`.input` or specifying the *mode* parameter in the call to :func:`.input` or
:class:`FileInput()`. If an I/O error occurs during opening or reading a file, :class:`FileInput`. If an I/O error occurs during opening or reading a file,
:exc:`IOError` is raised. :exc:`IOError` is raised.
If ``sys.stdin`` is used more than once, the second and further use will return 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: ...@@ -54,6 +54,16 @@ The following function is the primary interface of this module:
during iteration. The parameters to this function will be passed along to the during iteration. The parameters to this function will be passed along to the
constructor of the :class:`FileInput` class. constructor of the :class:`FileInput` class.
The :class:`FileInput` instance can be used as a context manager in the
:keyword:`with` statement. In this example, *input* is closed after the
:keyword:`with` statement is exited, even if an exception occurs::
with fileinput.input(files=('spam.txt', 'eggs.txt')) as input:
process(input)
.. versionchanged:: 3.2
Can be used as a context manager.
The following functions use the global state created by :func:`fileinput.input`; The following functions use the global state created by :func:`fileinput.input`;
if there is no active state, :exc:`RuntimeError` is raised. if there is no active state, :exc:`RuntimeError` is raised.
...@@ -132,13 +142,23 @@ available for subclassing as well: ...@@ -132,13 +142,23 @@ available for subclassing as well:
*filename* and *mode*, and returns an accordingly opened file-like object. You *filename* and *mode*, and returns an accordingly opened file-like object. You
cannot use *inplace* and *openhook* together. cannot use *inplace* and *openhook* together.
A :class:`FileInput` instance can be used as a context manager in the
:keyword:`with` statement. In this example, *input* is closed after the
:keyword:`with` statement is exited, even if an exception occurs::
with FileInput(files=('spam.txt', 'eggs.txt')) as input:
process(input)
.. versionchanged:: 3.2
Can be used as a context manager.
**Optional in-place filtering:** if the keyword argument ``inplace=1`` is passed **Optional in-place filtering:** if the keyword argument ``inplace=True`` is
to :func:`fileinput.input` or to the :class:`FileInput` constructor, the file is passed to :func:`fileinput.input` or to the :class:`FileInput` constructor, the
moved to a backup file and standard output is directed to the input file (if a file is moved to a backup file and standard output is directed to the input file
file of the same name as the backup file already exists, it will be replaced (if a file of the same name as the backup file already exists, it will be
silently). This makes it possible to write a filter that rewrites its input replaced silently). This makes it possible to write a filter that rewrites its
file in place. If the *backup* parameter is given (typically as input file in place. If the *backup* parameter is given (typically as
``backup='.<some extension>'``), it specifies the extension for the backup file, ``backup='.<some extension>'``), it specifies the extension for the backup file,
and the backup file remains around; by default, the extension is ``'.bak'`` and and the backup file remains around; by default, the extension is ``'.bak'`` and
it is deleted when the output file is closed. In-place filtering is disabled it is deleted when the output file is closed. In-place filtering is disabled
......
...@@ -238,6 +238,12 @@ class FileInput: ...@@ -238,6 +238,12 @@ class FileInput:
self.nextfile() self.nextfile()
self._files = () self._files = ()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def __iter__(self): def __iter__(self):
return self return self
......
...@@ -231,6 +231,30 @@ class FileInputTests(unittest.TestCase): ...@@ -231,6 +231,30 @@ class FileInputTests(unittest.TestCase):
## finally: ## finally:
## remove_tempfiles(t1) ## remove_tempfiles(t1)
def test_context_manager(self):
try:
t1 = writeTmp(1, ["A\nB\nC"])
t2 = writeTmp(2, ["D\nE\nF"])
with FileInput(files=(t1, t2)) as fi:
lines = list(fi)
self.assertEqual(lines, ["A\n", "B\n", "C", "D\n", "E\n", "F"])
self.assertEqual(fi.filelineno(), 3)
self.assertEqual(fi.lineno(), 6)
self.assertEqual(fi._files, ())
finally:
remove_tempfiles(t1, t2)
def test_close_on_exception(self):
try:
t1 = writeTmp(1, [""])
with FileInput(files=t1) as fi:
raise IOError
except IOError:
self.assertEqual(fi._files, ())
finally:
remove_tempfiles(t1)
def test_main(): def test_main():
run_unittest(BufferSizesTests, FileInputTests) run_unittest(BufferSizesTests, FileInputTests)
......
...@@ -15,6 +15,8 @@ Core and Builtins ...@@ -15,6 +15,8 @@ Core and Builtins
Library Library
------- -------
- Issue #1286: Allow using fileinput.FileInput as a context manager.
- Add lfu_cache() and lru_cache() decorators to the functools module. - Add lfu_cache() and lru_cache() decorators to the functools module.
......
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