Python Argument Parser,在-h之前引发异常

时间:2014-05-09 06:07:08

标签: python arguments argparse

我不知道为什么会这样。我的理解是,在执行默认操作之前,用户至少有机会使用-h。

import os, sys, argparse
class argument_parser():
  # call on all our file type parsers in the sequence_anlysis_method

    def __init__(self):
        self.db_directory = os.path.dirname(os.path.abspath(sys.argv[0]))

        """A customized argument parser that does a LOT of error checking"""
        self.parser = argparse.ArgumentParser(
            prog="igblast")

        general = self.parser.add_argument_group(
            title="\nGeneral Settings")

        general.add_argument(
            "-x", '--executable',
            default="/usr/bin/igblastn",
            type=self._check_if_executable_exists,
            help="The location of the executable, default is /usr/bin/igblastn")

        self.args = self.parser.parse_args()

    def _check_if_executable_exists(self,x_path):
        if not os.path.exists(x_path):
            msg = "path to executable {0} does not exist, use -h for help\n".format(x_path)
            raise argparse.ArgumentTypeError(msg)
        if not os.access(x_path, os.R_OK):
            msg1 = "executable {0} does have not permission to run\n".format(x_path)
            raise argparse.ArgumentTypeError(msg1)
        else:
            return x_path

if __name__ == '__main__':
    argument_class = argument_parser()

现在如果/ usr / bin / igblastn存在,那么它没问题,但如果没有,只需调用此程序就会在self_check_if_executable_exists中引发异常。

File "execution.py", line 220, in <module>
    argument_class = ap()
  File "/home/willisjr/utilities/pyig/src/arg_parse.py", line 159, in __init__
    self.args = self.parser.parse_args()
  File "/usr/local/lib/python2.7/argparse.py", line 1656, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/local/lib/python2.7/argparse.py", line 1678, in parse_known_args
    default = self._get_value(action, default)
  File "/usr/local/lib/python2.7/argparse.py", line 2203, in _get_value
    raise ArgumentError(action, msg)
argparse.ArgumentError: argument -x/--executable: path to executable /usr/bin/igblastn does not exist, use -h for help

我的理解是,用户始终有机会运行--help或-h或在采取任何操作之前导致此参数错误。我对arg解析器的理解不清楚吗?

2 个答案:

答案 0 :(得分:1)

您忘了在初始__init__

结束时运行parse_args()
class argument_parser(object):
    # call on all our file type parsers in the sequence_anlysis_method

    def __init__(self):
        self.db_directory = os.path.dirname(os.path.abspath(sys.argv[0]))

        """A customized argument parser that does a LOT of error checking"""
        self.parser = argparse.ArgumentParser(
            prog="igblast")

        general = self.parser.add_argument_group(
            title="\nGeneral Settings")

        general.add_argument(
            "-x", '--executable',
            default="/usr/bin/igblastn",
            type=self._check_if_executable_exists,
            help="The location of the executable, default is /usr/bin/igblastn")


        """ >>>>>>>>>>>>> add this line  <<<<<<<<<<< """
        self.parser.parse_args()

    def _check_if_executable_exists(self,x_path):
        if not os.path.exists(x_path):
            msg = "path to executable {0} does not exist, use -h for help\n".format(x_path)
            raise argparse.ArgumentTypeError(msg)
        if not os.access(x_path, os.R_OK):
            msg1 = "executable {0} does have not permission to run\n".format(x_path)
            raise argparse.ArgumentTypeError(msg1)
        else:
            return x_path

if __name__ == '__main__':
    argument_class = argument_parser()

答案 1 :(得分:1)

在Python 2.7.3中,在parse_known_args的早期(由parse_args调用),默认值将插入namespace

    # add any action defaults that aren't present
    for action in self._actions:
        if action.dest is not SUPPRESS:
            if not hasattr(namespace, action.dest):
                if action.default is not SUPPRESS:
                    default = action.default
                    if isinstance(action.default, basestring):  # delayed in 3.3.1
                        default = self._get_value(action, default)
                    setattr(namespace, action.dest, default)

如果default是一个字符串,则会传递_get_value,在您的案例type中调用相应的_check_if_executable_exists。这会产生你看到的错误。

在新闻3.3.1 https://docs.python.org/3.3/whatsnew/changelog.html

  

问题#12776,问题#11839:只调用一次argparse类型函数(由add_argument指定)。之前,在指定了默认值并且同时给出了参数的情况下,类型函数被调用了两次。这对于FileType类型尤其有问题,因为即使在命令行上指定了文件参数,也始终会打开默认文件。

通过此更改,_get_value调用被推迟到parse_known_args的末尾,并且仅在解析未在其中放置其他值时才会调用(默认值是必需的)。

    if isinstance(action.default, basestring):  # dropped in 3.3.1
        default = self._get_value(action, default)

因此,您的脚本在我的开发副本上按预期运行(使用'-h')。我不完全确定哪个版本的Python有这种更正。

因此,除非您可以运行更新的Python版本,否则您有责任确保default是有效值。即使有这个错误修复,最好确保默认值有效,然后再将其发送给add_argument()。无论何时处理,无效的默认设置都会使您的用户感到困惑。