Disable abbreviation in argparse

2019-01-26 05:31发布

argparse uses per default abbreviation in unambiguous cases.

I don't want abbreviation and I'd like to disable it. But didn't find it in the documentation.

Is it possible?

Example:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--send', action='store_true')
parser.parse_args(['--se']) # returns Namespace(send=True)

But I want it only to be true when the full parameter is supplied. To prevent user errors.

UPDATE:

I created a ticket at python bugtracker after Vikas answer. And it already has been processed.

4条回答
淡お忘
2楼-- · 2019-01-26 06:08

No, apparently this is not possible. At least in Python 2.7.2.

First, I took a look into the documentation - to no avail.

Then I opened the Lib\argparse.py and looked through the source code. Omitting a lot of details, it seems that each argument is parsed by a regular expression like this (argparse:2152):

    # allow one or more arguments
    elif nargs == ONE_OR_MORE:
        nargs_pattern = '(-*A[A-]*)'

This regex will successfully parse both '-' and '--', so we have no control over the short and long arguments. Other regexes use the -* construct too, so it does not depend on the type of the parameter (no sub-arguments, 1 sub-argument etc).

Later in the code double dashes are converted to one dash (only for non-optional args), again, without any flags to control by user:

    # if this is an optional action, -- is not allowed
    if action.option_strings:
        nargs_pattern = nargs_pattern.replace('-*', '')
        nargs_pattern = nargs_pattern.replace('-', '')
查看更多
Deceive 欺骗
3楼-- · 2019-01-26 06:12

No, well not without ugly hacks.

The code snippet @Vladimir posted, i suppose that is not what you are looking for. The actual code that is doing this is:

def _get_option_tuples(self, option_string):
    ...
    if option_string.startswith(option_prefix):
    ...

See the check is startswith not ==.

And you can always extend argparse.ArgumentParser to provide your own _get_option_tuples(self, option_string) to change this behavior. I just did by replacing two occurrence of option_string.startswith(option_prefix) to option_string == option_prefix and:

>>> parser = my_argparse.MyArgparse
>>> parser = my_argparse.MyArgparse()
>>> parser.add_argument('--send', action='store_true')
_StoreTrueAction(option_strings=['--send'], dest='send', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args(['--se'])
usage: [-h] [--send]
: error: unrecognized arguments: --se

A word of caution

The method _get_option_tuples is prefixed with _, which typically means a private method in python. And it is not a good idea to override a private.

查看更多
▲ chillily
4楼-- · 2019-01-26 06:16

Another way for Python 2.7. Let's get clunky! Say you want to recognize --dog without abbreviation.

p = argparse.ArgumentParser()
p.add_argument('--dog')
p.add_argument('--dox', help=argparse.SUPPRESS, metavar='IGNORE')

By adding a second argument --dox that differs from the argument you want only in the third letter, --d and --do become ambiguous. Therefore, the parser will refuse to recognize them. You would need to add code to catch the resulting exception and process it according to the context in which you are calling parse_args. You might also need to suppress/tweak the help text.

The help=... keeps the argument out of the option list on the default help message (per this), and metavar='IGNORE' is just to make it clear you really aren't doing anything with this option :) .

查看更多
Explosion°爆炸
5楼-- · 2019-01-26 06:21

As of Python 3.5.0 you can disable abbreviations by initiating the ArgumentParser with the following:

parser = argparse.ArgumentParser(allow_abbrev=False)

Also see the documentation.

查看更多
登录 后发表回答