My python script needs to read files from a directory passed on the command line. I have defined a readable_dir type as below to be used with argparse for validating that the directory passed on the command line is existent and readable.
Additionally, a default value (/tmp/non_existent_dir in the example below) has also been specified for the directory argument.
The problem here is that argparse invokes readable_dir() on the default value even in a situation where a directory argument is explicitly passed in on the command line. This causes the script to crap out as the default path /tmp/non_existent_dir does not exist in a context where a directory is explicitly passed in on the command line.
I could get around this by not specifying a default value and making this argument mandatory, or by deferring the validation until later in the script but is a more elegant solution that anyone is aware of?
#!/usr/bin/python
import argparse
import os
def readable_dir(prospective_dir):
if not os.path.isdir(prospective_dir):
raise Exception("readable_dir:{0} is not a valid path".format(prospective_dir))
if os.access(prospective_dir, os.R_OK):
return prospective_dir
else:
raise Exception("readable_dir:{0} is not a readable dir".format(prospective_dir))
parser = argparse.ArgumentParser(description='test', fromfile_prefix_chars="@")
parser.add_argument('-l', '--launch_directory', type=readable_dir, default='/tmp/non_existent_dir')
args = parser.parse_args()
You can create a custom action instead of a type:
But this seems a little fishy to me — if no directory is given, it passes a non-readable directory which seems to defeat the purpose of checking if the directory is accessible in the first place.
Note that as pointed out in the comments, it might be nicer to
raise argparse.ArgumentError(self, ...)rather thanargparse.ArgumentTypeError.EDIT
As far as I’m aware, there is no way to validate the default argument. I suppose the
argparsedevelopers just assumed that if you’re providing a default, then it should be valid. The quickest and easiest thing to do here is to simply validate the arguments immediately after you parse them. It looks like, you’re just trying to get a temporary directory to do some work. If that’s the case, you can use thetempfilemodule to get a new directory to work in. I updated my answer above to reflect this. I create a temporary directory, use that as the default argument (tempfilealready guarantees the directory it creates will be writeable) and then I register it to be deleted when your program exits.