The argparse docs don't say who's responsible for closing FileType objects

Peter Otten __peter__ at web.de
Tue May 30 02:03:48 EDT 2017


Bob Kline wrote:

> The subject line pretty much says it all. Should the programmer close the
> file? If the programmer does that, and the user has asked that the file
> object be hooked up to standard in (or standard out) what will happen? If
> the programmer doesn't close it, does it get closed cleanly in the face of
> an exception?
> 
> Thanks!

There's an example in the module docstring:

"""
The following is a simple usage example that sums integers from the
command-line and writes the result to a file::

    parser = argparse.ArgumentParser(
        description='sum the integers at the command line')
    parser.add_argument(
        'integers', metavar='int', nargs='+', type=int,
        help='an integer to be summed')
    parser.add_argument(
        '--log', default=sys.stdout, type=argparse.FileType('w'),
        help='the file where the sum should be written')
    args = parser.parse_args()
    args.log.write('%s' % sum(args.integers))
    args.log.close()
"""

To handle exceptions you can rewrite

    args.log.write('%s' % sum(args.integers))
    args.log.close()

as

    with args.log as outstream:
        outstream.write('%s' % sum(args.integers))

The reason I still don't use FileType is that I usually don't want to

(1) open the file immediately in parse_args()
(2) close sys.stdXXX

My workaround are various wrappers along the line of myopen() below...

$ cat argparse_myopen.py
import argparse
import sys
from contextlib import contextmanager

parser = argparse.ArgumentParser(
    description='sum the integers at the command line')
parser.add_argument(
    'integers', metavar='int', nargs='+', type=int,
    help='an integer to be summed')
parser.add_argument(
    '--log', default=sys.stdout,
    help='the file where the sum should be written')
args = parser.parse_args()

@contextmanager
def myopen(file, mode= "r"):
    assert mode == "w"
    if hasattr(file, "write"):
        yield file
    else:
        with open(file, mode) as outstream:
            yield outstream

with myopen(args.log, "w") as out:
    print(sum(args.integers), file=out)

assert out.closed == (out is not sys.stdout)
print("Bye")
$ python3 argparse_myopen.py 1 2 --log tmp.txt
Bye
$ cat tmp.txt
3
$ python3 argparse_myopen.py 2 3
5
Bye

...that I'm going to consolidate into a single one. Someday.




More information about the Python-list mailing list