passing multiple flags in argparse? - python

I am trying to pass multiple different flags using argparse. I know this kind of code would work for a single flag. if the -percentage flag is passed then do something
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-percentage', action='store_true')
but I'm trying to pass multiple flags, for example this code
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-serviceA', action='store_true')
parser.add_argument('-serviceB', action='store_true')
parser.add_argument('-serviceC', action='store_true')
parser.add_argument('-serviceD', action='store_true')
parser.add_argument('-activate', action='store_true')
and then pass flags -serivceB -activate, my intention is that the activate flag is basically a yes or no. and the service flag is the actual service. so that the service would get activated only when there is a activate flag next to it. how can I do this?
I hope i explained the situation in detail. please any help or tips are appreciated.

I was debugging it wrong. I spent last 5 hours trying to figure this out. Thanks to everyone who mentioned the comment!
for anyone experiencing the same issue, when you are debugging using a launch.json file. make sure your args are like this "args": [
"--serviceA", "--activate"
],
I had set up args like this "--serviceA --activate"

Related

Automatically add shorter (posix) argument in argparse

I have the following code:
import argparse
parser = argparse.ArgumentParser(description='Dedupe library.', allow_abbrev=True)
parser.add_argument( '-a', '--all', nargs='+', type=int, help='(Optional) Enter one or more IDs.')
Is it possible to automatically add in the -a option when it's not specified? For example, something like:
parser.add_argument('--all', nargs='+', type=int, help='(Optional) Enter one or more IDs.')
And it can be called with:
$ parse.py -a 2
$ parse.py --all 2
Or is that not an option with argparse?
A clean way to do something like this, is by subclassing ArgumentParser and creating your own:
import argparse
class MyArgumentParser(argparse.ArgumentParser):
def add_argument(self, *args, **kwargs):
# check if one was already passed, for backward compatibility
if not any(len(a) == 2 and a.startswith('-') for a in args):
for a in args:
if a.startswith('--'):
# you could do something more fancy here, like calling an (optional) callback
return super().add_argument(a[1:3], *args, **kwargs)
return super().add_argument(*args, **kwargs)
parser = MyArgumentParser(description='Dedupe library.', allow_abbrev=True)
parser.add_argument('--all', nargs='+', type=int, help='(Optional) Enter one or more IDs.', dest='all')
Mind you, it's not necessarily a good idea. You can have conflicting options (like multiple that start with the same letter, so you might need to add code for that). And then you may have a preference for which option takes which letter with many options. Etc.
In the end, you have to ask yourself if the "convenience" offered by a solution like this really outweighs the effort of writing it, the overhead of the extra code and the lack of clarity in the resulting code for future you and other contributors that wonder where the extra options are coming from. Not to mention that it's perhaps just a good thing to explicitly state what options you're setting up?
Just that something can be done, doesn't mean you should do it.

python argparse: name of argument not displayed in help menu, if choices attr supplied

