0

I've been using argparse and have problems writing the output into a file with an optional output argument for argparse (--outfile). I always get an empty file when using the --outfile argument, but using standard output works. I am quite new to Python so there may be something obvious that I am missing.

I'm actually working on a more complex program that is a bit too long to share, so I created a simple dummy example that gets the same error.

This is the code:

import argparse
import sys


def print_content(file):
    for lines in file:
        print(f'This is the content: {lines}')


def create_argument_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser('printer',
                                     description='a commandline tool that prints the content of a file')
    parser.add_argument('input_file',
                        type=argparse.FileType(encoding='utf-8'),
                        default=[sys.stdin],
                        metavar='FILE')
    parser.add_argument('--outfile', '-o',
                        type=argparse.FileType('w', encoding='utf-8'),
                        default=[sys.stdout],
                        metavar='FILE')
    parser.add_argument('--print',
                        help='if present, prints the content of the file',
                        action='store_true')
    return parser


def main():
    parser = create_argument_parser()
    args = parser.parse_args()

    if args.print:
        print_content(args.input_file)


if __name__ == '__main__':
    main()

If I use standard output as below it works:

$ python program.py text.txt --print < output.txt

However, if I use the --outfile argument, the file is created but remains empty.

$ python program.py text.txt --print --outfile output.txt

What am I missing? (I use Python 3.8.5.)

Jennifer
  • 47
  • 4

2 Answers2

1

argparse creates the file for you, but it's still up to you to do anything with the new file.

For example, you might try

def write_contents(in_file, out_file):
    for line in in_file:
        out_file.write(line)

def main():
    parser = create_argument_parser()
    args = parser.parse_args()

    if args.print:
        write_content(args.input_file, args.output_file)

You seem to assume that print prints to the file, but it simply prints to standard output, always; argparse doesn't do anything to actually add any contents to the file (and it would be surprising if it did; what if you had an argparse configuration which requested for there to be several output files? Should it write to them all? Or the last one? Or the first one? So it's simply up to you to decide what to actually do with any files.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Is there any possibility to write the entire output to that file? Of course the example code I gave is rather simple, in my actual program I don't just put the input file into the output file, but have a more complex console output. I'd like for the entire output to be put in that file. I guess there's no easy way to do that? – Jennifer Apr 29 '21 at 10:30
  • 1
    You could close `sys.stdout` and reopen it to the new file. See e.g. https://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python (and also notice how several answers there suggest that not doing this from Python at all might be a better solution). – tripleee Apr 29 '21 at 10:30
-1

you could use this to write to a file for lines of a list

def file_write_csv(csv_name, csv_content):
""" generic csv writer """
print("writing " + csv_name)
with open(csv_name, "w") as out:
    for csv_line in csv_content:
        if not "\n" in csv_line:
            csv_line = csv_line + "\n"
        out.write(csv_line)
user3732793
  • 1,699
  • 4
  • 24
  • 53