kateli1991

禁用argparse和optpars的唯一前缀匹配



当我使用Python的argparse或optparse命令行参数解析器时,参数的任何唯一前缀都被认为是有效的,例如

$ ./buildall.py --help
usage: buildall.py [-h] [-f]

Build all repositories

optional arguments:
  -h, --help   show this help message and exit
  -f, --force  Build dirty repositories

--help--hel--he一起使用,对于force选项使用--forc和{}。在

这种行为能被关闭吗?我想得到不完整参数的错误消息。在


已被浏览了11252次
6 日,19 小时 之前提问
3 个回答
fefe Tyson

python3.5中只添加了禁用缩写long选项的功能。从^{} documentation

The parse_args() method by default allows long options to be abbreviated to a prefix, if the abbreviation is unambiguous (the prefix matches a unique option) ... This feature can be disabled by setting allow_abbrev to False.

因此,如果您使用Python3.5,可以使用allow_abbrev=False创建解析器:

parser = argparse.ArgumentParser(..., allow_abbrev=False)

如果您使用optparse或pre-3.5argparse,那么您只需要使用缩写选项。在

评论 - 2020年7月29日 10:44
fefe Tyson

对于我们这些仍然坚持使用python2.7的人来说,这是本地禁用前缀匹配的最小更改:

class SaneArgumentParser(_argparse.ArgumentParser):
  """Disables prefix matching in ArgumentParser."""
  def _get_option_tuples(self, option_string):
    """Prevent argument parsing from looking for prefix matches."""
    return []

现在不用argparse.ArgumentParser,只需使用SaneArgumentParser。与chepner的回答不同,这不需要对argparse模块进行任何修改。这也是一个小得多的变化。希望其他陷入python过去的人会发现这很有用。在

评论 - 2020年7月29日 10:44
fefe Tyson

在Python3.5之前,您必须monkeypatch一个未记录的ArgumentParser方法。不要实际使用它;它未经测试,可能无法与Python的所有版本(或任何版本)一起使用。仅供娱乐之用。在

import argparse

# This is a copy from argparse.py, with a single change
def _get_option_tuples(self, option_string):
    result = []

    # option strings starting with two prefix characters are only
    # split at the '='
    chars = self.prefix_chars
    if option_string[0] in chars and option_string[1] in chars:
        if '=' in option_string:
            option_prefix, explicit_arg = option_string.split('=', 1)
        else:
            option_prefix = option_string
            explicit_arg = None
        for option_string in self._option_string_actions:
            # === This is the change ===
            # if option_string.startswith(option_prefix):
            if option_string == option_prefix:
                action = self._option_string_actions[option_string]
                tup = action, option_string, explicit_arg
                result.append(tup)

    # single character options can be concatenated with their arguments
    # but multiple character options always have to have their argument
    # separate
    elif option_string[0] in chars and option_string[1] not in chars:
        option_prefix = option_string
        explicit_arg = None
        short_option_prefix = option_string[:2]
        short_explicit_arg = option_string[2:]

        for option_string in self._option_string_actions:
            if option_string == short_option_prefix:
                action = self._option_string_actions[option_string]
                tup = action, option_string, short_explicit_arg
                result.append(tup)
            elif option_string.startswith(option_prefix):
                action = self._option_string_actions[option_string]
                tup = action, option_string, explicit_arg
                result.append(tup)

    # shouldn't ever get here
    else:
        self.error(_('unexpected option string: %s') % option_string)

    # return the collected option tuples
    return result

argparse.ArgumentParser._get_option_tuples = _get_option_tuples
p = argparse.ArgumentParser()
p.add_argument(" foo")
print p.parse_args(" f 5".split())
评论 - 2020年7月29日 10:44

最新Python问答

推荐Python问答