python argparse corss sub-command option - python

using argparse, i am trying to create an optional argument which is available globally (in all commands and sub-commands).
for instance, setting a --verbose optional argument. in the same way that --help is available by default.
the following snippet only works for me in the non-subcommand
parser.add_argument(
'-v', '--verbose',
help='verbose',
type=bool,
default=False,
action=argparse.BooleanOptionalAction
)
how can it be done?

Each parser, main and sub, gets an automatic help argument (unless you specify add_help=False). Further more a '-h' exits right away after displaying its message. So if the '-h' is before the subcommand string, you see the main help. If after you see that subcommand's help.
To make a command like '-v' available both in the main and the sub parsers, you have to define it in all parsers. The parents can streamline that. But this has problems, as #Alex points out. The default value for the subcommand overrides any value set in the main (default or user).
You can get around this by specifying a different dest for the main and the subs. You can still use the same '-v', but the values will be in different attributes in args.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-v','--verbose', action='store_true')
sp = parser.add_subparsers(dest='cmd')
sp1 = sp.add_parser('cmd1')
sp1.add_argument('-v', '--verbose', action='store_true', dest='subverbose')
args = parser.parse_args()
print(args)
sample runs:
0925:~/mypy$ python3 stack65773318.py -h
usage: stack65773318.py [-h] [-v] {cmd1} ...
positional arguments:
{cmd1}
optional arguments:
-h, --help show this help message and exit
-v, --verbose
0928:~/mypy$ python3 stack65773318.py cmd1 -h
usage: stack65773318.py cmd1 [-h] [-v]
optional arguments:
-h, --help show this help message and exit
-v, --verbose
0928:~/mypy$ python3 stack65773318.py -v
Namespace(cmd=None, verbose=True)
0928:~/mypy$ python3 stack65773318.py -v cmd1
Namespace(cmd='cmd1', subverbose=False, verbose=True)
0928:~/mypy$ python3 stack65773318.py cmd1 -v
Namespace(cmd='cmd1', subverbose=True, verbose=False)
0928:~/mypy$ python3 stack65773318.py -v cmd1 -v
Namespace(cmd='cmd1', subverbose=True, verbose=True)

You probably want to use parents like so:
import argparse
base_parser = argparse.ArgumentParser(add_help=False)
base_parser.add_argument("-v", "--verbose", help="verbose", action="store_true")
parser = argparse.ArgumentParser(parents=[base_parser])
subparsers = parser.add_subparsers()
parser_1 = subparsers.add_parser("sub", parents=[base_parser])
parser_1.add_argument("--foo", help="Some opt")
args = parser.parse_args()
print(args)
What this generates:
~ python args.py -h
usage: args.py [-h] [-v] {sub} ...
positional arguments:
{sub}
optional arguments:
-h, --help show this help message and exit
-v, --verbose verbose
~ python args.py sub -h
usage: args.py sub [-h] [-v] [--foo FOO]
optional arguments:
-h, --help show this help message and exit
-v, --verbose verbose
--foo FOO Some opt
This method requires the -v flag be used after the sub-command, though.
~ python args.py sub -v --foo 9
Namespace(verbose=True, foo='9') # -v is recognised
~ python args.py -v sub --foo 9
Namespace(verbose=False, foo='9') # -v is not recognised

Related

Command line args accepting -SS also where as expected is -S using argparse

I have command line argument -S as defined below
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
'-S',
'--save',
action='store_true',
help='Save to directory'
)
but if I use -SS instead of -S, python doesn't throw any error. I want invalid argument error. Can anybody tell me how to achieve this?
You need to use allow_abbrev=False in argparse.ArgumentParse
import argparse
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('-S',action='store_true',help='Save to directory')
parser.parse_args()
Output:
user#localhost:/tmp$ python3 temp.py -S
user#localhost:/tmp$ python3 temp.py -SS
usage: temp.py [-h] [-S]
temp.py: error: unrecognized arguments: -SS
Error is raised when it is called with -SS
Don't use Single Dash.
Use Double Dash. Because In single Dash(takes one single character),
when you do -SS it is equivalent to -S -S that's why no error.
But if you use Double Dash then it will be
--SS => --SS

git subcommand with --help arg, not working

