I would like to parse the name of a file into my script as a string, rather than directly converting the file into an object.
Here is a sample code, test.py
:
import argparse
import os.path
def is_valid_file(parser, arg):
if not os.path.exists(arg):
parser.error("The file %s does not exist! Use the --help flag for input options." % arg)
else:
return open(arg, 'r')
parser = argparse.ArgumentParser(description='test')
parser.add_argument("-test", dest="testfile", required=True,
help="test", type=lambda x: is_valid_file(parser, x))
args = parser.parse_args()
print args.testfile
testfile
is a .txt
file containing: 1,2,3,4
In principal would like print args.testfile
to return the invoked name of testfile
as a string:
$ python test.py -test test.txt
>> "test.txt"
To achieve this I need to prevent argparser from converting test.txt into an object. How can I do this?
Many thanks!
you can modify your function as follows to return the string after having checked it exists:
def is_valid_file(parser, arg):
if not os.path.exists(arg):
parser.error("The file %s does not exist! Use the --help flag for input options." % arg)
else:
return arg
There's also a more direct method:
parser.add_argument("-test", dest="testfile", required=True,
help="test", type=file) # file exists in python 2.x only
parser.add_argument("-test", dest="testfile", required=True,
help="test", type=lambda f: open(f)) # python 3.x
args = parser.parse_args()
print(args.testfile.name) # name of the file from the file handle
actually args.testfile
is the file handle, opened by argparser (exception if not found). You can read from it directly.
The FileType
type factory does most of what your code does, with a slightly different message mechanism:
In [16]: parser=argparse.ArgumentParser()
In [17]: parser.add_argument('-f',type=argparse.FileType('r'))
In [18]: args=parser.parse_args(['-f','test.txt'])
In [19]: args
Out[19]: Namespace(f=<_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'>)
In [20]: args.f.read()
Out[20]: ' 0.000000, 3.333333, 6.666667, 10.000000, 13.333333, 16.666667, 20.000000, 23.333333, 26.666667, 30.000000\n'
In [21]: args.f.close()
For a valid name it opens the file, which you can use and close. But you can't use it in a with
context.
If the file doesn't exist it exits with usage and a cant open
message.
In [22]: args=parser.parse_args(['-f','test11.txt'])
usage: ipython3 [-h] [-f F]
ipython3: error: argument -f: can't open 'test11.txt': [Errno 2] No such file or directory: 'test11.txt'
FileType
__call__
handles the error with an argparse.ArgumentTypeError
except OSError as e:
message = _("can't open '%s': %s")
raise ArgumentTypeError(message % (string, e))
Using this error mechanism, and omitting your open
I'd suggest:
def valid_file(astring):
if not os.path.exists(astring):
msg = "The file %s does not exist! Use the --help flag for input options." % astring
raise argparse.ArgumentTypeError(msg)
else:
return astring
Which could be used as:
In [32]: parser=argparse.ArgumentParser()
In [33]: parser.add_argument('-f',type=valid_file)
In [34]: args=parser.parse_args(['-f','test11.txt'])
usage: ipython3 [-h] [-f F]
ipython3: error: argument -f: The file test11.txt does not exist! Use the --help flag for input options.
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
In [35]: args=parser.parse_args(['-f','test.txt'])
In [36]: args
Out[36]: Namespace(f='test.txt')
In [37]: with open(args.f) as f:print(f.read())
0.000000, 3.333333, 6.666667, 10.000000, 13.333333, 16.666667, 20.000000, 23.333333, 26.666667, 30.000000
http://bugs.python.org/issue13824 worries about FileType
opening a file but not closing it. I proposed a FileContext
, modeled on FileType
, but instead of opening the file, returns an object that can be use as:
with arg.file() as f:
f.read()
It would do the file existence or creatablity testing, without actually opening or creating the file. It's a more complicated solution.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.