Отключить уникальные совпадения префиксов для argparse и optparse

когда я использую синтаксический анализатор аргументов командной строки argparse или optparse Python, любой уникальный префикс аргумента считается допустимым, например

$ ./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 для опции force.

можно ли как-то отключить это поведение? Я хочу получить сообщение об ошибке для неполных аргументов.

2 ответов


возможность отключения сокращенных длинных опций была добавлена только в Python 3.5. От argparse документация:

на parse_args() метод по умолчанию позволяет сокращать длинные опции до префикса, если аббревиатура однозначна (префикс соответствует уникальной опции) ... эту функцию можно отключить, установив allow_abbrev to False.

Итак, если вы на Python 3.5, вы можете создать свой парсер с allow_abbrev=False:

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

если вы находитесь на optparse или pre-3.5 argparse, вам просто нужно жить с сокращенными опциями.


до Python 3.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())