Custom synopsis variables/field names with Python's argparse.ArgumentParser [duplicate] - python

using argparse i have made a command line tool, which takes below arguments,
usage: ipush [-h] [-v] [-c] [-to [TO]] [-V] [-p PATCHES] [-d DIFF]
from the below code..
parser = argparse.ArgumentParser(prog='ipush',
description='Utility to push the last commit and email the color diff')
parser.add_argument('-v', '--verbose', action='store_true',
help='if enabled will spit every command and its resulting data.')
parser.add_argument('-c', '--compose', action='store_true',
help='compose message in default git editor to be sent prefixed with diff')
parser.add_argument('-to', type=validate_address, default=os.getenv('myemail'),
help='enter a valid email you want to send to.', nargs='?')
parser.add_argument('-V', '--version', action='version',
version='%(prog)s 1.0')
parser.add_argument('-p', '--patches', type=int, default=0,
help='total number of pathces of last commits to email')
parser.add_argument('-d', '--diff', required=False, default='HEAD^ HEAD',
help='if present pass arguments to it as you \
will do to git diff in inverted commas')
is it possible to display TO in [-to [TO]] PATCHES in [-p PATCHES] and DIFF in [-d DIFF] with a different text?

Yes, as described in the argparse documentation:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', metavar='YYY')
>>> parser.add_argument('bar', metavar='XXX')
>>> parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
>>> parser.print_help()
usage: [-h] [--foo YYY] XXX
positional arguments:
XXX
optional arguments:
-h, --help show this help message and exit
--foo YYY

Related

Python 2.7. Parse input parameters

Good time of the day! First of all, let me say that I'm a newbie in Python world. I've problems with parsing input parameters. At this moment I'm using Python 2.7 and module which is called argparse. I'm trying to design simple application which will be able to parse simple input parameters. Here is a short example:
my_app.py sync --force
Second example:
my_app.py patch --branch
I see that for this I can use add_argument which can work with positional and optional arguments. Like in my case I want to have few positional (but optional at the same time) and few optional arguments.
To do that I've design small script
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='My App')
parser.add_argument('sync', type=bool, const=True, nargs='?')
parser.add_argument('-f', '--force', dest='sync_force', type=bool, const=True, nargs='?')
parser.add_argument('-b', '--branch', type=str, const=True, nargs='?')
parser.add_argument('-u', '--url', type=str, const=True, nargs='?')
parser.add_argument('patch', type=bool, const=True, nargs='?')
parser.add_argument('revert', type=bool, const=True, nargs='?')
parser.add_argument('verify', type=bool, const=True, nargs='?')
values = parser.parse_args()
if values.revert:
handler.revert()
else:
parser.print_help()
I see that I can use nargs='?' to specify the positional parameter as optional, but each time when I'm calling my script it shows like I got 'sync' as input parameter, even if I specified 'patch'. So, I think that it shows just first added element.
Could you tell me what's wrong and where is a problem?
Update:
I'm trying to achieve a situation when I will be able to have only one positional argument at the same time(and at least one, but with any additional optional parameters). For example
my_app.py sync
my_app.py path
my_app.py verify --force
my_app.pyrevert --branch
With:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='My App')
parser.add_argument('cmd', choices=['sync','patch', 'revert','verify'])
parser.add_argument('-f', '--force', action='store_true')
parser.add_argument('-b', '--branch')
parser.add_argument('-u', '--url')
args = parser.parse_args()
print(args)
if args.cmd in ['revert']:
print('handler.revert()')
else:
parser.print_help()
testing
1243:~/mypy$ python stack60327766.py
usage: stack60327766.py [-h] [-f] [-b BRANCH] [-u URL]
{sync,patch,revert,verify}
stack60327766.py: error: too few arguments
1244:~/mypy$ python stack60327766.py revert
Namespace(branch=None, cmd='revert', force=False, url=None)
handler.revert()
1244:~/mypy$ python stack60327766.py revert -f -b foobar -u aurl
Namespace(branch='foobar', cmd='revert', force=True, url='aurl')
handler.revert()
1244:~/mypy$ python stack60327766.py verify-f -b foobar -u aurl
usage: stack60327766.py [-h] [-f] [-b BRANCH] [-u URL]
{sync,patch,revert,verify}
stack60327766.py: error: argument cmd: invalid choice: 'verify-f' (choose from 'sync', 'patch', 'revert', 'verify')
1245:~/mypy$ python stack60327766.py verify -f -b foobar -u aurl
Namespace(branch='foobar', cmd='verify', force=True, url='aurl')
usage: stack60327766.py [-h] [-f] [-b BRANCH] [-u URL]
{sync,patch,revert,verify}
My App
positional arguments:
{sync,patch,revert,verify}
optional arguments:
-h, --help show this help message and exit
-f, --force
-b BRANCH, --branch BRANCH
-u URL, --url URL
argparse has native support for subcommands.
Adapting from the above-linked documentation,
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
subparsers = parser.add_subparsers()
sync_parser = subparsers.add_parser('sync')
patch_parser = subparsers.add_parser('patch')
revert_parser = subparsers.add_parser('revert')
verify_parser = subparsers.add_parser('verify')
etc. is probably what you're looking for.
Beyond that, I can only recommend the Click library for a more fluent interface for CLIs.

