Search code examples
pythonargumentsdocopt

docopt required options and options with arguments


I am new to docopt and am having a bit of difficulty getting a small example working. I'm having two small problems just now and would welcome assistance on those problems and more general comments on improving the code. The first problem is getting the program to require the --required option. It should print the docstring on running without the required command line option. The second problem is getting the program to accept arguments (such as COMPUTER) for options (such as --computer). How would this be specified in the terminal and how should it be coded?

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
my example program

Usage:
    docopt_example_1.py [--ipaddress=IPADDRESS] [--computer=COMPUTER]
    docopt_example_1.py --network <network>
    docopt_example_1.py (--required)
    docopt_example_1.py --notrequired
    docopt_example_1.py --version

Arguments:
    IPADDRESS               I.P. address
    COMPUTER                computer identification
    <network>               network identification

Options:
    -h, --help              Show this help message.
    --version               Show the version and exit.
    --required              option required for running
    --notrequired           option not required for running
    --ipaddress=IPADDRESS   I.P. address
    --computer=COMPUTER     computer identification
    --network=NETWORK       network identification
"""
from docopt import docopt

def main(options):
    print("----------")
    print("a printout of the command line options as parsed by docopt:")
    print(options)
    print("----------")
    if options["--notrequired"]:
        print("required option selected")
    if options["--computer"]:
        print("computer name: {computer}".format(computer=options["COMPUTER"]))
    if options["--network"]:
        print("computer name: {network}".format(network=options["<network>"]))
    else:
        print("no options")

if __name__ == "__main__":
    options = docopt(__doc__, version='1')
    main(options)

Solution

  • Regarding your 1st problem, "All elements are required by default, if not included in brackets". All usage lines are parallel, which means inputs only need to match any one of usage lines, it will be considered valid. So you need to add 'required parameters' into all usage lines:

    Usage:
        docopt_example_1.py --required [--notrequired] [--ipaddress=IPADDRESS] [--computer=COMPUTER]
        docopt_example_1.py --required [--notrequired] --network <network>
        docopt_example_1.py --version
    

    In the above example, if your input is not "docopt_example_1.py --version" and doesn't contain "--required", it will print the docstring on running.


    Regarding 2nd problem, read the arguments of options by using the option names:

    print("computer name: {computer}".format(computer=options["--computer"]))
    print("network name: {network}".format(network=options["--network"]))
    

    Besides, you may want to take care of the note from official site:

    writing --input ARG (opposed to --input=ARG) is ambiguous, meaning it is not possible to tell whether ARG is option's argument or positional argument. In usage patterns this will be interpreted as option with argument only if option's description (covered below) for that option is provided. Otherwise it will be interpreted as separate option and positional argument.

    The help understand it, if you remove this line

    --network=NETWORK       network identification
    

    and inputs are docopt_example_1.py --required [--notrequired] --network network_name, then you won't be able to read "network_name" from options['--network'], instead you need to use options['<network>']. Because in this case "network_name" is considered a separate positional argument.


    Btw, the following lines seem have logic bug. The else only bond to the last if. I think this's not what you expected:

    if options["--notrequired"]:
        print("required option selected")
    if options["--computer"]:
        print("computer name: {computer}".format(computer=options["COMPUTER"]))
    if options["--network"]:
        print("computer name: {network}".format(network=options["<network>"]))
    else:
        print("no options")
    

    Reference: http://docopt.org/