argparser.print_help() not printing the full message - python

I have a program where I tried to put help in my code using argparse:
import argparse,sys
parser = argparse.ArgumentParser(description='prog desc')
parser.add_argument('path', help='name of directory')
args = parser.parse_args()
parser.print_help()
this prints:
>python testArgs.py
usage: testArgs.py [-h] path
testArgs.py: error: too few arguments
but I'm expecting same as if I entered -h:
>python testArgs.py -h
usage: testArgs.py [-h] path
prog desc
positional arguments:
path name of directory
optional arguments:
-h, --help show this help message and exit
But if I switch the position of the print_help() before parse_args(), then it works right:
import argparse,sys
parser = argparse.ArgumentParser(description='prog desc')
parser.add_argument('path', help='name of directory')
parser.print_help()
args = parser.parse_args()
output:
>python testArgs.py
usage: testArgs.py [-h] path
prog desc
positional arguments:
path name of directory
optional arguments:
-h, --help show this help message and exit
usage: testArgs.py [-h] path
testArgs.py: error: too few arguments
What am I doing wrong?

In your first example your program doesn't reach the parser.print_help() method, it fails on parser.parse_args(), prints the default error message (which is testArgs.py: error: too few arguments) and exits the program.
In your second example, when you switch between the functions, it still behaves the same but you see the help details because you called the print_help() function before the program fails (you can see it fails because it still prints the error message at the end).
If you want to print the help message when an argparse error occurred, read this post:
Display help message with python argparse when script is called without any arguments

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)

Python argparse --help description in sentence case

Extremely nitpicky question, but it annoys me that the default argparse help message is a sentence fragment. For example, for a script that contains
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
The -h and --help flag message shows:
$ tmp.py --help
usage: tmp.py [-h]
optional arguments:
-h, --help show this help message and exit
However I prefer complete sentences in documentation and "sentence case" for headers:
$ tmp.py --help
Usage: tmp.py [-h]
Optional arguments:
-h, --help Show this help message and exit.
How can I keep the behavior of script -h and script --help but change the message?
Welp found the answer 5 seconds later.
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.parse_args()
parser.add_argument(
'-h', '--help', action='help', help='Show this help message and exit.')
Defining your own action='help' argument is probably the best answer. But it is possible to edit the default help.
All the defined Actions are collected in the parser._actions list. Yes, it is marked hidden, but people do access it as needed. Normally the help action is the first one created (as default), so it is element [0] of that list.
In [15]: parser._actions[0].help
Out[15]: 'show this help message and exit'
In [16]: parser._actions[0].help = "Show this help message and exit."
testing:
In [17]: parser.print_help()
usage: ipython3 [-h] {mySubcommand,m} ...
positional arguments:
{mySubcommand,m} sub-command help
mySubcommand (m)
Subcommand help
optional arguments:
-h, --help Show this help message and exit.
def main():
parser = argparse.ArgumentParser()
# specific file
parser.add_argument('-f', '--file', type=str, default='file',
help=Fore.BLUE + '--file access_log -extract-ip' + Style.RESET_ALL)
# http get file
parser.add_argument('-hgf', '--http-get-file', type=str, default='http-get-file',
help=Fore.BLUE + '--http-get-file URL' + Style.RESET_ALL)

Removing dest variable from help text

While using argparse, the help dialog of my program displays dest variable. How do I remove this?
I tried the add_help=False object but that just removed the help dialog for that option entirely.
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--interface", dest="interface", help="foo")
parser.add_argument("-m", "--mac", dest="mac", help="bar")
I get the following result with INTERFACE and MAC next to my optional arguments:
usage: test.py [-h] [-i INTERFACE] [-m MAC]
optional arguments:
-h, --help show this help message and exit
-i INTERFACE, --interface INTERFACE
foo
-m MAC, --mac MAC bar
How can I remove DEST values from my output?
As #hpaulj suggested, you can set the metavar parameter of each argument to an empty string
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--interface", dest="interface", help="foo", metavar='')
parser.add_argument("-m", "--mac", dest="mac", help="bar", metavar='')
parser.parse_args()
which will output the following result:
usage: test.py [-h] [-i] [-m]
optional arguments:
-h, --help show this help message and exit
-i , --interface foo
-m , --mac bar
Let me know if that's the output you expected.