is it possible to change display text of argparse argument name

using argparse i have made a command line tool, which takes below arguments,
usage: ipush [-h] [-v] [-c] [-to [TO]] [-V] [-p PATCHES] [-d DIFF]
from the below code..
parser = argparse.ArgumentParser(prog='ipush',
description='Utility to push the last commit and email the color diff')
parser.add_argument('-v', '--verbose', action='store_true',
help='if enabled will spit every command and its resulting data.')
parser.add_argument('-c', '--compose', action='store_true',
help='compose message in default git editor to be sent prefixed with diff')
parser.add_argument('-to', type=validate_address, default=os.getenv('myemail'),
help='enter a valid email you want to send to.', nargs='?')
parser.add_argument('-V', '--version', action='version',
version='%(prog)s 1.0')
parser.add_argument('-p', '--patches', type=int, default=0,
help='total number of pathces of last commits to email')
parser.add_argument('-d', '--diff', required=False, default='HEAD^ HEAD',
help='if present pass arguments to it as you \
will do to git diff in inverted commas')
is it possible to display TO in [-to [TO]] PATCHES in [-p PATCHES] and DIFF in [-d DIFF] with a different text?
Yes, as described in the argparse documentation:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', metavar='YYY')
>>> parser.add_argument('bar', metavar='XXX')
>>> parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
>>> parser.print_help()
usage: [-h] [--foo YYY] XXX
positional arguments:
XXX
optional arguments:
-h, --help show this help message and exit
--foo YYY

Python argparse: name parameters

I'm writing a program that use argparse, for parsing some arguments that I need.
for now I have this:
parser.add_argument('--rename', type=str, nargs=2, help='some help')
when I run this script I see this:
optional arguments:
-h, --help show this help message and exit
--rename RENAME RENAME
some help
How can I change my code in that way that the help "page" will show me:
--rename OLDFILE NEWFILE
Can I then use OLDFILE and NEWFILE value in this way?
args.rename.oldfile
args.rename.newfile
If you set metavar=('OLDFILE', 'NEWFILE'):
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--rename', type=str, nargs=2, help='some help',
metavar=('OLDFILE', 'NEWFILE'))
args = parser.parse_args()
print(args)
Then test.py -h yields
usage: test.py [-h] [--rename OLDFILE NEWFILE]
optional arguments:
-h, --help show this help message and exit
--rename OLDFILE NEWFILE
some help
You can then access the arguments with
oldfile, newfile = args.rename
If you really want to access the oldfile with args.rename.oldfile
you could set up a custom action:
import argparse
class RenameAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest,
argparse.Namespace(
**dict(zip(('oldfile', 'newfile'),
values))))
parser = argparse.ArgumentParser()
parser.add_argument('--rename', type=str, nargs=2, help='some help',
metavar=('OLDFILE', 'NEWFILE'),
action=RenameAction)
args = parser.parse_args()
print(args.rename.oldfile)
but it extra code does not really seem worth it to me.
Read the argparse documentation (http://docs.python.org/2.7/library/argparse.html#metavar):
Different values of nargs may cause the metavar to be used multiple times. Providing a tuple to metavar specifies a different display for each of the arguments:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', nargs=2)
>>> parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
>>> parser.print_help()
usage: PROG [-h] [-x X X] [--foo bar baz]
optional arguments:
-h, --help show this help message and exit
-x X X
--foo bar baz

How do you print all levels of help in argparse?

If I have code such as this:
import argparse
# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
# create the parser for the "a" command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('bar', type=int, help='bar help')
# create the parser for the "b" command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='XYZ', help='baz help')
parser.parse_args()
Asking for the help in a subparser results in:
$ ./test.py a -h
usage: PROG a [-h] bar
positional arguments:
bar bar help
optional arguments:
-h, --help show this help message and exit
How do I make it show the --foo option and the help for it, when asking for the help in a subparser?

Creating hidden arguments with Python argparse

Is it possible to add an Argument to an python argparse.ArgumentParser without it showing up in the usage or help (script.py --help)?
Yes, you can set the help option to add_argument to argparse.SUPPRESS. Here's an example from the argparse documentation:
>>> parser = argparse.ArgumentParser(prog='frobble')
>>> parser.add_argument('--foo', help=argparse.SUPPRESS)
>>> parser.print_help()
usage: frobble [-h]
optional arguments:
-h, --help show this help message and exit
I do it by adding an option to enable the hidden ones, and grab that by looking at sysv.args.
If you do this, you have to include the special arg you pick out of sys.argv directly in the parse list if you Assume the option is -s to enable hidden options.
parser.add_argument('-a', '-axis',
dest="axis", action="store_true", default=False,
help="Rotate the earth")
if "-s" in sys.argv or "-secret" in sys.argv:
parser.add_argument('-s', '-secret',
dest="secret", action="store_true", default=False,
help="Enable secret options")
parser.add_argument('-d', '-drill',
dest="drill", action="store_true", default=False,
help="drill baby, drill")

Categories

Resources