2

In my example below, I am trying to setup the following command line scenarios:

$ myapp.py flowers [-h]
$ myapp.py flowers plants [-h]
$ myapp.py flowers plants add [-h]

The actual outcomes are:

$ python myapp.py flowers
usage: myapp.py flowers [-h] {plants} ...
myapp.py flowers: error: too few arguments
$ python myapp.py flowers plants
usage: myapp.py flowers plants [-h] [--format {plain,json}] {add} ...
myapp.py flowers plants: error: too few arguments
$ python myapp.py flowers plants add
Adding flowers...  The input format is expected to be plain

The problem is the second scenario. I intend for it to be an implicit "list" operation. How to do this?

Here is the source code to my example.

import sys
import argparse

def _flowers_plants_list(args):
    print('if this were real, the output format would be %s' % (args.format))       
    print('Here are all the flowers:')
    print('flower 1: rose')
    print('flower 2: tulip')
    print('flower 3: daisy')

def _flowers_plants_add(args):
    print('Adding flowers...  The input format is expected to be %s' % (args.format))

def main():
    # myapp.py
    parser_main = argparse.ArgumentParser()
    subparsers_main = parser_main.add_subparsers()

    # myapp.py flowers [-h]
    parser_flowers = subparsers_main.add_parser("flowers")
    subparsers_flowers = parser_flowers.add_subparsers()

    # (this is supposed to be an implicit list - NOT WORKING)
    # myapp.py flowers plants [-h]
    parser_flowers_plants = subparsers_flowers.add_parser("plants")
    parser_flowers_plants.add_argument("--format", default='plain', choices=['plain', 'json'], help="what format should the result be in")
    parser_flowers_plants.set_defaults(func=_flowers_plants_list)
    subparsers_flowers_plants = parser_flowers_plants.add_subparsers()

    # myapp.py flowers plants add [-h]
    parser_flowers_plants_add = subparsers_flowers_plants.add_parser("add")
    parser_flowers_plants_add.add_argument("--format", default='plain', choices=['plain', 'json'], help="what format will the input be in")
    parser_flowers_plants_add.set_defaults(func=_flowers_plants_add)

    args = parser_main.parse_args()
    r = args.func(args)
    return r

if __name__ == "__main__":
    sys.exit(main())
2
  • In newer versions, esp. Py3, subparsers are optional (that's mistake that's here to stay). In older ones subparsers are required. It looks like that's what's happening here. The parser_flowers_plants parser is complaining that it can't find an argument (with {'add'} choices). Commented May 15, 2018 at 18:02
  • An earlier SO exploration of nested or multiple subcommands: stackoverflow.com/questions/10448200/… Commented May 15, 2018 at 21:20

1 Answer 1

0

In Py3:

1420:~/mypy$ python3 stack50350537.py 
Traceback (most recent call last):
  File "stack50350537.py", line 40, in <module>
    sys.exit(main())
  File "stack50350537.py", line 36, in main
    r = args.func(args)
AttributeError: 'Namespace' object has no attribute 'func'
1421:~/mypy$ python3 stack50350537.py flowers
Traceback (most recent call last):
  File "stack50350537.py", line 40, in <module>
    sys.exit(main())
  File "stack50350537.py", line 36, in main
    r = args.func(args)
AttributeError: 'Namespace' object has no attribute 'func'
1421:~/mypy$ python3 stack50350537.py flowers plants
if this were real, the output format would be plain
Here are all the flowers:
flower 1: rose
flower 2: tulip
flower 3: daisy
1422:~/mypy$ python3 stack50350537.py flowers plants add
Adding flowers...  The input format is expected to be plain

In py2, subparsers are required:

1423:~/mypy$ python2 stack50350537.py
usage: stack50350537.py [-h] {flowers} ...
stack50350537.py: error: too few arguments
1423:~/mypy$ python2 stack50350537.py flowers
usage: stack50350537.py flowers [-h] {plants} ...
stack50350537.py flowers: error: too few arguments
1423:~/mypy$ python2 stack50350537.py flowers plants
usage: stack50350537.py flowers plants [-h] [--format {plain,json}] {add} ...
stack50350537.py flowers plants: error: too few arguments
1423:~/mypy$ python2 stack50350537.py flowers plants add
Adding flowers...  The input format is expected to be plain

In Py3, subparsers are not required. Initially that change was a bug, that resulted from a change in how required was tested. But it's been that way long enough that it is now a feature. There's a move toward giving users a bit more control over this feature, but I think the not required will remain the default.

Argparse with required subparser

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.