40

I want to accomplish something like this:

-LoadFiles
    -SourceFile "" -DestPath ""
    -SourceFolder "" -DestPath ""
-GenericOperation
    -SpecificOperation -Arga "" -Argb ""
    -OtherOperation -Argc "" -Argb "" -Argc ""

A user should be able to run things like:

-LoadFiles -SourceFile "somePath" -DestPath "somePath"

or

-LoadFiles -SourceFolder "somePath" -DestPath "somePath"

Basically, if you have -LoadFiles, you are required to have either -SourceFile or -SourceFolder after. If you have -SourceFile, you are required to have -DestPath, etc.

Is this chain of required arguments for other arguments possible? If not, can I at least do something like, if you have -SourceFile, you MUST have -DestPath?

akshat
  • 1,219
  • 1
  • 8
  • 24
user3715648
  • 1,498
  • 3
  • 16
  • 25
  • 1
    http://bugs.python.org/issue11588 explores ways of adding general interdependency tests, but until that is implemented, your best bet is to do the testing yourself, after parsing. – hpaulj Dec 10 '14 at 22:39
  • 1
    This is what _sub-commands_ are for. See [`ArgumentParser.add_subparsers()`](https://docs.python.org/3.8/library/argparse.html?highlight=argparse#argparse.ArgumentParser.add_subparsers). – Feuermurmel Mar 06 '20 at 16:14

4 Answers4

52

You can use subparsers in argparse

 import argparse
 parser = argparse.ArgumentParser(prog='PROG')
 parser.add_argument('--foo', required=True, help='foo help')
 subparsers = parser.add_subparsers(help='sub-command help')

 # create the parser for the "bar" command
 parser_a = subparsers.add_parser('bar', help='a help')
 parser_a.add_argument('bar', type=int, help='bar help')
 print(parser.parse_args())
Saeed Ghareh Daghi
  • 1,164
  • 1
  • 13
  • 21
35

After you call parse_args on the ArgumentParser instance you've created, it'll give you a Namespace object. Simply check that if one of the arguments is present then the other one has to be there too. Like:

args = parser.parse_args()
if ('LoadFiles' in vars(args) and 
    'SourceFolder' not in vars(args) and 
    'SourceFile' not in vars(args)):

    parser.error('The -LoadFiles argument requires the -SourceFolder or -SourceFile')
randomusername
  • 7,927
  • 23
  • 50
3

There are some argparse alternatives which you can easily manage cases like what you mentioned. packages like: click or docopt.

If we want to get around the manual implementation of chain arguments in argparse, check out the Commands and Groups in click for instance.

Mark K.
  • 1,969
  • 2
  • 16
  • 15
2

Here is a sample that in case you specify --makeDependency, forces you to specify --dependency with a value as well.

This is not done by argparse alone, but also by by the program that later on validates what the user specified.

#!/usr/bin/env python
import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument('--makeDependency', help='create dependency on --dependency', action='store_true')
parser.add_argument('--dependency', help='dependency example')

args = parser.parse_args()

if args.makeDependency and not args.dependency:
    print "error on dependency"
    sys.exit(1)

print "ok!"
Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
  • 1
    Best practice to write error message to stderr sys.stderr.write('error on dependency') – edc Dec 01 '21 at 16:26