How do you get argparse to choose a default subparser?

后端 未结 1 1111
后悔当初
后悔当初 2021-01-21 05:28

I have the following code in script.py:

import argparse

parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest=\'command\')
sp.default          


        
相关标签:
1条回答
  • 2021-01-21 06:00

    First a historical note - subparsers were not optional, and they still aren't in Python2. The fact that they are optional in Py3 is something of a bug that was introduced several years ago. There was a change in the test for required arguments, and subparsers (a kind of positional) fell through the cracks. If done right you should have had to explicitly set subparsers as not-required.

    Subparsers don't behave like other non-required arguments, ones with nargs='?' or flagged without the required parameter.

    In any case, your sp.default defines the value that will be put in the command dest, but it does not trigger the use of a_parser. That command='a' is never 'evaluated'.

    The use of parse_known_args might allow you to devaluate the remaining strings with a_parser.

    Without any arguments, we can do:

    In [159]: args, extras = parser.parse_known_args([])
    In [160]: args
    Out[160]: Namespace(command='a')
    In [161]: extras
    Out[161]: []
    

    Then conditionally run a_parser (if command is 'a' but no 'thing')

    In [163]: a_parser.parse_args(extras,namespace=args)
    Out[163]: Namespace(command='a', thing='thing')
    

    But if I try to include a --thing value:

    In [164]: args, extras = parser.parse_known_args('--thing ouch'.split())
    usage: ipython3 [-h] {a,b} ...
    ipython3: error: argument command: invalid choice: 'ouch' (choose from 'a', 'b')
    

    It tries to parse the 'ouch' as subparser name. The main parser doesn't known anything about the --thing argument.

    As I explained in the other argparse question today, the toplevel parser parses the inputs until it finds something that fits the 'subparsers' command (or in this example raises an error). Then it passes the parsing to the subparser. It does not resume parsing after.

    Add top level argparse arguments after subparser args

    How to Set a Default Subparser using Argparse Module with Python 2.7

    My answer to this Py2 request might work for you. I first run a parse_known_args with a parser that doesn't have subparsers, and conditionally run a second parser that handles the subparsers.

    In [165]: firstp = argparse.ArgumentParser()
    In [166]: args, extras = firstp.parse_known_args('--thing ouch'.split())
    In [167]: args
    Out[167]: Namespace()
    

    If extras doesn't have 'a' or 'b' call a_parser (alternatively just look at sys.argv[1:] directly):

    In [168]: extras
    Out[168]: ['--thing', 'ouch']
    In [169]: a_parser.parse_args(extras)
    Out[169]: Namespace(thing='ouch')
    

    Or modify extras to include the missing subparser command:

    In [170]: extras = ['a']+extras
    In [171]: parser.parse_args(extras)
    Out[171]: Namespace(command='a', thing='ouch')
    

    In any case, optional subparsers is not well developed in argparse. It's the side effect of a change made a while back, rather than a well thought out feature.

    0 讨论(0)
提交回复
热议问题