Mutually exclusive options for argparse I wrote a Python program that can take as argument either a string or a filename, with these options being mutually exclusive:

#!/usr/bin/env python

import argparse
import sys  

def parse_command_line():
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--text', dest = 'input_text', help = 'Text')
    parser.add_argument('-f', '--file', dest = 'input_file', help = 'File containing the text')
    return parser


if __name__ == '__main__':
    parser = parse_command_line()
    args = parser.parse_args()

    if args.input_text is not None and args.input_file is None:
        text = args.input_text
    elif args.input_file is not None and args.input_text is None:
        text = open(args.input_file, 'r').read()
    else:
        parser.print_help()
        sys.exit()

    # Program continues ...


The mutually exclusive check is not optimal and will become very ugly in case of three, four, ... options. How can I improve this code?
What you are looking for is add_mutually_exclusive_group. It allows you to define options that are mutually exclusive as well as specifying if selecting one of these options is a required action or not. And looking at your else: block, yours is; meaning if we call the program without arguments, it should fail with an error along the following:

usage: [-h] (-t TEXT | -f FILE)
program_name.py: error: one of the arguments -t/--text -f/--file is required


You are also handling files in your input and should avoid doing so manually. argparse provides a FileType object meant to be used as the type keyword of add_argument to handle files for you. It will fail with a proper error message if the file cannot be opened with the proper mode and will return the opened file object in the resulting parsed arguments.

Proposed improvements:

#!/usr/bin/env python

import argparse


def parse_command_line():
    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('-t', '--text', help='Text')
    group.add_argument('-f', '--file', type=argparse.FileType('r'), help='File containing the text')
    return parser


if __name__ == '__main__':
    args = parse_command_line().parse_args()

    if args.text is not None:
        text = args.text
    elif args.file is not None:
        with args.file as f:
            text = f.read()

    # Program continues ...


Also note the use of with to properly close the provided file.