Argparse nargs=“+” is eating positional argument

时光怂恿深爱的人放手 提交于 2019-12-11 12:59:13

问题


Here's a subsection of my parser configuration

parser.add_argument(
    'infile', help="The file to be imported",
    type=argparse.FileType('r'), default=sys.stdin
)

parser.add_argument(
    '--carpark', nargs='+', dest='CarparkID', type=int, default=[],
    help="One or many carpark IDs"
)

However, the --carpark argument seems to be too greedy and eats anything that follows it:

$ mycommand --carpark 17 ~/path-to-file
mycommand: error: argument --carpark: invalid int value: '/home/oli/path-to-file'

What's a good way around something like this? I need to pass a list of integer IDs into the command but also have a positional file (which can also be stdin).

Is there —for example— a non-greedy nargs option that will only parse as much of this as makes sense?


回答1:


If you want to specify multiple car park IDs, I would do one of two things instead of using nargs='+':

  1. Use the option once per ID (mycommand --carpark 17 --carpark 18)

    parser.add_argument('--carpark',
                        dest='carpark_ids',
                        type=int,
                        action='append',
                        default=[],
                        help="One carpark ID (can be used multiple times)"
    )
    
  2. Take a single, comma-delimited argument instead (mycommand --carpark 17,18)

    parser.add_argument('--carpark',
                        type=lambda s: map(int, s.split(",")),
                        dest='carpark_ids',
                        default=[],
                        help="One or more carpark IDs"
    )
    

    With a little more work, you could modify this to allow multiple uses of --carpark to accumulate all its values into a single list.

A third alternative, one I'm not particularly fond of, is to abandon the positional argument, making it an optional argument instead. (mycommand --carpark 17 18 --infile ~/path-to-file).

parser.add_argument('--infile',
                    help="The file to be imported",
                    type=argparse.FileType('r'),
                    default=sys.stdin
)

parser.add_argument('--carpark',
                    nargs='+',
                    dest='CarparkID',
                    type=int, default=[],
                    help="One or many carpark IDs"
)



回答2:


Does this work?

$ mycommand ~/path-to-file --carpark 17 

There is a Python bug/issue over + Actions that consume too many arguments, leaving none for following Actions.

The argument allocation is based on argument counts, not on type. The type function is applied after allocation, and there's no provision for returning 'rejected' arguments.

In correct behavior it should take into account that infile is expecting an argument - and there aren't any further flag strings - and thus reserve one string to that Action.

I could look that bug/issue up, but for now the fix is to supply the arguments in a different order. Or define a --infile action (instead of the positional).

An earlier question, with the bug/issue link (my answer focuses more on getting the usage right).

Argparse - do not catch positional arguments with `nargs`.



来源:https://stackoverflow.com/questions/36328769/argparse-nargs-is-eating-positional-argument

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!