Python 2.7. Parse input parameters - python

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.

Related

Python: help menu doesn't show all options when using parse_known_args()

I went through a "little" issue using python argument parser, I've created a parser like shown below:
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-l', '--log-level', help="log level")
parser.add_argument('-o', '--out-dir', help="output directory")
args, remaining = parser.parse_known_args()
outpu_dir = args.out_dir
parser.add_argument('-f', '--log-file', help = "log file directory")
args = parser.parse_args()
and the problem is that when calling the program with --help option, arguments added after parse_known_args() are not listed in the menu, I checked other topics related to this, but my case is a bit different! could any one give a help here please ?
Any code which is below the call to parse_known_args will not execute at all.
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-a')
parser.parse_known_args()
1/0
When running with --help this generates
usage: main.py [-h] [-a A]
optional arguments:
-h, --help show this help message and exit
-a A
Process finished with exit code 0
and not a ZeroDivisionError exception.
You can work around it by adding the help option after all the other args have been added & you've parsed the known args.
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, SUPPRESS
# don't add help right now
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter, add_help=False)
parser.add_argument('-l', '--log-level', help="log level")
parser.add_argument('-o', '--out-dir', help="output directory")
args, remaining = parser.parse_known_args()
outpu_dir = args.out_dir
parser.add_argument('-f', '--log-file', help="log file directory")
# add help later, when all other args have been added
parser.add_argument('-h', '--help', action='help', default=SUPPRESS,
help='Show this help message and exit.')
args = parser.parse_args()
Which results in:
(venv) ➜ python main.py --help
usage: main.py [-l LOG_LEVEL] [-o OUT_DIR] [-f LOG_FILE] [-h]
optional arguments:
-l LOG_LEVEL, --log-level LOG_LEVEL
log level (default: None)
-o OUT_DIR, --out-dir OUT_DIR
output directory (default: None)
-f LOG_FILE, --log-file LOG_FILE
log file directory (default: None)
-h, --help Show this help message and exit.
But it's much better if you can restructure your code to add all the argusments first before doing any parsing (i.e. avoid the call to parse_known_aergs before any other add_argument calls)

deferring exiting on --help when using parse_known_args()

I have a code that needs to build its command line arguments dynamically, based on configuration file. Schematically, what I end up doing is
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", type=str, default="",
help="Path to config file.")
args, unknown = parser.parse_known_args()
#here do stuff with args.config to extend parser list of arguments, and then:
parser.parse_args()
The argument management seems to work perfectly well but the trouble I have is that --help will exit at the first call parse_known_args, instead of the second parser.parse_args() which would have shown all the dynamically added arguments.... Is there a way to solve this?
I had the same problem some time ago. It can be solved by using two parsers.
A first pre-parser, with add_help=False to determine the configuration file;
The second full parser with help.
# test.py
import argparse
# First pre-parser to determine the configuration file
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("-c", "--config", default="", help="Path to config file.")
args = parser.parse_known_args()
# Do something with args.config
# Full and real parser
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", default="", help="Path to config file.")
parser.add_argument("-o", "--option", help="Option with default value from config file")
parser.parse_args()
This result in:
$ python3 test.py --help
usage: test.py [-h] [-c CONFIG] [-o OPTION]
optional arguments:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
Path to config file.
-o OPTION, --option OPTION
Option with default value from config file

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

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

Argparse: too few arguments translation API

I am using a google translation API and it is showing error:
translate boy -d french
usage: [-h] [-d DEST] [-s SRC] [-c] text
: error: too few arguments
The code of API is
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import argparse
import sys
from googletrans import Translator
def main():
parser = argparse.ArgumentParser(
description='Python Google Translator as a command-line tool')
parser.add_argument('text', help='The text you want to translate.')
parser.add_argument('-d', '--dest', default='en',
help='The destination language you want to translate. (Default: en)')
parser.add_argument('-s', '--src', default='auto',
help='The source language you want to translate. (Default: auto)')
parser.add_argument('-c', '--detect', action='store_true', default=False,
help='')
args = parser.parse_args()
translator = Translator()
if args.detect:
result = translator.detect(args.text)
result = """
[{lang}, {confidence}] {text}
""".strip().format(text=args.text,
lang=result.lang, confidence=result.confidence)
print(result)
return
result = translator.translate(args.text, dest=args.dest, src=args.src)
result = u"""
[{src}] {original}
->
[{dest}] {text}
[pron.] {pronunciation}
""".strip().format(src=result.src, dest=result.dest, original=result.origin,
text=result.text, pronunciation=result.pronunciation)
print(result)
if __name__ == '__main__':
main()
I think it is due to argparse module but I am not sure. I am a newbie so please explain completely. Thanks in advance.
Oops - I thought this code was your own; it appears to be the translate script from the github, https://github.com/ssut/py-googletrans/blob/master/translate
So there isn't another parser.
Still the diagnostics that suggest apply - print the sys.argv to see what the parser is getting, print args after parsing, and skip (for now) the call to Translate. And run with py3 if possible.
Your parser with just
parser = argparse.ArgumentParser(
description='Python Google Translator as a command-line tool')
parser.add_argument('text', help='The text you want to translate.')
parser.add_argument('-d', '--dest', default='en',
help='The destination language you want to translate. (Default: en)')
parser.add_argument('-s', '--src', default='auto',
help='The source language you want to translate. (Default: auto)')
parser.add_argument('-c', '--detect', action='store_true', default=False,
help='')
args = parser.parse_args()
print(args)
produces:
1347:~/mypy$ python2 stack47849057.py
usage: stack47849057.py [-h] [-d DEST] [-s SRC] [-c] text
stack47849057.py: error: too few arguments
1144:~/mypy$ python2 stack47849057.py boy
Namespace(dest='en', detect=False, src='auto', text='boy')
1144:~/mypy$ python2 stack47849057.py boy -d french
Namespace(dest='french', detect=False, src='auto', text='boy')
1145:~/mypy$ python3 stack47849057.py
usage: stack47849057.py [-h] [-d DEST] [-s SRC] [-c] text
stack47849057.py: error: the following arguments are required: text
In other words it works with your input. As noted in Py3 the error message is clearer.
I suspect there's a problem with Translator. It may have its own parser, and maybe even modifies the sys.argv. You could also print(sys.argv) to check that.
The error message seems to be coming from your parser, since the usage matches.

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

Categories

Resources