3

I would like to have 3 optional positional arguments (int, int, then str).

What I want:

$ ./args.py 0 100 vid
start=0
end=100
video='vid'

$ ./args.py 0 100
start=0
end=100
video=None

$ ./args.py 0
start=0
end=None
video=None

$ ./args.py vid
start=None
end=None
video='vid'

$ ./args.py
start=None
end=None
video=None

What I have tried:

#!/usr/bin/python3
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('start', type=int, nargs='?')
parser.add_argument('end',   type=int, nargs='?')
parser.add_argument('video', type=str, nargs='?')

print(parser.parse_args())

The problem with that code is:

$ ./args.py vid
usage: args.py [-h] [start] [end] [video]
args.py: error: argument start: invalid int value: 'vid'

argparse knows that the value 'vid' is not an integer, so I would like it to "skip" the two first arguments start and end since they don't match.

When I make the video argument mandatory, it works a bit better:

parser.add_argument('start', type=int, nargs='?')
parser.add_argument('end',   type=int, nargs='?')
parser.add_argument('video', type=str)

Demo:

# Fine!
$ ./args.py 0 100 vid
start=0
end=100
video='vid'

# Fine!
$ ./args.py vid
start=None
end=None
video='vid'

# Not fine
./args.py 
usage: args.py [-h] [start] [end] video
args.py: error: the following arguments are required: video
2
  • did you try setting a default value for video? Commented Dec 27, 2018 at 12:59
  • argparse raises an error when the type doesn't match; it doesn't skip that argument or go on to try another. Positional values like this are assigned strictly on position, not on value. Commented Dec 27, 2018 at 17:24

2 Answers 2

1

There is no built-in way to do this cleanly, I think. Thus, you'll just have to gather all of the options into a list and parse them out yourself.

e.g.

parser.add_argument('start_end_video', nargs='*')
args=parser.parse_args()
if len(args.start_end_video) == 1:
   video = args.start_end_video
elif len(args.start_end_video) == 3:
   start, end, video = args.start_end_video

etc.

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

Comments

1

I think you should add what your arguments are called:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-s', '--start', type=int)
parser.add_argument('-e', '--end', type=int)
parser.add_argument('-v', '--video', type=str)

args = parser.parse_args()
for arg in vars(args):
    print(arg, '=', getattr(args, arg))

That way you can specify the arguments and no confusion can occur:

$ ./args.py -s 0 -e 100 -v vid
start = 0
end = 100
video = vid
$ ./args.py -s 0 -e 100
start = 0
end = 100
video = None
$ ./args.py -s 0
start = 0
end = None
video = None
$ ./args.py -v vid
start = None
end = None
video = vid
$ ./args.py
start = None
end = None
video = None
$ ./args.py vid
usage: args.py [-h] [-s START] [-e END] [-v VIDEO]
args.py: error: unrecognized arguments: vid

Note: I have included short aliases in the arguments above. E.g. You can call -s instead of --start.

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.