String index out of range when converting to argparse - python

I changed from optparse to argparse but when I try to run it I get the following error:
if not option_string[0] in self.prefix_chars:
IndexError: string index out of range
My code is:
usage = "%prog -f <fasta TFs> -a <database all> -s <database small> -d <pfam database> [options]"
version = "1.0.1"
description = " "
epilog = " "\
" "
parser = argparse.ArgumentParser(usage=usage, description=description,
version="%prog "+version, epilog=epilog)
# options for running the program
# TF file
parser.add_argument("-f", "", dest="TF", metavar="<file>",
help="input file with transcription factors")
parser.set_defaults(fasta=None)
I can't find where this error comes from, how can fix this?

In argparse you can't pass empty argument strings to add_argument. argparse is trying to find a valid prefix_char (e.g. "-" or "--") in the empty string you pass (""), causing the error. Try this instead:
parser.add_argument("-f", dest="TF", metavar="<file>",
help="input file with transcription factors")

The only way to get this error is by asking for an index that doesn't exist -- in this case, option_string must be empty.

Related

While using Argparse "AttributeError: 'Namespace' object has no attribute 'command'" keeps showing up on terminal

After importing argparse (among others that I needed) I wrote the following piece of code:
parser = argparse.ArgumentParser()
(..some code with optional arguments...)
requiredArguments = parser.add_argument_group("Required arguments")
(..some code with required arguments...)
requiredArguments.add_argument("--extension", "-ext", help="set the extension", type=str)
args = parser.parse_args()
if args.version:
print("blahblahblah")
elif args.example:
print("blahblahblah")
elif args.width:
screen_width = "%i" % args.width
elif args.height:
screen_height = "%i" % args.height
elif args.sequence:
sequence = "%i" % args.sequence
elif args.url:
url = "%s" % args.url
elif args.ext:
ext = "%s" % args.ext
else:
print("blahblahblah")
[Some additional code irrelevant to the case as it is related to screenshots]
And in the following piece of code is where the problem arises:
number = 0
while number < args.sequence:
url = args.url+str(number)+args.ext
On my terminal I have specified all the necessary arguments (or at least I believe I have):
python script.py -k [keyword] -w [screen_width] -hg [screen_height] -s 10 -u "url" -ext "extension_to_the_url"
Regardless of the positioning of the arguments, of splitting "url = args.url+str(number)+args.ext" in several parts, using and not using brackets, and a long etcetera (as well as also trying "nargs"), the error is the same:
AttributeError: 'Namespace' object has no attribute 'ext'
There must be something wrong with how I'm using the 'ext' argument, because in a previous version of the script where 'ext' was not provided, Python didn't complain at all.
I'm new to Python and I'm running out of ideas. I read there's a bug that shows this error and that basically it means too few arguments were provided? But that would make no sense since all the arguments were provided via command line...
Any ideas?
Thanks in advance!
add dest='ext', like that:
requiredArguments.add_argument("--extension", "-ext", action='store', dest='ext', help="set the extension", type=str)
and use like:
python stack_args_exp.py -ext 23

missing args do not show defined error message

