From f34cf60cfcb22c8929543411c15fe662849e4a6a Mon Sep 17 00:00:00 2001 From: "steven.bethard" Date: Sun, 28 Feb 2010 08:04:33 +0000 Subject: Allow single character options, e.g. '-' and '+'. --- NEWS.txt | 1 + argparse.py | 29 ++++++++++------------------- test/test_argparse.py | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index c4859b5..98c7139 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -8,6 +8,7 @@ What's New in argparse 1.1 - Issue #38: Better error messages when 'dest' occurs twice for positional arguments. - Issue #39: Better error messages for invalid actions. - Issue #43: Deprecate ArgumentParser(..., version=XXX, ...) and friends. +- Issue #46: Allow single character options, e.g. '-' and '+'. - Namespace objects now support "in" (i.e. __contains__). - Usage and help (but not version) messages are written to stdout, not stderr. diff --git a/argparse.py b/argparse.py index fd21104..c89618b 100644 --- a/argparse.py +++ b/argparse.py @@ -1394,12 +1394,6 @@ class _ActionsContainer(object): option_strings = [] long_option_strings = [] for option_string in args: - # error on one-or-fewer-character option strings - if len(option_string) < 2: - msg = _('invalid option string %r: ' - 'must be at least two characters long') - raise ValueError(msg % option_string) - # error on strings that don't start with an appropriate prefix if not option_string[0] in self.prefix_chars: msg = _('invalid option string %r: ' @@ -1407,18 +1401,12 @@ class _ActionsContainer(object): tup = option_string, self.prefix_chars raise ValueError(msg % tup) - # error on strings that are all prefix characters - if not (_set(option_string) - _set(self.prefix_chars)): - msg = _('invalid option string %r: ' - 'must contain characters other than %r') - tup = option_string, self.prefix_chars - raise ValueError(msg % tup) - # strings starting with two prefix characters are long options option_strings.append(option_string) if option_string[0] in self.prefix_chars: - if option_string[1] in self.prefix_chars: - long_option_strings.append(option_string) + if len(option_string) > 1: + if option_string[1] in self.prefix_chars: + long_option_strings.append(option_string) # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' dest = kwargs.pop('dest', None) @@ -1428,6 +1416,9 @@ class _ActionsContainer(object): else: dest_option_string = option_strings[0] dest = dest_option_string.lstrip(self.prefix_chars) + if not dest: + msg = _('dest= is required for options like %r') + raise ValueError(msg % option_string) dest = dest.replace('-', '_') # return the updated keyword arguments @@ -2043,15 +2034,15 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): if not arg_string[0] in self.prefix_chars: return None - # if it's just dashes, it was meant to be positional - if not arg_string.strip('-'): - return None - # if the option string is present in the parser, return the action if arg_string in self._option_string_actions: action = self._option_string_actions[arg_string] return action, arg_string, None + # if it's just a single character, it was meant to be positional + if len(arg_string) == 1: + return None + # if the option string before the "=" is present, return the action if '=' in arg_string: option_string, explicit_arg = arg_string.split('=', 1) diff --git a/test/test_argparse.py b/test/test_argparse.py index 290b5e9..968843c 100644 --- a/test/test_argparse.py +++ b/test/test_argparse.py @@ -125,6 +125,7 @@ class NS(object): class ArgumentParserError(Exception): def __init__(self, message, stdout=None, stderr=None, error_code=None): + Exception.__init__(self, message, stdout, stderr) self.message = message self.stdout = stdout self.stderr = stderr @@ -1204,6 +1205,25 @@ class TestEmptyAndSpaceContainingArguments(ParserTestCase): ] +class TestPrefixCharacterOnlyArguments(ParserTestCase): + + parser_signature = Sig(prefix_chars='-+') + argument_signatures = [ + Sig('-', dest='x', nargs='?', const='badger'), + Sig('+', dest='y', type=int, default=42), + Sig('-+-', dest='z', action='store_true'), + ] + failures = ['-y', '+ -'] + successes = [ + ('', NS(x=None, y=42, z=False)), + ('-', NS(x='badger', y=42, z=False)), + ('- X', NS(x='X', y=42, z=False)), + ('+ -3', NS(x=None, y=-3, z=False)), + ('-+-', NS(x=None, y=42, z=True)), + ('- ===', NS(x='===', y=42, z=False)), + ] + + class TestNargsZeroOrMore(ParserTestCase): """Tests specifying an args for an Optional that accepts zero or more""" -- cgit v1.2.1