3

So I'm trying to come up with a strategy using the argparse library.

Here's how I want to interface with my program:

$ program list [<number>] 
$ program check <name>
$ program watch <name> [<quality>]

Right now I have an argument parser like the following:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('list')
group.add_argument('check')
group.add_argument('watch')

But how can I add an optional argument, say an integer, to an existing argument?

Meaning the user could invoke the list command in the following ways:

program list 

Where the list action would be called with a default value, or:

program list 10

Where the list action would be called with an argument of 10.

I saw the subcommands option in the documentation, but I ran into the problem where I would have a sub parser for list arguments, but then I would have to add a flag, such as -n and then provide the number. Perhaps this is a better way of doing it? But I like the idea of just providing the number if you want to, or omitting it if you don't.

Is what I'm trying to achieve good practice? Is it possible with argparse?

3
  • Have you looked here yet? Commented Apr 22, 2015 at 21:01
  • And here. Commented Apr 22, 2015 at 21:02
  • I don't think he wants to handle multiple subparsers at once. Commented Apr 22, 2015 at 21:32

1 Answer 1

2

This sample set me off in the wrong direction. I've sketched a subparser implementation at the end that I think does the trick.

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('list')
group.add_argument('check')
group.add_argument('watch')

It expects 3 strings, and will assign them to the 3 attributes.

However, you cannot put 3 'positional` arguments in a mutually exclusive group. One optional positional (yes the terminology is confusing) can be in such a group, but the rest must 'optionals' (flagged).


Going back to your initial list. Are these different patterns that you'd like to accept

program list [integer]
program check name
program watch name [quality]

where 'list','check','watch' are literal strings, while 'integer','name','quality' are variable names.

If that is the case, then subparsers is probably the best choice. nargs='?' can be used to make positional arguments 'optional'.

parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='cmd')  # put the command string in `cmd` attribute
p1 = sp.add_parser('list')
p2 = sp.add_parser('check')
p3 = sp.add_parser('watch')
p1.add_argument('value',dtype=int, nargs='?') # ok with 0 or 1 values
p2.add_argument('name')
p3.add_argument('name')
p3.add_argument('quality',nargs='?')

value and quality will get the default value if none is explicitly given. The default default is None. But you can define a meaningful alternative, e.g. default=0 for the integer value.


You could also define a parser like:

parser = ...
parser.add_argument('command', choices=['list','check','watch'])
parser.add_argument('rest', nargs='*')

This will expect one of the 3 'command' strings, and put anything else in the 'rest' attribute (as a list of strings). You could then interpret those strings however you want.

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

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.