Print help when positional arguments not provided

I'm trying to execute my Python program. It uses one positional argument. When the positional argument is not provided I want to print help. But all I get is
error : too few arguments
Here is the Python code :
parser = argparse.ArgumentParser(
description = '''My Script ''')
parser.add_argument('I', type=str, help='Provide the release log file')
args = parser.parse_args()
I'm expecting the following output when no positional arguments are specified:
usage: script.py [-h] I
My Script
positional arguments:
I Provide the release log file
optional arguments:
-h, --help show this help message and exit
Any thoughts how to achieve this would be appreciated.
argparse doesn't work that way. You need to ask for help with the -h argment. Otherwise it just gives the usage along with the error message.
0015:~/mypy$ python3 stack41671660.py
usage: stack41671660.py [-h] I
stack41671660.py: error: the following arguments are required: I
0015:~/mypy$ python stack41671660.py
usage: stack41671660.py [-h] I
stack41671660.py: error: too few arguments
0015:~/mypy$ python stack41671660.py -h
usage: stack41671660.py [-h] I
My Script
positional arguments:
I Provide the release log file
optional arguments:
-h, --help show this help message and exit
You could make the positional argument 'optional' with nargs='?', and add a test for the default value:
print(args)
if args.I is None:
parser.print_help()
sample runs:
0016:~/mypy$ python stack41671660.py
Namespace(I=None)
usage: stack41671660.py [-h] [I]
My Script
positional arguments:
I Provide the release log file
optional arguments:
-h, --help show this help message and exit
0019:~/mypy$ python stack41671660.py 2323
Namespace(I='2323')
Another option is to customize the parser.error method, so that it does print_help instead of print_usage. That will affect all parsing errors, not just this missing positional.
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
If you override this in a subclass, it should not return -- it
should either exit or raise an exception.
"""
# self.print_usage(_sys.stderr)
self.print_help(_sys.stderr)
args = {'prog': self.prog, 'message': message}
self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
`

How to make positional argument optional in argparser based on some condition in python

I want to write a python code in which, based on some arguments passed from command line I want to make positional argument optional.
For example,
My python program is test.py, and with it I can give --init, --snap, --check options. Now if I have given --snap and --check option, then file name is compulsory i.e.
test.py --snap file1
but if I have given --init option then it should not take any other arguments. i.e. in this case file name is optional:
test.py --init
How to implement this condition
If you are ok with changing the command line you are passing a little bit, then a set of subparsers should work.
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='sub-command help')
init_parser = subparsers.add_parser('init', help='do the init stuff')
snap_parser = subparsers.add_parser('snap', help='do the snap stuff')
snap_parser.add_argument('--file', '-f', required=True)
check_parser = subparsers.add_parser('check', help='do the check stuff')
check_parser.add_argument('--file', '-f', required=True)
args = parser.parse_args()
print args
And then the output...
> python foobar.py init
Namespace()
> python foobar.py check
usage: foobar.py check [-h] --file FILE
foobar.py check: error: argument --file/-f is required
> python foobar.py check --file foobar.txt
Namespace(file='foobar.txt')
General help:
> python foobar.py --help
usage: foobar.py [-h] {init,snap,check} ...
positional arguments:
{init,snap,check} sub-command help
init do the init stuff
snap do the snap stuff
check do the check stuff
optional arguments:
-h, --help show this help message and exit
And specific sub-command help
> python foobar.py snap -h
usage: foobar.py snap [-h] --file FILE
optional arguments:
-h, --help show this help message and exit
--file FILE, -f FILE
Your other option is to use nargs as #1.618 has already mentioned.
argparse allows you to specify that certain args have their own args, like so:
parser.add_argument("--snap", nargs=1)
or use a + to allow for an arbitrary number of "subargs"
After you call parse_args(), the values will be in a list:
filename = args.snap[0]

Categories

Resources