When using argparse in python 3.6, I've noticed that if I supply the 'choices' attr when adding one of the arguments, then in the help menu's section for that argument, the list of choices themselves show up rather than the name of the argument.
Using this stackoverflow answer Python argparse: Lots of choices results in ugly help output, I found to use the 'metavar' and 'numargs' attrs to
try and clean up the help menu. While this gets rid of the ugly choices being displayed as a hash, the name of the option still does not display at all in help.
Example...
This:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("works", type=int,
help="Shows up properly")
parser.add_argument("nope", type=int, choices=[1,2,3],
help="foobared")
parser.add_argument("nope2", type=int, choices=[1,2,3], nargs='?', metavar='',
help="still foobared")
parser.add_argument("why", type=int,
help="help me")
parser.parse_args()
Results in this help output:
$ python myparser.py --help
usage: myparser.py [-h] works {1,2,3} why
positional arguments:
works Shows up properly
{1,2,3} foobared
still foobared
why help me
optional arguments:
-h, --help show this help message and exit
This has to be simple... Can someone please advise me where I'm going wrong?
Although you answered the question yourself, I'd like to highlight the answer here to make other people easily find it.
You can use the metavar (https://docs.python.org/3/library/argparse.html#metavar) key word in order to say to an argument parser which is the name of the argument and it will be displayed if you type --help.
By default if you don't specify anything except name or flags (https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument) it is going to show that name just because it doesn't have any other mean to display it.

gem/git-style command line arguments in Python

Is there a Python module for doing gem/git-style command line arguments? What I mean by gem/git style is:
$ ./MyApp.py
The most commonly used MyApp commands are:
add Add file contents to the index
bisect Find by binary search the change that introduced a bug
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
...
$ ./MyApp.py branch
* current-branch
master
With no arguments, the output tells you how you can proceed. And there is a special "help" command:
$ ./MyApp.py help branch
Which gets you deeper tips about the "branch" command.
Edit:
And by doing I mean it does the usage printing for you, exits with invalid input, runs your functions according to your CLI specification. Sort of a "URL mapper" for the command line.
Yes, argparse with add_subparsers().
It's all well explained in the Sub-commands section.
Copying one of the examples from there:
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> checkout = subparsers.add_parser('checkout', aliases=['co'])
>>> checkout.add_argument('foo')
>>> parser.parse_args(['checkout', 'bar'])
Namespace(foo='bar')
Edit: Unfortunately there's no self generated special help command, but you can get the verbose help message (that you seem to want) with -h or --help like one normally would after the command:
$ ./MyApp.py branch --help
By verbose I don't mean that is like a man page, it's like every other --help kind of help: listing all the arguments, etc...
Example:
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(description='Sub description')
>>> checkout = subparsers.add_parser('checkout', description='Checkout description')
>>> checkout.add_argument('foo', help='This is the foo help')
>>> parser.parse_args(['checkout', '--help'])
usage: checkout [-h] foo
Checkout description
positional arguments:
foo This is the foo help
optional arguments:
-h, --help show this help message and exit
If you need to, it should be easy to implement an help command that redirects to --help.
A reasonable hack to get the gem/git style "help" behavior (I just wrote this for what I'm working on anyway):
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='sub_commands')
parser_branch = subparsers.add_parser('branch', description='list of branches')
parser_help = subparsers.add_parser('help')
parser_help.add_argument('command', nargs="?", default=None)
# I can't find a legitimate way to set a default subparser in the docs
# If you know of one, please let me know!
if len(sys.argv) < 2:
sys.argv.append('--help')
parsed = parser.parse_args()
if parsed.sub_commands == "help":
if not parsed.command:
parser.parse_args(['--help'])
else:
parser.parse_args([parsed.command, '--help'])
argparse is definitely a step up from optparse and other python solutions I've come across. But IMO the gem/git style of handling args is just a more logical and safer way to do things so it's annoying that it's not supported.
I wanted to do something similar to git commands, where I would load a second script based off of one of the command line options, and have that script populate more command line options, and also have the help work.
I was able to do this by disabling the help option, parse known args, add more arguments, re-enable the help option, and then parse the rest of the arguments.
This is what I came up with.
import argparse
#Note add_help=False
arg_parser = argparse.ArgumentParser(description='Add more arguments after parsing.',add_help=False)
arg_parser.add_argument('MODE', default='default',type=str, help='What commands to use')
args = arg_parser.parse_known_args()[0]
if args.MODE == 'branch':
arg_parser.add_argument('-d', '--delete', default='Delete a branch')
arg_parser.add_argument('-m', '--move', default='move a branch')
elif args.MODE == 'clone' :
arg_parser.add_argument('--local', '-l')
arg_parser.add_argument('--shared')
#Finally re-enable the help option, and reparse the arguments
arg_parser.add_argument(
'-h', '--help',
action='help', default=argparse.SUPPRESS,
help=argparse._('show this help message and exit'))
args = arg_parser.parse_args()

Setting default option in Python of two mutually exclusive options using the argparse module

import argparse
parser = argparse.ArgumentParser(description="List or update! That is the question!")
group = parser.add_mutually_exclusive_group()
group.add_argument('-l', '--list', dest="update", action='store_false')
group.add_argument('-u', '--update', dest="update", action='store_true')
args = parser.parse_args()
print args
If the user does not specify any optional arguments I want update=False.
[Edit]: I changed my question to not be so general, it was confusing. Sorry.
You should set different dest for the 2 options.
group.add_argument('-f', '--foo', dest="foo", action='store_false')
I think that you want add_mutually_exclusive_group(). The documentation is here.
Adding default=False for the --list option's parameters makes it do what you want. I am not exactly sure why, and note that adding it to the --update option's parameters instead does nothing.

How to make `help` act the same as `--help` in argparse

I want the help option act the same as --help.
sidenote: I have created a program with the same command line behavior as svn or hg. I managed to do this with subparsers. However I want to make things consistent. That's why I want help to work.
You can do the following to create an alias and make program help act the same as program --help
import argparse
def help(args):
args.parser.print_help()
parser = argparse.ArgumentParser(description='my program')
subparsers = parser.add_subparsers()
p_help = subparsers.add_parser('help')
p_help.set_defaults(func=help, parser=parser)
args = parser.parse_args()
args.func(args)
It seems to me that you want to define help as another subparser. I would naively say that you could then link it to a print_help() function that would copy the output of your standard --help, but I wonder if there is a way to call the native help() function.

Categories

Resources