I'm a newbie with python.
Can anyone tell me how to remove "None" output below?
def main(argv=None):
if argv is None: argv = sys.argv
usage = "%prog [options] [command]"
parser = OptionParser(usage=usage, add_help_option=False,
version="version %s" % VERSION)
parser.add_option("-v", action="count", dest="verbose",
help="print extra messages to stdout")
# help displays the module doc text plus the option help
def doHelp(option, opt, value, parser):
print( __doc__ )
parser.print_help()
sys.exit(0)
parser.add_option("-h", "--help",
help="show help message and exit",
action="callback", callback=doHelp)
Output:
[root ~]# ./test.py -h
None
Usage: test.py [options] [command]
Options:
--version show program's version number and exit
Remove the print( __doc__ ) line. This is for docstrings.
Related
I am working on python script where I need to do two things basis on the input parameters passed:
push: This will call an api to post some data.
status: This will call another api to check the data and print out details on the console.
When we use push parameter then we need to always pass these three mandatory parameters:
environment
instance
config
And when we use status parameter then we need to pass only these two mandatory parameters:
environment
instance
How can I make these arguments configurable in such a way using argparse in Python? I was reading more about this here but confuse on how to make above things work in nice way? Also usage message should clearly tell what to use with what input.
Is this possible to do using argparse? Any example will be greatly appreciated. In general we will call a method for push case which will use those parameters and similarly for status we will call some other method which will use those parameters.
Here's a simple example that uses argparse with two subcommands:
"""
How to have different mandatory parameters for two categories
using argparse python?
"""
import argparse
import sys
def main():
"""
Description here
"""
parser = argparse.ArgumentParser(
description='Stack Overflow 64995368 Parser'
)
parser.add_argument(
"-v",
"--verbose",
help="verbose output",
action="store_true"
)
subparser = parser.add_subparsers(
title="action",
dest='action',
required=True,
help='action sub-command help'
)
# create the subparser for the "push" command
parser_push = subparser.add_parser(
'push',
help='push help'
)
parser_push.add_argument(
'environment',
type=str,
help='push environment help'
)
parser_push.add_argument(
'instance',
type=str,
help='push instance help'
)
parser_push.add_argument(
'config',
type=str,
help='push config help'
)
# create the subparser for the "status" command
parser_status = subparser.add_parser(
'status',
help='status help'
)
parser_status.add_argument(
'environment',
type=str,
help='status environment help'
)
parser_status.add_argument(
'instance',
type=str,
help='status instance help'
)
args = parser.parse_args()
if args.action == 'push':
print('You chose push:',
args.environment, args.instance, args.config)
elif args.action == 'status':
print('You chose status:',
args.environment, args.instance)
else:
print('Something unexpected happened')
if __name__ == "__main__":
try:
sys.exit(main())
except KeyboardInterrupt:
print("\nCaught ctrl+c, exiting")
Example output for various command lines:
$ python3 test.py
usage: test.py [-h] [-v] {push,status} ...
test.py: error: the following arguments are required: action
$ python3 test.py -h
usage: test.py [-h] [-v] {push,status} ...
Stack Overflow 64995368 Parser
optional arguments:
-h, --help show this help message and exit
-v, --verbose verbose output
action:
{push,status} action sub-command help
push push help
status status help
$ python3 test.py push -h
usage: test.py push [-h] environment instance config
positional arguments:
environment push environment help
instance push instance help
config push config help
optional arguments:
-h, --help show this help message and exit
$ python3 test.py push
usage: test.py push [-h] environment instance config
test.py push: error: the following arguments are required: environment, instance, config
$ python3 test.py push myenv
usage: test.py push [-h] environment instance config
test.py push: error: the following arguments are required: instance, config
You could do something like this, using set_defaults to attribute a handler for each subcommand.
import argparse
def push(args):
return (args.environment, args.instance, args.config)
def status(args):
return (args.environment, args.instance)
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# create the parser for the push command
push_parser = subparsers.add_parser('push')
push_parser.set_defaults(func=push)
push_parser.add_argument('--environment', type=str)
push_parser.add_argument('--instance', type=str)
push_parser.add_argument('--config', type=str)
# create the parser for the status command
status_parser = subparsers.add_parser('status')
status_parser.set_defaults(func=status)
status_parser.add_argument('--environment', type=str)
status_parser.add_argument('--instance', type=str)
args = parser.parse_args(['push', '--environment=a', '--instance=b', '--config=c'])
print(args.func(args))
It's often easier just to use sys.argv contents directly.
https://www.tutorialspoint.com/python/python_command_line_arguments.htm
#! /usr/bin/env python3
import sys
s_args = sys .argv ## s_args[0] = script_name.py
def push( environment, instance, config ):
print( 'PUSH command:', environment, instance, config )
def status( environment, instance ):
print( 'STATUS command:', environment, instance )
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == '__main__':
if len( s_args ) < 4:
print( 'missing args:' )
print( ' PUSH environment instance config' )
print( ' STATUS environment instance' )
elif s_args[1] .lower() == 'push':
if len( s_args ) < 5:
print( 'missing args for PUSH command:' )
print( ' PUSH environment instance config' )
else:
push( s_args[2], s_args[3], s_args[4] )
elif s_args[1] .lower() == 'status':
if len( s_args ) < 4:
print( 'missing args for STATUS command:' )
print( ' STATUS environment instance' )
else:
status( s_args[2], s_args[3] )
else:
print( 'incorrect command:' )
print( ' PUSH environment instance config' )
print( ' STATUS environment instance' )
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm trying to create a python script that'll accept some arguments from the command line. I'm trying to use argparse but can't get it to work properly.
I need it to work similar to the way the aws cli works e.g. aws s3 cp has it's own arguments, aws s3 ls, has it's own etc
ref: https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html
https://docs.aws.amazon.com/cli/latest/reference/s3/ls.html
This is what I have but it always needs the mycmd option
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("mycmd", help="my test cmd")
parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true")
args = parser.parse_args()
if args.mycmd:
print(f"arg is mycmd")
if args.verbose:
print("args v")
End result should be that mycmd1 has arguments xyz, mycmd2 has arguments abc etc and both can be ran from a single python file e.g. python3 somename.py mycmd1 -x ...
You could use the Python Click package, which has explicit support for subcommands:
import click
#click.group()
def cli():
pass
#cli.command()
#click.option('--arg1')
def mycmd1(arg1):
click.echo('My command 1')
if arg1:
click.echo(arg1)
#cli.command()
#click.option('--arg2')
def mycmd2(arg2):
click.echo('My command 2')
if arg2:
click.echo(arg2)
if __name__ == '__main__':
cli()
Usage:
(~)$ python -m click-example --help
Usage: click-example.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
mycmd1
mycmd2
(~)$ python -m click-example mycmd1 --help
Usage: click-example.py mycmd1 [OPTIONS]
Options:
--arg1 TEXT
--help Show this message and exit.
(~)$ python -m click-example mycmd2 --help
Usage: click-example.py mycmd2 [OPTIONS]
Options:
--arg2 TEXT
--help Show this message and exit.
(~)$ python -m click-example mycmd2 --arg1 err
Usage: click-example.py mycmd2 [OPTIONS]
Try "click-example.py mycmd2 --help" for help.
Error: no such option: --arg1
(~)$ python -m click-example mycmd1 --arg1 hello
My command 1
hello
(~)$
I think your code is completely valid. "mycmd" is just the name of your argument. I made some changes to your code to make it clearer:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("mycmd", help="my test cmd")
parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true")
args = parser.parse_args()
if args.mycmd == "mycmd1":
print(f"arg is mycmd1")
elif args.mycmd == "mycmd2":
print(f"arg is mycmd2")
else:
print("arg not allowed")
if args.verbose:
print("args v")
On my machine:
$ python3 test.py mycmd1 -v
arg is mycmd1
args v
$ python3 test.py 12 -v
arg not allowed
args v
$ python3 test.py mycmd2 -v
arg is mycmd2
args v
As per argparse documentation, if you do not state whether a positional argument is optional or not, it will be always needed.
You can state how many times you want your option to be used by nargs. In your case, add nargs='?' to make it optional (interpreted like in regex, ? means "0 or 1").
See also nargs in argparse's documentation - there are nice examples of optional input/output files positional arguments
In your case, you might find useful parent arg parsers. Link to the part of the documentation about parents - just remember to read the part about handling colliding arguments (by default, both parsers will have -h option but you also might need some adjustments with your own arguments).
c.py
import argparse
import sys
parser = argparse.ArgumentParser(
prog='c', description="Description: to do some task",
epilog='Run c.py --help for more information')
subparser = parser.add_subparsers(title="Commands", help="commands")
mycmd_args = subparser.add_parser('mycmd', help='to dome some task',description="To do some task")
mycmd_args.add_argument("--arg1", "-a1", dest="argument1",help="provide argument")
mycmd_args.add_argument("--arg2", "-a2", dest="argument2",help="provide argument")
mycmd1_args = subparser.add_parser('mycmd1', help='to dome some task',description="To do some task")
mycmd1_args.add_argument("--arg1", "-a1", dest="argument1",help="provide argument")
mycmd1_args.add_argument("--arg2", "-a2", dest="argument2",help="provide argument")
if __name__=="__main__":
args=parser.parse_args(sys.argv[1:])
if len(sys.argv) <= 1:
sys.argv.append("-h")
elif sys.argv[1] == "mycmd":
print("mycmd arguemnts")
print(args.argument1)
print(args.argument2)
elif sys.argv[1] == "mycmd1":
print("mycmd1 arguemnts")
print(args.argument1)
print(args.argument2)
else:
sys.argv.append("-h")
output:
C:\Users\jt250054\Desktop>python c.py --help
usage: c [-h] {mycmd,mycmd1} ...
Description: to do some task
optional arguments:
-h, --help show this help message and exit
Commands:
{mycmd,mycmd1} commands
mycmd to dome some task
mycmd1 to dome some task
Run c.py --help for more information
C:\Users\jt250054\Desktop>python c.py mycmd --help
usage: c mycmd [-h] [--arg1 ARGUMENT1] [--arg2 ARGUMENT2]
To do some task
optional arguments:
-h, --help show this help message and exit
--arg1 ARGUMENT1, -a1 ARGUMENT1
provide argument
--arg2 ARGUMENT2, -a2 ARGUMENT2
provide argument
C:\Users\jt250054\Desktop>python c.py mycmd --arg1 argument1
mycmd arguemnts
argument1
None
C:\Users\jt250054\Desktop>python c.py mycmd --arg1 argument1 --arg2 arugment2
mycmd arguemnts
argument1
arugment2
C:\Users\jt250054\Desktop>
I have a python script that takes input from CLI, parses it and runs the appropriate function:
command subcommand subsubcommand1 --arg1 <value1>
When user doesn't provide subsubcommand I want the script to return an error, saying that at least one of the supported subcommand must be provided, instead it returns:
Namespace object has no attribute func
This is the code:
parser = argparse.ArgumentParser(description='The highlevel command')
parser.add_argument("-v", help="some help text", action='store_true', default=False)
subparsers = parser.add_subparsers(dest='action')
subparsers.required = True
subcommand_parser = subparsers.add_parser('subcommand', help='some help text for the subcommand')
subsub_subparser = subcommand_parser.add_subparsers()
subsubparser1 = subsub_subparser.add_parser('subsubcommand1', help='some help text for the subsubcommand1')
subsubparser1.set_defaults(action='subsubcommand_action', func=mylib.subsub1)
subsubparser1.add_argument('--arg1', required=True, help='arg1')
subsubparser1.add_argument('--arg2', required=False, default='hello', help='arg2')
How can I fix the current error and make the new error show up?
Correcting the omissions mentioned in my comments:
import argparse
parser = argparse.ArgumentParser(description='The highlevel command')
parser.add_argument("-v", help="some help text", action='store_true', default=False)
subparsers = parser.add_subparsers(dest='action')
subparsers.required = True
subcommand_parser = subparsers.add_parser('subcommand', help='some help text for the subcommand')
subsub_subparser = subcommand_parser.add_subparsers(dest='subaction') # EDIT
subsub_subparser.required = True # EDIT
subsubparser1 = subsub_subparser.add_parser('subsubcommand1', help='some help text for the subsubcommand1')
subsubparser1.set_defaults(func="mylib.subsub1") # EDIT
subsubparser1.add_argument('--arg1', required=True, help='arg1')
subsubparser1.add_argument('--arg2', required=False, default='hello', help='arg2')
subsubparser2 = subsub_subparser.add_parser('subsubcommand2') # EDIT
args = parser.parse_args()
print(args) # EDIT
if hasattr(args, 'func'):
print('func: ',args.func)
else:
print('func not defined')
sample runs:
2020:~/mypy$ python3 stack56435945.py
usage: stack56435945.py [-h] [-v] {subcommand} ...
stack56435945.py: error: the following arguments are required: action
2021:~/mypy$ python3 stack56435945.py subcommand
usage: stack56435945.py subcommand [-h] {subsubcommand1,subsubcommand2} ...
stack56435945.py subcommand: error: the following arguments are required: subaction
2021:~/mypy$ python3 stack56435945.py subcommand subsubcommand1 --arg1 foobar
Namespace(action='subcommand', arg1='foobar', arg2='hello', func='mylib.subsub1', subaction='subsubcommand1', v=False)
func: mylib.subsub1
2022:~/mypy$ python3 stack56435945.py subcommand subsubcommand2
Namespace(action='subcommand', subaction='subsubcommand2', v=False)
func not defined
im creating my first python "app" and im having problems with the args or lack of. If i execute the script with no arguments id expect a message stating usage, but instead im getting the following error
ERROR
unknown#ubuntu:~$ ./attack.py
Traceback (most recent call last):
File "./attack.py", line 60, in <module>
main(sys.argv[1:])
File "./attack.py", line 57, in main
print fread(FWORD)
File "./attack.py", line 19, in fread
flist = open(FWORD).readlines()
TypeError: coercing to Unicode: need string or buffer, NoneType found
CODE
#!/usr/bin/python
import sys, getopt, socket, fileinput, traceback
from Queue import Queue
from threading import Thread
def usage():
print "-h --help: help\n"
print "-f --file: File to read potential Sub-domains from.\n"
print "-p --PROXY: PROXY address and port. e.g http://192.168.1.64:8080\n"
print "-d --DOMAIN: DOMAIN to bruteforce.\n"
print "-t --thread: Thread count.\n"
print "-e: Turn debug on.\n"
sys.exit()
def fread(FWORD, *args):
flist = open(FWORD).readlines()
return flist
#def addcheck(fcontent):
def main(argv):
PROXY = None
DOMAIN = None
FWORD= None
try:
opts, argv =getopt.getopt(argv, "h:f:p:d:t:e",["help", "file=", "PROXY=", "DOMAIN=", "thread="])
except getopt.GetoptError as err:
print str(err)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-f", "--file"):
FWORD = arg
elif opt in ("-p", "--PROXY"):
PROXY = arg
elif opt in ("-d", "--DOMAIN"):
DOMAIN = arg
elif opt in ("-t", "--thread"):
thread = arg
elif opt in '-e':
global _debug
_debug = 1
else:
usage()
sys.exit()
print fread(FWORD)
if __name__ == "__main__":
main(sys.argv[1:])
Ok thanks all for the comments and pointers. ZMO im going to go with docopt it looks clean and simple (simple just like me). Im not entire sure what i need to do to my old code so am uploading what i think i need to do. Can anyone tell me if this is the right direction?
What do i do with def main() now? and
#!/usr/bin/python
import sys, getopt, socket, fileinput, traceback
from Queue import Queue
from threading import Thread
def fread(FWORD, *args):
flist = open(FWORD).readlines()
return flist
def main(argv):
"""
Usage:
your_script.py [-f <file>] [-p <proxy>] [-d <domain>] [-t] [-v]
your_script.py -h | --help
Options:
-h --help Show this screen.
-f --file File to read potential Sub-domains from.
-p --proxy Proxy address and port. [default: http://127.0.0.1:8080]
-d --domain Domain to bruteforce.
-t --thread Thread count.
-v --verbose Turn debug on.
"""
# […] your code (NOT SURE WHAT CODE YOU MEAN?
if __name__ == "__main__":
from docopt import docopt
arguments = docopt(__doc__, version='0.1a')
print fread(FWORD)
geptopt is deprecated in modern python, you should use argparse instead. I personally prefer the 3rd party docopt
It's useless to give the sys.argv array as argument to main() because you import the sys module globally in your module context (and there are many other things you'd use from sys aside from argv). Your code would only make sense if you were doing the import in the if __name__ == "__main__", but then that would be not good python practice. A better thing to do is to actually parse the arguments and then give the returned NamedTuple as an argument to main().
Argparse example
# […] your code
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Your script.')
parser.add_argument('--file', '-f', metavar='FILE', dest='file', type=file,
help='File to read potential Sub-domains from.')
parser.add_argument('--proxy', '-p', dest='proxy', action='store',
help='Proxy address and port.', default='http://127.0.0.1:8080')
parser.add_argument('--domain', '-d', dest='domain', action='store',
help='Domain to bruteforce.')
parser.add_argument('--thread', '-t', dest='thread', action='store_true',
help='Thread count.')
parser.add_argument('--verbose', '-v', dest='verbose', action='store_true',
help='Turn debug on.')
args = parser.parse_args()
main(args)
docopt example
Your script presentation.
"""
Usage:
your_script.py [-f <file>] [-p <proxy>] [-d <domain>] [-t] [-v]
your_script.py -h | --help
Options:
-h --help Show this screen.
-f --file File to read potential Sub-domains from.
-p --proxy Proxy address and port. [default: http://127.0.0.1:8080]
-d --domain Domain to bruteforce.
-t --thread Thread count.
-v --verbose Turn debug on.
"""
# […] your code
if __name__ == "__main__":
from docopt import docopt
arguments = docopt(__doc__, version='Naval Fate 2.0')
main(arguments) # here using the parameter makes sense ;-)
My code:
def main():
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
parser.add_option("-p", "--pending", action="callback", callback=pending, type="string", dest="test", help="View Pending Jobs")
(options, args) = parser.parse_args()
if x == 0:
print usage, " (-h or --help for help)"
print options.test
if i had:
script -p hello
i need options.test to print out the argument as type string
The arguments are available through sys.argv.
Ended up passing the argument to the function that is being called.