【问题标题】:Python Argument Parser, Raising an exception before -hPython 参数解析器,在 -h 之前引发异常
【发布时间】:2014-06-26 18:49:26
【问题描述】:

我不知道为什么会这样。据我了解,在执行默认操作之前,用户至少有机会使用 -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解析器的理解不清楚?

【问题讨论】:

  • 它在解析开始之前通过您的自定义类型运行您的默认文件名,然后再查看 argv。较新的版本将默认值的使用推迟到最后,并且仅在需要默认值时才使用。
  • 更新版本的python?
  • 3.3.1 和更新版本。我不确定2.7 方面。看我的回答。

标签: python arguments argparse


【解决方案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 调用适当的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() 调用之前确保它们是有效的也是一个好主意。无论何时处理,无效的默认值都会使您的用户感到困惑。

【讨论】:

    【解决方案2】:

    你忘记在初始化结束时运行parse_args() __init__

    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()
    

    【讨论】:

    • 抱歉,确实有。
    • 所以即使使用self.parser.parse_args() - 你得到一个错误?
    • 真的不是错误,只是引发该异常而不是输出帮助菜单。即使program.py --help 仍然会出现异常。
    • 奇怪。当我运行 program -h 或 --help 我得到usage: igblast [-h] [-x EXECUTABLE] optional arguments: -h, --help show this help message and exit General Settings: -x EXECUTABLE, --executable EXECUTABLE The location of the executable, default is /usr/bin/igblastn
    • 但是使用程序 -x usage: igblast [-h] [-x EXECUTABLE] igblast: error: argument -x/--executable: expected one argument
    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 2022-10-25
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    相关资源
    最近更新 更多