Having this example code:
#!/usr/bin/env python3
import argparse
def main():
parser = argparse.ArgumentParser(description="Some Description")
parser.add_argument('some-arg')
args = parser.parse_args()
print(args)
if __name__ == '__main__':
main()
I add this code to file called git-mycommand, made it executable and copied it to /usr/bin.
Now trying to run command with --help, gives me this unintended output:
user#user:~$ git mycommand --help
No manual entry for git-mycommand
See 'man 7 undocumented' for help when manual pages are not available.
If I run command normally without --help, It works properly, like:
oerp#oerp:~$ git mycommand some_val
Namespace(**{'some-arg': 'some_val'})
Or if I dont use it as git subcommand and run it directly, like:
oerp#oerp:~$ git-mycommand --help
usage: git-mycommand [-h] some-arg
Some Description
positional arguments:
some-arg
optional arguments:
-h, --help show this help message and exit
Does anyone know why custom git subcommand does not work properly with --help argument? Or maybe there is something else, I need to do, so it would show intended output?
The git command is receiving the --help option, not your subcommand.
Note that git --help ... is identical to git help ... because the former is internally converted into the latter.
https://git-scm.com/docs/git-help
git help invokes git-help which opens the man page for the given command.

How can I mark a cli arg to be dependant on another arg existance?

I am using python3.4
The question refers to the https://docs.python.org/3/library/argparse.html package
If I want an arg --with_extra_actions to always acompany --arg1 or --arg2 and give an error message if one of those two is missing?
Examples:
command --arg1 --with_extra_actions That should work
command --arg2 --with_extra_actions That should work
command --with_extra_actions That should fail with informative error.
I am doing it right now in the code itself. No issue there, but is there an intrinsic way for the argparse lib to do this?
You can do it using add_mutually_exclusive_group. Here example(test.py):
import argparse
import sys
parser = argparse.ArgumentParser(prog='our_cmd')
# with_extra_actions is always required
parser.add_argument(
'--with_extra_actions',
required=True,
action='store_false'
)
# only one argument from group is available
# group is required - one from possible arguments is required
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--arg1', action='store_true')
group.add_argument('--arg2', action='store_true')
parser.parse_args(sys.argv[1:])
Now let's check our script:
python test.py --with_extra_actions
usage: our_cmd [-h] --with_extra_actions (--arg1 | --arg2)
our_cmd: error: one of the arguments --arg1 --arg2 is required
Let's try with arg1 and arg2:
python test.py --arg1 --arg2 --with_extra_actions
usage: our_cmd [-h] --with_extra_actions (--arg1 | --arg2)
our_cmd: error: argument --arg2: not allowed with argument --arg1
Without any errors:
python test.py --arg1 --with_extra_actions
python test.py --arg2 --with_extra_actions
Hope this helps.

Define argument for which a special action is performed (rather than parsing) [duplicate]

In all my scripts I use the standard flags --help and --version, however I cannot seem to figure out how to make a --version with parser.add_argument(..., required=True).
import sys, os, argparse
parser = argparse.ArgumentParser(description='How to get --version to work?')
parser.add_argument('--version', action='store_true',
help='print version information')
parser.add_argument('-H', '--hostname', dest='hostname', required=True,
help='Host name, IP Address')
parser.add_argument('-d', '--database', dest='database', required=True,
help='Check database with indicated name')
parser.add_argument('-u', '--username', dest='username', required=True,
help='connect using the indicated username')
parser.add_argument('-p', '--password', dest='password', required=True,
help='use the password to authenticate the connection')
args = parser.parse_args()
if args.version == True:
print 'Version information here'
$ ./arg.py --version
usage: arg.py [-h] [--version] -H HOSTNAME -d DATABASE -u USERNAME -p PASSWORD
arg.py: error: argument -H/--hostname is required
Yes, I want --hostname and others required, but I always want --version to work appropriately like --help (and -h).
$ ./arg.py --help
usage: arg.py [-h] [--version] -H HOSTNAME -d DATABASE -u USERNAME -p PASSWORD
How to get --version to work?
optional arguments:
-h, --help show this help message and exit
--version print version information
-H HOSTNAME, --hostname HOSTNAME
Host name, IP Address
-d DATABASE, --database DATABASE
Check database with indicated name
-u USERNAME, --username USERNAME
connect using the indicated username
-p PASSWORD, --password PASSWORD
use the password to authenticate the connection
Any help on getting --version to work?
There is a special version action keyword argument to add_argument (As documented here: argparse#action).
Try this (copied from working code):
parser.add_argument('-V', '--version',
action='version',
version='%(prog)s (version 0.1)')

docopt not working and proceeding

The following version 0.6.2 docopt string is not working although i dont find any error in it:
"""Usage:
somecommand.py [-n nos] [-u] [-c] [-s start]
Options:
-h show help
-u some reply
-n number to fetch
-c ask to do it
-s start from?
"""
on commandline:
somecommand.py -n 2 -s 5
Usage:
privateunreadlybrate.py [-n nos] [-u] [-c] [-s start]
the execution does not proceed and it keeps on showing usage for any command entered.
So where is the error?
The 'nos' value also has to be given in the 'options:' part, try this:
"""Usage:
somecommand.py [-n nos] [-u] [-c] [-s start]
Options:
-h show help
-u some reply
-n nos number to fetch
-c ask to do it
-s start start from?
"""

Categories

Resources