I'd like to make a parser for a program like follows program --serve some/path /file/to/serve.html
Looking at the argparse documentation https://docs.python.org/3/library/argparse.html#type
I cannot for the life of me figure out how I could parse the first argument of --serve
as a string and the second as argparse.FileType('r')
I'd like to do something like
parser.add_argument('--serve', nargs=2, type=(str, argparse.FileType('r')), action='append', help='...')
Is there a way to do this with argparse?
CodePudding user response:
If you implement a custom type and instead of using --nargs=2
you use a delimiter to separate the two arguments, you could do something like this:
import os
import stat
import argparse
def mytype(v):
dirpath, filepath = v.split(':')
try:
res = os.stat(filepath)
except FileNotFoundError:
raise ValueError(f'{filepath} does not exist')
else:
if not stat.S_ISREG(res.st_mode):
raise ValueError(f'{filepath} is not a regular file')
return dirpath, filepath
p = argparse.ArgumentParser()
p.add_argument('--serve', type=mytype, action='append', help='...')
args = p.parse_args()
print(args)
If I run this in a directory that contains the file foo.txt
, we see:
# with a file that does not exist
$ python argtest.py --serve somedir:bar.txt
usage: argtest.py [-h] [--serve SERVE]
argtest.py: error: argument --serve: invalid mytype value: 'somedir:bar.txt'
# with a file that *does* exist
$ python argtest.py --serve somedir:foo.txt
Namespace(serve=[('somedir', 'foo.txt')])
This isn't opening the file; it's testing that the second argument points to a regular file. You could instead of the file and return a file object instead of the path if you want.