Home | History | Annotate | Download | only in test
      1 # Author: Steven J. Bethard <steven.bethard (at] gmail.com>.

      2 
      3 import codecs
      4 import inspect
      5 import os
      6 import shutil
      7 import stat
      8 import sys
      9 import textwrap
     10 import tempfile
     11 import unittest
     12 import argparse
     13 
     14 from StringIO import StringIO
     15 
     16 class StdIOBuffer(StringIO):
     17     pass
     18 
     19 from test import test_support
     20 
     21 class TestCase(unittest.TestCase):
     22 
     23     def assertEqual(self, obj1, obj2):
     24         if obj1 != obj2:
     25             print('')
     26             print(repr(obj1))
     27             print(repr(obj2))
     28             print(obj1)
     29             print(obj2)
     30         super(TestCase, self).assertEqual(obj1, obj2)
     31 
     32     def setUp(self):
     33         # The tests assume that line wrapping occurs at 80 columns, but this

     34         # behaviour can be overridden by setting the COLUMNS environment

     35         # variable.  To ensure that this assumption is true, unset COLUMNS.

     36         env = test_support.EnvironmentVarGuard()
     37         env.unset("COLUMNS")
     38         self.addCleanup(env.__exit__)
     39 
     40 
     41 class TempDirMixin(object):
     42 
     43     def setUp(self):
     44         self.temp_dir = tempfile.mkdtemp()
     45         self.old_dir = os.getcwd()
     46         os.chdir(self.temp_dir)
     47 
     48     def tearDown(self):
     49         os.chdir(self.old_dir)
     50         shutil.rmtree(self.temp_dir, True)
     51 
     52     def create_readonly_file(self, filename):
     53         file_path = os.path.join(self.temp_dir, filename)
     54         with open(file_path, 'w') as file:
     55             file.write(filename)
     56         os.chmod(file_path, stat.S_IREAD)
     57 
     58 class Sig(object):
     59 
     60     def __init__(self, *args, **kwargs):
     61         self.args = args
     62         self.kwargs = kwargs
     63 
     64 
     65 class NS(object):
     66 
     67     def __init__(self, **kwargs):
     68         self.__dict__.update(kwargs)
     69 
     70     def __repr__(self):
     71         sorted_items = sorted(self.__dict__.items())
     72         kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
     73         return '%s(%s)' % (type(self).__name__, kwarg_str)
     74 
     75     __hash__ = None
     76 
     77     def __eq__(self, other):
     78         return vars(self) == vars(other)
     79 
     80     def __ne__(self, other):
     81         return not (self == other)
     82 
     83 
     84 class ArgumentParserError(Exception):
     85 
     86     def __init__(self, message, stdout=None, stderr=None, error_code=None):
     87         Exception.__init__(self, message, stdout, stderr)
     88         self.message = message
     89         self.stdout = stdout
     90         self.stderr = stderr
     91         self.error_code = error_code
     92 
     93 
     94 def stderr_to_parser_error(parse_args, *args, **kwargs):
     95     # if this is being called recursively and stderr or stdout is already being

     96     # redirected, simply call the function and let the enclosing function

     97     # catch the exception

     98     if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
     99         return parse_args(*args, **kwargs)
    100 
    101     # if this is not being called recursively, redirect stderr and

    102     # use it as the ArgumentParserError message

    103     old_stdout = sys.stdout
    104     old_stderr = sys.stderr
    105     sys.stdout = StdIOBuffer()
    106     sys.stderr = StdIOBuffer()
    107     try:
    108         try:
    109             result = parse_args(*args, **kwargs)
    110             for key in list(vars(result)):
    111                 if getattr(result, key) is sys.stdout:
    112                     setattr(result, key, old_stdout)
    113                 if getattr(result, key) is sys.stderr:
    114                     setattr(result, key, old_stderr)
    115             return result
    116         except SystemExit:
    117             code = sys.exc_info()[1].code
    118             stdout = sys.stdout.getvalue()
    119             stderr = sys.stderr.getvalue()
    120             raise ArgumentParserError("SystemExit", stdout, stderr, code)
    121     finally:
    122         sys.stdout = old_stdout
    123         sys.stderr = old_stderr
    124 
    125 
    126 class ErrorRaisingArgumentParser(argparse.ArgumentParser):
    127 
    128     def parse_args(self, *args, **kwargs):
    129         parse_args = super(ErrorRaisingArgumentParser, self).parse_args
    130         return stderr_to_parser_error(parse_args, *args, **kwargs)
    131 
    132     def exit(self, *args, **kwargs):
    133         exit = super(ErrorRaisingArgumentParser, self).exit
    134         return stderr_to_parser_error(exit, *args, **kwargs)
    135 
    136     def error(self, *args, **kwargs):
    137         error = super(ErrorRaisingArgumentParser, self).error
    138         return stderr_to_parser_error(error, *args, **kwargs)
    139 
    140 
    141 class ParserTesterMetaclass(type):
    142     """Adds parser tests using the class attributes.
    143 
    144     Classes of this type should specify the following attributes:
    145 
    146     argument_signatures -- a list of Sig objects which specify
    147         the signatures of Argument objects to be created
    148     failures -- a list of args lists that should cause the parser
    149         to fail
    150     successes -- a list of (initial_args, options, remaining_args) tuples
    151         where initial_args specifies the string args to be parsed,
    152         options is a dict that should match the vars() of the options
    153         parsed out of initial_args, and remaining_args should be any
    154         remaining unparsed arguments
    155     """
    156 
    157     def __init__(cls, name, bases, bodydict):
    158         if name == 'ParserTestCase':
    159             return
    160 
    161         # default parser signature is empty

    162         if not hasattr(cls, 'parser_signature'):
    163             cls.parser_signature = Sig()
    164         if not hasattr(cls, 'parser_class'):
    165             cls.parser_class = ErrorRaisingArgumentParser
    166 
    167         # ---------------------------------------

    168         # functions for adding optional arguments

    169         # ---------------------------------------

    170         def no_groups(parser, argument_signatures):
    171             """Add all arguments directly to the parser"""
    172             for sig in argument_signatures:
    173                 parser.add_argument(*sig.args, **sig.kwargs)
    174 
    175         def one_group(parser, argument_signatures):
    176             """Add all arguments under a single group in the parser"""
    177             group = parser.add_argument_group('foo')
    178             for sig in argument_signatures:
    179                 group.add_argument(*sig.args, **sig.kwargs)
    180 
    181         def many_groups(parser, argument_signatures):
    182             """Add each argument in its own group to the parser"""
    183             for i, sig in enumerate(argument_signatures):
    184                 group = parser.add_argument_group('foo:%i' % i)
    185                 group.add_argument(*sig.args, **sig.kwargs)
    186 
    187         # --------------------------

    188         # functions for parsing args

    189         # --------------------------

    190         def listargs(parser, args):
    191             """Parse the args by passing in a list"""
    192             return parser.parse_args(args)
    193 
    194         def sysargs(parser, args):
    195             """Parse the args by defaulting to sys.argv"""
    196             old_sys_argv = sys.argv
    197             sys.argv = [old_sys_argv[0]] + args
    198             try:
    199                 return parser.parse_args()
    200             finally:
    201                 sys.argv = old_sys_argv
    202 
    203         # class that holds the combination of one optional argument

    204         # addition method and one arg parsing method

    205         class AddTests(object):
    206 
    207             def __init__(self, tester_cls, add_arguments, parse_args):
    208                 self._add_arguments = add_arguments
    209                 self._parse_args = parse_args
    210 
    211                 add_arguments_name = self._add_arguments.__name__
    212                 parse_args_name = self._parse_args.__name__
    213                 for test_func in [self.test_failures, self.test_successes]:
    214                     func_name = test_func.__name__
    215                     names = func_name, add_arguments_name, parse_args_name
    216                     test_name = '_'.join(names)
    217 
    218                     def wrapper(self, test_func=test_func):
    219                         test_func(self)
    220                     try:
    221                         wrapper.__name__ = test_name
    222                     except TypeError:
    223                         pass
    224                     setattr(tester_cls, test_name, wrapper)
    225 
    226             def _get_parser(self, tester):
    227                 args = tester.parser_signature.args
    228                 kwargs = tester.parser_signature.kwargs
    229                 parser = tester.parser_class(*args, **kwargs)
    230                 self._add_arguments(parser, tester.argument_signatures)
    231                 return parser
    232 
    233             def test_failures(self, tester):
    234                 parser = self._get_parser(tester)
    235                 for args_str in tester.failures:
    236                     args = args_str.split()
    237                     raises = tester.assertRaises
    238                     raises(ArgumentParserError, parser.parse_args, args)
    239 
    240             def test_successes(self, tester):
    241                 parser = self._get_parser(tester)
    242                 for args, expected_ns in tester.successes:
    243                     if isinstance(args, str):
    244                         args = args.split()
    245                     result_ns = self._parse_args(parser, args)
    246                     tester.assertEqual(expected_ns, result_ns)
    247 
    248         # add tests for each combination of an optionals adding method

    249         # and an arg parsing method

    250         for add_arguments in [no_groups, one_group, many_groups]:
    251             for parse_args in [listargs, sysargs]:
    252                 AddTests(cls, add_arguments, parse_args)
    253 
    254 bases = TestCase,
    255 ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
    256 
    257 # ===============

    258 # Optionals tests

    259 # ===============

    260 
    261 class TestOptionalsSingleDash(ParserTestCase):
    262     """Test an Optional with a single-dash option string"""
    263 
    264     argument_signatures = [Sig('-x')]
    265     failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
    266     successes = [
    267         ('', NS(x=None)),
    268         ('-x a', NS(x='a')),
    269         ('-xa', NS(x='a')),
    270         ('-x -1', NS(x='-1')),
    271         ('-x-1', NS(x='-1')),
    272     ]
    273 
    274 
    275 class TestOptionalsSingleDashCombined(ParserTestCase):
    276     """Test an Optional with a single-dash option string"""
    277 
    278     argument_signatures = [
    279         Sig('-x', action='store_true'),
    280         Sig('-yyy', action='store_const', const=42),
    281         Sig('-z'),
    282     ]
    283     failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
    284                 '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
    285     successes = [
    286         ('', NS(x=False, yyy=None, z=None)),
    287         ('-x', NS(x=True, yyy=None, z=None)),
    288         ('-za', NS(x=False, yyy=None, z='a')),
    289         ('-z a', NS(x=False, yyy=None, z='a')),
    290         ('-xza', NS(x=True, yyy=None, z='a')),
    291         ('-xz a', NS(x=True, yyy=None, z='a')),
    292         ('-x -za', NS(x=True, yyy=None, z='a')),
    293         ('-x -z a', NS(x=True, yyy=None, z='a')),
    294         ('-y', NS(x=False, yyy=42, z=None)),
    295         ('-yyy', NS(x=False, yyy=42, z=None)),
    296         ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
    297         ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
    298     ]
    299 
    300 
    301 class TestOptionalsSingleDashLong(ParserTestCase):
    302     """Test an Optional with a multi-character single-dash option string"""
    303 
    304     argument_signatures = [Sig('-foo')]
    305     failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
    306     successes = [
    307         ('', NS(foo=None)),
    308         ('-foo a', NS(foo='a')),
    309         ('-foo -1', NS(foo='-1')),
    310         ('-fo a', NS(foo='a')),
    311         ('-f a', NS(foo='a')),
    312     ]
    313 
    314 
    315 class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
    316     """Test Optionals where option strings are subsets of each other"""
    317 
    318     argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
    319     failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
    320     successes = [
    321         ('', NS(f=None, foobar=None, foorab=None)),
    322         ('-f a', NS(f='a', foobar=None, foorab=None)),
    323         ('-fa', NS(f='a', foobar=None, foorab=None)),
    324         ('-foa', NS(f='oa', foobar=None, foorab=None)),
    325         ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
    326         ('-foobar a', NS(f=None, foobar='a', foorab=None)),
    327         ('-foorab a', NS(f=None, foobar=None, foorab='a')),
    328     ]
    329 
    330 
    331 class TestOptionalsSingleDashAmbiguous(ParserTestCase):
    332     """Test Optionals that partially match but are not subsets"""
    333 
    334     argument_signatures = [Sig('-foobar'), Sig('-foorab')]
    335     failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
    336     successes = [
    337         ('', NS(foobar=None, foorab=None)),
    338         ('-foob a', NS(foobar='a', foorab=None)),
    339         ('-foor a', NS(foobar=None, foorab='a')),
    340         ('-fooba a', NS(foobar='a', foorab=None)),
    341         ('-foora a', NS(foobar=None, foorab='a')),
    342         ('-foobar a', NS(foobar='a', foorab=None)),
    343         ('-foorab a', NS(foobar=None, foorab='a')),
    344     ]
    345 
    346 
    347 class TestOptionalsNumeric(ParserTestCase):
    348     """Test an Optional with a short opt string"""
    349 
    350     argument_signatures = [Sig('-1', dest='one')]
    351     failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
    352     successes = [
    353         ('', NS(one=None)),
    354         ('-1 a', NS(one='a')),
    355         ('-1a', NS(one='a')),
    356         ('-1-2', NS(one='-2')),
    357     ]
    358 
    359 
    360 class TestOptionalsDoubleDash(ParserTestCase):
    361     """Test an Optional with a double-dash option string"""
    362 
    363     argument_signatures = [Sig('--foo')]
    364     failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
    365     successes = [
    366         ('', NS(foo=None)),
    367         ('--foo a', NS(foo='a')),
    368         ('--foo=a', NS(foo='a')),
    369         ('--foo -2.5', NS(foo='-2.5')),
    370         ('--foo=-2.5', NS(foo='-2.5')),
    371     ]
    372 
    373 
    374 class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
    375     """Tests partial matching with a double-dash option string"""
    376 
    377     argument_signatures = [
    378         Sig('--badger', action='store_true'),
    379         Sig('--bat'),
    380     ]
    381     failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
    382     successes = [
    383         ('', NS(badger=False, bat=None)),
    384         ('--bat X', NS(badger=False, bat='X')),
    385         ('--bad', NS(badger=True, bat=None)),
    386         ('--badg', NS(badger=True, bat=None)),
    387         ('--badge', NS(badger=True, bat=None)),
    388         ('--badger', NS(badger=True, bat=None)),
    389     ]
    390 
    391 
    392 class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
    393     """Tests when one double-dash option string is a prefix of another"""
    394 
    395     argument_signatures = [
    396         Sig('--badger', action='store_true'),
    397         Sig('--ba'),
    398     ]
    399     failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
    400     successes = [
    401         ('', NS(badger=False, ba=None)),
    402         ('--ba X', NS(badger=False, ba='X')),
    403         ('--ba=X', NS(badger=False, ba='X')),
    404         ('--bad', NS(badger=True, ba=None)),
    405         ('--badg', NS(badger=True, ba=None)),
    406         ('--badge', NS(badger=True, ba=None)),
    407         ('--badger', NS(badger=True, ba=None)),
    408     ]
    409 
    410 
    411 class TestOptionalsSingleDoubleDash(ParserTestCase):
    412     """Test an Optional with single- and double-dash option strings"""
    413 
    414     argument_signatures = [
    415         Sig('-f', action='store_true'),
    416         Sig('--bar'),
    417         Sig('-baz', action='store_const', const=42),
    418     ]
    419     failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
    420     successes = [
    421         ('', NS(f=False, bar=None, baz=None)),
    422         ('-f', NS(f=True, bar=None, baz=None)),
    423         ('--ba B', NS(f=False, bar='B', baz=None)),
    424         ('-f --bar B', NS(f=True, bar='B', baz=None)),
    425         ('-f -b', NS(f=True, bar=None, baz=42)),
    426         ('-ba -f', NS(f=True, bar=None, baz=42)),
    427     ]
    428 
    429 
    430 class TestOptionalsAlternatePrefixChars(ParserTestCase):
    431     """Test an Optional with option strings with custom prefixes"""
    432 
    433     parser_signature = Sig(prefix_chars='+:/', add_help=False)
    434     argument_signatures = [
    435         Sig('+f', action='store_true'),
    436         Sig('::bar'),
    437         Sig('/baz', action='store_const', const=42),
    438     ]
    439     failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
    440     successes = [
    441         ('', NS(f=False, bar=None, baz=None)),
    442         ('+f', NS(f=True, bar=None, baz=None)),
    443         ('::ba B', NS(f=False, bar='B', baz=None)),
    444         ('+f ::bar B', NS(f=True, bar='B', baz=None)),
    445         ('+f /b', NS(f=True, bar=None, baz=42)),
    446         ('/ba +f', NS(f=True, bar=None, baz=42)),
    447     ]
    448 
    449 
    450 class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
    451     """When ``-`` not in prefix_chars, default operators created for help
    452        should use the prefix_chars in use rather than - or --
    453        http://bugs.python.org/issue9444"""
    454 
    455     parser_signature = Sig(prefix_chars='+:/', add_help=True)
    456     argument_signatures = [
    457         Sig('+f', action='store_true'),
    458         Sig('::bar'),
    459         Sig('/baz', action='store_const', const=42),
    460     ]
    461     failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
    462     successes = [
    463         ('', NS(f=False, bar=None, baz=None)),
    464         ('+f', NS(f=True, bar=None, baz=None)),
    465         ('::ba B', NS(f=False, bar='B', baz=None)),
    466         ('+f ::bar B', NS(f=True, bar='B', baz=None)),
    467         ('+f /b', NS(f=True, bar=None, baz=42)),
    468         ('/ba +f', NS(f=True, bar=None, baz=42))
    469     ]
    470 
    471 
    472 class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
    473     """Verify that Optionals must be called with their defined prefixes"""
    474 
    475     parser_signature = Sig(prefix_chars='+-', add_help=False)
    476     argument_signatures = [
    477         Sig('-x', action='store_true'),
    478         Sig('+y', action='store_true'),
    479         Sig('+z', action='store_true'),
    480     ]
    481     failures = ['-w',
    482                 '-xyz',
    483                 '+x',
    484                 '-y',
    485                 '+xyz',
    486     ]
    487     successes = [
    488         ('', NS(x=False, y=False, z=False)),
    489         ('-x', NS(x=True, y=False, z=False)),
    490         ('+y -x', NS(x=True, y=True, z=False)),
    491         ('+yz -x', NS(x=True, y=True, z=True)),
    492     ]
    493 
    494 
    495 class TestOptionalsShortLong(ParserTestCase):
    496     """Test a combination of single- and double-dash option strings"""
    497 
    498     argument_signatures = [
    499         Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
    500     ]
    501     failures = ['--x --verbose', '-N', 'a', '-v x']
    502     successes = [
    503         ('', NS(verbose=False)),
    504         ('-v', NS(verbose=True)),
    505         ('--verbose', NS(verbose=True)),
    506         ('-n', NS(verbose=True)),
    507         ('--noisy', NS(verbose=True)),
    508     ]
    509 
    510 
    511 class TestOptionalsDest(ParserTestCase):
    512     """Tests various means of setting destination"""
    513 
    514     argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
    515     failures = ['a']
    516     successes = [
    517         ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
    518         ('--baz g', NS(foo_bar=None, zabbaz='g')),
    519         ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
    520         ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
    521     ]
    522 
    523 
    524 class TestOptionalsDefault(ParserTestCase):
    525     """Tests specifying a default for an Optional"""
    526 
    527     argument_signatures = [Sig('-x'), Sig('-y', default=42)]
    528     failures = ['a']
    529     successes = [
    530         ('', NS(x=None, y=42)),
    531         ('-xx', NS(x='x', y=42)),
    532         ('-yy', NS(x=None, y='y')),
    533     ]
    534 
    535 
    536 class TestOptionalsNargsDefault(ParserTestCase):
    537     """Tests not specifying the number of args for an Optional"""
    538 
    539     argument_signatures = [Sig('-x')]
    540     failures = ['a', '-x']
    541     successes = [
    542         ('', NS(x=None)),
    543         ('-x a', NS(x='a')),
    544     ]
    545 
    546 
    547 class TestOptionalsNargs1(ParserTestCase):
    548     """Tests specifying the 1 arg for an Optional"""
    549 
    550     argument_signatures = [Sig('-x', nargs=1)]
    551     failures = ['a', '-x']
    552     successes = [
    553         ('', NS(x=None)),
    554         ('-x a', NS(x=['a'])),
    555     ]
    556 
    557 
    558 class TestOptionalsNargs3(ParserTestCase):
    559     """Tests specifying the 3 args for an Optional"""
    560 
    561     argument_signatures = [Sig('-x', nargs=3)]
    562     failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
    563     successes = [
    564         ('', NS(x=None)),
    565         ('-x a b c', NS(x=['a', 'b', 'c'])),
    566     ]
    567 
    568 
    569 class TestOptionalsNargsOptional(ParserTestCase):
    570     """Tests specifying an Optional arg for an Optional"""
    571 
    572     argument_signatures = [
    573         Sig('-w', nargs='?'),
    574         Sig('-x', nargs='?', const=42),
    575         Sig('-y', nargs='?', default='spam'),
    576         Sig('-z', nargs='?', type=int, const='42', default='84'),
    577     ]
    578     failures = ['2']
    579     successes = [
    580         ('', NS(w=None, x=None, y='spam', z=84)),
    581         ('-w', NS(w=None, x=None, y='spam', z=84)),
    582         ('-w 2', NS(w='2', x=None, y='spam', z=84)),
    583         ('-x', NS(w=None, x=42, y='spam', z=84)),
    584         ('-x 2', NS(w=None, x='2', y='spam', z=84)),
    585         ('-y', NS(w=None, x=None, y=None, z=84)),
    586         ('-y 2', NS(w=None, x=None, y='2', z=84)),
    587         ('-z', NS(w=None, x=None, y='spam', z=42)),
    588         ('-z 2', NS(w=None, x=None, y='spam', z=2)),
    589     ]
    590 
    591 
    592 class TestOptionalsNargsZeroOrMore(ParserTestCase):
    593     """Tests specifying an args for an Optional that accepts zero or more"""
    594 
    595     argument_signatures = [
    596         Sig('-x', nargs='*'),
    597         Sig('-y', nargs='*', default='spam'),
    598     ]
    599     failures = ['a']
    600     successes = [
    601         ('', NS(x=None, y='spam')),
    602         ('-x', NS(x=[], y='spam')),
    603         ('-x a', NS(x=['a'], y='spam')),
    604         ('-x a b', NS(x=['a', 'b'], y='spam')),
    605         ('-y', NS(x=None, y=[])),
    606         ('-y a', NS(x=None, y=['a'])),
    607         ('-y a b', NS(x=None, y=['a', 'b'])),
    608     ]
    609 
    610 
    611 class TestOptionalsNargsOneOrMore(ParserTestCase):
    612     """Tests specifying an args for an Optional that accepts one or more"""
    613 
    614     argument_signatures = [
    615         Sig('-x', nargs='+'),
    616         Sig('-y', nargs='+', default='spam'),
    617     ]
    618     failures = ['a', '-x', '-y', 'a -x', 'a -y b']
    619     successes = [
    620         ('', NS(x=None, y='spam')),
    621         ('-x a', NS(x=['a'], y='spam')),
    622         ('-x a b', NS(x=['a', 'b'], y='spam')),
    623         ('-y a', NS(x=None, y=['a'])),
    624         ('-y a b', NS(x=None, y=['a', 'b'])),
    625     ]
    626 
    627 
    628 class TestOptionalsChoices(ParserTestCase):
    629     """Tests specifying the choices for an Optional"""
    630 
    631     argument_signatures = [
    632         Sig('-f', choices='abc'),
    633         Sig('-g', type=int, choices=range(5))]
    634     failures = ['a', '-f d', '-fad', '-ga', '-g 6']
    635     successes = [
    636         ('', NS(f=None, g=None)),
    637         ('-f a', NS(f='a', g=None)),
    638         ('-f c', NS(f='c', g=None)),
    639         ('-g 0', NS(f=None, g=0)),
    640         ('-g 03', NS(f=None, g=3)),
    641         ('-fb -g4', NS(f='b', g=4)),
    642     ]
    643 
    644 
    645 class TestOptionalsRequired(ParserTestCase):
    646     """Tests the an optional action that is required"""
    647 
    648     argument_signatures = [
    649         Sig('-x', type=int, required=True),
    650     ]
    651     failures = ['a', '']
    652     successes = [
    653         ('-x 1', NS(x=1)),
    654         ('-x42', NS(x=42)),
    655     ]
    656 
    657 
    658 class TestOptionalsActionStore(ParserTestCase):
    659     """Tests the store action for an Optional"""
    660 
    661     argument_signatures = [Sig('-x', action='store')]
    662     failures = ['a', 'a -x']
    663     successes = [
    664         ('', NS(x=None)),
    665         ('-xfoo', NS(x='foo')),
    666     ]
    667 
    668 
    669 class TestOptionalsActionStoreConst(ParserTestCase):
    670     """Tests the store_const action for an Optional"""
    671 
    672     argument_signatures = [Sig('-y', action='store_const', const=object)]
    673     failures = ['a']
    674     successes = [
    675         ('', NS(y=None)),
    676         ('-y', NS(y=object)),
    677     ]
    678 
    679 
    680 class TestOptionalsActionStoreFalse(ParserTestCase):
    681     """Tests the store_false action for an Optional"""
    682 
    683     argument_signatures = [Sig('-z', action='store_false')]
    684     failures = ['a', '-za', '-z a']
    685     successes = [
    686         ('', NS(z=True)),
    687         ('-z', NS(z=False)),
    688     ]
    689 
    690 
    691 class TestOptionalsActionStoreTrue(ParserTestCase):
    692     """Tests the store_true action for an Optional"""
    693 
    694     argument_signatures = [Sig('--apple', action='store_true')]
    695     failures = ['a', '--apple=b', '--apple b']
    696     successes = [
    697         ('', NS(apple=False)),
    698         ('--apple', NS(apple=True)),
    699     ]
    700 
    701 
    702 class TestOptionalsActionAppend(ParserTestCase):
    703     """Tests the append action for an Optional"""
    704 
    705     argument_signatures = [Sig('--baz', action='append')]
    706     failures = ['a', '--baz', 'a --baz', '--baz a b']
    707     successes = [
    708         ('', NS(baz=None)),
    709         ('--baz a', NS(baz=['a'])),
    710         ('--baz a --baz b', NS(baz=['a', 'b'])),
    711     ]
    712 
    713 
    714 class TestOptionalsActionAppendWithDefault(ParserTestCase):
    715     """Tests the append action for an Optional"""
    716 
    717     argument_signatures = [Sig('--baz', action='append', default=['X'])]
    718     failures = ['a', '--baz', 'a --baz', '--baz a b']
    719     successes = [
    720         ('', NS(baz=['X'])),
    721         ('--baz a', NS(baz=['X', 'a'])),
    722         ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
    723     ]
    724 
    725 
    726 class TestOptionalsActionAppendConst(ParserTestCase):
    727     """Tests the append_const action for an Optional"""
    728 
    729     argument_signatures = [
    730         Sig('-b', action='append_const', const=Exception),
    731         Sig('-c', action='append', dest='b'),
    732     ]
    733     failures = ['a', '-c', 'a -c', '-bx', '-b x']
    734     successes = [
    735         ('', NS(b=None)),
    736         ('-b', NS(b=[Exception])),
    737         ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
    738     ]
    739 
    740 
    741 class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
    742     """Tests the append_const action for an Optional"""
    743 
    744     argument_signatures = [
    745         Sig('-b', action='append_const', const=Exception, default=['X']),
    746         Sig('-c', action='append', dest='b'),
    747     ]
    748     failures = ['a', '-c', 'a -c', '-bx', '-b x']
    749     successes = [
    750         ('', NS(b=['X'])),
    751         ('-b', NS(b=['X', Exception])),
    752         ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
    753     ]
    754 
    755 
    756 class TestOptionalsActionCount(ParserTestCase):
    757     """Tests the count action for an Optional"""
    758 
    759     argument_signatures = [Sig('-x', action='count')]
    760     failures = ['a', '-x a', '-x b', '-x a -x b']
    761     successes = [
    762         ('', NS(x=None)),
    763         ('-x', NS(x=1)),
    764     ]
    765 
    766 
    767 # ================

    768 # Positional tests

    769 # ================

    770 
    771 class TestPositionalsNargsNone(ParserTestCase):
    772     """Test a Positional that doesn't specify nargs"""
    773 
    774     argument_signatures = [Sig('foo')]
    775     failures = ['', '-x', 'a b']
    776     successes = [
    777         ('a', NS(foo='a')),
    778     ]
    779 
    780 
    781 class TestPositionalsNargs1(ParserTestCase):
    782     """Test a Positional that specifies an nargs of 1"""
    783 
    784     argument_signatures = [Sig('foo', nargs=1)]
    785     failures = ['', '-x', 'a b']
    786     successes = [
    787         ('a', NS(foo=['a'])),
    788     ]
    789 
    790 
    791 class TestPositionalsNargs2(ParserTestCase):
    792     """Test a Positional that specifies an nargs of 2"""
    793 
    794     argument_signatures = [Sig('foo', nargs=2)]
    795     failures = ['', 'a', '-x', 'a b c']
    796     successes = [
    797         ('a b', NS(foo=['a', 'b'])),
    798     ]
    799 
    800 
    801 class TestPositionalsNargsZeroOrMore(ParserTestCase):
    802     """Test a Positional that specifies unlimited nargs"""
    803 
    804     argument_signatures = [Sig('foo', nargs='*')]
    805     failures = ['-x']
    806     successes = [
    807         ('', NS(foo=[])),
    808         ('a', NS(foo=['a'])),
    809         ('a b', NS(foo=['a', 'b'])),
    810     ]
    811 
    812 
    813 class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
    814     """Test a Positional that specifies unlimited nargs and a default"""
    815 
    816     argument_signatures = [Sig('foo', nargs='*', default='bar')]
    817     failures = ['-x']
    818     successes = [
    819         ('', NS(foo='bar')),
    820         ('a', NS(foo=['a'])),
    821         ('a b', NS(foo=['a', 'b'])),
    822     ]
    823 
    824 
    825 class TestPositionalsNargsOneOrMore(ParserTestCase):
    826     """Test a Positional that specifies one or more nargs"""
    827 
    828     argument_signatures = [Sig('foo', nargs='+')]
    829     failures = ['', '-x']
    830     successes = [
    831         ('a', NS(foo=['a'])),
    832         ('a b', NS(foo=['a', 'b'])),
    833     ]
    834 
    835 
    836 class TestPositionalsNargsOptional(ParserTestCase):
    837     """Tests an Optional Positional"""
    838 
    839     argument_signatures = [Sig('foo', nargs='?')]
    840     failures = ['-x', 'a b']
    841     successes = [
    842         ('', NS(foo=None)),
    843         ('a', NS(foo='a')),
    844     ]
    845 
    846 
    847 class TestPositionalsNargsOptionalDefault(ParserTestCase):
    848     """Tests an Optional Positional with a default value"""
    849 
    850     argument_signatures = [Sig('foo', nargs='?', default=42)]
    851     failures = ['-x', 'a b']
    852     successes = [
    853         ('', NS(foo=42)),
    854         ('a', NS(foo='a')),
    855     ]
    856 
    857 
    858 class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
    859     """Tests an Optional Positional with a default value
    860     that needs to be converted to the appropriate type.
    861     """
    862 
    863     argument_signatures = [
    864         Sig('foo', nargs='?', type=int, default='42'),
    865     ]
    866     failures = ['-x', 'a b', '1 2']
    867     successes = [
    868         ('', NS(foo=42)),
    869         ('1', NS(foo=1)),
    870     ]
    871 
    872 
    873 class TestPositionalsNargsNoneNone(ParserTestCase):
    874     """Test two Positionals that don't specify nargs"""
    875 
    876     argument_signatures = [Sig('foo'), Sig('bar')]
    877     failures = ['', '-x', 'a', 'a b c']
    878     successes = [
    879         ('a b', NS(foo='a', bar='b')),
    880     ]
    881 
    882 
    883 class TestPositionalsNargsNone1(ParserTestCase):
    884     """Test a Positional with no nargs followed by one with 1"""
    885 
    886     argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
    887     failures = ['', '--foo', 'a', 'a b c']
    888     successes = [
    889         ('a b', NS(foo='a', bar=['b'])),
    890     ]
    891 
    892 
    893 class TestPositionalsNargs2None(ParserTestCase):
    894     """Test a Positional with 2 nargs followed by one with none"""
    895 
    896     argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
    897     failures = ['', '--foo', 'a', 'a b', 'a b c d']
    898     successes = [
    899         ('a b c', NS(foo=['a', 'b'], bar='c')),
    900     ]
    901 
    902 
    903 class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
    904     """Test a Positional with no nargs followed by one with unlimited"""
    905 
    906     argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
    907     failures = ['', '--foo']
    908     successes = [
    909         ('a', NS(foo='a', bar=[])),
    910         ('a b', NS(foo='a', bar=['b'])),
    911         ('a b c', NS(foo='a', bar=['b', 'c'])),
    912     ]
    913 
    914 
    915 class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
    916     """Test a Positional with no nargs followed by one with one or more"""
    917 
    918     argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
    919     failures = ['', '--foo', 'a']
    920     successes = [
    921         ('a b', NS(foo='a', bar=['b'])),
    922         ('a b c', NS(foo='a', bar=['b', 'c'])),
    923     ]
    924 
    925 
    926 class TestPositionalsNargsNoneOptional(ParserTestCase):
    927     """Test a Positional with no nargs followed by one with an Optional"""
    928 
    929     argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
    930     failures = ['', '--foo', 'a b c']
    931     successes = [
    932         ('a', NS(foo='a', bar=None)),
    933         ('a b', NS(foo='a', bar='b')),
    934     ]
    935 
    936 
    937 class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
    938     """Test a Positional with unlimited nargs followed by one with none"""
    939 
    940     argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
    941     failures = ['', '--foo']
    942     successes = [
    943         ('a', NS(foo=[], bar='a')),
    944         ('a b', NS(foo=['a'], bar='b')),
    945         ('a b c', NS(foo=['a', 'b'], bar='c')),
    946     ]
    947 
    948 
    949 class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
    950     """Test a Positional with one or more nargs followed by one with none"""
    951 
    952     argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
    953     failures = ['', '--foo', 'a']
    954     successes = [
    955         ('a b', NS(foo=['a'], bar='b')),
    956         ('a b c', NS(foo=['a', 'b'], bar='c')),
    957     ]
    958 
    959 
    960 class TestPositionalsNargsOptionalNone(ParserTestCase):
    961     """Test a Positional with an Optional nargs followed by one with none"""
    962 
    963     argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
    964     failures = ['', '--foo', 'a b c']
    965     successes = [
    966         ('a', NS(foo=42, bar='a')),
    967         ('a b', NS(foo='a', bar='b')),
    968     ]
    969 
    970 
    971 class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
    972     """Test a Positional with 2 nargs followed by one with unlimited"""
    973 
    974     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
    975     failures = ['', '--foo', 'a']
    976     successes = [
    977         ('a b', NS(foo=['a', 'b'], bar=[])),
    978         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
    979     ]
    980 
    981 
    982 class TestPositionalsNargs2OneOrMore(ParserTestCase):
    983     """Test a Positional with 2 nargs followed by one with one or more"""
    984 
    985     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
    986     failures = ['', '--foo', 'a', 'a b']
    987     successes = [
    988         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
    989     ]
    990 
    991 
    992 class TestPositionalsNargs2Optional(ParserTestCase):
    993     """Test a Positional with 2 nargs followed by one optional"""
    994 
    995     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
    996     failures = ['', '--foo', 'a', 'a b c d']
    997     successes = [
    998         ('a b', NS(foo=['a', 'b'], bar=None)),
    999         ('a b c', NS(foo=['a', 'b'], bar='c')),
   1000     ]
   1001 
   1002 
   1003 class TestPositionalsNargsZeroOrMore1(ParserTestCase):
   1004     """Test a Positional with unlimited nargs followed by one with 1"""
   1005 
   1006     argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
   1007     failures = ['', '--foo', ]
   1008     successes = [
   1009         ('a', NS(foo=[], bar=['a'])),
   1010         ('a b', NS(foo=['a'], bar=['b'])),
   1011         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
   1012     ]
   1013 
   1014 
   1015 class TestPositionalsNargsOneOrMore1(ParserTestCase):
   1016     """Test a Positional with one or more nargs followed by one with 1"""
   1017 
   1018     argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
   1019     failures = ['', '--foo', 'a']
   1020     successes = [
   1021         ('a b', NS(foo=['a'], bar=['b'])),
   1022         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
   1023     ]
   1024 
   1025 
   1026 class TestPositionalsNargsOptional1(ParserTestCase):
   1027     """Test a Positional with an Optional nargs followed by one with 1"""
   1028 
   1029     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
   1030     failures = ['', '--foo', 'a b c']
   1031     successes = [
   1032         ('a', NS(foo=None, bar=['a'])),
   1033         ('a b', NS(foo='a', bar=['b'])),
   1034     ]
   1035 
   1036 
   1037 class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
   1038     """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
   1039 
   1040     argument_signatures = [
   1041         Sig('foo'),
   1042         Sig('bar', nargs='*'),
   1043         Sig('baz', nargs=1),
   1044     ]
   1045     failures = ['', '--foo', 'a']
   1046     successes = [
   1047         ('a b', NS(foo='a', bar=[], baz=['b'])),
   1048         ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
   1049     ]
   1050 
   1051 
   1052 class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
   1053     """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
   1054 
   1055     argument_signatures = [
   1056         Sig('foo'),
   1057         Sig('bar', nargs='+'),
   1058         Sig('baz', nargs=1),
   1059     ]
   1060     failures = ['', '--foo', 'a', 'b']
   1061     successes = [
   1062         ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
   1063         ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
   1064     ]
   1065 
   1066 
   1067 class TestPositionalsNargsNoneOptional1(ParserTestCase):
   1068     """Test three Positionals: no nargs, optional narg and 1 nargs"""
   1069 
   1070     argument_signatures = [
   1071         Sig('foo'),
   1072         Sig('bar', nargs='?', default=0.625),
   1073         Sig('baz', nargs=1),
   1074     ]
   1075     failures = ['', '--foo', 'a']
   1076     successes = [
   1077         ('a b', NS(foo='a', bar=0.625, baz=['b'])),
   1078         ('a b c', NS(foo='a', bar='b', baz=['c'])),
   1079     ]
   1080 
   1081 
   1082 class TestPositionalsNargsOptionalOptional(ParserTestCase):
   1083     """Test two optional nargs"""
   1084 
   1085     argument_signatures = [
   1086         Sig('foo', nargs='?'),
   1087         Sig('bar', nargs='?', default=42),
   1088     ]
   1089     failures = ['--foo', 'a b c']
   1090     successes = [
   1091         ('', NS(foo=None, bar=42)),
   1092         ('a', NS(foo='a', bar=42)),
   1093         ('a b', NS(foo='a', bar='b')),
   1094     ]
   1095 
   1096 
   1097 class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
   1098     """Test an Optional narg followed by unlimited nargs"""
   1099 
   1100     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
   1101     failures = ['--foo']
   1102     successes = [
   1103         ('', NS(foo=None, bar=[])),
   1104         ('a', NS(foo='a', bar=[])),
   1105         ('a b', NS(foo='a', bar=['b'])),
   1106         ('a b c', NS(foo='a', bar=['b', 'c'])),
   1107     ]
   1108 
   1109 
   1110 class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
   1111     """Test an Optional narg followed by one or more nargs"""
   1112 
   1113     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
   1114     failures = ['', '--foo']
   1115     successes = [
   1116         ('a', NS(foo=None, bar=['a'])),
   1117         ('a b', NS(foo='a', bar=['b'])),
   1118         ('a b c', NS(foo='a', bar=['b', 'c'])),
   1119     ]
   1120 
   1121 
   1122 class TestPositionalsChoicesString(ParserTestCase):
   1123     """Test a set of single-character choices"""
   1124 
   1125     argument_signatures = [Sig('spam', choices=set('abcdefg'))]
   1126     failures = ['', '--foo', 'h', '42', 'ef']
   1127     successes = [
   1128         ('a', NS(spam='a')),
   1129         ('g', NS(spam='g')),
   1130     ]
   1131 
   1132 
   1133 class TestPositionalsChoicesInt(ParserTestCase):
   1134     """Test a set of integer choices"""
   1135 
   1136     argument_signatures = [Sig('spam', type=int, choices=range(20))]
   1137     failures = ['', '--foo', 'h', '42', 'ef']
   1138     successes = [
   1139         ('4', NS(spam=4)),
   1140         ('15', NS(spam=15)),
   1141     ]
   1142 
   1143 
   1144 class TestPositionalsActionAppend(ParserTestCase):
   1145     """Test the 'append' action"""
   1146 
   1147     argument_signatures = [
   1148         Sig('spam', action='append'),
   1149         Sig('spam', action='append', nargs=2),
   1150     ]
   1151     failures = ['', '--foo', 'a', 'a b', 'a b c d']
   1152     successes = [
   1153         ('a b c', NS(spam=['a', ['b', 'c']])),
   1154     ]
   1155 
   1156 # ========================================

   1157 # Combined optionals and positionals tests

   1158 # ========================================

   1159 
   1160 class TestOptionalsNumericAndPositionals(ParserTestCase):
   1161     """Tests negative number args when numeric options are present"""
   1162 
   1163     argument_signatures = [
   1164         Sig('x', nargs='?'),
   1165         Sig('-4', dest='y', action='store_true'),
   1166     ]
   1167     failures = ['-2', '-315']
   1168     successes = [
   1169         ('', NS(x=None, y=False)),
   1170         ('a', NS(x='a', y=False)),
   1171         ('-4', NS(x=None, y=True)),
   1172         ('-4 a', NS(x='a', y=True)),
   1173     ]
   1174 
   1175 
   1176 class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
   1177     """Tests negative number args when almost numeric options are present"""
   1178 
   1179     argument_signatures = [
   1180         Sig('x', nargs='?'),
   1181         Sig('-k4', dest='y', action='store_true'),
   1182     ]
   1183     failures = ['-k3']
   1184     successes = [
   1185         ('', NS(x=None, y=False)),
   1186         ('-2', NS(x='-2', y=False)),
   1187         ('a', NS(x='a', y=False)),
   1188         ('-k4', NS(x=None, y=True)),
   1189         ('-k4 a', NS(x='a', y=True)),
   1190     ]
   1191 
   1192 
   1193 class TestEmptyAndSpaceContainingArguments(ParserTestCase):
   1194 
   1195     argument_signatures = [
   1196         Sig('x', nargs='?'),
   1197         Sig('-y', '--yyy', dest='y'),
   1198     ]
   1199     failures = ['-y']
   1200     successes = [
   1201         ([''], NS(x='', y=None)),
   1202         (['a badger'], NS(x='a badger', y=None)),
   1203         (['-a badger'], NS(x='-a badger', y=None)),
   1204         (['-y', ''], NS(x=None, y='')),
   1205         (['-y', 'a badger'], NS(x=None, y='a badger')),
   1206         (['-y', '-a badger'], NS(x=None, y='-a badger')),
   1207         (['--yyy=a badger'], NS(x=None, y='a badger')),
   1208         (['--yyy=-a badger'], NS(x=None, y='-a badger')),
   1209     ]
   1210 
   1211 
   1212 class TestPrefixCharacterOnlyArguments(ParserTestCase):
   1213 
   1214     parser_signature = Sig(prefix_chars='-+')
   1215     argument_signatures = [
   1216         Sig('-', dest='x', nargs='?', const='badger'),
   1217         Sig('+', dest='y', type=int, default=42),
   1218         Sig('-+-', dest='z', action='store_true'),
   1219     ]
   1220     failures = ['-y', '+ -']
   1221     successes = [
   1222         ('', NS(x=None, y=42, z=False)),
   1223         ('-', NS(x='badger', y=42, z=False)),
   1224         ('- X', NS(x='X', y=42, z=False)),
   1225         ('+ -3', NS(x=None, y=-3, z=False)),
   1226         ('-+-', NS(x=None, y=42, z=True)),
   1227         ('- ===', NS(x='===', y=42, z=False)),
   1228     ]
   1229 
   1230 
   1231 class TestNargsZeroOrMore(ParserTestCase):
   1232     """Tests specifying an args for an Optional that accepts zero or more"""
   1233 
   1234     argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
   1235     failures = []
   1236     successes = [
   1237         ('', NS(x=None, y=[])),
   1238         ('-x', NS(x=[], y=[])),
   1239         ('-x a', NS(x=['a'], y=[])),
   1240         ('-x a -- b', NS(x=['a'], y=['b'])),
   1241         ('a', NS(x=None, y=['a'])),
   1242         ('a -x', NS(x=[], y=['a'])),
   1243         ('a -x b', NS(x=['b'], y=['a'])),
   1244     ]
   1245 
   1246 
   1247 class TestNargsRemainder(ParserTestCase):
   1248     """Tests specifying a positional with nargs=REMAINDER"""
   1249 
   1250     argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
   1251     failures = ['', '-z', '-z Z']
   1252     successes = [
   1253         ('X', NS(x='X', y=[], z=None)),
   1254         ('-z Z X', NS(x='X', y=[], z='Z')),
   1255         ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
   1256         ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
   1257     ]
   1258 
   1259 
   1260 class TestOptionLike(ParserTestCase):
   1261     """Tests options that may or may not be arguments"""
   1262 
   1263     argument_signatures = [
   1264         Sig('-x', type=float),
   1265         Sig('-3', type=float, dest='y'),
   1266         Sig('z', nargs='*'),
   1267     ]
   1268     failures = ['-x', '-y2.5', '-xa', '-x -a',
   1269                 '-x -3', '-x -3.5', '-3 -3.5',
   1270                 '-x -2.5', '-x -2.5 a', '-3 -.5',
   1271                 'a x -1', '-x -1 a', '-3 -1 a']
   1272     successes = [
   1273         ('', NS(x=None, y=None, z=[])),
   1274         ('-x 2.5', NS(x=2.5, y=None, z=[])),
   1275         ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
   1276         ('-3.5', NS(x=None, y=0.5, z=[])),
   1277         ('-3-.5', NS(x=None, y=-0.5, z=[])),
   1278         ('-3 .5', NS(x=None, y=0.5, z=[])),
   1279         ('a -3.5', NS(x=None, y=0.5, z=['a'])),
   1280         ('a', NS(x=None, y=None, z=['a'])),
   1281         ('a -x 1', NS(x=1.0, y=None, z=['a'])),
   1282         ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
   1283         ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
   1284     ]
   1285 
   1286 
   1287 class TestDefaultSuppress(ParserTestCase):
   1288     """Test actions with suppressed defaults"""
   1289 
   1290     argument_signatures = [
   1291         Sig('foo', nargs='?', default=argparse.SUPPRESS),
   1292         Sig('bar', nargs='*', default=argparse.SUPPRESS),
   1293         Sig('--baz', action='store_true', default=argparse.SUPPRESS),
   1294     ]
   1295     failures = ['-x']
   1296     successes = [
   1297         ('', NS()),
   1298         ('a', NS(foo='a')),
   1299         ('a b', NS(foo='a', bar=['b'])),
   1300         ('--baz', NS(baz=True)),
   1301         ('a --baz', NS(foo='a', baz=True)),
   1302         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1303     ]
   1304 
   1305 
   1306 class TestParserDefaultSuppress(ParserTestCase):
   1307     """Test actions with a parser-level default of SUPPRESS"""
   1308 
   1309     parser_signature = Sig(argument_default=argparse.SUPPRESS)
   1310     argument_signatures = [
   1311         Sig('foo', nargs='?'),
   1312         Sig('bar', nargs='*'),
   1313         Sig('--baz', action='store_true'),
   1314     ]
   1315     failures = ['-x']
   1316     successes = [
   1317         ('', NS()),
   1318         ('a', NS(foo='a')),
   1319         ('a b', NS(foo='a', bar=['b'])),
   1320         ('--baz', NS(baz=True)),
   1321         ('a --baz', NS(foo='a', baz=True)),
   1322         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1323     ]
   1324 
   1325 
   1326 class TestParserDefault42(ParserTestCase):
   1327     """Test actions with a parser-level default of 42"""
   1328 
   1329     parser_signature = Sig(argument_default=42, version='1.0')
   1330     argument_signatures = [
   1331         Sig('foo', nargs='?'),
   1332         Sig('bar', nargs='*'),
   1333         Sig('--baz', action='store_true'),
   1334     ]
   1335     failures = ['-x']
   1336     successes = [
   1337         ('', NS(foo=42, bar=42, baz=42)),
   1338         ('a', NS(foo='a', bar=42, baz=42)),
   1339         ('a b', NS(foo='a', bar=['b'], baz=42)),
   1340         ('--baz', NS(foo=42, bar=42, baz=True)),
   1341         ('a --baz', NS(foo='a', bar=42, baz=True)),
   1342         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1343     ]
   1344 
   1345 
   1346 class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
   1347     """Test reading arguments from a file"""
   1348 
   1349     def setUp(self):
   1350         super(TestArgumentsFromFile, self).setUp()
   1351         file_texts = [
   1352             ('hello', 'hello world!\n'),
   1353             ('recursive', '-a\n'
   1354                           'A\n'
   1355                           '@hello'),
   1356             ('invalid', '@no-such-path\n'),
   1357         ]
   1358         for path, text in file_texts:
   1359             file = open(path, 'w')
   1360             file.write(text)
   1361             file.close()
   1362 
   1363     parser_signature = Sig(fromfile_prefix_chars='@')
   1364     argument_signatures = [
   1365         Sig('-a'),
   1366         Sig('x'),
   1367         Sig('y', nargs='+'),
   1368     ]
   1369     failures = ['', '-b', 'X', '@invalid', '@missing']
   1370     successes = [
   1371         ('X Y', NS(a=None, x='X', y=['Y'])),
   1372         ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
   1373         ('@hello X', NS(a=None, x='hello world!', y=['X'])),
   1374         ('X @hello', NS(a=None, x='X', y=['hello world!'])),
   1375         ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
   1376         ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
   1377     ]
   1378 
   1379 
   1380 class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
   1381     """Test reading arguments from a file"""
   1382 
   1383     def setUp(self):
   1384         super(TestArgumentsFromFileConverter, self).setUp()
   1385         file_texts = [
   1386             ('hello', 'hello world!\n'),
   1387         ]
   1388         for path, text in file_texts:
   1389             file = open(path, 'w')
   1390             file.write(text)
   1391             file.close()
   1392 
   1393     class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
   1394 
   1395         def convert_arg_line_to_args(self, arg_line):
   1396             for arg in arg_line.split():
   1397                 if not arg.strip():
   1398                     continue
   1399                 yield arg
   1400     parser_class = FromFileConverterArgumentParser
   1401     parser_signature = Sig(fromfile_prefix_chars='@')
   1402     argument_signatures = [
   1403         Sig('y', nargs='+'),
   1404     ]
   1405     failures = []
   1406     successes = [
   1407         ('@hello X', NS(y=['hello', 'world!', 'X'])),
   1408     ]
   1409 
   1410 
   1411 # =====================

   1412 # Type conversion tests

   1413 # =====================

   1414 
   1415 class TestFileTypeRepr(TestCase):
   1416 
   1417     def test_r(self):
   1418         type = argparse.FileType('r')
   1419         self.assertEqual("FileType('r')", repr(type))
   1420 
   1421     def test_wb_1(self):
   1422         type = argparse.FileType('wb', 1)
   1423         self.assertEqual("FileType('wb', 1)", repr(type))
   1424 
   1425 
   1426 class RFile(object):
   1427     seen = {}
   1428 
   1429     def __init__(self, name):
   1430         self.name = name
   1431 
   1432     __hash__ = None
   1433 
   1434     def __eq__(self, other):
   1435         if other in self.seen:
   1436             text = self.seen[other]
   1437         else:
   1438             text = self.seen[other] = other.read()
   1439             other.close()
   1440         if not isinstance(text, str):
   1441             text = text.decode('ascii')
   1442         return self.name == other.name == text
   1443 
   1444 
   1445 class TestFileTypeR(TempDirMixin, ParserTestCase):
   1446     """Test the FileType option/argument type for reading files"""
   1447 
   1448     def setUp(self):
   1449         super(TestFileTypeR, self).setUp()
   1450         for file_name in ['foo', 'bar']:
   1451             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1452             file.write(file_name)
   1453             file.close()
   1454         self.create_readonly_file('readonly')
   1455 
   1456     argument_signatures = [
   1457         Sig('-x', type=argparse.FileType()),
   1458         Sig('spam', type=argparse.FileType('r')),
   1459     ]
   1460     failures = ['-x', '-x bar', 'non-existent-file.txt']
   1461     successes = [
   1462         ('foo', NS(x=None, spam=RFile('foo'))),
   1463         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1464         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1465         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1466         ('readonly', NS(x=None, spam=RFile('readonly'))),
   1467     ]
   1468 
   1469 
   1470 class TestFileTypeRB(TempDirMixin, ParserTestCase):
   1471     """Test the FileType option/argument type for reading files"""
   1472 
   1473     def setUp(self):
   1474         super(TestFileTypeRB, self).setUp()
   1475         for file_name in ['foo', 'bar']:
   1476             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1477             file.write(file_name)
   1478             file.close()
   1479 
   1480     argument_signatures = [
   1481         Sig('-x', type=argparse.FileType('rb')),
   1482         Sig('spam', type=argparse.FileType('rb')),
   1483     ]
   1484     failures = ['-x', '-x bar']
   1485     successes = [
   1486         ('foo', NS(x=None, spam=RFile('foo'))),
   1487         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1488         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1489         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1490     ]
   1491 
   1492 
   1493 class WFile(object):
   1494     seen = set()
   1495 
   1496     def __init__(self, name):
   1497         self.name = name
   1498 
   1499     __hash__ = None
   1500 
   1501     def __eq__(self, other):
   1502         if other not in self.seen:
   1503             text = 'Check that file is writable.'
   1504             if 'b' in other.mode:
   1505                 text = text.encode('ascii')
   1506             other.write(text)
   1507             other.close()
   1508             self.seen.add(other)
   1509         return self.name == other.name
   1510 
   1511 
   1512 class TestFileTypeW(TempDirMixin, ParserTestCase):
   1513     """Test the FileType option/argument type for writing files"""
   1514 
   1515     def setUp(self):
   1516         super(TestFileTypeW, self).setUp()
   1517         self.create_readonly_file('readonly')
   1518 
   1519     argument_signatures = [
   1520         Sig('-x', type=argparse.FileType('w')),
   1521         Sig('spam', type=argparse.FileType('w')),
   1522     ]
   1523     failures = ['-x', '-x bar']
   1524     failures = ['-x', '-x bar', 'readonly']
   1525     successes = [
   1526         ('foo', NS(x=None, spam=WFile('foo'))),
   1527         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1528         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1529         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1530     ]
   1531 
   1532 
   1533 class TestFileTypeWB(TempDirMixin, ParserTestCase):
   1534 
   1535     argument_signatures = [
   1536         Sig('-x', type=argparse.FileType('wb')),
   1537         Sig('spam', type=argparse.FileType('wb')),
   1538     ]
   1539     failures = ['-x', '-x bar']
   1540     successes = [
   1541         ('foo', NS(x=None, spam=WFile('foo'))),
   1542         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1543         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1544         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1545     ]
   1546 
   1547 
   1548 class TestTypeCallable(ParserTestCase):
   1549     """Test some callables as option/argument types"""
   1550 
   1551     argument_signatures = [
   1552         Sig('--eggs', type=complex),
   1553         Sig('spam', type=float),
   1554     ]
   1555     failures = ['a', '42j', '--eggs a', '--eggs 2i']
   1556     successes = [
   1557         ('--eggs=42 42', NS(eggs=42, spam=42.0)),
   1558         ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
   1559         ('1024.675', NS(eggs=None, spam=1024.675)),
   1560     ]
   1561 
   1562 
   1563 class TestTypeUserDefined(ParserTestCase):
   1564     """Test a user-defined option/argument type"""
   1565 
   1566     class MyType(TestCase):
   1567 
   1568         def __init__(self, value):
   1569             self.value = value
   1570 
   1571         __hash__ = None
   1572 
   1573         def __eq__(self, other):
   1574             return (type(self), self.value) == (type(other), other.value)
   1575 
   1576     argument_signatures = [
   1577         Sig('-x', type=MyType),
   1578         Sig('spam', type=MyType),
   1579     ]
   1580     failures = []
   1581     successes = [
   1582         ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
   1583         ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
   1584     ]
   1585 
   1586 
   1587 class TestTypeClassicClass(ParserTestCase):
   1588     """Test a classic class type"""
   1589 
   1590     class C:
   1591 
   1592         def __init__(self, value):
   1593             self.value = value
   1594 
   1595         __hash__ = None
   1596 
   1597         def __eq__(self, other):
   1598             return (type(self), self.value) == (type(other), other.value)
   1599 
   1600     argument_signatures = [
   1601         Sig('-x', type=C),
   1602         Sig('spam', type=C),
   1603     ]
   1604     failures = []
   1605     successes = [
   1606         ('a -x b', NS(x=C('b'), spam=C('a'))),
   1607         ('-xf g', NS(x=C('f'), spam=C('g'))),
   1608     ]
   1609 
   1610 
   1611 class TestTypeRegistration(TestCase):
   1612     """Test a user-defined type by registering it"""
   1613 
   1614     def test(self):
   1615 
   1616         def get_my_type(string):
   1617             return 'my_type{%s}' % string
   1618 
   1619         parser = argparse.ArgumentParser()
   1620         parser.register('type', 'my_type', get_my_type)
   1621         parser.add_argument('-x', type='my_type')
   1622         parser.add_argument('y', type='my_type')
   1623 
   1624         self.assertEqual(parser.parse_args('1'.split()),
   1625                          NS(x=None, y='my_type{1}'))
   1626         self.assertEqual(parser.parse_args('-x 1 42'.split()),
   1627                          NS(x='my_type{1}', y='my_type{42}'))
   1628 
   1629 
   1630 # ============

   1631 # Action tests

   1632 # ============

   1633 
   1634 class TestActionUserDefined(ParserTestCase):
   1635     """Test a user-defined option/argument action"""
   1636 
   1637     class OptionalAction(argparse.Action):
   1638 
   1639         def __call__(self, parser, namespace, value, option_string=None):
   1640             try:
   1641                 # check destination and option string

   1642                 assert self.dest == 'spam', 'dest: %s' % self.dest
   1643                 assert option_string == '-s', 'flag: %s' % option_string
   1644                 # when option is before argument, badger=2, and when

   1645                 # option is after argument, badger=<whatever was set>

   1646                 expected_ns = NS(spam=0.25)
   1647                 if value in [0.125, 0.625]:
   1648                     expected_ns.badger = 2
   1649                 elif value in [2.0]:
   1650                     expected_ns.badger = 84
   1651                 else:
   1652                     raise AssertionError('value: %s' % value)
   1653                 assert expected_ns == namespace, ('expected %s, got %s' %
   1654                                                   (expected_ns, namespace))
   1655             except AssertionError:
   1656                 e = sys.exc_info()[1]
   1657                 raise ArgumentParserError('opt_action failed: %s' % e)
   1658             setattr(namespace, 'spam', value)
   1659 
   1660     class PositionalAction(argparse.Action):
   1661 
   1662         def __call__(self, parser, namespace, value, option_string=None):
   1663             try:
   1664                 assert option_string is None, ('option_string: %s' %
   1665                                                option_string)
   1666                 # check destination

   1667                 assert self.dest == 'badger', 'dest: %s' % self.dest
   1668                 # when argument is before option, spam=0.25, and when

   1669                 # option is after argument, spam=<whatever was set>

   1670                 expected_ns = NS(badger=2)
   1671                 if value in [42, 84]:
   1672                     expected_ns.spam = 0.25
   1673                 elif value in [1]:
   1674                     expected_ns.spam = 0.625
   1675                 elif value in [2]:
   1676                     expected_ns.spam = 0.125
   1677                 else:
   1678                     raise AssertionError('value: %s' % value)
   1679                 assert expected_ns == namespace, ('expected %s, got %s' %
   1680                                                   (expected_ns, namespace))
   1681             except AssertionError:
   1682                 e = sys.exc_info()[1]
   1683                 raise ArgumentParserError('arg_action failed: %s' % e)
   1684             setattr(namespace, 'badger', value)
   1685 
   1686     argument_signatures = [
   1687         Sig('-s', dest='spam', action=OptionalAction,
   1688             type=float, default=0.25),
   1689         Sig('badger', action=PositionalAction,
   1690             type=int, nargs='?', default=2),
   1691     ]
   1692     failures = []
   1693     successes = [
   1694         ('-s0.125', NS(spam=0.125, badger=2)),
   1695         ('42', NS(spam=0.25, badger=42)),
   1696         ('-s 0.625 1', NS(spam=0.625, badger=1)),
   1697         ('84 -s2', NS(spam=2.0, badger=84)),
   1698     ]
   1699 
   1700 
   1701 class TestActionRegistration(TestCase):
   1702     """Test a user-defined action supplied by registering it"""
   1703 
   1704     class MyAction(argparse.Action):
   1705 
   1706         def __call__(self, parser, namespace, values, option_string=None):
   1707             setattr(namespace, self.dest, 'foo[%s]' % values)
   1708 
   1709     def test(self):
   1710 
   1711         parser = argparse.ArgumentParser()
   1712         parser.register('action', 'my_action', self.MyAction)
   1713         parser.add_argument('badger', action='my_action')
   1714 
   1715         self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
   1716         self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
   1717 
   1718 
   1719 # ================

   1720 # Subparsers tests

   1721 # ================

   1722 
   1723 class TestAddSubparsers(TestCase):
   1724     """Test the add_subparsers method"""
   1725 
   1726     def assertArgumentParserError(self, *args, **kwargs):
   1727         self.assertRaises(ArgumentParserError, *args, **kwargs)
   1728 
   1729     def _get_parser(self, subparser_help=False, prefix_chars=None):
   1730         # create a parser with a subparsers argument

   1731         if prefix_chars:
   1732             parser = ErrorRaisingArgumentParser(
   1733                 prog='PROG', description='main description', prefix_chars=prefix_chars)
   1734             parser.add_argument(
   1735                 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
   1736         else:
   1737             parser = ErrorRaisingArgumentParser(
   1738                 prog='PROG', description='main description')
   1739             parser.add_argument(
   1740                 '--foo', action='store_true', help='foo help')
   1741         parser.add_argument(
   1742             'bar', type=float, help='bar help')
   1743 
   1744         # check that only one subparsers argument can be added

   1745         subparsers = parser.add_subparsers(help='command help')
   1746         self.assertArgumentParserError(parser.add_subparsers)
   1747 
   1748         # add first sub-parser

   1749         parser1_kwargs = dict(description='1 description')
   1750         if subparser_help:
   1751             parser1_kwargs['help'] = '1 help'
   1752         parser1 = subparsers.add_parser('1', **parser1_kwargs)
   1753         parser1.add_argument('-w', type=int, help='w help')
   1754         parser1.add_argument('x', choices='abc', help='x help')
   1755 
   1756         # add second sub-parser

   1757         parser2_kwargs = dict(description='2 description')
   1758         if subparser_help:
   1759             parser2_kwargs['help'] = '2 help'
   1760         parser2 = subparsers.add_parser('2', **parser2_kwargs)
   1761         parser2.add_argument('-y', choices='123', help='y help')
   1762         parser2.add_argument('z', type=complex, nargs='*', help='z help')
   1763 
   1764         # return the main parser

   1765         return parser
   1766 
   1767     def setUp(self):
   1768         super(TestAddSubparsers, self).setUp()
   1769         self.parser = self._get_parser()
   1770         self.command_help_parser = self._get_parser(subparser_help=True)
   1771 
   1772     def test_parse_args_failures(self):
   1773         # check some failure cases:

   1774         for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
   1775                          '0.5 1 -y', '0.5 2 -w']:
   1776             args = args_str.split()
   1777             self.assertArgumentParserError(self.parser.parse_args, args)
   1778 
   1779     def test_parse_args(self):
   1780         # check some non-failure cases:

   1781         self.assertEqual(
   1782             self.parser.parse_args('0.5 1 b -w 7'.split()),
   1783             NS(foo=False, bar=0.5, w=7, x='b'),
   1784         )
   1785         self.assertEqual(
   1786             self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
   1787             NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
   1788         )
   1789         self.assertEqual(
   1790             self.parser.parse_args('--foo 0.125 1 c'.split()),
   1791             NS(foo=True, bar=0.125, w=None, x='c'),
   1792         )
   1793 
   1794     def test_parse_known_args(self):
   1795         self.assertEqual(
   1796             self.parser.parse_known_args('0.5 1 b -w 7'.split()),
   1797             (NS(foo=False, bar=0.5, w=7, x='b'), []),
   1798         )
   1799         self.assertEqual(
   1800             self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
   1801             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1802         )
   1803         self.assertEqual(
   1804             self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
   1805             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1806         )
   1807         self.assertEqual(
   1808             self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
   1809             (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
   1810         )
   1811         self.assertEqual(
   1812             self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
   1813             (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
   1814         )
   1815 
   1816     def test_dest(self):
   1817         parser = ErrorRaisingArgumentParser()
   1818         parser.add_argument('--foo', action='store_true')
   1819         subparsers = parser.add_subparsers(dest='bar')
   1820         parser1 = subparsers.add_parser('1')
   1821         parser1.add_argument('baz')
   1822         self.assertEqual(NS(foo=False, bar='1', baz='2'),
   1823                          parser.parse_args('1 2'.split()))
   1824 
   1825     def test_help(self):
   1826         self.assertEqual(self.parser.format_usage(),
   1827                          'usage: PROG [-h] [--foo] bar {1,2} ...\n')
   1828         self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
   1829             usage: PROG [-h] [--foo] bar {1,2} ...
   1830 
   1831             main description
   1832 
   1833             positional arguments:
   1834               bar         bar help
   1835               {1,2}       command help
   1836 
   1837             optional arguments:
   1838               -h, --help  show this help message and exit
   1839               --foo       foo help
   1840             '''))
   1841 
   1842     def test_help_extra_prefix_chars(self):
   1843         # Make sure - is still used for help if it is a non-first prefix char

   1844         parser = self._get_parser(prefix_chars='+:-')
   1845         self.assertEqual(parser.format_usage(),
   1846                          'usage: PROG [-h] [++foo] bar {1,2} ...\n')
   1847         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1848             usage: PROG [-h] [++foo] bar {1,2} ...
   1849 
   1850             main description
   1851 
   1852             positional arguments:
   1853               bar         bar help
   1854               {1,2}       command help
   1855 
   1856             optional arguments:
   1857               -h, --help  show this help message and exit
   1858               ++foo       foo help
   1859             '''))
   1860 
   1861 
   1862     def test_help_alternate_prefix_chars(self):
   1863         parser = self._get_parser(prefix_chars='+:/')
   1864         self.assertEqual(parser.format_usage(),
   1865                          'usage: PROG [+h] [++foo] bar {1,2} ...\n')
   1866         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1867             usage: PROG [+h] [++foo] bar {1,2} ...
   1868 
   1869             main description
   1870 
   1871             positional arguments:
   1872               bar         bar help
   1873               {1,2}       command help
   1874 
   1875             optional arguments:
   1876               +h, ++help  show this help message and exit
   1877               ++foo       foo help
   1878             '''))
   1879 
   1880     def test_parser_command_help(self):
   1881         self.assertEqual(self.command_help_parser.format_usage(),
   1882                          'usage: PROG [-h] [--foo] bar {1,2} ...\n')
   1883         self.assertEqual(self.command_help_parser.format_help(),
   1884                          textwrap.dedent('''\
   1885             usage: PROG [-h] [--foo] bar {1,2} ...
   1886 
   1887             main description
   1888 
   1889             positional arguments:
   1890               bar         bar help
   1891               {1,2}       command help
   1892                 1         1 help
   1893                 2         2 help
   1894 
   1895             optional arguments:
   1896               -h, --help  show this help message and exit
   1897               --foo       foo help
   1898             '''))
   1899 
   1900     def test_subparser_title_help(self):
   1901         parser = ErrorRaisingArgumentParser(prog='PROG',
   1902                                             description='main description')
   1903         parser.add_argument('--foo', action='store_true', help='foo help')
   1904         parser.add_argument('bar', help='bar help')
   1905         subparsers = parser.add_subparsers(title='subcommands',
   1906                                            description='command help',
   1907                                            help='additional text')
   1908         parser1 = subparsers.add_parser('1')
   1909         parser2 = subparsers.add_parser('2')
   1910         self.assertEqual(parser.format_usage(),
   1911                          'usage: PROG [-h] [--foo] bar {1,2} ...\n')
   1912         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1913             usage: PROG [-h] [--foo] bar {1,2} ...
   1914 
   1915             main description
   1916 
   1917             positional arguments:
   1918               bar         bar help
   1919 
   1920             optional arguments:
   1921               -h, --help  show this help message and exit
   1922               --foo       foo help
   1923 
   1924             subcommands:
   1925               command help
   1926 
   1927               {1,2}       additional text
   1928             '''))
   1929 
   1930     def _test_subparser_help(self, args_str, expected_help):
   1931         try:
   1932             self.parser.parse_args(args_str.split())
   1933         except ArgumentParserError:
   1934             err = sys.exc_info()[1]
   1935             if err.stdout != expected_help:
   1936                 print(repr(expected_help))
   1937                 print(repr(err.stdout))
   1938             self.assertEqual(err.stdout, expected_help)
   1939 
   1940     def test_subparser1_help(self):
   1941         self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
   1942             usage: PROG bar 1 [-h] [-w W] {a,b,c}
   1943 
   1944             1 description
   1945 
   1946             positional arguments:
   1947               {a,b,c}     x help
   1948 
   1949             optional arguments:
   1950               -h, --help  show this help message and exit
   1951               -w W        w help
   1952             '''))
   1953 
   1954     def test_subparser2_help(self):
   1955         self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
   1956             usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
   1957 
   1958             2 description
   1959 
   1960             positional arguments:
   1961               z           z help
   1962 
   1963             optional arguments:
   1964               -h, --help  show this help message and exit
   1965               -y {1,2,3}  y help
   1966             '''))
   1967 
   1968 # ============

   1969 # Groups tests

   1970 # ============

   1971 
   1972 class TestPositionalsGroups(TestCase):
   1973     """Tests that order of group positionals matches construction order"""
   1974 
   1975     def test_nongroup_first(self):
   1976         parser = ErrorRaisingArgumentParser()
   1977         parser.add_argument('foo')
   1978         group = parser.add_argument_group('g')
   1979         group.add_argument('bar')
   1980         parser.add_argument('baz')
   1981         expected = NS(foo='1', bar='2', baz='3')
   1982         result = parser.parse_args('1 2 3'.split())
   1983         self.assertEqual(expected, result)
   1984 
   1985     def test_group_first(self):
   1986         parser = ErrorRaisingArgumentParser()
   1987         group = parser.add_argument_group('xxx')
   1988         group.add_argument('foo')
   1989         parser.add_argument('bar')
   1990         parser.add_argument('baz')
   1991         expected = NS(foo='1', bar='2', baz='3')
   1992         result = parser.parse_args('1 2 3'.split())
   1993         self.assertEqual(expected, result)
   1994 
   1995     def test_interleaved_groups(self):
   1996         parser = ErrorRaisingArgumentParser()
   1997         group = parser.add_argument_group('xxx')
   1998         parser.add_argument('foo')
   1999         group.add_argument('bar')
   2000         parser.add_argument('baz')
   2001         group = parser.add_argument_group('yyy')
   2002         group.add_argument('frell')
   2003         expected = NS(foo='1', bar='2', baz='3', frell='4')
   2004         result = parser.parse_args('1 2 3 4'.split())
   2005         self.assertEqual(expected, result)
   2006 
   2007 # ===================

   2008 # Parent parser tests

   2009 # ===================

   2010 
   2011 class TestParentParsers(TestCase):
   2012     """Tests that parsers can be created with parent parsers"""
   2013 
   2014     def assertArgumentParserError(self, *args, **kwargs):
   2015         self.assertRaises(ArgumentParserError, *args, **kwargs)
   2016 
   2017     def setUp(self):
   2018         super(TestParentParsers, self).setUp()
   2019         self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
   2020         self.wxyz_parent.add_argument('--w')
   2021         x_group = self.wxyz_parent.add_argument_group('x')
   2022         x_group.add_argument('-y')
   2023         self.wxyz_parent.add_argument('z')
   2024 
   2025         self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
   2026         self.abcd_parent.add_argument('a')
   2027         self.abcd_parent.add_argument('-b')
   2028         c_group = self.abcd_parent.add_argument_group('c')
   2029         c_group.add_argument('--d')
   2030 
   2031         self.w_parent = ErrorRaisingArgumentParser(add_help=False)
   2032         self.w_parent.add_argument('--w')
   2033 
   2034         self.z_parent = ErrorRaisingArgumentParser(add_help=False)
   2035         self.z_parent.add_argument('z')
   2036 
   2037         # parents with mutually exclusive groups

   2038         self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
   2039         group = self.ab_mutex_parent.add_mutually_exclusive_group()
   2040         group.add_argument('-a', action='store_true')
   2041         group.add_argument('-b', action='store_true')
   2042 
   2043         self.main_program = os.path.basename(sys.argv[0])
   2044 
   2045     def test_single_parent(self):
   2046         parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
   2047         self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
   2048                          NS(w='3', y='1', z='2'))
   2049 
   2050     def test_single_parent_mutex(self):
   2051         self._test_mutex_ab(self.ab_mutex_parent.parse_args)
   2052         parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
   2053         self._test_mutex_ab(parser.parse_args)
   2054 
   2055     def test_single_granparent_mutex(self):
   2056         parents = [self.ab_mutex_parent]
   2057         parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
   2058         parser = ErrorRaisingArgumentParser(parents=[parser])
   2059         self._test_mutex_ab(parser.parse_args)
   2060 
   2061     def _test_mutex_ab(self, parse_args):
   2062         self.assertEqual(parse_args([]), NS(a=False, b=False))
   2063         self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
   2064         self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
   2065         self.assertArgumentParserError(parse_args, ['-a', '-b'])
   2066         self.assertArgumentParserError(parse_args, ['-b', '-a'])
   2067         self.assertArgumentParserError(parse_args, ['-c'])
   2068         self.assertArgumentParserError(parse_args, ['-a', '-c'])
   2069         self.assertArgumentParserError(parse_args, ['-b', '-c'])
   2070 
   2071     def test_multiple_parents(self):
   2072         parents = [self.abcd_parent, self.wxyz_parent]
   2073         parser = ErrorRaisingArgumentParser(parents=parents)
   2074         self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
   2075                          NS(a='3', b=None, d='1', w='2', y=None, z='4'))
   2076 
   2077     def test_multiple_parents_mutex(self):
   2078         parents = [self.ab_mutex_parent, self.wxyz_parent]
   2079         parser = ErrorRaisingArgumentParser(parents=parents)
   2080         self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
   2081                          NS(a=True, b=False, w='2', y=None, z='3'))
   2082         self.assertArgumentParserError(
   2083             parser.parse_args, '-a --w 2 3 -b'.split())
   2084         self.assertArgumentParserError(
   2085             parser.parse_args, '-a -b --w 2 3'.split())
   2086 
   2087     def test_conflicting_parents(self):
   2088         self.assertRaises(
   2089             argparse.ArgumentError,
   2090             argparse.ArgumentParser,
   2091             parents=[self.w_parent, self.wxyz_parent])
   2092 
   2093     def test_conflicting_parents_mutex(self):
   2094         self.assertRaises(
   2095             argparse.ArgumentError,
   2096             argparse.ArgumentParser,
   2097             parents=[self.abcd_parent, self.ab_mutex_parent])
   2098 
   2099     def test_same_argument_name_parents(self):
   2100         parents = [self.wxyz_parent, self.z_parent]
   2101         parser = ErrorRaisingArgumentParser(parents=parents)
   2102         self.assertEqual(parser.parse_args('1 2'.split()),
   2103                          NS(w=None, y=None, z='2'))
   2104 
   2105     def test_subparser_parents(self):
   2106         parser = ErrorRaisingArgumentParser()
   2107         subparsers = parser.add_subparsers()
   2108         abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
   2109         abcde_parser.add_argument('e')
   2110         self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
   2111                          NS(a='3', b='1', d='2', e='4'))
   2112 
   2113     def test_subparser_parents_mutex(self):
   2114         parser = ErrorRaisingArgumentParser()
   2115         subparsers = parser.add_subparsers()
   2116         parents = [self.ab_mutex_parent]
   2117         abc_parser = subparsers.add_parser('foo', parents=parents)
   2118         c_group = abc_parser.add_argument_group('c_group')
   2119         c_group.add_argument('c')
   2120         parents = [self.wxyz_parent, self.ab_mutex_parent]
   2121         wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
   2122         wxyzabe_parser.add_argument('e')
   2123         self.assertEqual(parser.parse_args('foo -a 4'.split()),
   2124                          NS(a=True, b=False, c='4'))
   2125         self.assertEqual(parser.parse_args('bar -b  --w 2 3 4'.split()),
   2126                          NS(a=False, b=True, w='2', y=None, z='3', e='4'))
   2127         self.assertArgumentParserError(
   2128             parser.parse_args, 'foo -a -b 4'.split())
   2129         self.assertArgumentParserError(
   2130             parser.parse_args, 'bar -b -a 4'.split())
   2131 
   2132     def test_parent_help(self):
   2133         parents = [self.abcd_parent, self.wxyz_parent]
   2134         parser = ErrorRaisingArgumentParser(parents=parents)
   2135         parser_help = parser.format_help()
   2136         self.assertEqual(parser_help, textwrap.dedent('''\
   2137             usage: {} [-h] [-b B] [--d D] [--w W] [-y Y] a z
   2138 
   2139             positional arguments:
   2140               a
   2141               z
   2142 
   2143             optional arguments:
   2144               -h, --help  show this help message and exit
   2145               -b B
   2146               --w W
   2147 
   2148             c:
   2149               --d D
   2150 
   2151             x:
   2152               -y Y
   2153         '''.format(self.main_program)))
   2154 
   2155     def test_groups_parents(self):
   2156         parent = ErrorRaisingArgumentParser(add_help=False)
   2157         g = parent.add_argument_group(title='g', description='gd')
   2158         g.add_argument('-w')
   2159         g.add_argument('-x')
   2160         m = parent.add_mutually_exclusive_group()
   2161         m.add_argument('-y')
   2162         m.add_argument('-z')
   2163         parser = ErrorRaisingArgumentParser(parents=[parent])
   2164 
   2165         self.assertRaises(ArgumentParserError, parser.parse_args,
   2166             ['-y', 'Y', '-z', 'Z'])
   2167 
   2168         parser_help = parser.format_help()
   2169         self.assertEqual(parser_help, textwrap.dedent('''\
   2170             usage: {} [-h] [-w W] [-x X] [-y Y | -z Z]
   2171 
   2172             optional arguments:
   2173               -h, --help  show this help message and exit
   2174               -y Y
   2175               -z Z
   2176 
   2177             g:
   2178               gd
   2179 
   2180               -w W
   2181               -x X
   2182         '''.format(self.main_program)))
   2183 
   2184 # ==============================

   2185 # Mutually exclusive group tests

   2186 # ==============================

   2187 
   2188 class TestMutuallyExclusiveGroupErrors(TestCase):
   2189 
   2190     def test_invalid_add_argument_group(self):
   2191         parser = ErrorRaisingArgumentParser()
   2192         raises = self.assertRaises
   2193         raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
   2194 
   2195     def test_invalid_add_argument(self):
   2196         parser = ErrorRaisingArgumentParser()
   2197         group = parser.add_mutually_exclusive_group()
   2198         add_argument = group.add_argument
   2199         raises = self.assertRaises
   2200         raises(ValueError, add_argument, '--foo', required=True)
   2201         raises(ValueError, add_argument, 'bar')
   2202         raises(ValueError, add_argument, 'bar', nargs='+')
   2203         raises(ValueError, add_argument, 'bar', nargs=1)
   2204         raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
   2205 
   2206     def test_help(self):
   2207         parser = ErrorRaisingArgumentParser(prog='PROG')
   2208         group1 = parser.add_mutually_exclusive_group()
   2209         group1.add_argument('--foo', action='store_true')
   2210         group1.add_argument('--bar', action='store_false')
   2211         group2 = parser.add_mutually_exclusive_group()
   2212         group2.add_argument('--soup', action='store_true')
   2213         group2.add_argument('--nuts', action='store_false')
   2214         expected = '''\
   2215             usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
   2216 
   2217             optional arguments:
   2218               -h, --help  show this help message and exit
   2219               --foo
   2220               --bar
   2221               --soup
   2222               --nuts
   2223               '''
   2224         self.assertEqual(parser.format_help(), textwrap.dedent(expected))
   2225 
   2226 class MEMixin(object):
   2227 
   2228     def test_failures_when_not_required(self):
   2229         parse_args = self.get_parser(required=False).parse_args
   2230         error = ArgumentParserError
   2231         for args_string in self.failures:
   2232             self.assertRaises(error, parse_args, args_string.split())
   2233 
   2234     def test_failures_when_required(self):
   2235         parse_args = self.get_parser(required=True).parse_args
   2236         error = ArgumentParserError
   2237         for args_string in self.failures + ['']:
   2238             self.assertRaises(error, parse_args, args_string.split())
   2239 
   2240     def test_successes_when_not_required(self):
   2241         parse_args = self.get_parser(required=False).parse_args
   2242         successes = self.successes + self.successes_when_not_required
   2243         for args_string, expected_ns in successes:
   2244             actual_ns = parse_args(args_string.split())
   2245             self.assertEqual(actual_ns, expected_ns)
   2246 
   2247     def test_successes_when_required(self):
   2248         parse_args = self.get_parser(required=True).parse_args
   2249         for args_string, expected_ns in self.successes:
   2250             actual_ns = parse_args(args_string.split())
   2251             self.assertEqual(actual_ns, expected_ns)
   2252 
   2253     def test_usage_when_not_required(self):
   2254         format_usage = self.get_parser(required=False).format_usage
   2255         expected_usage = self.usage_when_not_required
   2256         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2257 
   2258     def test_usage_when_required(self):
   2259         format_usage = self.get_parser(required=True).format_usage
   2260         expected_usage = self.usage_when_required
   2261         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2262 
   2263     def test_help_when_not_required(self):
   2264         format_help = self.get_parser(required=False).format_help
   2265         help = self.usage_when_not_required + self.help
   2266         self.assertEqual(format_help(), textwrap.dedent(help))
   2267 
   2268     def test_help_when_required(self):
   2269         format_help = self.get_parser(required=True).format_help
   2270         help = self.usage_when_required + self.help
   2271         self.assertEqual(format_help(), textwrap.dedent(help))
   2272 
   2273 
   2274 class TestMutuallyExclusiveSimple(MEMixin, TestCase):
   2275 
   2276     def get_parser(self, required=None):
   2277         parser = ErrorRaisingArgumentParser(prog='PROG')
   2278         group = parser.add_mutually_exclusive_group(required=required)
   2279         group.add_argument('--bar', help='bar help')
   2280         group.add_argument('--baz', nargs='?', const='Z', help='baz help')
   2281         return parser
   2282 
   2283     failures = ['--bar X --baz Y', '--bar X --baz']
   2284     successes = [
   2285         ('--bar X', NS(bar='X', baz=None)),
   2286         ('--bar X --bar Z', NS(bar='Z', baz=None)),
   2287         ('--baz Y', NS(bar=None, baz='Y')),
   2288         ('--baz', NS(bar=None, baz='Z')),
   2289     ]
   2290     successes_when_not_required = [
   2291         ('', NS(bar=None, baz=None)),
   2292     ]
   2293 
   2294     usage_when_not_required = '''\
   2295         usage: PROG [-h] [--bar BAR | --baz [BAZ]]
   2296         '''
   2297     usage_when_required = '''\
   2298         usage: PROG [-h] (--bar BAR | --baz [BAZ])
   2299         '''
   2300     help = '''\
   2301 
   2302         optional arguments:
   2303           -h, --help   show this help message and exit
   2304           --bar BAR    bar help
   2305           --baz [BAZ]  baz help
   2306         '''
   2307 
   2308 
   2309 class TestMutuallyExclusiveLong(MEMixin, TestCase):
   2310 
   2311     def get_parser(self, required=None):
   2312         parser = ErrorRaisingArgumentParser(prog='PROG')
   2313         parser.add_argument('--abcde', help='abcde help')
   2314         parser.add_argument('--fghij', help='fghij help')
   2315         group = parser.add_mutually_exclusive_group(required=required)
   2316         group.add_argument('--klmno', help='klmno help')
   2317         group.add_argument('--pqrst', help='pqrst help')
   2318         return parser
   2319 
   2320     failures = ['--klmno X --pqrst Y']
   2321     successes = [
   2322         ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
   2323         ('--abcde Y --klmno X',
   2324             NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
   2325         ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
   2326         ('--pqrst X --fghij Y',
   2327             NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
   2328     ]
   2329     successes_when_not_required = [
   2330         ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
   2331     ]
   2332 
   2333     usage_when_not_required = '''\
   2334     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2335                 [--klmno KLMNO | --pqrst PQRST]
   2336     '''
   2337     usage_when_required = '''\
   2338     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2339                 (--klmno KLMNO | --pqrst PQRST)
   2340     '''
   2341     help = '''\
   2342 
   2343     optional arguments:
   2344       -h, --help     show this help message and exit
   2345       --abcde ABCDE  abcde help
   2346       --fghij FGHIJ  fghij help
   2347       --klmno KLMNO  klmno help
   2348       --pqrst PQRST  pqrst help
   2349     '''
   2350 
   2351 
   2352 class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
   2353 
   2354     def get_parser(self, required):
   2355         parser = ErrorRaisingArgumentParser(prog='PROG')
   2356         group = parser.add_mutually_exclusive_group(required=required)
   2357         group.add_argument('-x', help=argparse.SUPPRESS)
   2358         group.add_argument('-y', action='store_false', help='y help')
   2359         return parser
   2360 
   2361     failures = ['-x X -y']
   2362     successes = [
   2363         ('-x X', NS(x='X', y=True)),
   2364         ('-x X -x Y', NS(x='Y', y=True)),
   2365         ('-y', NS(x=None, y=False)),
   2366     ]
   2367     successes_when_not_required = [
   2368         ('', NS(x=None, y=True)),
   2369     ]
   2370 
   2371     usage_when_not_required = '''\
   2372         usage: PROG [-h] [-y]
   2373         '''
   2374     usage_when_required = '''\
   2375         usage: PROG [-h] -y
   2376         '''
   2377     help = '''\
   2378 
   2379         optional arguments:
   2380           -h, --help  show this help message and exit
   2381           -y          y help
   2382         '''
   2383 
   2384 
   2385 class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
   2386 
   2387     def get_parser(self, required):
   2388         parser = ErrorRaisingArgumentParser(prog='PROG')
   2389         group = parser.add_mutually_exclusive_group(required=required)
   2390         add = group.add_argument
   2391         add('--spam', action='store_true', help=argparse.SUPPRESS)
   2392         add('--badger', action='store_false', help=argparse.SUPPRESS)
   2393         add('--bladder', help=argparse.SUPPRESS)
   2394         return parser
   2395 
   2396     failures = [
   2397         '--spam --badger',
   2398         '--badger --bladder B',
   2399         '--bladder B --spam',
   2400     ]
   2401     successes = [
   2402         ('--spam', NS(spam=True, badger=True, bladder=None)),
   2403         ('--badger', NS(spam=False, badger=False, bladder=None)),
   2404         ('--bladder B', NS(spam=False, badger=True, bladder='B')),
   2405         ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
   2406     ]
   2407     successes_when_not_required = [
   2408         ('', NS(spam=False, badger=True, bladder=None)),
   2409     ]
   2410 
   2411     usage_when_required = usage_when_not_required = '''\
   2412         usage: PROG [-h]
   2413         '''
   2414     help = '''\
   2415 
   2416         optional arguments:
   2417           -h, --help  show this help message and exit
   2418         '''
   2419 
   2420 
   2421 class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
   2422 
   2423     def get_parser(self, required):
   2424         parser = ErrorRaisingArgumentParser(prog='PROG')
   2425         group = parser.add_mutually_exclusive_group(required=required)
   2426         group.add_argument('--foo', action='store_true', help='FOO')
   2427         group.add_argument('--spam', help='SPAM')
   2428         group.add_argument('badger', nargs='*', default='X', help='BADGER')
   2429         return parser
   2430 
   2431     failures = [
   2432         '--foo --spam S',
   2433         '--spam S X',
   2434         'X --foo',
   2435         'X Y Z --spam S',
   2436         '--foo X Y',
   2437     ]
   2438     successes = [
   2439         ('--foo', NS(foo=True, spam=None, badger='X')),
   2440         ('--spam S', NS(foo=False, spam='S', badger='X')),
   2441         ('X', NS(foo=False, spam=None, badger=['X'])),
   2442         ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
   2443     ]
   2444     successes_when_not_required = [
   2445         ('', NS(foo=False, spam=None, badger='X')),
   2446     ]
   2447 
   2448     usage_when_not_required = '''\
   2449         usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
   2450         '''
   2451     usage_when_required = '''\
   2452         usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
   2453         '''
   2454     help = '''\
   2455 
   2456         positional arguments:
   2457           badger       BADGER
   2458 
   2459         optional arguments:
   2460           -h, --help   show this help message and exit
   2461           --foo        FOO
   2462           --spam SPAM  SPAM
   2463         '''
   2464 
   2465 
   2466 class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
   2467 
   2468     def get_parser(self, required):
   2469         parser = ErrorRaisingArgumentParser(prog='PROG')
   2470         parser.add_argument('-x', action='store_true', help='x help')
   2471         group = parser.add_mutually_exclusive_group(required=required)
   2472         group.add_argument('-a', action='store_true', help='a help')
   2473         group.add_argument('-b', action='store_true', help='b help')
   2474         parser.add_argument('-y', action='store_true', help='y help')
   2475         group.add_argument('-c', action='store_true', help='c help')
   2476         return parser
   2477 
   2478     failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
   2479     successes = [
   2480         ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
   2481         ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
   2482         ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
   2483         ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
   2484         ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
   2485         ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
   2486     ]
   2487     successes_when_not_required = [
   2488         ('', NS(a=False, b=False, c=False, x=False, y=False)),
   2489         ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
   2490         ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
   2491     ]
   2492 
   2493     usage_when_required = usage_when_not_required = '''\
   2494         usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
   2495         '''
   2496     help = '''\
   2497 
   2498         optional arguments:
   2499           -h, --help  show this help message and exit
   2500           -x          x help
   2501           -a          a help
   2502           -b          b help
   2503           -y          y help
   2504           -c          c help
   2505         '''
   2506 
   2507 
   2508 class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
   2509 
   2510     def get_parser(self, required=None):
   2511         parser = ErrorRaisingArgumentParser(prog='PROG')
   2512         titled_group = parser.add_argument_group(
   2513             title='Titled group', description='Group description')
   2514         mutex_group = \
   2515             titled_group.add_mutually_exclusive_group(required=required)
   2516         mutex_group.add_argument('--bar', help='bar help')
   2517         mutex_group.add_argument('--baz', help='baz help')
   2518         return parser
   2519 
   2520     failures = ['--bar X --baz Y', '--baz X --bar Y']
   2521     successes = [
   2522         ('--bar X', NS(bar='X', baz=None)),
   2523         ('--baz Y', NS(bar=None, baz='Y')),
   2524     ]
   2525     successes_when_not_required = [
   2526         ('', NS(bar=None, baz=None)),
   2527     ]
   2528 
   2529     usage_when_not_required = '''\
   2530         usage: PROG [-h] [--bar BAR | --baz BAZ]
   2531         '''
   2532     usage_when_required = '''\
   2533         usage: PROG [-h] (--bar BAR | --baz BAZ)
   2534         '''
   2535     help = '''\
   2536 
   2537         optional arguments:
   2538           -h, --help  show this help message and exit
   2539 
   2540         Titled group:
   2541           Group description
   2542 
   2543           --bar BAR   bar help
   2544           --baz BAZ   baz help
   2545         '''
   2546 
   2547 
   2548 class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
   2549 
   2550     def get_parser(self, required):
   2551         parser = ErrorRaisingArgumentParser(prog='PROG')
   2552         parser.add_argument('x', help='x help')
   2553         parser.add_argument('-y', action='store_true', help='y help')
   2554         group = parser.add_mutually_exclusive_group(required=required)
   2555         group.add_argument('a', nargs='?', help='a help')
   2556         group.add_argument('-b', action='store_true', help='b help')
   2557         group.add_argument('-c', action='store_true', help='c help')
   2558         return parser
   2559 
   2560     failures = ['X A -b', '-b -c', '-c X A']
   2561     successes = [
   2562         ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
   2563         ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
   2564         ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
   2565         ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
   2566         ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
   2567     ]
   2568     successes_when_not_required = [
   2569         ('X', NS(a=None, b=False, c=False, x='X', y=False)),
   2570         ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
   2571     ]
   2572 
   2573     usage_when_required = usage_when_not_required = '''\
   2574         usage: PROG [-h] [-y] [-b] [-c] x [a]
   2575         '''
   2576     help = '''\
   2577 
   2578         positional arguments:
   2579           x           x help
   2580           a           a help
   2581 
   2582         optional arguments:
   2583           -h, --help  show this help message and exit
   2584           -y          y help
   2585           -b          b help
   2586           -c          c help
   2587         '''
   2588 
   2589 # =================================================

   2590 # Mutually exclusive group in parent parser tests

   2591 # =================================================

   2592 
   2593 class MEPBase(object):
   2594 
   2595     def get_parser(self, required=None):
   2596         parent = super(MEPBase, self).get_parser(required=required)
   2597         parser = ErrorRaisingArgumentParser(
   2598             prog=parent.prog, add_help=False, parents=[parent])
   2599         return parser
   2600 
   2601 
   2602 class TestMutuallyExclusiveGroupErrorsParent(
   2603     MEPBase, TestMutuallyExclusiveGroupErrors):
   2604     pass
   2605 
   2606 
   2607 class TestMutuallyExclusiveSimpleParent(
   2608     MEPBase, TestMutuallyExclusiveSimple):
   2609     pass
   2610 
   2611 
   2612 class TestMutuallyExclusiveLongParent(
   2613     MEPBase, TestMutuallyExclusiveLong):
   2614     pass
   2615 
   2616 
   2617 class TestMutuallyExclusiveFirstSuppressedParent(
   2618     MEPBase, TestMutuallyExclusiveFirstSuppressed):
   2619     pass
   2620 
   2621 
   2622 class TestMutuallyExclusiveManySuppressedParent(
   2623     MEPBase, TestMutuallyExclusiveManySuppressed):
   2624     pass
   2625 
   2626 
   2627 class TestMutuallyExclusiveOptionalAndPositionalParent(
   2628     MEPBase, TestMutuallyExclusiveOptionalAndPositional):
   2629     pass
   2630 
   2631 
   2632 class TestMutuallyExclusiveOptionalsMixedParent(
   2633     MEPBase, TestMutuallyExclusiveOptionalsMixed):
   2634     pass
   2635 
   2636 
   2637 class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
   2638     MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
   2639     pass
   2640 
   2641 # =================

   2642 # Set default tests

   2643 # =================

   2644 
   2645 class TestSetDefaults(TestCase):
   2646 
   2647     def test_set_defaults_no_args(self):
   2648         parser = ErrorRaisingArgumentParser()
   2649         parser.set_defaults(x='foo')
   2650         parser.set_defaults(y='bar', z=1)
   2651         self.assertEqual(NS(x='foo', y='bar', z=1),
   2652                          parser.parse_args([]))
   2653         self.assertEqual(NS(x='foo', y='bar', z=1),
   2654                          parser.parse_args([], NS()))
   2655         self.assertEqual(NS(x='baz', y='bar', z=1),
   2656                          parser.parse_args([], NS(x='baz')))
   2657         self.assertEqual(NS(x='baz', y='bar', z=2),
   2658                          parser.parse_args([], NS(x='baz', z=2)))
   2659 
   2660     def test_set_defaults_with_args(self):
   2661         parser = ErrorRaisingArgumentParser()
   2662         parser.set_defaults(x='foo', y='bar')
   2663         parser.add_argument('-x', default='xfoox')
   2664         self.assertEqual(NS(x='xfoox', y='bar'),
   2665                          parser.parse_args([]))
   2666         self.assertEqual(NS(x='xfoox', y='bar'),
   2667                          parser.parse_args([], NS()))
   2668         self.assertEqual(NS(x='baz', y='bar'),
   2669                          parser.parse_args([], NS(x='baz')))
   2670         self.assertEqual(NS(x='1', y='bar'),
   2671                          parser.parse_args('-x 1'.split()))
   2672         self.assertEqual(NS(x='1', y='bar'),
   2673                          parser.parse_args('-x 1'.split(), NS()))
   2674         self.assertEqual(NS(x='1', y='bar'),
   2675                          parser.parse_args('-x 1'.split(), NS(x='baz')))
   2676 
   2677     def test_set_defaults_subparsers(self):
   2678         parser = ErrorRaisingArgumentParser()
   2679         parser.set_defaults(x='foo')
   2680         subparsers = parser.add_subparsers()
   2681         parser_a = subparsers.add_parser('a')
   2682         parser_a.set_defaults(y='bar')
   2683         self.assertEqual(NS(x='foo', y='bar'),
   2684                          parser.parse_args('a'.split()))
   2685 
   2686     def test_set_defaults_parents(self):
   2687         parent = ErrorRaisingArgumentParser(add_help=False)
   2688         parent.set_defaults(x='foo')
   2689         parser = ErrorRaisingArgumentParser(parents=[parent])
   2690         self.assertEqual(NS(x='foo'), parser.parse_args([]))
   2691 
   2692     def test_set_defaults_same_as_add_argument(self):
   2693         parser = ErrorRaisingArgumentParser()
   2694         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2695         parser.add_argument('-w')
   2696         parser.add_argument('-x', default='XX')
   2697         parser.add_argument('y', nargs='?')
   2698         parser.add_argument('z', nargs='?', default='ZZ')
   2699 
   2700         # defaults set previously

   2701         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2702                          parser.parse_args([]))
   2703 
   2704         # reset defaults

   2705         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2706         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2707                          parser.parse_args([]))
   2708 
   2709     def test_set_defaults_same_as_add_argument_group(self):
   2710         parser = ErrorRaisingArgumentParser()
   2711         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2712         group = parser.add_argument_group('foo')
   2713         group.add_argument('-w')
   2714         group.add_argument('-x', default='XX')
   2715         group.add_argument('y', nargs='?')
   2716         group.add_argument('z', nargs='?', default='ZZ')
   2717 
   2718 
   2719         # defaults set previously

   2720         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2721                          parser.parse_args([]))
   2722 
   2723         # reset defaults

   2724         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2725         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2726                          parser.parse_args([]))
   2727 
   2728 # =================

   2729 # Get default tests

   2730 # =================

   2731 
   2732 class TestGetDefault(TestCase):
   2733 
   2734     def test_get_default(self):
   2735         parser = ErrorRaisingArgumentParser()
   2736         self.assertEqual(None, parser.get_default("foo"))
   2737         self.assertEqual(None, parser.get_default("bar"))
   2738 
   2739         parser.add_argument("--foo")
   2740         self.assertEqual(None, parser.get_default("foo"))
   2741         self.assertEqual(None, parser.get_default("bar"))
   2742 
   2743         parser.add_argument("--bar", type=int, default=42)
   2744         self.assertEqual(None, parser.get_default("foo"))
   2745         self.assertEqual(42, parser.get_default("bar"))
   2746 
   2747         parser.set_defaults(foo="badger")
   2748         self.assertEqual("badger", parser.get_default("foo"))
   2749         self.assertEqual(42, parser.get_default("bar"))
   2750 
   2751 # ==========================

   2752 # Namespace 'contains' tests

   2753 # ==========================

   2754 
   2755 class TestNamespaceContainsSimple(TestCase):
   2756 
   2757     def test_empty(self):
   2758         ns = argparse.Namespace()
   2759         self.assertEqual('' in ns, False)
   2760         self.assertEqual('' not in ns, True)
   2761         self.assertEqual('x' in ns, False)
   2762 
   2763     def test_non_empty(self):
   2764         ns = argparse.Namespace(x=1, y=2)
   2765         self.assertEqual('x' in ns, True)
   2766         self.assertEqual('x' not in ns, False)
   2767         self.assertEqual('y' in ns, True)
   2768         self.assertEqual('' in ns, False)
   2769         self.assertEqual('xx' in ns, False)
   2770         self.assertEqual('z' in ns, False)
   2771 
   2772 # =====================

   2773 # Help formatting tests

   2774 # =====================

   2775 
   2776 class TestHelpFormattingMetaclass(type):
   2777 
   2778     def __init__(cls, name, bases, bodydict):
   2779         if name == 'HelpTestCase':
   2780             return
   2781 
   2782         class AddTests(object):
   2783 
   2784             def __init__(self, test_class, func_suffix, std_name):
   2785                 self.func_suffix = func_suffix
   2786                 self.std_name = std_name
   2787 
   2788                 for test_func in [self.test_format,
   2789                                   self.test_print,
   2790                                   self.test_print_file]:
   2791                     test_name = '%s_%s' % (test_func.__name__, func_suffix)
   2792 
   2793                     def test_wrapper(self, test_func=test_func):
   2794                         test_func(self)
   2795                     try:
   2796                         test_wrapper.__name__ = test_name
   2797                     except TypeError:
   2798                         pass
   2799                     setattr(test_class, test_name, test_wrapper)
   2800 
   2801             def _get_parser(self, tester):
   2802                 parser = argparse.ArgumentParser(
   2803                     *tester.parser_signature.args,
   2804                     **tester.parser_signature.kwargs)
   2805                 for argument_sig in getattr(tester, 'argument_signatures', []):
   2806                     parser.add_argument(*argument_sig.args,
   2807                                         **argument_sig.kwargs)
   2808                 group_sigs = getattr(tester, 'argument_group_signatures', [])
   2809                 for group_sig, argument_sigs in group_sigs:
   2810                     group = parser.add_argument_group(*group_sig.args,
   2811                                                       **group_sig.kwargs)
   2812                     for argument_sig in argument_sigs:
   2813                         group.add_argument(*argument_sig.args,
   2814                                            **argument_sig.kwargs)
   2815                 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
   2816                 if subparsers_sigs:
   2817                     subparsers = parser.add_subparsers()
   2818                     for subparser_sig in subparsers_sigs:
   2819                         subparsers.add_parser(*subparser_sig.args,
   2820                                                **subparser_sig.kwargs)
   2821                 return parser
   2822 
   2823             def _test(self, tester, parser_text):
   2824                 expected_text = getattr(tester, self.func_suffix)
   2825                 expected_text = textwrap.dedent(expected_text)
   2826                 if expected_text != parser_text:
   2827                     print(repr(expected_text))
   2828                     print(repr(parser_text))
   2829                     for char1, char2 in zip(expected_text, parser_text):
   2830                         if char1 != char2:
   2831                             print('first diff: %r %r' % (char1, char2))
   2832                             break
   2833                 tester.assertEqual(expected_text, parser_text)
   2834 
   2835             def test_format(self, tester):
   2836                 parser = self._get_parser(tester)
   2837                 format = getattr(parser, 'format_%s' % self.func_suffix)
   2838                 self._test(tester, format())
   2839 
   2840             def test_print(self, tester):
   2841                 parser = self._get_parser(tester)
   2842                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2843                 old_stream = getattr(sys, self.std_name)
   2844                 setattr(sys, self.std_name, StdIOBuffer())
   2845                 try:
   2846                     print_()
   2847                     parser_text = getattr(sys, self.std_name).getvalue()
   2848                 finally:
   2849                     setattr(sys, self.std_name, old_stream)
   2850                 self._test(tester, parser_text)
   2851 
   2852             def test_print_file(self, tester):
   2853                 parser = self._get_parser(tester)
   2854                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2855                 sfile = StdIOBuffer()
   2856                 print_(sfile)
   2857                 parser_text = sfile.getvalue()
   2858                 self._test(tester, parser_text)
   2859 
   2860         # add tests for {format,print}_{usage,help,version}

   2861         for func_suffix, std_name in [('usage', 'stdout'),
   2862                                       ('help', 'stdout'),
   2863                                       ('version', 'stderr')]:
   2864             AddTests(cls, func_suffix, std_name)
   2865 
   2866 bases = TestCase,
   2867 HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
   2868 
   2869 
   2870 class TestHelpBiggerOptionals(HelpTestCase):
   2871     """Make sure that argument help aligns when options are longer"""
   2872 
   2873     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   2874                            epilog='EPILOG', version='0.1')
   2875     argument_signatures = [
   2876         Sig('-x', action='store_true', help='X HELP'),
   2877         Sig('--y', help='Y HELP'),
   2878         Sig('foo', help='FOO HELP'),
   2879         Sig('bar', help='BAR HELP'),
   2880     ]
   2881     argument_group_signatures = []
   2882     usage = '''\
   2883         usage: PROG [-h] [-v] [-x] [--y Y] foo bar
   2884         '''
   2885     help = usage + '''\
   2886 
   2887         DESCRIPTION
   2888 
   2889         positional arguments:
   2890           foo            FOO HELP
   2891           bar            BAR HELP
   2892 
   2893         optional arguments:
   2894           -h, --help     show this help message and exit
   2895           -v, --version  show program's version number and exit
   2896           -x             X HELP
   2897           --y Y          Y HELP
   2898 
   2899         EPILOG
   2900     '''
   2901     version = '''\
   2902         0.1
   2903         '''
   2904 
   2905 
   2906 class TestHelpBiggerOptionalGroups(HelpTestCase):
   2907     """Make sure that argument help aligns when options are longer"""
   2908 
   2909     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   2910                            epilog='EPILOG', version='0.1')
   2911     argument_signatures = [
   2912         Sig('-x', action='store_true', help='X HELP'),
   2913         Sig('--y', help='Y HELP'),
   2914         Sig('foo', help='FOO HELP'),
   2915         Sig('bar', help='BAR HELP'),
   2916     ]
   2917     argument_group_signatures = [
   2918         (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
   2919             Sig('baz', help='BAZ HELP'),
   2920             Sig('-z', nargs='+', help='Z HELP')]),
   2921     ]
   2922     usage = '''\
   2923         usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
   2924         '''
   2925     help = usage + '''\
   2926 
   2927         DESCRIPTION
   2928 
   2929         positional arguments:
   2930           foo            FOO HELP
   2931           bar            BAR HELP
   2932 
   2933         optional arguments:
   2934           -h, --help     show this help message and exit
   2935           -v, --version  show program's version number and exit
   2936           -x             X HELP
   2937           --y Y          Y HELP
   2938 
   2939         GROUP TITLE:
   2940           GROUP DESCRIPTION
   2941 
   2942           baz            BAZ HELP
   2943           -z Z [Z ...]   Z HELP
   2944 
   2945         EPILOG
   2946     '''
   2947     version = '''\
   2948         0.1
   2949         '''
   2950 
   2951 
   2952 class TestHelpBiggerPositionals(HelpTestCase):
   2953     """Make sure that help aligns when arguments are longer"""
   2954 
   2955     parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
   2956     argument_signatures = [
   2957         Sig('-x', action='store_true', help='X HELP'),
   2958         Sig('--y', help='Y HELP'),
   2959         Sig('ekiekiekifekang', help='EKI HELP'),
   2960         Sig('bar', help='BAR HELP'),
   2961     ]
   2962     argument_group_signatures = []
   2963     usage = '''\
   2964         usage: USAGE
   2965         '''
   2966     help = usage + '''\
   2967 
   2968         DESCRIPTION
   2969 
   2970         positional arguments:
   2971           ekiekiekifekang  EKI HELP
   2972           bar              BAR HELP
   2973 
   2974         optional arguments:
   2975           -h, --help       show this help message and exit
   2976           -x               X HELP
   2977           --y Y            Y HELP
   2978         '''
   2979 
   2980     version = ''
   2981 
   2982 
   2983 class TestHelpReformatting(HelpTestCase):
   2984     """Make sure that text after short names starts on the first line"""
   2985 
   2986     parser_signature = Sig(
   2987         prog='PROG',
   2988         description='   oddly    formatted\n'
   2989                     'description\n'
   2990                     '\n'
   2991                     'that is so long that it should go onto multiple '
   2992                     'lines when wrapped')
   2993     argument_signatures = [
   2994         Sig('-x', metavar='XX', help='oddly\n'
   2995                                      '    formatted -x help'),
   2996         Sig('y', metavar='yyy', help='normal y help'),
   2997     ]
   2998     argument_group_signatures = [
   2999         (Sig('title', description='\n'
   3000                                   '    oddly formatted group\n'
   3001                                   '\n'
   3002                                   'description'),
   3003          [Sig('-a', action='store_true',
   3004               help=' oddly \n'
   3005                    'formatted    -a  help  \n'
   3006                    '    again, so long that it should be wrapped over '
   3007                    'multiple lines')]),
   3008     ]
   3009     usage = '''\
   3010         usage: PROG [-h] [-x XX] [-a] yyy
   3011         '''
   3012     help = usage + '''\
   3013 
   3014         oddly formatted description that is so long that it should go onto \
   3015 multiple
   3016         lines when wrapped
   3017 
   3018         positional arguments:
   3019           yyy         normal y help
   3020 
   3021         optional arguments:
   3022           -h, --help  show this help message and exit
   3023           -x XX       oddly formatted -x help
   3024 
   3025         title:
   3026           oddly formatted group description
   3027 
   3028           -a          oddly formatted -a help again, so long that it should \
   3029 be wrapped
   3030                       over multiple lines
   3031         '''
   3032     version = ''
   3033 
   3034 
   3035 class TestHelpWrappingShortNames(HelpTestCase):
   3036     """Make sure that text after short names starts on the first line"""
   3037 
   3038     parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
   3039     argument_signatures = [
   3040         Sig('-x', metavar='XX', help='XHH HX' * 20),
   3041         Sig('y', metavar='yyy', help='YH YH' * 20),
   3042     ]
   3043     argument_group_signatures = [
   3044         (Sig('ALPHAS'), [
   3045             Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
   3046     ]
   3047     usage = '''\
   3048         usage: PROG [-h] [-x XX] [-a] yyy
   3049         '''
   3050     help = usage + '''\
   3051 
   3052         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3053 DD DD DD
   3054         DD DD DD DD D
   3055 
   3056         positional arguments:
   3057           yyy         YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3058 YHYH YHYH
   3059                       YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3060 
   3061         optional arguments:
   3062           -h, --help  show this help message and exit
   3063           -x XX       XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
   3064 HXXHH HXXHH
   3065                       HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
   3066 
   3067         ALPHAS:
   3068           -a          AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
   3069 HHAAHHH
   3070                       HHAAHHH HHAAHHH HHA
   3071         '''
   3072     version = ''
   3073 
   3074 
   3075 class TestHelpWrappingLongNames(HelpTestCase):
   3076     """Make sure that text after long names starts on the next line"""
   3077 
   3078     parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
   3079                            version='V V'*30)
   3080     argument_signatures = [
   3081         Sig('-x', metavar='X' * 25, help='XH XH' * 20),
   3082         Sig('y', metavar='y' * 25, help='YH YH' * 20),
   3083     ]
   3084     argument_group_signatures = [
   3085         (Sig('ALPHAS'), [
   3086             Sig('-a', metavar='A' * 25, help='AH AH' * 20),
   3087             Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
   3088     ]
   3089     usage = '''\
   3090         usage: USAGE
   3091         '''
   3092     help = usage + '''\
   3093 
   3094         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3095 DD DD DD
   3096         DD DD DD DD D
   3097 
   3098         positional arguments:
   3099           yyyyyyyyyyyyyyyyyyyyyyyyy
   3100                                 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3101 YHYH YHYH
   3102                                 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3103 
   3104         optional arguments:
   3105           -h, --help            show this help message and exit
   3106           -v, --version         show program's version number and exit
   3107           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3108                                 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
   3109 XHXH XHXH
   3110                                 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
   3111 
   3112         ALPHAS:
   3113           -a AAAAAAAAAAAAAAAAAAAAAAAAA
   3114                                 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
   3115 AHAH AHAH
   3116                                 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
   3117           zzzzzzzzzzzzzzzzzzzzzzzzz
   3118                                 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
   3119 ZHZH ZHZH
   3120                                 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
   3121         '''
   3122     version = '''\
   3123         V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
   3124 VV VV VV
   3125         VV VV VV VV V
   3126         '''
   3127 
   3128 
   3129 class TestHelpUsage(HelpTestCase):
   3130     """Test basic usage messages"""
   3131 
   3132     parser_signature = Sig(prog='PROG')
   3133     argument_signatures = [
   3134         Sig('-w', nargs='+', help='w'),
   3135         Sig('-x', nargs='*', help='x'),
   3136         Sig('a', help='a'),
   3137         Sig('b', help='b', nargs=2),
   3138         Sig('c', help='c', nargs='?'),
   3139     ]
   3140     argument_group_signatures = [
   3141         (Sig('group'), [
   3142             Sig('-y', nargs='?', help='y'),
   3143             Sig('-z', nargs=3, help='z'),
   3144             Sig('d', help='d', nargs='*'),
   3145             Sig('e', help='e', nargs='+'),
   3146         ])
   3147     ]
   3148     usage = '''\
   3149         usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
   3150                     a b b [c] [d [d ...]] e [e ...]
   3151         '''
   3152     help = usage + '''\
   3153 
   3154         positional arguments:
   3155           a               a
   3156           b               b
   3157           c               c
   3158 
   3159         optional arguments:
   3160           -h, --help      show this help message and exit
   3161           -w W [W ...]    w
   3162           -x [X [X ...]]  x
   3163 
   3164         group:
   3165           -y [Y]          y
   3166           -z Z Z Z        z
   3167           d               d
   3168           e               e
   3169         '''
   3170     version = ''
   3171 
   3172 
   3173 class TestHelpOnlyUserGroups(HelpTestCase):
   3174     """Test basic usage messages"""
   3175 
   3176     parser_signature = Sig(prog='PROG', add_help=False)
   3177     argument_signatures = []
   3178     argument_group_signatures = [
   3179         (Sig('xxxx'), [
   3180             Sig('-x', help='x'),
   3181             Sig('a', help='a'),
   3182         ]),
   3183         (Sig('yyyy'), [
   3184             Sig('b', help='b'),
   3185             Sig('-y', help='y'),
   3186         ]),
   3187     ]
   3188     usage = '''\
   3189         usage: PROG [-x X] [-y Y] a b
   3190         '''
   3191     help = usage + '''\
   3192 
   3193         xxxx:
   3194           -x X  x
   3195           a     a
   3196 
   3197         yyyy:
   3198           b     b
   3199           -y Y  y
   3200         '''
   3201     version = ''
   3202 
   3203 
   3204 class TestHelpUsageLongProg(HelpTestCase):
   3205     """Test usage messages where the prog is long"""
   3206 
   3207     parser_signature = Sig(prog='P' * 60)
   3208     argument_signatures = [
   3209         Sig('-w', metavar='W'),
   3210         Sig('-x', metavar='X'),
   3211         Sig('a'),
   3212         Sig('b'),
   3213     ]
   3214     argument_group_signatures = []
   3215     usage = '''\
   3216         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3217                [-h] [-w W] [-x X] a b
   3218         '''
   3219     help = usage + '''\
   3220 
   3221         positional arguments:
   3222           a
   3223           b
   3224 
   3225         optional arguments:
   3226           -h, --help  show this help message and exit
   3227           -w W
   3228           -x X
   3229         '''
   3230     version = ''
   3231 
   3232 
   3233 class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
   3234     """Test usage messages where the prog is long and the optionals wrap"""
   3235 
   3236     parser_signature = Sig(prog='P' * 60)
   3237     argument_signatures = [
   3238         Sig('-w', metavar='W' * 25),
   3239         Sig('-x', metavar='X' * 25),
   3240         Sig('-y', metavar='Y' * 25),
   3241         Sig('-z', metavar='Z' * 25),
   3242         Sig('a'),
   3243         Sig('b'),
   3244     ]
   3245     argument_group_signatures = []
   3246     usage = '''\
   3247         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3248                [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3249 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3250                [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3251                a b
   3252         '''
   3253     help = usage + '''\
   3254 
   3255         positional arguments:
   3256           a
   3257           b
   3258 
   3259         optional arguments:
   3260           -h, --help            show this help message and exit
   3261           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3262           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3263           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3264           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3265         '''
   3266     version = ''
   3267 
   3268 
   3269 class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
   3270     """Test usage messages where the prog is long and the positionals wrap"""
   3271 
   3272     parser_signature = Sig(prog='P' * 60, add_help=False)
   3273     argument_signatures = [
   3274         Sig('a' * 25),
   3275         Sig('b' * 25),
   3276         Sig('c' * 25),
   3277     ]
   3278     argument_group_signatures = []
   3279     usage = '''\
   3280         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3281                aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3282                ccccccccccccccccccccccccc
   3283         '''
   3284     help = usage + '''\
   3285 
   3286         positional arguments:
   3287           aaaaaaaaaaaaaaaaaaaaaaaaa
   3288           bbbbbbbbbbbbbbbbbbbbbbbbb
   3289           ccccccccccccccccccccccccc
   3290         '''
   3291     version = ''
   3292 
   3293 
   3294 class TestHelpUsageOptionalsWrap(HelpTestCase):
   3295     """Test usage messages where the optionals wrap"""
   3296 
   3297     parser_signature = Sig(prog='PROG')
   3298     argument_signatures = [
   3299         Sig('-w', metavar='W' * 25),
   3300         Sig('-x', metavar='X' * 25),
   3301         Sig('-y', metavar='Y' * 25),
   3302         Sig('-z', metavar='Z' * 25),
   3303         Sig('a'),
   3304         Sig('b'),
   3305         Sig('c'),
   3306     ]
   3307     argument_group_signatures = []
   3308     usage = '''\
   3309         usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3310 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3311                     [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
   3312 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3313                     a b c
   3314         '''
   3315     help = usage + '''\
   3316 
   3317         positional arguments:
   3318           a
   3319           b
   3320           c
   3321 
   3322         optional arguments:
   3323           -h, --help            show this help message and exit
   3324           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3325           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3326           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3327           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3328         '''
   3329     version = ''
   3330 
   3331 
   3332 class TestHelpUsagePositionalsWrap(HelpTestCase):
   3333     """Test usage messages where the positionals wrap"""
   3334 
   3335     parser_signature = Sig(prog='PROG')
   3336     argument_signatures = [
   3337         Sig('-x'),
   3338         Sig('-y'),
   3339         Sig('-z'),
   3340         Sig('a' * 25),
   3341         Sig('b' * 25),
   3342         Sig('c' * 25),
   3343     ]
   3344     argument_group_signatures = []
   3345     usage = '''\
   3346         usage: PROG [-h] [-x X] [-y Y] [-z Z]
   3347                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3348                     ccccccccccccccccccccccccc
   3349         '''
   3350     help = usage + '''\
   3351 
   3352         positional arguments:
   3353           aaaaaaaaaaaaaaaaaaaaaaaaa
   3354           bbbbbbbbbbbbbbbbbbbbbbbbb
   3355           ccccccccccccccccccccccccc
   3356 
   3357         optional arguments:
   3358           -h, --help            show this help message and exit
   3359           -x X
   3360           -y Y
   3361           -z Z
   3362         '''
   3363     version = ''
   3364 
   3365 
   3366 class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
   3367     """Test usage messages where the optionals and positionals wrap"""
   3368 
   3369     parser_signature = Sig(prog='PROG')
   3370     argument_signatures = [
   3371         Sig('-x', metavar='X' * 25),
   3372         Sig('-y', metavar='Y' * 25),
   3373         Sig('-z', metavar='Z' * 25),
   3374         Sig('a' * 25),
   3375         Sig('b' * 25),
   3376         Sig('c' * 25),
   3377     ]
   3378     argument_group_signatures = []
   3379     usage = '''\
   3380         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3381 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3382                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3383                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3384                     ccccccccccccccccccccccccc
   3385         '''
   3386     help = usage + '''\
   3387 
   3388         positional arguments:
   3389           aaaaaaaaaaaaaaaaaaaaaaaaa
   3390           bbbbbbbbbbbbbbbbbbbbbbbbb
   3391           ccccccccccccccccccccccccc
   3392 
   3393         optional arguments:
   3394           -h, --help            show this help message and exit
   3395           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3396           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3397           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3398         '''
   3399     version = ''
   3400 
   3401 
   3402 class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
   3403     """Test usage messages where there are only optionals and they wrap"""
   3404 
   3405     parser_signature = Sig(prog='PROG')
   3406     argument_signatures = [
   3407         Sig('-x', metavar='X' * 25),
   3408         Sig('-y', metavar='Y' * 25),
   3409         Sig('-z', metavar='Z' * 25),
   3410     ]
   3411     argument_group_signatures = []
   3412     usage = '''\
   3413         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3414 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3415                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3416         '''
   3417     help = usage + '''\
   3418 
   3419         optional arguments:
   3420           -h, --help            show this help message and exit
   3421           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3422           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3423           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3424         '''
   3425     version = ''
   3426 
   3427 
   3428 class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
   3429     """Test usage messages where there are only positionals and they wrap"""
   3430 
   3431     parser_signature = Sig(prog='PROG', add_help=False)
   3432     argument_signatures = [
   3433         Sig('a' * 25),
   3434         Sig('b' * 25),
   3435         Sig('c' * 25),
   3436     ]
   3437     argument_group_signatures = []
   3438     usage = '''\
   3439         usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3440                     ccccccccccccccccccccccccc
   3441         '''
   3442     help = usage + '''\
   3443 
   3444         positional arguments:
   3445           aaaaaaaaaaaaaaaaaaaaaaaaa
   3446           bbbbbbbbbbbbbbbbbbbbbbbbb
   3447           ccccccccccccccccccccccccc
   3448         '''
   3449     version = ''
   3450 
   3451 
   3452 class TestHelpVariableExpansion(HelpTestCase):
   3453     """Test that variables are expanded properly in help messages"""
   3454 
   3455     parser_signature = Sig(prog='PROG')
   3456     argument_signatures = [
   3457         Sig('-x', type=int,
   3458             help='x %(prog)s %(default)s %(type)s %%'),
   3459         Sig('-y', action='store_const', default=42, const='XXX',
   3460             help='y %(prog)s %(default)s %(const)s'),
   3461         Sig('--foo', choices='abc',
   3462             help='foo %(prog)s %(default)s %(choices)s'),
   3463         Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
   3464             help='bar %(prog)s %(default)s %(dest)s'),
   3465         Sig('spam', help='spam %(prog)s %(default)s'),
   3466         Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
   3467     ]
   3468     argument_group_signatures = [
   3469         (Sig('group'), [
   3470             Sig('-a', help='a %(prog)s %(default)s'),
   3471             Sig('-b', default=-1, help='b %(prog)s %(default)s'),
   3472         ])
   3473     ]
   3474     usage = ('''\
   3475         usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
   3476                     spam badger
   3477         ''')
   3478     help = usage + '''\
   3479 
   3480         positional arguments:
   3481           spam           spam PROG None
   3482           badger         badger PROG 0.5
   3483 
   3484         optional arguments:
   3485           -h, --help     show this help message and exit
   3486           -x X           x PROG None int %
   3487           -y             y PROG 42 XXX
   3488           --foo {a,b,c}  foo PROG None a, b, c
   3489           --bar BBB      bar PROG baz bar
   3490 
   3491         group:
   3492           -a A           a PROG None
   3493           -b B           b PROG -1
   3494         '''
   3495     version = ''
   3496 
   3497 
   3498 class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
   3499     """Test that variables are expanded properly when usage= is present"""
   3500 
   3501     parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
   3502     argument_signatures = []
   3503     argument_group_signatures = []
   3504     usage = ('''\
   3505         usage: PROG FOO
   3506         ''')
   3507     help = usage + '''\
   3508 
   3509         optional arguments:
   3510           -h, --help  show this help message and exit
   3511         '''
   3512     version = ''
   3513 
   3514 
   3515 class TestHelpVariableExpansionNoArguments(HelpTestCase):
   3516     """Test that variables are expanded properly with no arguments"""
   3517 
   3518     parser_signature = Sig(prog='PROG', add_help=False)
   3519     argument_signatures = []
   3520     argument_group_signatures = []
   3521     usage = ('''\
   3522         usage: PROG
   3523         ''')
   3524     help = usage
   3525     version = ''
   3526 
   3527 
   3528 class TestHelpSuppressUsage(HelpTestCase):
   3529     """Test that items can be suppressed in usage messages"""
   3530 
   3531     parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
   3532     argument_signatures = [
   3533         Sig('--foo', help='foo help'),
   3534         Sig('spam', help='spam help'),
   3535     ]
   3536     argument_group_signatures = []
   3537     help = '''\
   3538         positional arguments:
   3539           spam        spam help
   3540 
   3541         optional arguments:
   3542           -h, --help  show this help message and exit
   3543           --foo FOO   foo help
   3544         '''
   3545     usage = ''
   3546     version = ''
   3547 
   3548 
   3549 class TestHelpSuppressOptional(HelpTestCase):
   3550     """Test that optional arguments can be suppressed in help messages"""
   3551 
   3552     parser_signature = Sig(prog='PROG', add_help=False)
   3553     argument_signatures = [
   3554         Sig('--foo', help=argparse.SUPPRESS),
   3555         Sig('spam', help='spam help'),
   3556     ]
   3557     argument_group_signatures = []
   3558     usage = '''\
   3559         usage: PROG spam
   3560         '''
   3561     help = usage + '''\
   3562 
   3563         positional arguments:
   3564           spam  spam help
   3565         '''
   3566     version = ''
   3567 
   3568 
   3569 class TestHelpSuppressOptionalGroup(HelpTestCase):
   3570     """Test that optional groups can be suppressed in help messages"""
   3571 
   3572     parser_signature = Sig(prog='PROG')
   3573     argument_signatures = [
   3574         Sig('--foo', help='foo help'),
   3575         Sig('spam', help='spam help'),
   3576     ]
   3577     argument_group_signatures = [
   3578         (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
   3579     ]
   3580     usage = '''\
   3581         usage: PROG [-h] [--foo FOO] spam
   3582         '''
   3583     help = usage + '''\
   3584 
   3585         positional arguments:
   3586           spam        spam help
   3587 
   3588         optional arguments:
   3589           -h, --help  show this help message and exit
   3590           --foo FOO   foo help
   3591         '''
   3592     version = ''
   3593 
   3594 
   3595 class TestHelpSuppressPositional(HelpTestCase):
   3596     """Test that positional arguments can be suppressed in help messages"""
   3597 
   3598     parser_signature = Sig(prog='PROG')
   3599     argument_signatures = [
   3600         Sig('--foo', help='foo help'),
   3601         Sig('spam', help=argparse.SUPPRESS),
   3602     ]
   3603     argument_group_signatures = []
   3604     usage = '''\
   3605         usage: PROG [-h] [--foo FOO]
   3606         '''
   3607     help = usage + '''\
   3608 
   3609         optional arguments:
   3610           -h, --help  show this help message and exit
   3611           --foo FOO   foo help
   3612         '''
   3613     version = ''
   3614 
   3615 
   3616 class TestHelpRequiredOptional(HelpTestCase):
   3617     """Test that required options don't look optional"""
   3618 
   3619     parser_signature = Sig(prog='PROG')
   3620     argument_signatures = [
   3621         Sig('--foo', required=True, help='foo help'),
   3622     ]
   3623     argument_group_signatures = []
   3624     usage = '''\
   3625         usage: PROG [-h] --foo FOO
   3626         '''
   3627     help = usage + '''\
   3628 
   3629         optional arguments:
   3630           -h, --help  show this help message and exit
   3631           --foo FOO   foo help
   3632         '''
   3633     version = ''
   3634 
   3635 
   3636 class TestHelpAlternatePrefixChars(HelpTestCase):
   3637     """Test that options display with different prefix characters"""
   3638 
   3639     parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
   3640     argument_signatures = [
   3641         Sig('^^foo', action='store_true', help='foo help'),
   3642         Sig(';b', ';;bar', help='bar help'),
   3643     ]
   3644     argument_group_signatures = []
   3645     usage = '''\
   3646         usage: PROG [^^foo] [;b BAR]
   3647         '''
   3648     help = usage + '''\
   3649 
   3650         optional arguments:
   3651           ^^foo              foo help
   3652           ;b BAR, ;;bar BAR  bar help
   3653         '''
   3654     version = ''
   3655 
   3656 
   3657 class TestHelpNoHelpOptional(HelpTestCase):
   3658     """Test that the --help argument can be suppressed help messages"""
   3659 
   3660     parser_signature = Sig(prog='PROG', add_help=False)
   3661     argument_signatures = [
   3662         Sig('--foo', help='foo help'),
   3663         Sig('spam', help='spam help'),
   3664     ]
   3665     argument_group_signatures = []
   3666     usage = '''\
   3667         usage: PROG [--foo FOO] spam
   3668         '''
   3669     help = usage + '''\
   3670 
   3671         positional arguments:
   3672           spam       spam help
   3673 
   3674         optional arguments:
   3675           --foo FOO  foo help
   3676         '''
   3677     version = ''
   3678 
   3679 
   3680 class TestHelpVersionOptional(HelpTestCase):
   3681     """Test that the --version argument can be suppressed help messages"""
   3682 
   3683     parser_signature = Sig(prog='PROG', version='1.0')
   3684     argument_signatures = [
   3685         Sig('--foo', help='foo help'),
   3686         Sig('spam', help='spam help'),
   3687     ]
   3688     argument_group_signatures = []
   3689     usage = '''\
   3690         usage: PROG [-h] [-v] [--foo FOO] spam
   3691         '''
   3692     help = usage + '''\
   3693 
   3694         positional arguments:
   3695           spam           spam help
   3696 
   3697         optional arguments:
   3698           -h, --help     show this help message and exit
   3699           -v, --version  show program's version number and exit
   3700           --foo FOO      foo help
   3701         '''
   3702     version = '''\
   3703         1.0
   3704         '''
   3705 
   3706 
   3707 class TestHelpNone(HelpTestCase):
   3708     """Test that no errors occur if no help is specified"""
   3709 
   3710     parser_signature = Sig(prog='PROG')
   3711     argument_signatures = [
   3712         Sig('--foo'),
   3713         Sig('spam'),
   3714     ]
   3715     argument_group_signatures = []
   3716     usage = '''\
   3717         usage: PROG [-h] [--foo FOO] spam
   3718         '''
   3719     help = usage + '''\
   3720 
   3721         positional arguments:
   3722           spam
   3723 
   3724         optional arguments:
   3725           -h, --help  show this help message and exit
   3726           --foo FOO
   3727         '''
   3728     version = ''
   3729 
   3730 
   3731 class TestHelpTupleMetavar(HelpTestCase):
   3732     """Test specifying metavar as a tuple"""
   3733 
   3734     parser_signature = Sig(prog='PROG')
   3735     argument_signatures = [
   3736         Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
   3737         Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
   3738         Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
   3739         Sig('-z', help='z', nargs='?', metavar=('Z1', )),
   3740     ]
   3741     argument_group_signatures = []
   3742     usage = '''\
   3743         usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
   3744 [-z [Z1]]
   3745         '''
   3746     help = usage + '''\
   3747 
   3748         optional arguments:
   3749           -h, --help        show this help message and exit
   3750           -w W1 [W2 ...]    w
   3751           -x [X1 [X2 ...]]  x
   3752           -y Y1 Y2 Y3       y
   3753           -z [Z1]           z
   3754         '''
   3755     version = ''
   3756 
   3757 
   3758 class TestHelpRawText(HelpTestCase):
   3759     """Test the RawTextHelpFormatter"""
   3760 
   3761     parser_signature = Sig(
   3762         prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
   3763         description='Keep the formatting\n'
   3764                     '    exactly as it is written\n'
   3765                     '\n'
   3766                     'here\n')
   3767 
   3768     argument_signatures = [
   3769         Sig('--foo', help='    foo help should also\n'
   3770                           'appear as given here'),
   3771         Sig('spam', help='spam help'),
   3772     ]
   3773     argument_group_signatures = [
   3774         (Sig('title', description='    This text\n'
   3775                                   '  should be indented\n'
   3776                                   '    exactly like it is here\n'),
   3777          [Sig('--bar', help='bar help')]),
   3778     ]
   3779     usage = '''\
   3780         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3781         '''
   3782     help = usage + '''\
   3783 
   3784         Keep the formatting
   3785             exactly as it is written
   3786 
   3787         here
   3788 
   3789         positional arguments:
   3790           spam        spam help
   3791 
   3792         optional arguments:
   3793           -h, --help  show this help message and exit
   3794           --foo FOO       foo help should also
   3795                       appear as given here
   3796 
   3797         title:
   3798               This text
   3799             should be indented
   3800               exactly like it is here
   3801 
   3802           --bar BAR   bar help
   3803         '''
   3804     version = ''
   3805 
   3806 
   3807 class TestHelpRawDescription(HelpTestCase):
   3808     """Test the RawTextHelpFormatter"""
   3809 
   3810     parser_signature = Sig(
   3811         prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
   3812         description='Keep the formatting\n'
   3813                     '    exactly as it is written\n'
   3814                     '\n'
   3815                     'here\n')
   3816 
   3817     argument_signatures = [
   3818         Sig('--foo', help='  foo help should not\n'
   3819                           '    retain this odd formatting'),
   3820         Sig('spam', help='spam help'),
   3821     ]
   3822     argument_group_signatures = [
   3823         (Sig('title', description='    This text\n'
   3824                                   '  should be indented\n'
   3825                                   '    exactly like it is here\n'),
   3826          [Sig('--bar', help='bar help')]),
   3827     ]
   3828     usage = '''\
   3829         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3830         '''
   3831     help = usage + '''\
   3832 
   3833         Keep the formatting
   3834             exactly as it is written
   3835 
   3836         here
   3837 
   3838         positional arguments:
   3839           spam        spam help
   3840 
   3841         optional arguments:
   3842           -h, --help  show this help message and exit
   3843           --foo FOO   foo help should not retain this odd formatting
   3844 
   3845         title:
   3846               This text
   3847             should be indented
   3848               exactly like it is here
   3849 
   3850           --bar BAR   bar help
   3851         '''
   3852     version = ''
   3853 
   3854 
   3855 class TestHelpArgumentDefaults(HelpTestCase):
   3856     """Test the ArgumentDefaultsHelpFormatter"""
   3857 
   3858     parser_signature = Sig(
   3859         prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
   3860         description='description')
   3861 
   3862     argument_signatures = [
   3863         Sig('--foo', help='foo help - oh and by the way, %(default)s'),
   3864         Sig('--bar', action='store_true', help='bar help'),
   3865         Sig('spam', help='spam help'),
   3866         Sig('badger', nargs='?', default='wooden', help='badger help'),
   3867     ]
   3868     argument_group_signatures = [
   3869         (Sig('title', description='description'),
   3870          [Sig('--baz', type=int, default=42, help='baz help')]),
   3871     ]
   3872     usage = '''\
   3873         usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
   3874         '''
   3875     help = usage + '''\
   3876 
   3877         description
   3878 
   3879         positional arguments:
   3880           spam        spam help
   3881           badger      badger help (default: wooden)
   3882 
   3883         optional arguments:
   3884           -h, --help  show this help message and exit
   3885           --foo FOO   foo help - oh and by the way, None
   3886           --bar       bar help (default: False)
   3887 
   3888         title:
   3889           description
   3890 
   3891           --baz BAZ   baz help (default: 42)
   3892         '''
   3893     version = ''
   3894 
   3895 class TestHelpVersionAction(HelpTestCase):
   3896     """Test the default help for the version action"""
   3897 
   3898     parser_signature = Sig(prog='PROG', description='description')
   3899     argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
   3900     argument_group_signatures = []
   3901     usage = '''\
   3902         usage: PROG [-h] [-V]
   3903         '''
   3904     help = usage + '''\
   3905 
   3906         description
   3907 
   3908         optional arguments:
   3909           -h, --help     show this help message and exit
   3910           -V, --version  show program's version number and exit
   3911         '''
   3912     version = ''
   3913 
   3914 class TestHelpSubparsersOrdering(HelpTestCase):
   3915     """Test ordering of subcommands in help matches the code"""
   3916     parser_signature = Sig(prog='PROG',
   3917                            description='display some subcommands',
   3918                            version='0.1')
   3919 
   3920     subparsers_signatures = [Sig(name=name)
   3921                              for name in ('a', 'b', 'c', 'd', 'e')]
   3922 
   3923     usage = '''\
   3924         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   3925         '''
   3926 
   3927     help = usage + '''\
   3928 
   3929         display some subcommands
   3930 
   3931         positional arguments:
   3932           {a,b,c,d,e}
   3933 
   3934         optional arguments:
   3935           -h, --help     show this help message and exit
   3936           -v, --version  show program's version number and exit
   3937         '''
   3938 
   3939     version = '''\
   3940         0.1
   3941         '''
   3942 
   3943 class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
   3944     """Test ordering of subcommands in help matches the code"""
   3945     parser_signature = Sig(prog='PROG',
   3946                            description='display some subcommands',
   3947                            version='0.1')
   3948 
   3949     subcommand_data = (('a', 'a subcommand help'),
   3950                        ('b', 'b subcommand help'),
   3951                        ('c', 'c subcommand help'),
   3952                        ('d', 'd subcommand help'),
   3953                        ('e', 'e subcommand help'),
   3954                        )
   3955 
   3956     subparsers_signatures = [Sig(name=name, help=help)
   3957                              for name, help in subcommand_data]
   3958 
   3959     usage = '''\
   3960         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   3961         '''
   3962 
   3963     help = usage + '''\
   3964 
   3965         display some subcommands
   3966 
   3967         positional arguments:
   3968           {a,b,c,d,e}
   3969             a            a subcommand help
   3970             b            b subcommand help
   3971             c            c subcommand help
   3972             d            d subcommand help
   3973             e            e subcommand help
   3974 
   3975         optional arguments:
   3976           -h, --help     show this help message and exit
   3977           -v, --version  show program's version number and exit
   3978         '''
   3979 
   3980     version = '''\
   3981         0.1
   3982         '''
   3983 
   3984 
   3985 # =====================================
   3986 # Optional/Positional constructor tests
   3987 # =====================================
   3988 
   3989 class TestInvalidArgumentConstructors(TestCase):
   3990     """Test a bunch of invalid Argument constructors"""
   3991 
   3992     def assertTypeError(self, *args, **kwargs):
   3993         parser = argparse.ArgumentParser()
   3994         self.assertRaises(TypeError, parser.add_argument,
   3995                           *args, **kwargs)
   3996 
   3997     def assertValueError(self, *args, **kwargs):
   3998         parser = argparse.ArgumentParser()
   3999         self.assertRaises(ValueError, parser.add_argument,
   4000                           *args, **kwargs)
   4001 
   4002     def test_invalid_keyword_arguments(self):
   4003         self.assertTypeError('-x', bar=None)
   4004         self.assertTypeError('-y', callback='foo')
   4005         self.assertTypeError('-y', callback_args=())
   4006         self.assertTypeError('-y', callback_kwargs={})
   4007 
   4008     def test_missing_destination(self):
   4009         self.assertTypeError()
   4010         for action in ['append', 'store']:
   4011             self.assertTypeError(action=action)
   4012 
   4013     def test_invalid_option_strings(self):
   4014         self.assertValueError('--')
   4015         self.assertValueError('---')
   4016 
   4017     def test_invalid_type(self):
   4018         self.assertValueError('--foo', type='int')
   4019         self.assertValueError('--foo', type=(int, float))
   4020 
   4021     def test_invalid_action(self):
   4022         self.assertValueError('-x', action='foo')
   4023         self.assertValueError('foo', action='baz')
   4024         self.assertValueError('--foo', action=('store', 'append'))
   4025         parser = argparse.ArgumentParser()
   4026         try:
   4027             parser.add_argument("--foo", action="store-true")
   4028         except ValueError:
   4029             e = sys.exc_info()[1]
   4030             expected = 'unknown action'
   4031             msg = 'expected %r, found %r' % (expected, e)
   4032             self.assertTrue(expected in str(e), msg)
   4033 
   4034     def test_multiple_dest(self):
   4035         parser = argparse.ArgumentParser()
   4036         parser.add_argument(dest='foo')
   4037         try:
   4038             parser.add_argument('bar', dest='baz')
   4039         except ValueError:
   4040             e = sys.exc_info()[1]
   4041             expected = 'dest supplied twice for positional argument'
   4042             msg = 'expected %r, found %r' % (expected, e)
   4043             self.assertTrue(expected in str(e), msg)
   4044 
   4045     def test_no_argument_actions(self):
   4046         for action in ['store_const', 'store_true', 'store_false',
   4047                        'append_const', 'count']:
   4048             for attrs in [dict(type=int), dict(nargs='+'),
   4049                           dict(choices='ab')]:
   4050                 self.assertTypeError('-x', action=action, **attrs)
   4051 
   4052     def test_no_argument_no_const_actions(self):
   4053         # options with zero arguments
   4054         for action in ['store_true', 'store_false', 'count']:
   4055 
   4056             # const is always disallowed
   4057             self.assertTypeError('-x', const='foo', action=action)
   4058 
   4059             # nargs is always disallowed
   4060             self.assertTypeError('-x', nargs='*', action=action)
   4061 
   4062     def test_more_than_one_argument_actions(self):
   4063         for action in ['store', 'append']:
   4064 
   4065             # nargs=0 is disallowed
   4066             self.assertValueError('-x', nargs=0, action=action)
   4067             self.assertValueError('spam', nargs=0, action=action)
   4068 
   4069             # const is disallowed with non-optional arguments
   4070             for nargs in [1, '*', '+']:
   4071                 self.assertValueError('-x', const='foo',
   4072                                       nargs=nargs, action=action)
   4073                 self.assertValueError('spam', const='foo',
   4074                                       nargs=nargs, action=action)
   4075 
   4076     def test_required_const_actions(self):
   4077         for action in ['store_const', 'append_const']:
   4078 
   4079             # nargs is always disallowed
   4080             self.assertTypeError('-x', nargs='+', action=action)
   4081 
   4082     def test_parsers_action_missing_params(self):
   4083         self.assertTypeError('command', action='parsers')
   4084         self.assertTypeError('command', action='parsers', prog='PROG')
   4085         self.assertTypeError('command', action='parsers',
   4086                              parser_class=argparse.ArgumentParser)
   4087 
   4088     def test_required_positional(self):
   4089         self.assertTypeError('foo', required=True)
   4090 
   4091     def test_user_defined_action(self):
   4092 
   4093         class Success(Exception):
   4094             pass
   4095 
   4096         class Action(object):
   4097 
   4098             def __init__(self,
   4099                          option_strings,
   4100                          dest,
   4101                          const,
   4102                          default,
   4103                          required=False):
   4104                 if dest == 'spam':
   4105                     if const is Success:
   4106                         if default is Success:
   4107                             raise Success()
   4108 
   4109             def __call__(self, *args, **kwargs):
   4110                 pass
   4111 
   4112         parser = argparse.ArgumentParser()
   4113         self.assertRaises(Success, parser.add_argument, '--spam',
   4114                           action=Action, default=Success, const=Success)
   4115         self.assertRaises(Success, parser.add_argument, 'spam',
   4116                           action=Action, default=Success, const=Success)
   4117 
   4118 # ================================
   4119 # Actions returned by add_argument
   4120 # ================================
   4121 
   4122 class TestActionsReturned(TestCase):
   4123 
   4124     def test_dest(self):
   4125         parser = argparse.ArgumentParser()
   4126         action = parser.add_argument('--foo')
   4127         self.assertEqual(action.dest, 'foo')
   4128         action = parser.add_argument('-b', '--bar')
   4129         self.assertEqual(action.dest, 'bar')
   4130         action = parser.add_argument('-x', '-y')
   4131         self.assertEqual(action.dest, 'x')
   4132 
   4133     def test_misc(self):
   4134         parser = argparse.ArgumentParser()
   4135         action = parser.add_argument('--foo', nargs='?', const=42,
   4136                                      default=84, type=int, choices=[1, 2],
   4137                                      help='FOO', metavar='BAR', dest='baz')
   4138         self.assertEqual(action.nargs, '?')
   4139         self.assertEqual(action.const, 42)
   4140         self.assertEqual(action.default, 84)
   4141         self.assertEqual(action.type, int)
   4142         self.assertEqual(action.choices, [1, 2])
   4143         self.assertEqual(action.help, 'FOO')
   4144         self.assertEqual(action.metavar, 'BAR')
   4145         self.assertEqual(action.dest, 'baz')
   4146 
   4147 
   4148 # ================================
   4149 # Argument conflict handling tests
   4150 # ================================
   4151 
   4152 class TestConflictHandling(TestCase):
   4153 
   4154     def test_bad_type(self):
   4155         self.assertRaises(ValueError, argparse.ArgumentParser,
   4156                           conflict_handler='foo')
   4157 
   4158     def test_conflict_error(self):
   4159         parser = argparse.ArgumentParser()
   4160         parser.add_argument('-x')
   4161         self.assertRaises(argparse.ArgumentError,
   4162                           parser.add_argument, '-x')
   4163         parser.add_argument('--spam')
   4164         self.assertRaises(argparse.ArgumentError,
   4165                           parser.add_argument, '--spam')
   4166 
   4167     def test_resolve_error(self):
   4168         get_parser = argparse.ArgumentParser
   4169         parser = get_parser(prog='PROG', conflict_handler='resolve')
   4170 
   4171         parser.add_argument('-x', help='OLD X')
   4172         parser.add_argument('-x', help='NEW X')
   4173         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4174             usage: PROG [-h] [-x X]
   4175 
   4176             optional arguments:
   4177               -h, --help  show this help message and exit
   4178               -x X        NEW X
   4179             '''))
   4180 
   4181         parser.add_argument('--spam', metavar='OLD_SPAM')
   4182         parser.add_argument('--spam', metavar='NEW_SPAM')
   4183         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4184             usage: PROG [-h] [-x X] [--spam NEW_SPAM]
   4185 
   4186             optional arguments:
   4187               -h, --help       show this help message and exit
   4188               -x X             NEW X
   4189               --spam NEW_SPAM
   4190             '''))
   4191 
   4192 
   4193 # =============================
   4194 # Help and Version option tests
   4195 # =============================
   4196 
   4197 class TestOptionalsHelpVersionActions(TestCase):
   4198     """Test the help and version actions"""
   4199 
   4200     def _get_error(self, func, *args, **kwargs):
   4201         try:
   4202             func(*args, **kwargs)
   4203         except ArgumentParserError:
   4204             return sys.exc_info()[1]
   4205         else:
   4206             self.assertRaises(ArgumentParserError, func, *args, **kwargs)
   4207 
   4208     def assertPrintHelpExit(self, parser, args_str):
   4209         self.assertEqual(
   4210             parser.format_help(),
   4211             self._get_error(parser.parse_args, args_str.split()).stdout)
   4212 
   4213     def assertPrintVersionExit(self, parser, args_str):
   4214         self.assertEqual(
   4215             parser.format_version(),
   4216             self._get_error(parser.parse_args, args_str.split()).stderr)
   4217 
   4218     def assertArgumentParserError(self, parser, *args):
   4219         self.assertRaises(ArgumentParserError, parser.parse_args, args)
   4220 
   4221     def test_version(self):
   4222         parser = ErrorRaisingArgumentParser(version='1.0')
   4223         self.assertPrintHelpExit(parser, '-h')
   4224         self.assertPrintHelpExit(parser, '--help')
   4225         self.assertPrintVersionExit(parser, '-v')
   4226         self.assertPrintVersionExit(parser, '--version')
   4227 
   4228     def test_version_format(self):
   4229         parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
   4230         msg = self._get_error(parser.parse_args, ['-v']).stderr
   4231         self.assertEqual('PPP 3.5\n', msg)
   4232 
   4233     def test_version_no_help(self):
   4234         parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
   4235         self.assertArgumentParserError(parser, '-h')
   4236         self.assertArgumentParserError(parser, '--help')
   4237         self.assertPrintVersionExit(parser, '-v')
   4238         self.assertPrintVersionExit(parser, '--version')
   4239 
   4240     def test_version_action(self):
   4241         parser = ErrorRaisingArgumentParser(prog='XXX')
   4242         parser.add_argument('-V', action='version', version='%(prog)s 3.7')
   4243         msg = self._get_error(parser.parse_args, ['-V']).stderr
   4244         self.assertEqual('XXX 3.7\n', msg)
   4245 
   4246     def test_no_help(self):
   4247         parser = ErrorRaisingArgumentParser(add_help=False)
   4248         self.assertArgumentParserError(parser, '-h')
   4249         self.assertArgumentParserError(parser, '--help')
   4250         self.assertArgumentParserError(parser, '-v')
   4251         self.assertArgumentParserError(parser, '--version')
   4252 
   4253     def test_alternate_help_version(self):
   4254         parser = ErrorRaisingArgumentParser()
   4255         parser.add_argument('-x', action='help')
   4256         parser.add_argument('-y', action='version')
   4257         self.assertPrintHelpExit(parser, '-x')
   4258         self.assertPrintVersionExit(parser, '-y')
   4259         self.assertArgumentParserError(parser, '-v')
   4260         self.assertArgumentParserError(parser, '--version')
   4261 
   4262     def test_help_version_extra_arguments(self):
   4263         parser = ErrorRaisingArgumentParser(version='1.0')
   4264         parser.add_argument('-x', action='store_true')
   4265         parser.add_argument('y')
   4266 
   4267         # try all combinations of valid prefixes and suffixes
   4268         valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
   4269         valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
   4270         for prefix in valid_prefixes:
   4271             for suffix in valid_suffixes:
   4272                 format = '%s %%s %s' % (prefix, suffix)
   4273             self.assertPrintHelpExit(parser, format % '-h')
   4274             self.assertPrintHelpExit(parser, format % '--help')
   4275             self.assertPrintVersionExit(parser, format % '-v')
   4276             self.assertPrintVersionExit(parser, format % '--version')
   4277 
   4278 
   4279 # ======================
   4280 # str() and repr() tests
   4281 # ======================
   4282 
   4283 class TestStrings(TestCase):
   4284     """Test str()  and repr() on Optionals and Positionals"""
   4285 
   4286     def assertStringEqual(self, obj, result_string):
   4287         for func in [str, repr]:
   4288             self.assertEqual(func(obj), result_string)
   4289 
   4290     def test_optional(self):
   4291         option = argparse.Action(
   4292             option_strings=['--foo', '-a', '-b'],
   4293             dest='b',
   4294             type='int',
   4295             nargs='+',
   4296             default=42,
   4297             choices=[1, 2, 3],
   4298             help='HELP',
   4299             metavar='METAVAR')
   4300         string = (
   4301             "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
   4302             "nargs='+', const=None, default=42, type='int', "
   4303             "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
   4304         self.assertStringEqual(option, string)
   4305 
   4306     def test_argument(self):
   4307         argument = argparse.Action(
   4308             option_strings=[],
   4309             dest='x',
   4310             type=float,
   4311             nargs='?',
   4312             default=2.5,
   4313             choices=[0.5, 1.5, 2.5],
   4314             help='H HH H',
   4315             metavar='MV MV MV')
   4316         string = (
   4317             "Action(option_strings=[], dest='x', nargs='?', "
   4318             "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
   4319             "help='H HH H', metavar='MV MV MV')" % float)
   4320         self.assertStringEqual(argument, string)
   4321 
   4322     def test_namespace(self):
   4323         ns = argparse.Namespace(foo=42, bar='spam')
   4324         string = "Namespace(bar='spam', foo=42)"
   4325         self.assertStringEqual(ns, string)
   4326 
   4327     def test_parser(self):
   4328         parser = argparse.ArgumentParser(prog='PROG')
   4329         string = (
   4330             "ArgumentParser(prog='PROG', usage=None, description=None, "
   4331             "version=None, formatter_class=%r, conflict_handler='error', "
   4332             "add_help=True)" % argparse.HelpFormatter)
   4333         self.assertStringEqual(parser, string)
   4334 
   4335 # ===============
   4336 # Namespace tests
   4337 # ===============
   4338 
   4339 class TestNamespace(TestCase):
   4340 
   4341     def test_constructor(self):
   4342         ns = argparse.Namespace()
   4343         self.assertRaises(AttributeError, getattr, ns, 'x')
   4344 
   4345         ns = argparse.Namespace(a=42, b='spam')
   4346         self.assertEqual(ns.a, 42)
   4347         self.assertEqual(ns.b, 'spam')
   4348 
   4349     def test_equality(self):
   4350         ns1 = argparse.Namespace(a=1, b=2)
   4351         ns2 = argparse.Namespace(b=2, a=1)
   4352         ns3 = argparse.Namespace(a=1)
   4353         ns4 = argparse.Namespace(b=2)
   4354 
   4355         self.assertEqual(ns1, ns2)
   4356         self.assertNotEqual(ns1, ns3)
   4357         self.assertNotEqual(ns1, ns4)
   4358         self.assertNotEqual(ns2, ns3)
   4359         self.assertNotEqual(ns2, ns4)
   4360         self.assertTrue(ns1 != ns3)
   4361         self.assertTrue(ns1 != ns4)
   4362         self.assertTrue(ns2 != ns3)
   4363         self.assertTrue(ns2 != ns4)
   4364 
   4365 
   4366 # ===================
   4367 # File encoding tests
   4368 # ===================
   4369 
   4370 class TestEncoding(TestCase):
   4371 
   4372     def _test_module_encoding(self, path):
   4373         path, _ = os.path.splitext(path)
   4374         path += ".py"
   4375         with codecs.open(path, 'r', 'utf8') as f:
   4376             f.read()
   4377 
   4378     def test_argparse_module_encoding(self):
   4379         self._test_module_encoding(argparse.__file__)
   4380 
   4381     def test_test_argparse_module_encoding(self):
   4382         self._test_module_encoding(__file__)
   4383 
   4384 # ===================
   4385 # ArgumentError tests
   4386 # ===================
   4387 
   4388 class TestArgumentError(TestCase):
   4389 
   4390     def test_argument_error(self):
   4391         msg = "my error here"
   4392         error = argparse.ArgumentError(None, msg)
   4393         self.assertEqual(str(error), msg)
   4394 
   4395 # =======================
   4396 # ArgumentTypeError tests
   4397 # =======================
   4398 
   4399 class TestArgumentTypeError(TestCase):
   4400 
   4401     def test_argument_type_error(self):
   4402 
   4403         def spam(string):
   4404             raise argparse.ArgumentTypeError('spam!')
   4405 
   4406         parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
   4407         parser.add_argument('x', type=spam)
   4408         try:
   4409             parser.parse_args(['XXX'])
   4410         except ArgumentParserError:
   4411             expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
   4412             msg = sys.exc_info()[1].stderr
   4413             self.assertEqual(expected, msg)
   4414         else:
   4415             self.fail()
   4416 
   4417 # ======================
   4418 # parse_known_args tests
   4419 # ======================
   4420 
   4421 class TestParseKnownArgs(TestCase):
   4422 
   4423     def test_optionals(self):
   4424         parser = argparse.ArgumentParser()
   4425         parser.add_argument('--foo')
   4426         args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
   4427         self.assertEqual(NS(foo='F'), args)
   4428         self.assertEqual(['--bar', '--baz'], extras)
   4429 
   4430     def test_mixed(self):
   4431         parser = argparse.ArgumentParser()
   4432         parser.add_argument('-v', nargs='?', const=1, type=int)
   4433         parser.add_argument('--spam', action='store_false')
   4434         parser.add_argument('badger')
   4435 
   4436         argv = ["B", "C", "--foo", "-v", "3", "4"]
   4437         args, extras = parser.parse_known_args(argv)
   4438         self.assertEqual(NS(v=3, spam=True, badger="B"), args)
   4439         self.assertEqual(["C", "--foo", "4"], extras)
   4440 
   4441 # ==========================
   4442 # add_argument metavar tests
   4443 # ==========================
   4444 
   4445 class TestAddArgumentMetavar(TestCase):
   4446 
   4447     EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
   4448 
   4449     def do_test_no_exception(self, nargs, metavar):
   4450         parser = argparse.ArgumentParser()
   4451         parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4452 
   4453     def do_test_exception(self, nargs, metavar):
   4454         parser = argparse.ArgumentParser()
   4455         with self.assertRaises(ValueError) as cm:
   4456             parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4457         self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
   4458 
   4459     # Unit tests for different values of metavar when nargs=None
   4460 
   4461     def test_nargs_None_metavar_string(self):
   4462         self.do_test_no_exception(nargs=None, metavar="1")
   4463 
   4464     def test_nargs_None_metavar_length0(self):
   4465         self.do_test_exception(nargs=None, metavar=tuple())
   4466 
   4467     def test_nargs_None_metavar_length1(self):
   4468         self.do_test_no_exception(nargs=None, metavar=("1"))
   4469 
   4470     def test_nargs_None_metavar_length2(self):
   4471         self.do_test_exception(nargs=None, metavar=("1", "2"))
   4472 
   4473     def test_nargs_None_metavar_length3(self):
   4474         self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
   4475 
   4476     # Unit tests for different values of metavar when nargs=?
   4477 
   4478     def test_nargs_optional_metavar_string(self):
   4479         self.do_test_no_exception(nargs="?", metavar="1")
   4480 
   4481     def test_nargs_optional_metavar_length0(self):
   4482         self.do_test_exception(nargs="?", metavar=tuple())
   4483 
   4484     def test_nargs_optional_metavar_length1(self):
   4485         self.do_test_no_exception(nargs="?", metavar=("1"))
   4486 
   4487     def test_nargs_optional_metavar_length2(self):
   4488         self.do_test_exception(nargs="?", metavar=("1", "2"))
   4489 
   4490     def test_nargs_optional_metavar_length3(self):
   4491         self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
   4492 
   4493     # Unit tests for different values of metavar when nargs=*
   4494 
   4495     def test_nargs_zeroormore_metavar_string(self):
   4496         self.do_test_no_exception(nargs="*", metavar="1")
   4497 
   4498     def test_nargs_zeroormore_metavar_length0(self):
   4499         self.do_test_exception(nargs="*", metavar=tuple())
   4500 
   4501     def test_nargs_zeroormore_metavar_length1(self):
   4502         self.do_test_no_exception(nargs="*", metavar=("1"))
   4503 
   4504     def test_nargs_zeroormore_metavar_length2(self):
   4505         self.do_test_no_exception(nargs="*", metavar=("1", "2"))
   4506 
   4507     def test_nargs_zeroormore_metavar_length3(self):
   4508         self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
   4509 
   4510     # Unit tests for different values of metavar when nargs=+
   4511 
   4512     def test_nargs_oneormore_metavar_string(self):
   4513         self.do_test_no_exception(nargs="+", metavar="1")
   4514 
   4515     def test_nargs_oneormore_metavar_length0(self):
   4516         self.do_test_exception(nargs="+", metavar=tuple())
   4517 
   4518     def test_nargs_oneormore_metavar_length1(self):
   4519         self.do_test_no_exception(nargs="+", metavar=("1"))
   4520 
   4521     def test_nargs_oneormore_metavar_length2(self):
   4522         self.do_test_no_exception(nargs="+", metavar=("1", "2"))
   4523 
   4524     def test_nargs_oneormore_metavar_length3(self):
   4525         self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
   4526 
   4527     # Unit tests for different values of metavar when nargs=...
   4528 
   4529     def test_nargs_remainder_metavar_string(self):
   4530         self.do_test_no_exception(nargs="...", metavar="1")
   4531 
   4532     def test_nargs_remainder_metavar_length0(self):
   4533         self.do_test_no_exception(nargs="...", metavar=tuple())
   4534 
   4535     def test_nargs_remainder_metavar_length1(self):
   4536         self.do_test_no_exception(nargs="...", metavar=("1"))
   4537 
   4538     def test_nargs_remainder_metavar_length2(self):
   4539         self.do_test_no_exception(nargs="...", metavar=("1", "2"))
   4540 
   4541     def test_nargs_remainder_metavar_length3(self):
   4542         self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
   4543 
   4544     # Unit tests for different values of metavar when nargs=A...
   4545 
   4546     def test_nargs_parser_metavar_string(self):
   4547         self.do_test_no_exception(nargs="A...", metavar="1")
   4548 
   4549     def test_nargs_parser_metavar_length0(self):
   4550         self.do_test_exception(nargs="A...", metavar=tuple())
   4551 
   4552     def test_nargs_parser_metavar_length1(self):
   4553         self.do_test_no_exception(nargs="A...", metavar=("1"))
   4554 
   4555     def test_nargs_parser_metavar_length2(self):
   4556         self.do_test_exception(nargs="A...", metavar=("1", "2"))
   4557 
   4558     def test_nargs_parser_metavar_length3(self):
   4559         self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
   4560 
   4561     # Unit tests for different values of metavar when nargs=1
   4562 
   4563     def test_nargs_1_metavar_string(self):
   4564         self.do_test_no_exception(nargs=1, metavar="1")
   4565 
   4566     def test_nargs_1_metavar_length0(self):
   4567         self.do_test_exception(nargs=1, metavar=tuple())
   4568 
   4569     def test_nargs_1_metavar_length1(self):
   4570         self.do_test_no_exception(nargs=1, metavar=("1"))
   4571 
   4572     def test_nargs_1_metavar_length2(self):
   4573         self.do_test_exception(nargs=1, metavar=("1", "2"))
   4574 
   4575     def test_nargs_1_metavar_length3(self):
   4576         self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
   4577 
   4578     # Unit tests for different values of metavar when nargs=2
   4579 
   4580     def test_nargs_2_metavar_string(self):
   4581         self.do_test_no_exception(nargs=2, metavar="1")
   4582 
   4583     def test_nargs_2_metavar_length0(self):
   4584         self.do_test_exception(nargs=2, metavar=tuple())
   4585 
   4586     def test_nargs_2_metavar_length1(self):
   4587         self.do_test_no_exception(nargs=2, metavar=("1"))
   4588 
   4589     def test_nargs_2_metavar_length2(self):
   4590         self.do_test_no_exception(nargs=2, metavar=("1", "2"))
   4591 
   4592     def test_nargs_2_metavar_length3(self):
   4593         self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
   4594 
   4595     # Unit tests for different values of metavar when nargs=3
   4596 
   4597     def test_nargs_3_metavar_string(self):
   4598         self.do_test_no_exception(nargs=3, metavar="1")
   4599 
   4600     def test_nargs_3_metavar_length0(self):
   4601         self.do_test_exception(nargs=3, metavar=tuple())
   4602 
   4603     def test_nargs_3_metavar_length1(self):
   4604         self.do_test_no_exception(nargs=3, metavar=("1"))
   4605 
   4606     def test_nargs_3_metavar_length2(self):
   4607         self.do_test_exception(nargs=3, metavar=("1", "2"))
   4608 
   4609     def test_nargs_3_metavar_length3(self):
   4610         self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
   4611 
   4612 # ============================
   4613 # from argparse import * tests
   4614 # ============================
   4615 
   4616 class TestImportStar(TestCase):
   4617 
   4618     def test(self):
   4619         for name in argparse.__all__:
   4620             self.assertTrue(hasattr(argparse, name))
   4621 
   4622     def test_all_exports_everything_but_modules(self):
   4623         items = [
   4624             name
   4625             for name, value in vars(argparse).items()
   4626             if not name.startswith("_")
   4627             if not inspect.ismodule(value)
   4628         ]
   4629         self.assertEqual(sorted(items), sorted(argparse.__all__))
   4630 
   4631 def test_main():
   4632     # silence warnings about version argument - these are expected
   4633     with test_support.check_warnings(
   4634             ('The "version" argument to ArgumentParser is deprecated.',
   4635              DeprecationWarning),
   4636             ('The (format|print)_version method is deprecated',
   4637              DeprecationWarning)):
   4638         test_support.run_unittest(__name__)
   4639     # Remove global references to avoid looking like we have refleaks.
   4640     RFile.seen = {}
   4641     WFile.seen = set()
   4642 
   4643 
   4644 
   4645 if __name__ == '__main__':
   4646     test_main()
   4647