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?
Argparse attempts to convert the default argument to whatever type was given to it.
The reason for this design choice is a little weird to me, but it is probably so that you can pass strings to
defaultjust 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
typekeyword 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 customAction, but for this example, it’s probably just easiest to do: