Does argparse (python) support mutually exclusive groups of arguments?

前端 未结 4 617
醉话见心
醉话见心 2020-12-09 16:55

If I have the arguments \'-a\', \'-b\', \'-c\', \'-d\', with the add_mutually_exclusive_group() function my program will have to use just one of th

4条回答
  •  醉酒成梦
    2020-12-09 17:07

    The argparse enhancement request referenced in @hpaulj's comment is still open after more than nine years, so I figured other people might benefit from the workaround I just discovered. Based on this comment in the enhancement request, I found I was able to add an option to two different mutually-exclusive groups using this syntax:

    #!/usr/bin/env python                                                                                                                                                                     
    import argparse
    import os
    import sys
    
    def parse_args():
        parser = argparse.ArgumentParser(
            formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
    
        parser.add_argument("-d", "--device", help="Path to UART device", default="./ttyS0")
    
        mutex_group1 = parser.add_mutually_exclusive_group()
        mutex_group2 = parser.add_mutually_exclusive_group()
    
        mutex_group1.add_argument(
            "-o",
            "--output-file",
            help="Name of output CSV file",
            default="sensor_data_sent.csv",
        )
    
        input_file_action = mutex_group1.add_argument(
            "-i", "--input-file", type=argparse.FileType("r"), help="Name of input CSV file"
        )
    
        # See: https://bugs.python.org/issue10984#msg219660
        mutex_group2._group_actions.append(input_file_action)
    
        mutex_group2.add_argument(
            "-t",
            "--time",
            type=int,
            help="How long to run, in seconds (-1 = loop forever)",
            default=-1,
        )
    
        # Add missing ']' to usage message
        usage = parser.format_usage()
        usage = usage.replace('usage: ', '')
        usage = usage.replace(']\n', ']]\n')
        parser.usage = usage
    
        return parser.parse_args()
    
    
    if __name__ == "__main__":
        args = parse_args()
        print("Args parsed successfully...")
        sys.exit(0)
    

    This works well enough for my purposes:

    $ ./fake_sensor.py -i input.csv -o output.csv                                                                                                                                             
    usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
    fake_sensor.py: error: argument -o/--output-file: not allowed with argument -i/--input-file
    
    $ ./fake_sensor.py -i input.csv -t 30         
    usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
    fake_sensor.py: error: argument -t/--time: not allowed with argument -i/--input-file
    
    $ ./fake_sensor.py -i input.csv
    Args parsed successfully...
    
    $ ./fake_sensor.py -o output.csv
    Args parsed successfully...
    
    $ ./fake_sensor.py -o output.csv -t 30
    Args parsed successfully...
    

    Accessing private members of argparse is, of course, rather brittle, so I probably wouldn't use this approach in production code. Also, an astute reader may notice that the usage message is misleading, since it implies that -o and -i can be used together when they cannot(!) However, I'm using this script for testing only, so I'm not overly concerned. (Fixing the usage message 'for real' would, I think, require much more time than I can spare for this task, but please comment if you know a clever hack for this.)

提交回复
热议问题