Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying default filenames with argparse, but not opening them on --help?

Let's say I have a script that does some work on a file. It takes this file's name on the command line, but if it's not provided, it defaults to a known filename (content.txt, say). With python's argparse, I use the following:

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()
# do some work on args.content, which is a file-like object

This works great. The only problem is that if I run python myscript --help, I get an ArgumentError if the file isn't there (which I guess makes sense), and the help text is not shown. I'd rather it not try to open the file if the user just wants --help. Is there any way to do this? I know I could make the argument a string and take care of opening the file myself later (and I've been doing that), but it would be convenient to have argparse take care of it.

like image 255
Ismail Badawi Avatar asked Nov 23 '11 03:11

Ismail Badawi


1 Answers

Looking at the argparse code, I see:

  • ArgumentParser.parse_args calls parse_known_args and makes sure that there isn't any pending argument to be parsed.
  • ArgumentParser.parse_known_args sets default values and calls ArgumentParser._parse_known_args

Hence, the workaround would be to use ArgumentParser._parse_known_args directly to detect -h and, after that, use ArgumentParser.parse_args as usual.

import sys, argparse
parser = argparse.ArgumentParser(description='my illustrative example', argument_default=argparse.SUPPRESS)
parser.add_argument('--content', metavar='file',
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
parser._parse_known_args(sys.argv[1:], argparse.Namespace())
args = parser.parse_args()

Note that ArgumentParser._parse_known_args needs a couple of parameters: the arguments from the command line and the namespace.

Of course, I wouldn't recommend this approach since it takes advantage of the internal argparse implementation and that might change in the future. However, I don't find it too messy, so you still might want to use it if you think maintenance risks pay off.

like image 68
jcollado Avatar answered Oct 22 '22 03:10

jcollado