If I run my command as python manage.py foo --help
It returns:
Usage: manage.py load_cartridge_types_delivery_windows [options]
Options:
-v VERBOSITY, --verbosity=VERBOSITY
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
...
-h, --help show this help message and exit
At the bottom, it shows -h and the standard help message, "show this help message and exit". How do I change that help message to describe my command?
Just define the help attribute on the class.
Related
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
I am playing around with this Instagram ID tracker because my friends are constantly changing usernames so I can never keep up. The code is from here. The only way I am aware of, is that you have to go to any sort of terminal and type a command in this format
$ usage: t.py [-h] -u USERNAME [-p] [-s] [-t]
I've already tried to do some on my own and I recently saw other people running command lines in the Python text editor but it doesn't seem to work for me. This is what I did
import os
import main
import api
os.system('python3 main.py -u <USERNAME>')
There are 2 files, main.py and api.py. I imported both but when I run it, it still says
usage: t.py [-h] -u USERNAME [-p] [-s] [-t]
t.py: error: the following arguments are required: -u/--username
Is there an easier way to go about this?
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.
So I am trying to pass a command from python to command line as hex newline: \x0a
Which in python is also know as "\n"
what I'm trying to print through the command line is:
check_nrpe -H 127.0.0.1 -c check_users -a "echo -e "\x0a ls " #" 4 4
I tried
import subprocess as sb
sb.check_call(["check_nrpe", \ # first argument
"-H", host, # host
"-c", "check_users", # wanted remote command
"-a", # option
"\"`echo -e",
"\"\\x0a", # <new line>, problem is that python changes this to \n
parameter,
"\"` #\"", "4", "4"]])
"\"\x0a" # , problem is that python changes this to \n when passing the argument to the command line
So what i want to do is \x0a to be printed instead of \n
also i tried to encode
"\n".encode("hex")
which prints "0a"
Question is that how i tell python to pass the argument \x0a to the command line.
Clarify your check_nrpe call
Assuming, you have Nagios installed (I have it and run Ubuntu)
cd /urs/lib/nagios/plugins
See, check_nrpe help
$ ./check_nrpe -h
NRPE Plugin for Nagios
Copyright (c) 1999-2008 Ethan Galstad (nagios#nagios.org)
Version: 2.12
Last Modified: 03-10-2008
License: GPL v2 with exemptions (-l for more info)
SSL/TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required
Usage: check_nrpe -H <host> [-n] [-u] [-p <port>] [-t <timeout>] [-c <command>] [-a <arglist...>]
Options:
-n = Do no use SSL
-u = Make socket timeouts return an UNKNOWN state instead of CRITICAL
<host> = The address of the host running the NRPE daemon
[port] = The port on which the daemon is running (default=5666)
[timeout] = Number of seconds before connection times out (default=10)
[command] = The name of the command that the remote daemon should run
[arglist] = Optional arguments that should be passed to the command. Multiple
arguments should be separated by a space. If provided, this must be
the last option supplied on the command line.
-h,--help Print this short help.
-l,--license Print licensing information.
-n,--no-ssl Do not initial an ssl handshake with the server, talk in plaintext.
Note:
This plugin requires that you have the NRPE daemon running on the remote host.
You must also have configured the daemon to associate a specific plugin command
with the [command] option you are specifying here. Upon receipt of the
[command] argument, the NRPE daemon will run the appropriate plugin command and
send the plugin output and return code back to *this* plugin. This allows you
to execute plugins on remote hosts and 'fake' the results to make Nagios think
the plugin is being run locally.
Review your sample call (I have corrected formatting which got lost in your original post, it was hiding backquotes):
$ check_nrpe -H 127.0.0.1 -c check_users -a "`echo -e "\x0a ls "` #" 4 4
It seems like you try to call check_users command and pass it some arguments. So the final call on remote (NRPE driven) machine would look like:
$ check_users "`echo -e "\x0a ls "` #" 4 4
Comparing it to what check_users proposes on help screen:
$ ./check_users -h
check_users v1.4.15 (nagios-plugins 1.4.15)
Copyright (c) 1999 Ethan Galstad
Copyright (c) 2000-2007 Nagios Plugin Development Team
<nagiosplug-devel#lists.sourceforge.net>
This plugin checks the number of users currently logged in on the local
system and generates an error if the number exceeds the thresholds specified.
Usage:
check_users -w <users> -c <users>
Options:
-h, --help
Print detailed help screen
-V, --version
Print version information
-w, --warning=INTEGER
Set WARNING status if more than INTEGER users are logged in
-c, --critical=INTEGER
Set CRITICAL status if more than INTEGER users are logged in
Send email to nagios-users#lists.sourceforge.net if you have questions
regarding use of this software. To submit patches or suggest improvements,
send email to nagiosplug-devel#lists.sourceforge.net
It is clear, your attempt to call check_users over check_nrpe is broken as check_users expects exactly four arguments and the call should look like (assuming you consider 4 users be both critical and warning level):
$ ./check_users -c 4 -w 4
So your final call of check_nrpe could look like:
$ check_nrpe -H 127.0.0.1 -c check_users -a -c 4 -w 4
Note, that if you are trying to pass dynamic values to critical and warning, you shall do that over Nagios variables and do not assume, it will be shaped by command line (which happens on your remote machine). Such a technique could work, but is rather tricky.
Passing newline or other characters to command line calls
Another topic is, how to pass newlines or other special characters to commands from Python.
Here it is not so difficult, as you have a chance passing a list of arguments, which does not get interpreted by shell, but is directly passed to the command.
Simple commandline script bcmd.py
Following script allows testing what parameters were passed into it from command line:
import sys
print sys.argv
Test of calling commands from Python code
from subprocess import call
args = ["python", "bcmd.py"]
args.append("alfa")
args.append("be\nta")
args.append("""gama
hama""")
args.append("omega\x0aOMEGA")
args.append("double-omega\x0adouble-OMEGA")
args.append("literaly\\x0aliteraly")
call(args)
Call it:
$ python callit.py
['bcmd.py', 'alfa', 'be\nta', 'gama\n hama', 'omega\nOMEGA', 'double-omega\ndouble-OMEGA', 'literaly\\x0aliteraly']
and learn from it.
Conclusion:
Python allows calling commands and passing arguments via list bypassing shell parsing rules.
In your case, the real problem seem to be in use of check_nrpe rather then in passing in newlines.
In my python script myscript.py I use argparse to pass command-line arguments. When I want to display the help information about the input arguments, I just do:
$ python myscript.py --help
If instead I want to use ipython to run my script, the help message won't be displayed. Ipython will display its own help information:
$ ipython -- myscript.py -h
=========
IPython
=========
Tools for Interactive Computing in Python
=========================================
A Python shell with automatic history (input and output), dynamic object
introspection, easier configuration, command completion, access to the
system shell and more. IPython can also be embedded in running programs.
Usage
ipython [subcommand] [options] [files]
It's not so annoying, but is there a way around it?
You need to run your .py script inside the ipython. Something like that:
%run script.py -h
This is an IPython bug, corrected in https://github.com/ipython/ipython/pull/2663.
My 0.13 has this error; it is corrected in 0.13.2. The fix is in IPthyon/config/application.py Application.parse_command_line. This function looks for help and version flags (-h,-V) in sys.argv before passing things on to parse_known_args (hence the custom help formatting). In the corrected release, it checks sys.argv only up to the first --. Before it looked in the whole array.
earlier:
A fix for earlier releases is to define an alternate help flag in the script:
simple.py script:
import argparse, sys
print(sys.argv)
p = argparse.ArgumentParser(add_help=False) # turn off the regular -h
p.add_argument('-t')
p.add_argument('-a','--ayuda',action=argparse._HelpAction,help='alternate help')
print(p.parse_args())
Invoke with:
$ ./ipython3 -- simple.py -a
['/home/paul/mypy/argdev/simple.py', '-a']
usage: simple.py [-t T] [-a]
optional arguments:
-t T
-a, --ayuda alternate help
$ ./ipython3 -- simple.py -t test
['/home/paul/mypy/argdev/simple.py', '-t', 'test']
Namespace(t='test')