Home > database >  Best way to take Command Line Arguments in Python Script
Best way to take Command Line Arguments in Python Script

Time:11-30

In my Python script, I have a lot of command line arguments. Some of them are mandatory while others are optional. Some of the optional are mandatory for certain values of mandatory params as well. What is the best way to take in such a case of command line arguments. I am using argparse.Argumentparser for my purpose.

To clarify the use case, here is an example. Let's say I have 3 mandatory params: mode, foo, bar and 5 optional params: op1, op2, op3, op4, op5. Lets say, mode can have 3 values: m1, m2, m3. If mode is m1, op1 and op2 are mandatory. If mode is m2, op3 is mandatory and if mode is m3, op4 and op5 are mandatory.

What is the best way to put it into code? What I'm doing now seems too exhaustive and just feels that there has to be better ways to do this.

-> Current code

import argparse

# create and execute parser
my_parser = argparse.ArgumentParser(description="Demo")
my_parser.add_argument("--mode", action="store", type=str, required=True)
my_parser.add_argument("--foo", action="store", type=str, required=True)
my_parser.add_argument("--bar", action="store", type=str, required=True)
my_parser.add_argument("--op1", action="store", type=str, required=False, default=None)
my_parser.add_argument("--op2", action="store", type=str, required=False, default=None)
my_parser.add_argument("--op3", action="store", type=str, required=False, default=None)
my_parser.add_argument("--op4", action="store", type=str, required=False, default=None)
my_parser.add_argument("--op5", action="store", type=str, required=False, default=None)
args = my_parser.parse_args()
try:
    if args.mode == "m1":
        op1 = args.op1.lower()
        op2 = args.op2.lower()
    if args.mode == "m2":
        op3 = args.op3.split(',')
    if args.mode == "m3":
        op4 = args.op4.lower()
        op5 = args.op5.lower()
except AttributeError:
    print("Wrong mode set for optional arguments")
    exit()

As you can see, even this example just "looks" aesthetically bad (esp try block parsing) and I have a lot many optional arguments to deal with in my case. Any help will be much appreciated.

Also, this approach doesn't exactly force the user to enter, eg, op1 and op2 in case his mode=m1. If it is possible to do something like this as well, it would be bonus benefits for me.

Thanks.

CodePudding user response:

It seems like your program is handling multiple different tasks. The way to support this is to split up your parser into sub-commands:

import argparse

parser = argparse.ArgumentParser(description="Demo")
parser.add_argument("--foo", required=True)
parser.add_argument("--bar", required=True)
subparsers = parser.add_subparsers(dest='mode', required=True)

m1_parser = subparsers.add_parser('m1', help='mode 1')
m1_parser.add_argument("--op1", required=True)
m1_parser.add_argument("--op2", required=True)
m1_parser.add_argument("--op3")
m1_parser.add_argument("--op4")
m1_parser.add_argument("--op5")

m2_parser = subparsers.add_parser('m2', help='mode 2')
m2_parser.add_argument("--op1")
m2_parser.add_argument("--op2")
m2_parser.add_argument("--op3", required=True)
m2_parser.add_argument("--op4")
m2_parser.add_argument("--op5")

m3_parser = subparsers.add_parser('m3', help='mode 3')
m3_parser.add_argument("--op1")
m3_parser.add_argument("--op2")
m3_parser.add_argument("--op3")
m3_parser.add_argument("--op4", required=True)
m3_parser.add_argument("--op5", required=True)

args = parser.parse_args()

if args.mode == 'm1':
    print(args.op1) # it will always exist

Usage:

$ python3 args.py m1
usage: args.py m1 [-h] --op1 OP1 --op2 OP2 [--op3 OP3] [--op4 OP4] [--op5 OP5]
args.py m1: error: the following arguments are required: --op1, --op2

While this seems repetitive, you now have the option of giving better names to the various options that are specific to the sub-commands.

  • Related