I'm trying to do mathematical operations between images. I have defined (simplified version of my real code):
parser = argparse.ArgumentParser(description='Arithmetic operations on images')
parser.add_argument("input1", metavar='input1', action='store',
help='list of input images to operate with', nargs="+", type=str)
parser.add_argument("operation", metavar='operation', action='store', type=str,
help='type of operation (+,-,*,/) to be done', nargs=1)
parser.add_argument("input2",metavar='input2', action='store', nargs="+",
type=str, help='image (or value) with which to perform the operation on input1')
This code, produces:
arith.py -h
usage: arith.py [-h] input1 [input1 ...] operation input2 [input2 ...]
so it does understand that input1 could contain one or more elements, operation will be a single one, and input2 could be any number of elements.
The problem, of course, is that having two positional arguments with an undetermined number of elements, argparse confuses what is what. I have tried adding choices=["+", "-", "*", "/"] to 'operation', so that it would know where to do the separation, but it seems argparse is not able to do it. Actually, in the argparse documentation, talking about nargs='*' you can read:
Note that it generally doesn’t make much sense to have more than one positional argument with nargs='*'
I have thought that I could add together args.input1, args.operation and args.input2 and separate myself looking for "+", "-", "/", "*", but before doing something so ugly I thought about tapping the collective mind.
When allocating strings to positionals, the parser only distinguishes between ones that start with a prefix char (e.g. '-') and the rest. It cannot distinguish between strings that represent 'numbers' and ones that represent 'operations'. In effect it performs this regex operation:
re.match('(A+)(A)(A+)','AAAAAAAAA')
which would produce (AAAAAA),(A),(A)
. It allocates enough strings to the the last 2 groups to satisfy their specs, and allocates the rest to the first.
So you need some sort of 'flag' to mark the end of the first list.
This is, I think, the closest you'll get with argparse
:
parser.add_argument("input1", nargs="+", type=int)
parser.add_argument("-o", "--operation", choices=['+','minus','*','/'] )
parser.add_argument("input2", nargs="+", type=int)
which should turn
PROG 1 3 4 -o + 5 6 7
PROG 1 3 4 -o+ 5 6 7
PROG 1 3 4 --operation=+ 5 6 7
into (I think)
namespace(input1=[1,3,4], operation='+', input2=[5,6,7])
Notice that the list of choices
does not include '-'. That's because the parser treats that as a prefix_char. There may be a way of sneaking it in as an argument value, but I'm not going to take the time to find it.
I converted the input1
values to integers in the parser. You could do that after. And of course make the floats instead.
I omitted default parameters like type=str
, action='store'
.
But perhaps a better solution is to take all the values as 1 list, and split it up yourself. At least with these 3 arguments you aren't making much use of argparse
power.
alist = ['1','2','3','+','4','5','6']
i = <find index of '+-/*'>
input1 = alist[:i]
operations = alist[i]
input2 = alsits[i+1:]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With