emmalg
emmalg

Reputation: 346

Python argparse - option with options to dict

I am trying to parse some options with argparse. I have found some similar problems discussed and found what I thought was a similar issue with a sensible solution given by Owen in Options with Options with Python argparse?

I want to be able to specify, for example:

script.py infile --line <path to file1> beglab='str1' endlab='str2' 
                 --line <path to file2>  
                 --line <path to file3> beglab='str3' 
                 outfile

--line can be specified multiple times. Initially I had no extra arguments for the line option and I was able to create a list of the files without a problem using:

parser.add_argument("--line", action='append')

Now I need to optionally add labels to go with the lines. There can be 0, 1 or 2 labels associated with a given line as shown above. This is why I felt the example in the link provided seemed appropriate, unfortunately when I try:

parser.add_argument("--line", action='append', nargs="+")

And run:

script.py infile --line somefile beglab='A' endlab='B' 
                 --line otherfile beglab='a' endlab='b' outfile

or

script.py infile --line somefile outfile

I get an error stating that there are too few arguments. If I remove the --line options from the command so I have just the positional ones, it works, so I know I haven't missed anything required. So I went and I read up on the nargs options. If --line is specified, it must have at least the filename, therefore I think that nargs='+' is the appropriate option, it looks about right in the help [--line LINE [LINE ...]], so I am really confused about where this error has come from.

I am happy to consider alternative methods of dealing with this, I just liked the simplicity of providing the inputs like this and creating a dictionary with them.

Upvotes: 3

Views: 606

Answers (2)

Robᵩ
Robᵩ

Reputation: 168626

The parser you want to build is ambiguous. If endlab='b' is optional, then argparse can't tell if the operator intends that outfile is a parameter to --line or a positional argument.

You don't have to change your parser, but you do have to change your command line:

Try:

script.py infile outfile
          --line somefile beglab='A' endlab='B' 
          --line otherfile beglab='a' endlab='b' 

Or:

script.py infile 
          --line somefile beglab='A' endlab='B' 
          --line otherfile beglab='a' endlab='b' 
          --
          outfile

Upvotes: 2

Cargo23
Cargo23

Reputation: 3189

I'm not sure about how to accomplish this with argparse, but for simplicity, I would consider doing something like:

--line <path_to_file>,<beglab>,<endlab>

And then parse the argument either in code or using argparse's custom type functionality. You can have the custom type function return a dict like {'filepath':'<path_to_file>', 'beglab':'<beglab>', 'endlab':'<endlab>'}

Upvotes: 0

Related Questions