禁用 argparse 和 optparse 的唯一前缀匹配
Disable unique prefix matches for argparse and optparse
当我使用 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
一起用于帮助选项,以及 --forc
和 --fo
用于强制选项。
能否以某种方式关闭此行为?我想收到不完整参数的错误消息。
仅在 Python 3.5 中添加了禁用缩写长选项的功能。来自 argparse
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
.
因此,如果您使用的是 Python 3.5,则可以使用 allow_abbrev=False
:
创建解析器
parser = argparse.ArgumentParser(..., allow_abbrev=False)
如果您使用的是 optparse 或 3.5 之前的 argparse,您只需要使用缩写选项即可。
在 Python 3.5 之前,您必须对未记录的 ArgumentParser
方法进行 monkeypatch。实际上不要使用它;它未经测试,可能不适用于 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())
对于我们这些仍然停留在 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 过去的其他人会发现这很有用。
当我使用 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
一起用于帮助选项,以及 --forc
和 --fo
用于强制选项。
能否以某种方式关闭此行为?我想收到不完整参数的错误消息。
仅在 Python 3.5 中添加了禁用缩写长选项的功能。来自 argparse
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 toFalse
.
因此,如果您使用的是 Python 3.5,则可以使用 allow_abbrev=False
:
parser = argparse.ArgumentParser(..., allow_abbrev=False)
如果您使用的是 optparse 或 3.5 之前的 argparse,您只需要使用缩写选项即可。
在 Python 3.5 之前,您必须对未记录的 ArgumentParser
方法进行 monkeypatch。实际上不要使用它;它未经测试,可能不适用于 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())
对于我们这些仍然停留在 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 过去的其他人会发现这很有用。