使用argparse指定默认文件名,但不能在--help上打开它们?

时间:2011-11-23 03:26:04

标签: python argparse

假设我有一个脚本可以对文件进行一些操作。它在命令行中使用此文件的名称,但如果未提供,则默认为已知文件名(例如content.txt)。使用python的argparse,我使用以下内容:

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()
# do some work on args.content, which is a file-like object

这很有效。唯一的问题是,如果我运行python myscript --help,如果文件不存在(我认为有意义的话),我会得到一个ArgumentError,并且不会显示帮助文本。如果用户只想要--help,我宁愿不尝试打开文件。有没有办法做到这一点?我知道我可以将参数设置为一个字符串,并在以后自己打开文件(我一直这样做),但让argparse处理它会很方便。

4 个答案:

答案 0 :(得分:12)

你可以继承argparse.FileType

import argparse
import warnings

class ForgivingFileType(argparse.FileType):
    def __call__(self, string):
        try:
            super(ForgivingFileType,self).__call__(string)
        except IOError as err:
            warnings.warn(err)

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=ForgivingFileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()

无需触及ArgumentParser._parse_known_args等私密方法即可使用。

答案 1 :(得分:9)

查看argparse代码,我看到了:

  • ArgumentParser.parse_args调用parse_known_args并确保没有任何待解析的参数被解析。
  • ArgumentParser.parse_known_args设置默认值并调用ArgumentParser._parse_known_args

因此,解决方法是直接使用ArgumentParser._parse_known_args来检测-h,然后照常使用ArgumentParser.parse_args

import sys, argparse
parser = argparse.ArgumentParser(description='my illustrative example', argument_default=argparse.SUPPRESS)
parser.add_argument('--content', metavar='file',
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
parser._parse_known_args(sys.argv[1:], argparse.Namespace())
args = parser.parse_args()

请注意ArgumentParser._parse_known_args需要几个参数:命令行和命名空间中的参数。

当然,我不推荐这种方法,因为它利用了内部argparse实现,并且可能在将来发生变化。但是,我发现它并不太杂乱,所以如果您认为维护风险得到了回报,您仍然可能想要使用它。

答案 2 :(得分:2)

使用stdin作为默认值:

parser.add_argument('file', default='-', nargs='?', type=argparse.FileType('r'))

答案 3 :(得分:1)

也许您可以在add_argument调用中定义自己的typeaction来检查文件是否存在,如果存在,则返回文件句柄None(或其他)否则。

这也需要你自己编写一些代码,但如果不能总是使用默认值,你可能迟早要做一些检查。就像Manny D所说,你可能想重新考虑你的默认值。