This is my first post, so please excuse any missing info or stupid questions.So what I am trying to do is run a command line python script (I'm in a Windows machine), pass it 2 arguments, check if the arguments were passed, if not, display an error message specific to that argument. I am getting a missing argument error, but it isnt displaying the message I would like (defined in the function). I'm not sure if I didn't create the function properly, or if I am missing something. I also want to check if the arguments passed are correct strings, not int, but it seems that the arguments are defaulting to strings, so checking if they are int is not working either.
Can someone give me a hint or point me in the right direction? I've been searching online but havent found anything that has answered this question. I am brand new to python, so still learning how to read documentation properly (seems like there are too few examples for me to understand the docs). Here is the code I am using:
import argparse
#parser to create and grab args from CLI
parser = argparse.ArgumentParser()
parser.add_argument("-i", help="File path of original folder")
parser.add_argument("-o", help="File path of output folder")
args = parser.parse_args()
#check if args have been passed and display error if missing
def check_args(input_path,output_path):
if input_path == None:
print("Please input a valid folder path for original folder destination")
elif output_path == None:
print("Please input a valid folder path for output folder destination")
else:
return args
#grab first and sec argument
input_path = args.i
output_path = args.o
check_args(input_path, output_path)
Output:
Program>python JPGtoPNG_conv.py -i 3 -o
usage: JPGtoPNG_conv.py [-h] [-i I] [-o O]
JPGtoPNG_conv.py: error: argument -o: expected one argument
Thanks so much for any help!
The code below should do the job for you
import argparse
import sys
class MyParser(argparse.ArgumentParser):
def error(self, message):
sys.stderr.write('error: %s\n' % message)
self.print_help()
sys.exit(2)
parser = MyParser()
parser.add_argument("-i", help="File path of original folder", required=True)
parser.add_argument("-o", help="File path of output folder", required=True)
args = parser.parse_args()
# grab first and sec argument
input_path = args.i
output_path = args.o

Python argparse cut half of argument

I'm trying to enter sha512 hash as an argument but argparse just cut off half of it for no reason. When I enter Unix hash( MiqkFWCm1fNJI ) it works as it supposed. I tried to search for something like this but didn't find anything.
My code for command line arguments looks like this :
def check_args():
parse = argparse.ArgumentParser()
parse.add_argument('-p', '--password', type=str, action='store', help='enter your hashed password: -p your_hash')
parse.add_argument('-w', '--wordlist', help='add your wordlist: -w wordlist')
parse.add_argument('-f', '--file', help='file with hashes: -f your_hashes')
args_list = parse.parse_args()
return args_list
Part of code where it's used:
c_arg = check_args()
psw = c_arg.password
wordlist = c_arg.wordlist
file = c_arg.file
print(psw)
so when I run script
python crack.py -p $6$krVh8s..$ttQmt30au3s9wHywp/KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
I get this output:
../KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
which should be:
$6$krVh8s..$ttQmt30au3s9wHywp/KGdFKGe1WoEK4xpFJupMA.I06/tdv1//4x7e1gSU2e2Qu/1kQ0rfqXRxghfBX0Io1BJ.
if I run same script with argument like this it works as supposed:
python crack.py -p MiqkFWCm1fNJI
Output:
MiqkFWCm1fNJI
What can be wrong about this and how can I make argparse read this kind of strings?
Your problem has nothing to do with argparse or Python.
$6 and the like are references to [non-existent] environment variables in Unix/Linux. Their values are '' (empty strings). Enclose your entire hash in single quotation marks to protect the data from being interpreted by the shell: '$6$krVh8s..$ttQmt30au3s9wHywp/...'.

Python: Can optparse have the ACTION attribute to act both like STORE and STORE_TRUE?

I am using optparse to get command line input.
Lets say that I am running a script demo.py and it creates some output. But unless I specify the command line input, the output is not written to a file.
I am trying to do the following:
python demo.py in command line should run the script, but not write the output anywhere.
python demo.py -o in command line should write the output to my default file name output.txt.
python demo.py -o demooutput.txt in command line should write the output to file demooutput.txt.
PS: I would not prefer to switch to argparse from optparse.
You can use optparse-callbacks to achieve this.
Here is how it wiill work for your use case.
parser.add_option("-o", action="callback", dest="output", callback=my_callback)
def my_callback(option, opt, value, parser):
if len(parser.rargs) > 0:
next_arg = parser.rargs[0]
if not next_arg.startswith("-"):
# Next argument is not another option
del parser.rargs[0]
setattr(parser.values, option.dest, next_arg)
return
# If not processed, set the default value
setattr(parser.values, option.dest, "output.txt")
I don't think there is unfortunately - the only way I can think of is hacking around the problem by adding your own logic statements. The following code should do the trick.
import re, sys
import optparse from OptionParser
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
if '-f' in argv:
a = argv.index('-f')
if (a != len(argv)-1) and re.search('[.]txt', argv[a+1]):
parser.add_option("-f", "--foo", dest="foo")
else:
parser.add_option("-f", dest="foo", action="store_true")
This doesn't answer the direct question, 'how to define an Action...', but it handles the inputs in a simple way.
Set '-o' to be 'store_true'. If True check the 'args' variable for a file name.
(options, args) = parser.parse_args()
if options.o:
if args:
dest = args[0]
else:
dest = 'output.txt'
else:
dest = ''
(In argparse the equivalent would be to define a positional argument with nargs='?'.)
If these are the only arguments, you could also get by with checking for the filename without requiring the `-o'.
Another possibility - 'store_const', with the positional 'filename' having priority:
parser = optparse.OptionParser()
parser.add_option('-o',dest='dest',action='store_const', const='output.txt', default='')
(options, args) = parser.parse_args()
if args:
options.dest = args[0]
print options

argparse.add_argument() default always used... sometimes

This simplified script is enough to cause the issue... just checking if the '-d' argument is a valid directory, supplying a default if it's not provided...
#!/usr/bin/python
import os
import argparse
def valid(dir):
subdir = dir + '/Desktop'
if not os.path.exists(subdir):
raise argparse.ArgumentTypeError("%s is not a valid directory" % subdir)
return dir
parser = argparse.ArgumentParser(description="blah blah blah")
parser.add_argument('-d', '--directory', help='directory to check', default=os.getcwd(), type=valid)
args = parser.parse_args()
And it doesn't matter what the default argument is, when I run the script it uses the default, no matter what I enter on the command line, and throws an uncaught exception as follows:
Traceback (most recent call last):
File "./parsertest.py", line 15, in <module>
args = parser.parse_args()
File "/usr/lib/python2.7/argparse.py", line 1688, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/usr/lib/python2.7/argparse.py", line 1710, in parse_known_args
default = self._get_value(action, default)
File "/usr/lib/python2.7/argparse.py", line 2239, in _get_value
raise ArgumentError(action, msg)
argparse.ArgumentError: argument -d/--directory: /home/users/jrice/Desktop/Desktop is not a valid directory
Runs fine, and by fine I mean, handles the ArgumentTypeError as and when it should, just printing the msg when if I do the following:
Remove the 'default=' argument
Do not append '/Desktop' to dir, so subdir = dir, or just check dir itself
Run the script from my home directory!?!?
Elaboration: If I do any of the above, even if '-d' isn't valid, everything is fine. This is the output, which is what I want.
>./Desktop/parsertest.py -d blah
usage: parsertest.py [-h] [-d DIRECTORY]
parsertest.py: error: argument -d/--directory: blah/Desktop is not a valid directory
why should os.getcwd() + '/Desktop' be any different?
I believe your "type checking" is too aggressive. You treat a non-existing directory as an invalid type, which is not the way argparse has been thought. In your case, the default value might not be a "valid type" which confuses argparse. Check out the following code and its output:
#!/usr/bin/python
import os
import argparse
def valid(dir):
print "Checking " + dir
subdir = dir + '/Desktop'
#if not os.path.exists(subdir):
# raise argparse.ArgumentTypeError("%s is not a valid directory" % subdir)
return dir
parser = argparse.ArgumentParser(description="blah blah blah")
parser.add_argument('-d', '--directory', help='directory to check', type=valid, default=os.getcwd())
args = parser.parse_args()
Executing it from /home/user/Desktop with -d /home/user gives:
Checking /home/user/Desktop
Checking /home/user
As you can see, argparse first converts the default value and only then the command-line given value.
To solve the above issue, either make sure that the default value is always a "valid type" or that you check the directory after argparse is done.
Argparse attempts to convert the default argument to whatever type was given to it.
import argparse
parser = argparse.ArgumentParser(description="blah blah blah")
parser.add_argument('-i',default="1",type=int)
args = parser.parse_args([])
print args # Namespace(i=1)
print type(args.i) # <type 'int'>
The reason for this design choice is a little weird to me, but it is probably so that you can pass strings to default just as it would get them on the commandline and then the help will be formatted properly.
Note I don't really like passing validation code to the type keyword argument even though they do it in the documentation. That argument is to convert the input string into some other type. If you really want to do the validation as you parse, you should consider using a custom Action, but for this example, it's probably just easiest to do:
#...snip...
parser.add_argument('-d', '--directory', help='directory to check')
args = parser.parse_args()
args.directory = valid(args.directory if args.directory is not None else os.getcwd())
#the following should work too.
#args.directory = valid(args.directory if args.directory else os.getcwd())

Categories

Resources