diff -r 04b939c0c84d Doc/library/argparse.rst --- a/Doc/library/argparse.rst Sun May 27 01:53:33 2012 +1000 +++ b/Doc/library/argparse.rst Sat May 26 16:20:42 2012 -0400 @@ -132,7 +132,8 @@ .. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \ [argument_default], [parents], [prefix_chars], \ - [conflict_handler], [formatter_class]) + [conflict_handler], [formatter_class], \ + [allow_abbrev]) Create a new :class:`ArgumentParser` object. Each parameter has its own more detailed description below, but in short they are: @@ -157,6 +158,9 @@ * formatter_class_ - A class for customizing the help output. + * allow_abbrev_ - Allows long options to be abbreviated if the + abbreviation is unambiguous. (default: ``True``) + * conflict_handler_ - Usually unnecessary, defines strategy for resolving conflicting optionals. @@ -467,6 +471,36 @@ -h, --help show this help message and exit --foo int +allow_abbrev +^^^^^^^^^^^^ + +Normally, when you pass an argument list to the +:meth:`~ArgumentParser.parse_args` method of a :class:`ArgumentParser`, +it recognizes abbreviations of long options:: + + >>> parser = argparse.ArgumentParser(prog='PROG') + >>> parser.add_argument('--foobar', action='store_true') + >>> parser.add_argument('--foonley', action='store_false') + >>> parser.parse_args('--foon'.split()) + Namespace(foobar=False, foonley=False) + +However, if the abbreviation is ambiguous:: + + >>> parser.parse_args('--foo'.split()) + usage: PROG [-h] [--foobar] [--foonley] + PROG: error: ambiguous option: --foo could match --foonley, --foobar + An exception has occurred, use %tb to see the full traceback. + +However, this feature can also be disabled, by setting ``allow_abbrev=`` +to false:: + + >>> parser = argparse.ArgumentParser(prog='PROG', allow_abbrev=False) + >>> parser.add_argument('--foobar', action='store_true') + >>> parser.add_argument('--foonley', action='store_false') + >>> parser.parse_args('--foon'.split()) + usage: PROG [-h] [--foobar] [--foonley] + PROG: error: unrecognized arguments: --food + An exception has occurred, use %tb to see the full traceback. conflict_handler ^^^^^^^^^^^^^^^^ @@ -1353,8 +1387,8 @@ Argument abbreviations ^^^^^^^^^^^^^^^^^^^^^^ -The :meth:`~ArgumentParser.parse_args` method allows long options to be -abbreviated if the abbreviation is unambiguous:: +The :meth:`~ArgumentParser.parse_args` method by default allows long +options to be abbreviated if the abbreviation is unambiguous:: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-bacon') diff -r 04b939c0c84d Lib/argparse.py --- a/Lib/argparse.py Sun May 27 01:53:33 2012 +1000 +++ b/Lib/argparse.py Sat May 26 16:20:42 2012 -0400 @@ -1571,6 +1571,7 @@ additional arguments - argument_default -- The default value for all arguments - conflict_handler -- String indicating how to handle conflicts + - accept_abbrev -- Allow long options to be abbreviated unambiguously - add_help -- Add a -h/-help option """ @@ -1586,6 +1587,7 @@ fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', + allow_abbrev=True, add_help=True): if version is not None: @@ -1612,6 +1614,7 @@ self.version = version self.formatter_class = formatter_class self.fromfile_prefix_chars = fromfile_prefix_chars + self.allow_abbrev = allow_abbrev self.add_help = add_help add_group = self.add_argument_group @@ -2084,23 +2087,24 @@ action = self._option_string_actions[option_string] return action, option_string, explicit_arg - # search through all possible prefixes of the option string - # and all actions in the parser for possible interpretations - option_tuples = self._get_option_tuples(arg_string) - - # if multiple actions match, the option string was ambiguous - if len(option_tuples) > 1: - options = ', '.join([option_string - for action, option_string, explicit_arg in option_tuples]) - args = {'option': arg_string, 'matches': options} - msg = _('ambiguous option: %(option)s could match %(matches)s') - self.error(msg % args) - - # if exactly one action matched, this segmentation is good, - # so return the parsed action - elif len(option_tuples) == 1: - option_tuple, = option_tuples - return option_tuple + if self.allow_abbrev is True: + # search through all possible prefixes of the option string + # and all actions in the parser for possible interpretations + option_tuples = self._get_option_tuples(arg_string) + + # if multiple actions match, the option string was ambiguous + if len(option_tuples) > 1: + options = ', '.join([option_string + for action, option_string, explicit_arg in option_tuples]) + args = {'option': arg_string, 'matches': options} + msg = _('ambiguous option: %(option)s could match %(matches)s') + self.error(msg % args) + + # if exactly one action matched, this segmentation is good, + # so return the parsed action + elif len(option_tuples) == 1: + option_tuple, = option_tuples + return option_tuple # if it was not found as an option, but it looks like a negative # number, it was meant to be positional diff -r 04b939c0c84d Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Sun May 27 01:53:33 2012 +1000 +++ b/Lib/test/test_argparse.py Sat May 26 16:20:42 2012 -0400 @@ -760,6 +760,43 @@ ('-x', NS(x=1)), ] +class TestOptionalsAllowLongAbbreviation(ParserTestCase): + """Allow long options to be abbreviated unambiguously""" + + argument_signatures = [ + Sig('--foo'), + Sig('--foobaz'), + Sig('--fooble', action='store_true'), + ] + failures = [ '--foob 5', '--foob', ] + successes = [ + ('', NS(foo=None, foobaz=None, fooble=False)), + ('--foo 7', NS(foo='7', foobaz=None, fooble=False)), + ('--fooba a', NS(foo=None, foobaz='a', fooble=False)), + ('--foobl --foo g', NS(foo='g', foobaz=None, fooble=True)), + ] + + +class TestOptionalsDisallowLongAbbreviation(ParserTestCase): + """Do not allow abbreviations of long options at all""" + + parser_signature = Sig(allow_abbrev=False) + argument_signatures = [ + Sig('--foo'), + Sig('--foodle', action='store_true'), + Sig('--foonly'), + ] + failures = [ + '-foon 3', + '--food', + '--food --foo 2' + ] + successes = [ + ('', NS(foo=None, foodle=False, foonly=None)), + ('--foo 3', NS(foo='3', foodle=False, foonly=None)), + ('--foonly 7 --foodle --foo 2', NS(foo='2', foodle=True, foonly='7')), + ] + # ================ # Positional tests