Argparse is not recognizing my positional argument. Here's the setup:
parser = argparse.ArgumentParser()
parser.add_argument("url")
parser.add_argument("-u", "--username")
parser.add_argument("-p", "--password")
parser.add_argument("-d", "--depth", default=sys.maxsize)
parser.add_argument("-t", "--threads", default=4)
At the bottom, i have this:
if __name__ == "__main__":
if len(sys.argv) > 1:
print sys.argv
args = parser.parse_args(sys.argv)
if args.username is not None and args.password is not None:
auth = [args.username, args.password]
else:
auth = None
spider(args.url,
basic_auth=auth,
threads=int(args.threads),
depth=int(args.depth))
else:
parser.print_help() # Handle 0 command-line arguments
When i call my script on the command line like staunch$ ./spiderer.py http://www.example.com/, i get this:
usage: spiderer.py [-h] [-u USERNAME] [-p PASSWORD] [-d DEPTH] [-t THREADS]
url
spiderer.py: error: unrecognized arguments: http://www.example.com/
I tried adding nargs=1 to the url add_argument, but that didn't work. Neither does calling ./spiderer.py with all of the other arguments specified. What's goin' on?
It works if you change
args = parser.parse_args(sys.argv)
to
args = parser.parse_args()
Otherwise parse_args will read sys.argv[0] (the name of your program) as the positional argument, and then sys.argv[1] will be an unexpected second positional argument.
You could alternatively call:
args = parser.parse_args(sys.argv[1:])
if you prefer.
Related
I'd like to implement arguments parsing.
./app.py -E [optional arg] -T [optional arg]
The script requires at least one of parameters: -E or -T
What should I pass in parser.add_argument to have such functionality?
UPDATE
For some reason(s) the suggested solution with add_mutually_exclusive_group didn't work, when I added nargs='?' and const= attributes:
parser = argparse.ArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-F', '--foo', nargs='?', const='/tmp')
group.add_argument('-B', '--bar', nargs='?', const='/tmp')
parser.parse_args([])
Running as script.py -F still throws error:
PROG: error: one of the arguments -F/--foo -B/--bar is required
However, the following workaround helped me:
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('-F', '--foo', nargs='?', const='/tmp')
parser.add_argument('-B', '--bar', nargs='?', const='/tmp')
args = parser.parse_args()
if (not args.foo and not args.bar) or (args.foo and args.bar):
print('Must specify one of -F/-B options.')
sys.exit(1)
if args.foo:
foo_func(arg.foo)
elif args.bar:
bar_func(args.bar)
...
You can make them both optional and check in your code if they are set.
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--bar')
args = parser.parse_args()
if args.foo is None and args.bar is None:
parser.error("please specify at least one of --foo or --bar")
If you want only one of the two arguments to be present, see [add_mutually_exclusive_group] (https://docs.python.org/2/library/argparse.html#mutual-exclusion) with required=True
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> group = parser.add_mutually_exclusive_group(required=True)
>>> group.add_argument('--foo', action='store_true')
>>> group.add_argument('--bar', action='store_false')
>>> parser.parse_args([])
usage: PROG [-h] (--foo | --bar)
PROG: error: one of the arguments --foo --bar is required
I made a script that takes a few arguments to run. Originally it could be run automatically with the argument 'auto', but I'm trying to daemonize it so it will run the run the script with the specified arguments as a daemon. The problem is that python-daemon and argparse don't seem to get along when it comes to deciding who parses what.
parser = argparse.ArgumentParser(usage='pyfilter.py <file> <options> <actions>')
parser.add_argument('file', help='blacklist file containing IPs', type=str)
subparsers = parser.add_subparsers(help='help', dest='action')
parser_update = subparsers.add_parser('update', help='update help')
parser_update.add_argument('-c', '--check', help="check IPs for abuse reports", dest="check", type=str, nargs=1)
parser_blacklist = subparsers.add_parser('blacklist', help='create iptables rules for malicious IPs specified'
'in the provided file')
parser_clear = subparsers.add_parser('clear', help='clear iptables')
parser_auto = subparsers.add_parser('auto', help='automatically run update and blacklist on a loop')
parser_auto.add_argument('-i', '--interval', help='specify the loop interval', dest='interval', type=int, nargs=1)
parser_auto.add_argument('-c', '--check', help="check IPs for abuse reports", dest="check", type=str, nargs=1)
parser.add_argument('-p', '--port', help='specify the port to block', type=int)
parser.add_argument('-v', '--verbose', help='write output to screen', nargs=1)
args = parser.parse_args()
. . .
class pyfilterDaemon():
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/tty'
self.stderr_path = '/dev/tty'
self.pidfile_path = '/tmp/pyfilter.pid'
self.pidfile_timeout = 5
def run(self):
while True:
update()
blacklist()
time.sleep(interval)
. . .
def main():
#handle()
d = pyfilterDaemon()
daemon_runner = runner.DaemonRunner(d)
daemon_runner.start()
Here's the commands I've tried to make this work:
root#tfof:~# ./pyfilter.py start
ERROR: File 'start' not found # argparse parsed 'start' accidentally
root#tfof:~# ./pyfilter.py /etc/blacklist.lst -v yes auto
usage: checkfilter.py stop|restart|start # now the argparse arguments are satisfied, but python-daemon is looking for its argument
root#tfof:~# ./pyfilter.py /etc/blacklist.lst -v yes auto start
usage: pyfilter.py <file> <options> <actions>
pyfilter.py: error: unrecognized arguments: start # argparse is trying to parse 'start'
Would it be possible to pass off the 'start' argument to python-daemon or something? Or if I could just get rid of the argparsing it'd be fine, but the 'file' argument is a must.
Argparse takes arguments from sys.argv per default (see here).
It is not surprising that the behaviour you see here is happening,
as you just call the parse_args function with the default arguments.
You can just pass whatever you want to parse to it, instead of sys.argv.
See this question for an example.
So consume whatever you need for python-deamon and then parse the remaining args with argparse.
I have an argparse function:
def argParse():
# Possible Arguments
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--search", dest="s", help="Seach parameters")
parser.add_argument("-d", "--directory", dest="d", help="Choose Directory to save data")
args = parser.parse_args()
params = str(args.s)
directory = str(args.d)
if params == "None":
print("Search parameters are null, exiting program.")
parser.print_help()
exit(1)
if directory == "None":
print("directory is null, storing to current working directory.")
But, it is adding a extra capitol S and D to the useage output? Any idea on how to clean this up?
usage: scan.py [-h] [-s S] [-d D]
optional arguments:
-h, --help show this help message and exit
-s S, --search S Seach parameters
-d D, --directory D Choose Directory to save data
I think you're looking for the metavar kwarg.
try this:
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--search', dest='s', metavar='\b', help='Search parameters')
args = parser.parse_args()
parse_args()
\b is the backspace character, so it also removes the space between the two,
as opposed to using "" which I beleive would still leave a space after the initial variable name.
output of python argparse_test.py -h:
usage: argparse_test.py [-h] [-s]
optional arguments:
-h, --help show this help message and exit
-s, --search Search parameters
I need to do the following:
if there weren't argument's for script variable test == False
elif there was argument -t or --test variable test == True
else there were another arguments get them as string and pass to third code
Now I got an error:
# ./cli something
usage: cli [-t]
cli: error: unrecognized arguments: something
My code for first 2 steps:
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-t', '--test', action="store_true")
args = parser.parse_args()
if args.test is True:
intro = None
Within argparse you need that as a separate parameter, for example:
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-t', '--test', action="store_true")
parser.add_argument('params', nargs='+')
args = parser.parse_args()
if args.test is True:
intro = None
elif args.params:
pass # process the params here
else:
pass # no params whatsoever
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.