FileInput method to iterate over files explicitly for in-place mode?


Let’s say I want to use fileinput to modify command line-supplied files in-place (inplace=True) and that this modification involves prepending and appending new lines to the beginning and end of each file.

As far as I can tell, prepending a line to each file can only be done by checking fileinput.isfirstline() in each iteration, which is fairly ugly. Appending a line doesn’t seem possible at all (without extreme hacks), as by the time you know you’ve reached the end of a file, fileinput will have already un-patched stdout so it no longer writes to that file.

But I think this is a fairly common task in the kinds of file processing contexts you might want to use fileinput for, so IMHO there should be (better) ways of doing this.


I would like to suggest adding another method to the FileInput class that allows iteration over files and performs the necessary stdout (un)patching before and after each such iteration (disabling the per-line patching), so that one could write e.g.

import fileinput

with fileinput.input(inplace=True) as outer_input:
    for input in outer_input.iterfiles():
        for i, line in enumerate(input, start=1):
            print(f"{i} {line}", end="")

to append and prepend lines containing --- to each file while also processing each line.


At this point, I think you’re better off just creating a new FileInput instance for each file in the argument list.

for fname in sys.argv[1:]:
    with FileInput(fname, inplace=True) as f:
        for i, line in enumerate(f, start=1):
            print(f"{i} {line}", end="")

This doesn’t work with the current fileinput implementation and will print the ---s to the actual stdout instead for exactly the reason I mentioned above (being that stdout is patched after reading the first line from the input and restored after reading EOF).

So to support this pattern we’d also need changes to fileinput.

Some thoughts on this idea compared to mine:


  • No new method needed.
  • The fact that stdout (un)patching doesn’t happen on entering/exiting the FileInput context is confusing anyway and this would get rid of this weird behavior.


  • Not strictly backwards compatible (someone might rely on stdout not being (un)patched upon context enter/exit, although I guess it’s unlikely).
  • Part of the point of fileinput is to abstract over sys.argv and this breaks the abstraction.
  • To be exactly equivalent to fileinput’s CLI argument handling, you’d also need to handle the possibility of no arguments = read from stdin, so you wouldn’t be able to just use argv[1:] but something like argv[1:] if len(argv) > 1 else ["-"]; as mentioned in the point above, kind of duplicating what fileinput is meant to be responsible for…