Home > Software engineering >  Making a flag in argparse require 2 arguments with different types
Making a flag in argparse require 2 arguments with different types

Time:01-11

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.

  • Related