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         (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
   1378     ]
   1379 
   1380 
   1381 class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
   1382     """Test reading arguments from a file"""
   1383 
   1384     def setUp(self):
   1385         super(TestArgumentsFromFileConverter, self).setUp()
   1386         file_texts = [
   1387             ('hello', 'hello world!\n'),
   1388         ]
   1389         for path, text in file_texts:
   1390             file = open(path, 'w')
   1391             file.write(text)
   1392             file.close()
   1393 
   1394     class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
   1395 
   1396         def convert_arg_line_to_args(self, arg_line):
   1397             for arg in arg_line.split():
   1398                 if not arg.strip():
   1399                     continue
   1400                 yield arg
   1401     parser_class = FromFileConverterArgumentParser
   1402     parser_signature = Sig(fromfile_prefix_chars='@')
   1403     argument_signatures = [
   1404         Sig('y', nargs='+'),
   1405     ]
   1406     failures = []
   1407     successes = [
   1408         ('@hello X', NS(y=['hello', 'world!', 'X'])),
   1409     ]
   1410 
   1411 
   1412 # =====================
   1413 # Type conversion tests
   1414 # =====================
   1415 
   1416 class TestFileTypeRepr(TestCase):
   1417 
   1418     def test_r(self):
   1419         type = argparse.FileType('r')
   1420         self.assertEqual("FileType('r')", repr(type))
   1421 
   1422     def test_wb_1(self):
   1423         type = argparse.FileType('wb', 1)
   1424         self.assertEqual("FileType('wb', 1)", repr(type))
   1425 
   1426 
   1427 class RFile(object):
   1428     seen = {}
   1429 
   1430     def __init__(self, name):
   1431         self.name = name
   1432 
   1433     __hash__ = None
   1434 
   1435     def __eq__(self, other):
   1436         if other in self.seen:
   1437             text = self.seen[other]
   1438         else:
   1439             text = self.seen[other] = other.read()
   1440             other.close()
   1441         if not isinstance(text, str):
   1442             text = text.decode('ascii')
   1443         return self.name == other.name == text
   1444 
   1445 
   1446 class TestFileTypeR(TempDirMixin, ParserTestCase):
   1447     """Test the FileType option/argument type for reading files"""
   1448 
   1449     def setUp(self):
   1450         super(TestFileTypeR, self).setUp()
   1451         for file_name in ['foo', 'bar']:
   1452             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1453             file.write(file_name)
   1454             file.close()
   1455         self.create_readonly_file('readonly')
   1456 
   1457     argument_signatures = [
   1458         Sig('-x', type=argparse.FileType()),
   1459         Sig('spam', type=argparse.FileType('r')),
   1460     ]
   1461     failures = ['-x', '-x bar', 'non-existent-file.txt']
   1462     successes = [
   1463         ('foo', NS(x=None, spam=RFile('foo'))),
   1464         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1465         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1466         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1467         ('readonly', NS(x=None, spam=RFile('readonly'))),
   1468     ]
   1469 
   1470 class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
   1471     """Test that a file is not created unless the default is needed"""
   1472     def setUp(self):
   1473         super(TestFileTypeDefaults, self).setUp()
   1474         file = open(os.path.join(self.temp_dir, 'good'), 'w')
   1475         file.write('good')
   1476         file.close()
   1477 
   1478     argument_signatures = [
   1479         Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
   1480     ]
   1481     # should provoke no such file error
   1482     failures = ['']
   1483     # should not provoke error because default file is created
   1484     successes = [('-c good', NS(c=RFile('good')))]
   1485 
   1486 
   1487 class TestFileTypeRB(TempDirMixin, ParserTestCase):
   1488     """Test the FileType option/argument type for reading files"""
   1489 
   1490     def setUp(self):
   1491         super(TestFileTypeRB, self).setUp()
   1492         for file_name in ['foo', 'bar']:
   1493             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1494             file.write(file_name)
   1495             file.close()
   1496 
   1497     argument_signatures = [
   1498         Sig('-x', type=argparse.FileType('rb')),
   1499         Sig('spam', type=argparse.FileType('rb')),
   1500     ]
   1501     failures = ['-x', '-x bar']
   1502     successes = [
   1503         ('foo', NS(x=None, spam=RFile('foo'))),
   1504         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1505         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1506         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1507     ]
   1508 
   1509 
   1510 class WFile(object):
   1511     seen = set()
   1512 
   1513     def __init__(self, name):
   1514         self.name = name
   1515 
   1516     __hash__ = None
   1517 
   1518     def __eq__(self, other):
   1519         if other not in self.seen:
   1520             text = 'Check that file is writable.'
   1521             if 'b' in other.mode:
   1522                 text = text.encode('ascii')
   1523             other.write(text)
   1524             other.close()
   1525             self.seen.add(other)
   1526         return self.name == other.name
   1527 
   1528 
   1529 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
   1530                  "non-root user required")
   1531 class TestFileTypeW(TempDirMixin, ParserTestCase):
   1532     """Test the FileType option/argument type for writing files"""
   1533 
   1534     def setUp(self):
   1535         super(TestFileTypeW, self).setUp()
   1536         self.create_readonly_file('readonly')
   1537 
   1538     argument_signatures = [
   1539         Sig('-x', type=argparse.FileType('w')),
   1540         Sig('spam', type=argparse.FileType('w')),
   1541     ]
   1542     failures = ['-x', '-x bar']
   1543     failures = ['-x', '-x bar', 'readonly']
   1544     successes = [
   1545         ('foo', NS(x=None, spam=WFile('foo'))),
   1546         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1547         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1548         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1549     ]
   1550 
   1551 
   1552 class TestFileTypeWB(TempDirMixin, ParserTestCase):
   1553 
   1554     argument_signatures = [
   1555         Sig('-x', type=argparse.FileType('wb')),
   1556         Sig('spam', type=argparse.FileType('wb')),
   1557     ]
   1558     failures = ['-x', '-x bar']
   1559     successes = [
   1560         ('foo', NS(x=None, spam=WFile('foo'))),
   1561         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1562         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1563         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1564     ]
   1565 
   1566 
   1567 class TestTypeCallable(ParserTestCase):
   1568     """Test some callables as option/argument types"""
   1569 
   1570     argument_signatures = [
   1571         Sig('--eggs', type=complex),
   1572         Sig('spam', type=float),
   1573     ]
   1574     failures = ['a', '42j', '--eggs a', '--eggs 2i']
   1575     successes = [
   1576         ('--eggs=42 42', NS(eggs=42, spam=42.0)),
   1577         ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
   1578         ('1024.675', NS(eggs=None, spam=1024.675)),
   1579     ]
   1580 
   1581 
   1582 class TestTypeUserDefined(ParserTestCase):
   1583     """Test a user-defined option/argument type"""
   1584 
   1585     class MyType(TestCase):
   1586 
   1587         def __init__(self, value):
   1588             self.value = value
   1589 
   1590         __hash__ = None
   1591 
   1592         def __eq__(self, other):
   1593             return (type(self), self.value) == (type(other), other.value)
   1594 
   1595     argument_signatures = [
   1596         Sig('-x', type=MyType),
   1597         Sig('spam', type=MyType),
   1598     ]
   1599     failures = []
   1600     successes = [
   1601         ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
   1602         ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
   1603     ]
   1604 
   1605 
   1606 class TestTypeClassicClass(ParserTestCase):
   1607     """Test a classic class type"""
   1608 
   1609     class C:
   1610 
   1611         def __init__(self, value):
   1612             self.value = value
   1613 
   1614         __hash__ = None
   1615 
   1616         def __eq__(self, other):
   1617             return (type(self), self.value) == (type(other), other.value)
   1618 
   1619     argument_signatures = [
   1620         Sig('-x', type=C),
   1621         Sig('spam', type=C),
   1622     ]
   1623     failures = []
   1624     successes = [
   1625         ('a -x b', NS(x=C('b'), spam=C('a'))),
   1626         ('-xf g', NS(x=C('f'), spam=C('g'))),
   1627     ]
   1628 
   1629 
   1630 class TestTypeRegistration(TestCase):
   1631     """Test a user-defined type by registering it"""
   1632 
   1633     def test(self):
   1634 
   1635         def get_my_type(string):
   1636             return 'my_type{%s}' % string
   1637 
   1638         parser = argparse.ArgumentParser()
   1639         parser.register('type', 'my_type', get_my_type)
   1640         parser.add_argument('-x', type='my_type')
   1641         parser.add_argument('y', type='my_type')
   1642 
   1643         self.assertEqual(parser.parse_args('1'.split()),
   1644                          NS(x=None, y='my_type{1}'))
   1645         self.assertEqual(parser.parse_args('-x 1 42'.split()),
   1646                          NS(x='my_type{1}', y='my_type{42}'))
   1647 
   1648 
   1649 # ============
   1650 # Action tests
   1651 # ============
   1652 
   1653 class TestActionUserDefined(ParserTestCase):
   1654     """Test a user-defined option/argument action"""
   1655 
   1656     class OptionalAction(argparse.Action):
   1657 
   1658         def __call__(self, parser, namespace, value, option_string=None):
   1659             try:
   1660                 # check destination and option string
   1661                 assert self.dest == 'spam', 'dest: %s' % self.dest
   1662                 assert option_string == '-s', 'flag: %s' % option_string
   1663                 # when option is before argument, badger=2, and when
   1664                 # option is after argument, badger=<whatever was set>
   1665                 expected_ns = NS(spam=0.25)
   1666                 if value in [0.125, 0.625]:
   1667                     expected_ns.badger = 2
   1668                 elif value in [2.0]:
   1669                     expected_ns.badger = 84
   1670                 else:
   1671                     raise AssertionError('value: %s' % value)
   1672                 assert expected_ns == namespace, ('expected %s, got %s' %
   1673                                                   (expected_ns, namespace))
   1674             except AssertionError:
   1675                 e = sys.exc_info()[1]
   1676                 raise ArgumentParserError('opt_action failed: %s' % e)
   1677             setattr(namespace, 'spam', value)
   1678 
   1679     class PositionalAction(argparse.Action):
   1680 
   1681         def __call__(self, parser, namespace, value, option_string=None):
   1682             try:
   1683                 assert option_string is None, ('option_string: %s' %
   1684                                                option_string)
   1685                 # check destination
   1686                 assert self.dest == 'badger', 'dest: %s' % self.dest
   1687                 # when argument is before option, spam=0.25, and when
   1688                 # option is after argument, spam=<whatever was set>
   1689                 expected_ns = NS(badger=2)
   1690                 if value in [42, 84]:
   1691                     expected_ns.spam = 0.25
   1692                 elif value in [1]:
   1693                     expected_ns.spam = 0.625
   1694                 elif value in [2]:
   1695                     expected_ns.spam = 0.125
   1696                 else:
   1697                     raise AssertionError('value: %s' % value)
   1698                 assert expected_ns == namespace, ('expected %s, got %s' %
   1699                                                   (expected_ns, namespace))
   1700             except AssertionError:
   1701                 e = sys.exc_info()[1]
   1702                 raise ArgumentParserError('arg_action failed: %s' % e)
   1703             setattr(namespace, 'badger', value)
   1704 
   1705     argument_signatures = [
   1706         Sig('-s', dest='spam', action=OptionalAction,
   1707             type=float, default=0.25),
   1708         Sig('badger', action=PositionalAction,
   1709             type=int, nargs='?', default=2),
   1710     ]
   1711     failures = []
   1712     successes = [
   1713         ('-s0.125', NS(spam=0.125, badger=2)),
   1714         ('42', NS(spam=0.25, badger=42)),
   1715         ('-s 0.625 1', NS(spam=0.625, badger=1)),
   1716         ('84 -s2', NS(spam=2.0, badger=84)),
   1717     ]
   1718 
   1719 
   1720 class TestActionRegistration(TestCase):
   1721     """Test a user-defined action supplied by registering it"""
   1722 
   1723     class MyAction(argparse.Action):
   1724 
   1725         def __call__(self, parser, namespace, values, option_string=None):
   1726             setattr(namespace, self.dest, 'foo[%s]' % values)
   1727 
   1728     def test(self):
   1729 
   1730         parser = argparse.ArgumentParser()
   1731         parser.register('action', 'my_action', self.MyAction)
   1732         parser.add_argument('badger', action='my_action')
   1733 
   1734         self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
   1735         self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
   1736 
   1737 
   1738 # ================
   1739 # Subparsers tests
   1740 # ================
   1741 
   1742 class TestAddSubparsers(TestCase):
   1743     """Test the add_subparsers method"""
   1744 
   1745     def assertArgumentParserError(self, *args, **kwargs):
   1746         self.assertRaises(ArgumentParserError, *args, **kwargs)
   1747 
   1748     def _get_parser(self, subparser_help=False, prefix_chars=None):
   1749         # create a parser with a subparsers argument
   1750         if prefix_chars:
   1751             parser = ErrorRaisingArgumentParser(
   1752                 prog='PROG', description='main description', prefix_chars=prefix_chars)
   1753             parser.add_argument(
   1754                 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
   1755         else:
   1756             parser = ErrorRaisingArgumentParser(
   1757                 prog='PROG', description='main description')
   1758             parser.add_argument(
   1759                 '--foo', action='store_true', help='foo help')
   1760         parser.add_argument(
   1761             'bar', type=float, help='bar help')
   1762 
   1763         # check that only one subparsers argument can be added
   1764         subparsers = parser.add_subparsers(help='command help')
   1765         self.assertArgumentParserError(parser.add_subparsers)
   1766 
   1767         # add first sub-parser
   1768         parser1_kwargs = dict(description='1 description')
   1769         if subparser_help:
   1770             parser1_kwargs['help'] = '1 help'
   1771         parser1 = subparsers.add_parser('1', **parser1_kwargs)
   1772         parser1.add_argument('-w', type=int, help='w help')
   1773         parser1.add_argument('x', choices='abc', help='x help')
   1774 
   1775         # add second sub-parser
   1776         parser2_kwargs = dict(description='2 description')
   1777         if subparser_help:
   1778             parser2_kwargs['help'] = '2 help'
   1779         parser2 = subparsers.add_parser('2', **parser2_kwargs)
   1780         parser2.add_argument('-y', choices='123', help='y help')
   1781         parser2.add_argument('z', type=complex, nargs='*', help='z help')
   1782 
   1783         # add third sub-parser
   1784         parser3_kwargs = dict(description='3 description')
   1785         if subparser_help:
   1786             parser3_kwargs['help'] = '3 help'
   1787         parser3 = subparsers.add_parser('3', **parser3_kwargs)
   1788         parser3.add_argument('t', type=int, help='t help')
   1789         parser3.add_argument('u', nargs='...', help='u help')
   1790 
   1791         # return the main parser
   1792         return parser
   1793 
   1794     def setUp(self):
   1795         super(TestAddSubparsers, self).setUp()
   1796         self.parser = self._get_parser()
   1797         self.command_help_parser = self._get_parser(subparser_help=True)
   1798 
   1799     def test_parse_args_failures(self):
   1800         # check some failure cases:
   1801         for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
   1802                          '0.5 1 -y', '0.5 2 -w']:
   1803             args = args_str.split()
   1804             self.assertArgumentParserError(self.parser.parse_args, args)
   1805 
   1806     def test_parse_args(self):
   1807         # check some non-failure cases:
   1808         self.assertEqual(
   1809             self.parser.parse_args('0.5 1 b -w 7'.split()),
   1810             NS(foo=False, bar=0.5, w=7, x='b'),
   1811         )
   1812         self.assertEqual(
   1813             self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
   1814             NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
   1815         )
   1816         self.assertEqual(
   1817             self.parser.parse_args('--foo 0.125 1 c'.split()),
   1818             NS(foo=True, bar=0.125, w=None, x='c'),
   1819         )
   1820         self.assertEqual(
   1821             self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
   1822             NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
   1823         )
   1824 
   1825     def test_parse_known_args(self):
   1826         self.assertEqual(
   1827             self.parser.parse_known_args('0.5 1 b -w 7'.split()),
   1828             (NS(foo=False, bar=0.5, w=7, x='b'), []),
   1829         )
   1830         self.assertEqual(
   1831             self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
   1832             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1833         )
   1834         self.assertEqual(
   1835             self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
   1836             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1837         )
   1838         self.assertEqual(
   1839             self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
   1840             (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
   1841         )
   1842         self.assertEqual(
   1843             self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
   1844             (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
   1845         )
   1846 
   1847     def test_dest(self):
   1848         parser = ErrorRaisingArgumentParser()
   1849         parser.add_argument('--foo', action='store_true')
   1850         subparsers = parser.add_subparsers(dest='bar')
   1851         parser1 = subparsers.add_parser('1')
   1852         parser1.add_argument('baz')
   1853         self.assertEqual(NS(foo=False, bar='1', baz='2'),
   1854                          parser.parse_args('1 2'.split()))
   1855 
   1856     def test_help(self):
   1857         self.assertEqual(self.parser.format_usage(),
   1858                          'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
   1859         self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
   1860             usage: PROG [-h] [--foo] bar {1,2,3} ...
   1861 
   1862             main description
   1863 
   1864             positional arguments:
   1865               bar         bar help
   1866               {1,2,3}     command help
   1867 
   1868             optional arguments:
   1869               -h, --help  show this help message and exit
   1870               --foo       foo help
   1871             '''))
   1872 
   1873     def test_help_extra_prefix_chars(self):
   1874         # Make sure - is still used for help if it is a non-first prefix char
   1875         parser = self._get_parser(prefix_chars='+:-')
   1876         self.assertEqual(parser.format_usage(),
   1877                          'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
   1878         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1879             usage: PROG [-h] [++foo] bar {1,2,3} ...
   1880 
   1881             main description
   1882 
   1883             positional arguments:
   1884               bar         bar help
   1885               {1,2,3}     command help
   1886 
   1887             optional arguments:
   1888               -h, --help  show this help message and exit
   1889               ++foo       foo help
   1890             '''))
   1891 
   1892 
   1893     def test_help_alternate_prefix_chars(self):
   1894         parser = self._get_parser(prefix_chars='+:/')
   1895         self.assertEqual(parser.format_usage(),
   1896                          'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
   1897         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1898             usage: PROG [+h] [++foo] bar {1,2,3} ...
   1899 
   1900             main description
   1901 
   1902             positional arguments:
   1903               bar         bar help
   1904               {1,2,3}     command help
   1905 
   1906             optional arguments:
   1907               +h, ++help  show this help message and exit
   1908               ++foo       foo help
   1909             '''))
   1910 
   1911     def test_parser_command_help(self):
   1912         self.assertEqual(self.command_help_parser.format_usage(),
   1913                          'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
   1914         self.assertEqual(self.command_help_parser.format_help(),
   1915                          textwrap.dedent('''\
   1916             usage: PROG [-h] [--foo] bar {1,2,3} ...
   1917 
   1918             main description
   1919 
   1920             positional arguments:
   1921               bar         bar help
   1922               {1,2,3}     command help
   1923                 1         1 help
   1924                 2         2 help
   1925                 3         3 help
   1926 
   1927             optional arguments:
   1928               -h, --help  show this help message and exit
   1929               --foo       foo help
   1930             '''))
   1931 
   1932     def test_subparser_title_help(self):
   1933         parser = ErrorRaisingArgumentParser(prog='PROG',
   1934                                             description='main description')
   1935         parser.add_argument('--foo', action='store_true', help='foo help')
   1936         parser.add_argument('bar', help='bar help')
   1937         subparsers = parser.add_subparsers(title='subcommands',
   1938                                            description='command help',
   1939                                            help='additional text')
   1940         parser1 = subparsers.add_parser('1')
   1941         parser2 = subparsers.add_parser('2')
   1942         self.assertEqual(parser.format_usage(),
   1943                          'usage: PROG [-h] [--foo] bar {1,2} ...\n')
   1944         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1945             usage: PROG [-h] [--foo] bar {1,2} ...
   1946 
   1947             main description
   1948 
   1949             positional arguments:
   1950               bar         bar help
   1951 
   1952             optional arguments:
   1953               -h, --help  show this help message and exit
   1954               --foo       foo help
   1955 
   1956             subcommands:
   1957               command help
   1958 
   1959               {1,2}       additional text
   1960             '''))
   1961 
   1962     def _test_subparser_help(self, args_str, expected_help):
   1963         try:
   1964             self.parser.parse_args(args_str.split())
   1965         except ArgumentParserError:
   1966             err = sys.exc_info()[1]
   1967             if err.stdout != expected_help:
   1968                 print(repr(expected_help))
   1969                 print(repr(err.stdout))
   1970             self.assertEqual(err.stdout, expected_help)
   1971 
   1972     def test_subparser1_help(self):
   1973         self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
   1974             usage: PROG bar 1 [-h] [-w W] {a,b,c}
   1975 
   1976             1 description
   1977 
   1978             positional arguments:
   1979               {a,b,c}     x help
   1980 
   1981             optional arguments:
   1982               -h, --help  show this help message and exit
   1983               -w W        w help
   1984             '''))
   1985 
   1986     def test_subparser2_help(self):
   1987         self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
   1988             usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
   1989 
   1990             2 description
   1991 
   1992             positional arguments:
   1993               z           z help
   1994 
   1995             optional arguments:
   1996               -h, --help  show this help message and exit
   1997               -y {1,2,3}  y help
   1998             '''))
   1999 
   2000 # ============
   2001 # Groups tests
   2002 # ============
   2003 
   2004 class TestPositionalsGroups(TestCase):
   2005     """Tests that order of group positionals matches construction order"""
   2006 
   2007     def test_nongroup_first(self):
   2008         parser = ErrorRaisingArgumentParser()
   2009         parser.add_argument('foo')
   2010         group = parser.add_argument_group('g')
   2011         group.add_argument('bar')
   2012         parser.add_argument('baz')
   2013         expected = NS(foo='1', bar='2', baz='3')
   2014         result = parser.parse_args('1 2 3'.split())
   2015         self.assertEqual(expected, result)
   2016 
   2017     def test_group_first(self):
   2018         parser = ErrorRaisingArgumentParser()
   2019         group = parser.add_argument_group('xxx')
   2020         group.add_argument('foo')
   2021         parser.add_argument('bar')
   2022         parser.add_argument('baz')
   2023         expected = NS(foo='1', bar='2', baz='3')
   2024         result = parser.parse_args('1 2 3'.split())
   2025         self.assertEqual(expected, result)
   2026 
   2027     def test_interleaved_groups(self):
   2028         parser = ErrorRaisingArgumentParser()
   2029         group = parser.add_argument_group('xxx')
   2030         parser.add_argument('foo')
   2031         group.add_argument('bar')
   2032         parser.add_argument('baz')
   2033         group = parser.add_argument_group('yyy')
   2034         group.add_argument('frell')
   2035         expected = NS(foo='1', bar='2', baz='3', frell='4')
   2036         result = parser.parse_args('1 2 3 4'.split())
   2037         self.assertEqual(expected, result)
   2038 
   2039 # ===================
   2040 # Parent parser tests
   2041 # ===================
   2042 
   2043 class TestParentParsers(TestCase):
   2044     """Tests that parsers can be created with parent parsers"""
   2045 
   2046     def assertArgumentParserError(self, *args, **kwargs):
   2047         self.assertRaises(ArgumentParserError, *args, **kwargs)
   2048 
   2049     def setUp(self):
   2050         super(TestParentParsers, self).setUp()
   2051         self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
   2052         self.wxyz_parent.add_argument('--w')
   2053         x_group = self.wxyz_parent.add_argument_group('x')
   2054         x_group.add_argument('-y')
   2055         self.wxyz_parent.add_argument('z')
   2056 
   2057         self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
   2058         self.abcd_parent.add_argument('a')
   2059         self.abcd_parent.add_argument('-b')
   2060         c_group = self.abcd_parent.add_argument_group('c')
   2061         c_group.add_argument('--d')
   2062 
   2063         self.w_parent = ErrorRaisingArgumentParser(add_help=False)
   2064         self.w_parent.add_argument('--w')
   2065 
   2066         self.z_parent = ErrorRaisingArgumentParser(add_help=False)
   2067         self.z_parent.add_argument('z')
   2068 
   2069         # parents with mutually exclusive groups
   2070         self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
   2071         group = self.ab_mutex_parent.add_mutually_exclusive_group()
   2072         group.add_argument('-a', action='store_true')
   2073         group.add_argument('-b', action='store_true')
   2074 
   2075         self.main_program = os.path.basename(sys.argv[0])
   2076 
   2077     def test_single_parent(self):
   2078         parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
   2079         self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
   2080                          NS(w='3', y='1', z='2'))
   2081 
   2082     def test_single_parent_mutex(self):
   2083         self._test_mutex_ab(self.ab_mutex_parent.parse_args)
   2084         parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
   2085         self._test_mutex_ab(parser.parse_args)
   2086 
   2087     def test_single_granparent_mutex(self):
   2088         parents = [self.ab_mutex_parent]
   2089         parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
   2090         parser = ErrorRaisingArgumentParser(parents=[parser])
   2091         self._test_mutex_ab(parser.parse_args)
   2092 
   2093     def _test_mutex_ab(self, parse_args):
   2094         self.assertEqual(parse_args([]), NS(a=False, b=False))
   2095         self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
   2096         self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
   2097         self.assertArgumentParserError(parse_args, ['-a', '-b'])
   2098         self.assertArgumentParserError(parse_args, ['-b', '-a'])
   2099         self.assertArgumentParserError(parse_args, ['-c'])
   2100         self.assertArgumentParserError(parse_args, ['-a', '-c'])
   2101         self.assertArgumentParserError(parse_args, ['-b', '-c'])
   2102 
   2103     def test_multiple_parents(self):
   2104         parents = [self.abcd_parent, self.wxyz_parent]
   2105         parser = ErrorRaisingArgumentParser(parents=parents)
   2106         self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
   2107                          NS(a='3', b=None, d='1', w='2', y=None, z='4'))
   2108 
   2109     def test_multiple_parents_mutex(self):
   2110         parents = [self.ab_mutex_parent, self.wxyz_parent]
   2111         parser = ErrorRaisingArgumentParser(parents=parents)
   2112         self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
   2113                          NS(a=True, b=False, w='2', y=None, z='3'))
   2114         self.assertArgumentParserError(
   2115             parser.parse_args, '-a --w 2 3 -b'.split())
   2116         self.assertArgumentParserError(
   2117             parser.parse_args, '-a -b --w 2 3'.split())
   2118 
   2119     def test_conflicting_parents(self):
   2120         self.assertRaises(
   2121             argparse.ArgumentError,
   2122             argparse.ArgumentParser,
   2123             parents=[self.w_parent, self.wxyz_parent])
   2124 
   2125     def test_conflicting_parents_mutex(self):
   2126         self.assertRaises(
   2127             argparse.ArgumentError,
   2128             argparse.ArgumentParser,
   2129             parents=[self.abcd_parent, self.ab_mutex_parent])
   2130 
   2131     def test_same_argument_name_parents(self):
   2132         parents = [self.wxyz_parent, self.z_parent]
   2133         parser = ErrorRaisingArgumentParser(parents=parents)
   2134         self.assertEqual(parser.parse_args('1 2'.split()),
   2135                          NS(w=None, y=None, z='2'))
   2136 
   2137     def test_subparser_parents(self):
   2138         parser = ErrorRaisingArgumentParser()
   2139         subparsers = parser.add_subparsers()
   2140         abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
   2141         abcde_parser.add_argument('e')
   2142         self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
   2143                          NS(a='3', b='1', d='2', e='4'))
   2144 
   2145     def test_subparser_parents_mutex(self):
   2146         parser = ErrorRaisingArgumentParser()
   2147         subparsers = parser.add_subparsers()
   2148         parents = [self.ab_mutex_parent]
   2149         abc_parser = subparsers.add_parser('foo', parents=parents)
   2150         c_group = abc_parser.add_argument_group('c_group')
   2151         c_group.add_argument('c')
   2152         parents = [self.wxyz_parent, self.ab_mutex_parent]
   2153         wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
   2154         wxyzabe_parser.add_argument('e')
   2155         self.assertEqual(parser.parse_args('foo -a 4'.split()),
   2156                          NS(a=True, b=False, c='4'))
   2157         self.assertEqual(parser.parse_args('bar -b  --w 2 3 4'.split()),
   2158                          NS(a=False, b=True, w='2', y=None, z='3', e='4'))
   2159         self.assertArgumentParserError(
   2160             parser.parse_args, 'foo -a -b 4'.split())
   2161         self.assertArgumentParserError(
   2162             parser.parse_args, 'bar -b -a 4'.split())
   2163 
   2164     def test_parent_help(self):
   2165         parents = [self.abcd_parent, self.wxyz_parent]
   2166         parser = ErrorRaisingArgumentParser(parents=parents)
   2167         parser_help = parser.format_help()
   2168         progname = self.main_program
   2169         self.assertEqual(parser_help, textwrap.dedent('''\
   2170             usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
   2171 
   2172             positional arguments:
   2173               a
   2174               z
   2175 
   2176             optional arguments:
   2177               -h, --help  show this help message and exit
   2178               -b B
   2179               --w W
   2180 
   2181             c:
   2182               --d D
   2183 
   2184             x:
   2185               -y Y
   2186         '''.format(progname, ' ' if progname else '' )))
   2187 
   2188     def test_groups_parents(self):
   2189         parent = ErrorRaisingArgumentParser(add_help=False)
   2190         g = parent.add_argument_group(title='g', description='gd')
   2191         g.add_argument('-w')
   2192         g.add_argument('-x')
   2193         m = parent.add_mutually_exclusive_group()
   2194         m.add_argument('-y')
   2195         m.add_argument('-z')
   2196         parser = ErrorRaisingArgumentParser(parents=[parent])
   2197 
   2198         self.assertRaises(ArgumentParserError, parser.parse_args,
   2199             ['-y', 'Y', '-z', 'Z'])
   2200 
   2201         parser_help = parser.format_help()
   2202         progname = self.main_program
   2203         self.assertEqual(parser_help, textwrap.dedent('''\
   2204             usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
   2205 
   2206             optional arguments:
   2207               -h, --help  show this help message and exit
   2208               -y Y
   2209               -z Z
   2210 
   2211             g:
   2212               gd
   2213 
   2214               -w W
   2215               -x X
   2216         '''.format(progname, ' ' if progname else '' )))
   2217 
   2218 # ==============================
   2219 # Mutually exclusive group tests
   2220 # ==============================
   2221 
   2222 class TestMutuallyExclusiveGroupErrors(TestCase):
   2223 
   2224     def test_invalid_add_argument_group(self):
   2225         parser = ErrorRaisingArgumentParser()
   2226         raises = self.assertRaises
   2227         raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
   2228 
   2229     def test_invalid_add_argument(self):
   2230         parser = ErrorRaisingArgumentParser()
   2231         group = parser.add_mutually_exclusive_group()
   2232         add_argument = group.add_argument
   2233         raises = self.assertRaises
   2234         raises(ValueError, add_argument, '--foo', required=True)
   2235         raises(ValueError, add_argument, 'bar')
   2236         raises(ValueError, add_argument, 'bar', nargs='+')
   2237         raises(ValueError, add_argument, 'bar', nargs=1)
   2238         raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
   2239 
   2240     def test_help(self):
   2241         parser = ErrorRaisingArgumentParser(prog='PROG')
   2242         group1 = parser.add_mutually_exclusive_group()
   2243         group1.add_argument('--foo', action='store_true')
   2244         group1.add_argument('--bar', action='store_false')
   2245         group2 = parser.add_mutually_exclusive_group()
   2246         group2.add_argument('--soup', action='store_true')
   2247         group2.add_argument('--nuts', action='store_false')
   2248         expected = '''\
   2249             usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
   2250 
   2251             optional arguments:
   2252               -h, --help  show this help message and exit
   2253               --foo
   2254               --bar
   2255               --soup
   2256               --nuts
   2257               '''
   2258         self.assertEqual(parser.format_help(), textwrap.dedent(expected))
   2259 
   2260 class MEMixin(object):
   2261 
   2262     def test_failures_when_not_required(self):
   2263         parse_args = self.get_parser(required=False).parse_args
   2264         error = ArgumentParserError
   2265         for args_string in self.failures:
   2266             self.assertRaises(error, parse_args, args_string.split())
   2267 
   2268     def test_failures_when_required(self):
   2269         parse_args = self.get_parser(required=True).parse_args
   2270         error = ArgumentParserError
   2271         for args_string in self.failures + ['']:
   2272             self.assertRaises(error, parse_args, args_string.split())
   2273 
   2274     def test_successes_when_not_required(self):
   2275         parse_args = self.get_parser(required=False).parse_args
   2276         successes = self.successes + self.successes_when_not_required
   2277         for args_string, expected_ns in successes:
   2278             actual_ns = parse_args(args_string.split())
   2279             self.assertEqual(actual_ns, expected_ns)
   2280 
   2281     def test_successes_when_required(self):
   2282         parse_args = self.get_parser(required=True).parse_args
   2283         for args_string, expected_ns in self.successes:
   2284             actual_ns = parse_args(args_string.split())
   2285             self.assertEqual(actual_ns, expected_ns)
   2286 
   2287     def test_usage_when_not_required(self):
   2288         format_usage = self.get_parser(required=False).format_usage
   2289         expected_usage = self.usage_when_not_required
   2290         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2291 
   2292     def test_usage_when_required(self):
   2293         format_usage = self.get_parser(required=True).format_usage
   2294         expected_usage = self.usage_when_required
   2295         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2296 
   2297     def test_help_when_not_required(self):
   2298         format_help = self.get_parser(required=False).format_help
   2299         help = self.usage_when_not_required + self.help
   2300         self.assertEqual(format_help(), textwrap.dedent(help))
   2301 
   2302     def test_help_when_required(self):
   2303         format_help = self.get_parser(required=True).format_help
   2304         help = self.usage_when_required + self.help
   2305         self.assertEqual(format_help(), textwrap.dedent(help))
   2306 
   2307 
   2308 class TestMutuallyExclusiveSimple(MEMixin, TestCase):
   2309 
   2310     def get_parser(self, required=None):
   2311         parser = ErrorRaisingArgumentParser(prog='PROG')
   2312         group = parser.add_mutually_exclusive_group(required=required)
   2313         group.add_argument('--bar', help='bar help')
   2314         group.add_argument('--baz', nargs='?', const='Z', help='baz help')
   2315         return parser
   2316 
   2317     failures = ['--bar X --baz Y', '--bar X --baz']
   2318     successes = [
   2319         ('--bar X', NS(bar='X', baz=None)),
   2320         ('--bar X --bar Z', NS(bar='Z', baz=None)),
   2321         ('--baz Y', NS(bar=None, baz='Y')),
   2322         ('--baz', NS(bar=None, baz='Z')),
   2323     ]
   2324     successes_when_not_required = [
   2325         ('', NS(bar=None, baz=None)),
   2326     ]
   2327 
   2328     usage_when_not_required = '''\
   2329         usage: PROG [-h] [--bar BAR | --baz [BAZ]]
   2330         '''
   2331     usage_when_required = '''\
   2332         usage: PROG [-h] (--bar BAR | --baz [BAZ])
   2333         '''
   2334     help = '''\
   2335 
   2336         optional arguments:
   2337           -h, --help   show this help message and exit
   2338           --bar BAR    bar help
   2339           --baz [BAZ]  baz help
   2340         '''
   2341 
   2342 
   2343 class TestMutuallyExclusiveLong(MEMixin, TestCase):
   2344 
   2345     def get_parser(self, required=None):
   2346         parser = ErrorRaisingArgumentParser(prog='PROG')
   2347         parser.add_argument('--abcde', help='abcde help')
   2348         parser.add_argument('--fghij', help='fghij help')
   2349         group = parser.add_mutually_exclusive_group(required=required)
   2350         group.add_argument('--klmno', help='klmno help')
   2351         group.add_argument('--pqrst', help='pqrst help')
   2352         return parser
   2353 
   2354     failures = ['--klmno X --pqrst Y']
   2355     successes = [
   2356         ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
   2357         ('--abcde Y --klmno X',
   2358             NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
   2359         ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
   2360         ('--pqrst X --fghij Y',
   2361             NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
   2362     ]
   2363     successes_when_not_required = [
   2364         ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
   2365     ]
   2366 
   2367     usage_when_not_required = '''\
   2368     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2369                 [--klmno KLMNO | --pqrst PQRST]
   2370     '''
   2371     usage_when_required = '''\
   2372     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2373                 (--klmno KLMNO | --pqrst PQRST)
   2374     '''
   2375     help = '''\
   2376 
   2377     optional arguments:
   2378       -h, --help     show this help message and exit
   2379       --abcde ABCDE  abcde help
   2380       --fghij FGHIJ  fghij help
   2381       --klmno KLMNO  klmno help
   2382       --pqrst PQRST  pqrst help
   2383     '''
   2384 
   2385 
   2386 class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
   2387 
   2388     def get_parser(self, required):
   2389         parser = ErrorRaisingArgumentParser(prog='PROG')
   2390         group = parser.add_mutually_exclusive_group(required=required)
   2391         group.add_argument('-x', help=argparse.SUPPRESS)
   2392         group.add_argument('-y', action='store_false', help='y help')
   2393         return parser
   2394 
   2395     failures = ['-x X -y']
   2396     successes = [
   2397         ('-x X', NS(x='X', y=True)),
   2398         ('-x X -x Y', NS(x='Y', y=True)),
   2399         ('-y', NS(x=None, y=False)),
   2400     ]
   2401     successes_when_not_required = [
   2402         ('', NS(x=None, y=True)),
   2403     ]
   2404 
   2405     usage_when_not_required = '''\
   2406         usage: PROG [-h] [-y]
   2407         '''
   2408     usage_when_required = '''\
   2409         usage: PROG [-h] -y
   2410         '''
   2411     help = '''\
   2412 
   2413         optional arguments:
   2414           -h, --help  show this help message and exit
   2415           -y          y help
   2416         '''
   2417 
   2418 
   2419 class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
   2420 
   2421     def get_parser(self, required):
   2422         parser = ErrorRaisingArgumentParser(prog='PROG')
   2423         group = parser.add_mutually_exclusive_group(required=required)
   2424         add = group.add_argument
   2425         add('--spam', action='store_true', help=argparse.SUPPRESS)
   2426         add('--badger', action='store_false', help=argparse.SUPPRESS)
   2427         add('--bladder', help=argparse.SUPPRESS)
   2428         return parser
   2429 
   2430     failures = [
   2431         '--spam --badger',
   2432         '--badger --bladder B',
   2433         '--bladder B --spam',
   2434     ]
   2435     successes = [
   2436         ('--spam', NS(spam=True, badger=True, bladder=None)),
   2437         ('--badger', NS(spam=False, badger=False, bladder=None)),
   2438         ('--bladder B', NS(spam=False, badger=True, bladder='B')),
   2439         ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
   2440     ]
   2441     successes_when_not_required = [
   2442         ('', NS(spam=False, badger=True, bladder=None)),
   2443     ]
   2444 
   2445     usage_when_required = usage_when_not_required = '''\
   2446         usage: PROG [-h]
   2447         '''
   2448     help = '''\
   2449 
   2450         optional arguments:
   2451           -h, --help  show this help message and exit
   2452         '''
   2453 
   2454 
   2455 class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
   2456 
   2457     def get_parser(self, required):
   2458         parser = ErrorRaisingArgumentParser(prog='PROG')
   2459         group = parser.add_mutually_exclusive_group(required=required)
   2460         group.add_argument('--foo', action='store_true', help='FOO')
   2461         group.add_argument('--spam', help='SPAM')
   2462         group.add_argument('badger', nargs='*', default='X', help='BADGER')
   2463         return parser
   2464 
   2465     failures = [
   2466         '--foo --spam S',
   2467         '--spam S X',
   2468         'X --foo',
   2469         'X Y Z --spam S',
   2470         '--foo X Y',
   2471     ]
   2472     successes = [
   2473         ('--foo', NS(foo=True, spam=None, badger='X')),
   2474         ('--spam S', NS(foo=False, spam='S', badger='X')),
   2475         ('X', NS(foo=False, spam=None, badger=['X'])),
   2476         ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
   2477     ]
   2478     successes_when_not_required = [
   2479         ('', NS(foo=False, spam=None, badger='X')),
   2480     ]
   2481 
   2482     usage_when_not_required = '''\
   2483         usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
   2484         '''
   2485     usage_when_required = '''\
   2486         usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
   2487         '''
   2488     help = '''\
   2489 
   2490         positional arguments:
   2491           badger       BADGER
   2492 
   2493         optional arguments:
   2494           -h, --help   show this help message and exit
   2495           --foo        FOO
   2496           --spam SPAM  SPAM
   2497         '''
   2498 
   2499 
   2500 class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
   2501 
   2502     def get_parser(self, required):
   2503         parser = ErrorRaisingArgumentParser(prog='PROG')
   2504         parser.add_argument('-x', action='store_true', help='x help')
   2505         group = parser.add_mutually_exclusive_group(required=required)
   2506         group.add_argument('-a', action='store_true', help='a help')
   2507         group.add_argument('-b', action='store_true', help='b help')
   2508         parser.add_argument('-y', action='store_true', help='y help')
   2509         group.add_argument('-c', action='store_true', help='c help')
   2510         return parser
   2511 
   2512     failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
   2513     successes = [
   2514         ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
   2515         ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
   2516         ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
   2517         ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
   2518         ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
   2519         ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
   2520     ]
   2521     successes_when_not_required = [
   2522         ('', NS(a=False, b=False, c=False, x=False, y=False)),
   2523         ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
   2524         ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
   2525     ]
   2526 
   2527     usage_when_required = usage_when_not_required = '''\
   2528         usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
   2529         '''
   2530     help = '''\
   2531 
   2532         optional arguments:
   2533           -h, --help  show this help message and exit
   2534           -x          x help
   2535           -a          a help
   2536           -b          b help
   2537           -y          y help
   2538           -c          c help
   2539         '''
   2540 
   2541 
   2542 class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
   2543 
   2544     def get_parser(self, required=None):
   2545         parser = ErrorRaisingArgumentParser(prog='PROG')
   2546         titled_group = parser.add_argument_group(
   2547             title='Titled group', description='Group description')
   2548         mutex_group = \
   2549             titled_group.add_mutually_exclusive_group(required=required)
   2550         mutex_group.add_argument('--bar', help='bar help')
   2551         mutex_group.add_argument('--baz', help='baz help')
   2552         return parser
   2553 
   2554     failures = ['--bar X --baz Y', '--baz X --bar Y']
   2555     successes = [
   2556         ('--bar X', NS(bar='X', baz=None)),
   2557         ('--baz Y', NS(bar=None, baz='Y')),
   2558     ]
   2559     successes_when_not_required = [
   2560         ('', NS(bar=None, baz=None)),
   2561     ]
   2562 
   2563     usage_when_not_required = '''\
   2564         usage: PROG [-h] [--bar BAR | --baz BAZ]
   2565         '''
   2566     usage_when_required = '''\
   2567         usage: PROG [-h] (--bar BAR | --baz BAZ)
   2568         '''
   2569     help = '''\
   2570 
   2571         optional arguments:
   2572           -h, --help  show this help message and exit
   2573 
   2574         Titled group:
   2575           Group description
   2576 
   2577           --bar BAR   bar help
   2578           --baz BAZ   baz help
   2579         '''
   2580 
   2581 
   2582 class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
   2583 
   2584     def get_parser(self, required):
   2585         parser = ErrorRaisingArgumentParser(prog='PROG')
   2586         parser.add_argument('x', help='x help')
   2587         parser.add_argument('-y', action='store_true', help='y help')
   2588         group = parser.add_mutually_exclusive_group(required=required)
   2589         group.add_argument('a', nargs='?', help='a help')
   2590         group.add_argument('-b', action='store_true', help='b help')
   2591         group.add_argument('-c', action='store_true', help='c help')
   2592         return parser
   2593 
   2594     failures = ['X A -b', '-b -c', '-c X A']
   2595     successes = [
   2596         ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
   2597         ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
   2598         ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
   2599         ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
   2600         ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
   2601     ]
   2602     successes_when_not_required = [
   2603         ('X', NS(a=None, b=False, c=False, x='X', y=False)),
   2604         ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
   2605     ]
   2606 
   2607     usage_when_required = usage_when_not_required = '''\
   2608         usage: PROG [-h] [-y] [-b] [-c] x [a]
   2609         '''
   2610     help = '''\
   2611 
   2612         positional arguments:
   2613           x           x help
   2614           a           a help
   2615 
   2616         optional arguments:
   2617           -h, --help  show this help message and exit
   2618           -y          y help
   2619           -b          b help
   2620           -c          c help
   2621         '''
   2622 
   2623 # =================================================
   2624 # Mutually exclusive group in parent parser tests
   2625 # =================================================
   2626 
   2627 class MEPBase(object):
   2628 
   2629     def get_parser(self, required=None):
   2630         parent = super(MEPBase, self).get_parser(required=required)
   2631         parser = ErrorRaisingArgumentParser(
   2632             prog=parent.prog, add_help=False, parents=[parent])
   2633         return parser
   2634 
   2635 
   2636 class TestMutuallyExclusiveGroupErrorsParent(
   2637     MEPBase, TestMutuallyExclusiveGroupErrors):
   2638     pass
   2639 
   2640 
   2641 class TestMutuallyExclusiveSimpleParent(
   2642     MEPBase, TestMutuallyExclusiveSimple):
   2643     pass
   2644 
   2645 
   2646 class TestMutuallyExclusiveLongParent(
   2647     MEPBase, TestMutuallyExclusiveLong):
   2648     pass
   2649 
   2650 
   2651 class TestMutuallyExclusiveFirstSuppressedParent(
   2652     MEPBase, TestMutuallyExclusiveFirstSuppressed):
   2653     pass
   2654 
   2655 
   2656 class TestMutuallyExclusiveManySuppressedParent(
   2657     MEPBase, TestMutuallyExclusiveManySuppressed):
   2658     pass
   2659 
   2660 
   2661 class TestMutuallyExclusiveOptionalAndPositionalParent(
   2662     MEPBase, TestMutuallyExclusiveOptionalAndPositional):
   2663     pass
   2664 
   2665 
   2666 class TestMutuallyExclusiveOptionalsMixedParent(
   2667     MEPBase, TestMutuallyExclusiveOptionalsMixed):
   2668     pass
   2669 
   2670 
   2671 class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
   2672     MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
   2673     pass
   2674 
   2675 # =================
   2676 # Set default tests
   2677 # =================
   2678 
   2679 class TestSetDefaults(TestCase):
   2680 
   2681     def test_set_defaults_no_args(self):
   2682         parser = ErrorRaisingArgumentParser()
   2683         parser.set_defaults(x='foo')
   2684         parser.set_defaults(y='bar', z=1)
   2685         self.assertEqual(NS(x='foo', y='bar', z=1),
   2686                          parser.parse_args([]))
   2687         self.assertEqual(NS(x='foo', y='bar', z=1),
   2688                          parser.parse_args([], NS()))
   2689         self.assertEqual(NS(x='baz', y='bar', z=1),
   2690                          parser.parse_args([], NS(x='baz')))
   2691         self.assertEqual(NS(x='baz', y='bar', z=2),
   2692                          parser.parse_args([], NS(x='baz', z=2)))
   2693 
   2694     def test_set_defaults_with_args(self):
   2695         parser = ErrorRaisingArgumentParser()
   2696         parser.set_defaults(x='foo', y='bar')
   2697         parser.add_argument('-x', default='xfoox')
   2698         self.assertEqual(NS(x='xfoox', y='bar'),
   2699                          parser.parse_args([]))
   2700         self.assertEqual(NS(x='xfoox', y='bar'),
   2701                          parser.parse_args([], NS()))
   2702         self.assertEqual(NS(x='baz', y='bar'),
   2703                          parser.parse_args([], NS(x='baz')))
   2704         self.assertEqual(NS(x='1', y='bar'),
   2705                          parser.parse_args('-x 1'.split()))
   2706         self.assertEqual(NS(x='1', y='bar'),
   2707                          parser.parse_args('-x 1'.split(), NS()))
   2708         self.assertEqual(NS(x='1', y='bar'),
   2709                          parser.parse_args('-x 1'.split(), NS(x='baz')))
   2710 
   2711     def test_set_defaults_subparsers(self):
   2712         parser = ErrorRaisingArgumentParser()
   2713         parser.set_defaults(x='foo')
   2714         subparsers = parser.add_subparsers()
   2715         parser_a = subparsers.add_parser('a')
   2716         parser_a.set_defaults(y='bar')
   2717         self.assertEqual(NS(x='foo', y='bar'),
   2718                          parser.parse_args('a'.split()))
   2719 
   2720     def test_set_defaults_parents(self):
   2721         parent = ErrorRaisingArgumentParser(add_help=False)
   2722         parent.set_defaults(x='foo')
   2723         parser = ErrorRaisingArgumentParser(parents=[parent])
   2724         self.assertEqual(NS(x='foo'), parser.parse_args([]))
   2725 
   2726     def test_set_defaults_same_as_add_argument(self):
   2727         parser = ErrorRaisingArgumentParser()
   2728         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2729         parser.add_argument('-w')
   2730         parser.add_argument('-x', default='XX')
   2731         parser.add_argument('y', nargs='?')
   2732         parser.add_argument('z', nargs='?', default='ZZ')
   2733 
   2734         # defaults set previously
   2735         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2736                          parser.parse_args([]))
   2737 
   2738         # reset defaults
   2739         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2740         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2741                          parser.parse_args([]))
   2742 
   2743     def test_set_defaults_same_as_add_argument_group(self):
   2744         parser = ErrorRaisingArgumentParser()
   2745         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2746         group = parser.add_argument_group('foo')
   2747         group.add_argument('-w')
   2748         group.add_argument('-x', default='XX')
   2749         group.add_argument('y', nargs='?')
   2750         group.add_argument('z', nargs='?', default='ZZ')
   2751 
   2752 
   2753         # defaults set previously
   2754         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2755                          parser.parse_args([]))
   2756 
   2757         # reset defaults
   2758         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2759         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2760                          parser.parse_args([]))
   2761 
   2762 # =================
   2763 # Get default tests
   2764 # =================
   2765 
   2766 class TestGetDefault(TestCase):
   2767 
   2768     def test_get_default(self):
   2769         parser = ErrorRaisingArgumentParser()
   2770         self.assertEqual(None, parser.get_default("foo"))
   2771         self.assertEqual(None, parser.get_default("bar"))
   2772 
   2773         parser.add_argument("--foo")
   2774         self.assertEqual(None, parser.get_default("foo"))
   2775         self.assertEqual(None, parser.get_default("bar"))
   2776 
   2777         parser.add_argument("--bar", type=int, default=42)
   2778         self.assertEqual(None, parser.get_default("foo"))
   2779         self.assertEqual(42, parser.get_default("bar"))
   2780 
   2781         parser.set_defaults(foo="badger")
   2782         self.assertEqual("badger", parser.get_default("foo"))
   2783         self.assertEqual(42, parser.get_default("bar"))
   2784 
   2785 # ==========================
   2786 # Namespace 'contains' tests
   2787 # ==========================
   2788 
   2789 class TestNamespaceContainsSimple(TestCase):
   2790 
   2791     def test_empty(self):
   2792         ns = argparse.Namespace()
   2793         self.assertEqual('' in ns, False)
   2794         self.assertEqual('' not in ns, True)
   2795         self.assertEqual('x' in ns, False)
   2796 
   2797     def test_non_empty(self):
   2798         ns = argparse.Namespace(x=1, y=2)
   2799         self.assertEqual('x' in ns, True)
   2800         self.assertEqual('x' not in ns, False)
   2801         self.assertEqual('y' in ns, True)
   2802         self.assertEqual('' in ns, False)
   2803         self.assertEqual('xx' in ns, False)
   2804         self.assertEqual('z' in ns, False)
   2805 
   2806 # =====================
   2807 # Help formatting tests
   2808 # =====================
   2809 
   2810 class TestHelpFormattingMetaclass(type):
   2811 
   2812     def __init__(cls, name, bases, bodydict):
   2813         if name == 'HelpTestCase':
   2814             return
   2815 
   2816         class AddTests(object):
   2817 
   2818             def __init__(self, test_class, func_suffix, std_name):
   2819                 self.func_suffix = func_suffix
   2820                 self.std_name = std_name
   2821 
   2822                 for test_func in [self.test_format,
   2823                                   self.test_print,
   2824                                   self.test_print_file]:
   2825                     test_name = '%s_%s' % (test_func.__name__, func_suffix)
   2826 
   2827                     def test_wrapper(self, test_func=test_func):
   2828                         test_func(self)
   2829                     try:
   2830                         test_wrapper.__name__ = test_name
   2831                     except TypeError:
   2832                         pass
   2833                     setattr(test_class, test_name, test_wrapper)
   2834 
   2835             def _get_parser(self, tester):
   2836                 parser = argparse.ArgumentParser(
   2837                     *tester.parser_signature.args,
   2838                     **tester.parser_signature.kwargs)
   2839                 for argument_sig in getattr(tester, 'argument_signatures', []):
   2840                     parser.add_argument(*argument_sig.args,
   2841                                         **argument_sig.kwargs)
   2842                 group_sigs = getattr(tester, 'argument_group_signatures', [])
   2843                 for group_sig, argument_sigs in group_sigs:
   2844                     group = parser.add_argument_group(*group_sig.args,
   2845                                                       **group_sig.kwargs)
   2846                     for argument_sig in argument_sigs:
   2847                         group.add_argument(*argument_sig.args,
   2848                                            **argument_sig.kwargs)
   2849                 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
   2850                 if subparsers_sigs:
   2851                     subparsers = parser.add_subparsers()
   2852                     for subparser_sig in subparsers_sigs:
   2853                         subparsers.add_parser(*subparser_sig.args,
   2854                                                **subparser_sig.kwargs)
   2855                 return parser
   2856 
   2857             def _test(self, tester, parser_text):
   2858                 expected_text = getattr(tester, self.func_suffix)
   2859                 expected_text = textwrap.dedent(expected_text)
   2860                 if expected_text != parser_text:
   2861                     print(repr(expected_text))
   2862                     print(repr(parser_text))
   2863                     for char1, char2 in zip(expected_text, parser_text):
   2864                         if char1 != char2:
   2865                             print('first diff: %r %r' % (char1, char2))
   2866                             break
   2867                 tester.assertEqual(expected_text, parser_text)
   2868 
   2869             def test_format(self, tester):
   2870                 parser = self._get_parser(tester)
   2871                 format = getattr(parser, 'format_%s' % self.func_suffix)
   2872                 self._test(tester, format())
   2873 
   2874             def test_print(self, tester):
   2875                 parser = self._get_parser(tester)
   2876                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2877                 old_stream = getattr(sys, self.std_name)
   2878                 setattr(sys, self.std_name, StdIOBuffer())
   2879                 try:
   2880                     print_()
   2881                     parser_text = getattr(sys, self.std_name).getvalue()
   2882                 finally:
   2883                     setattr(sys, self.std_name, old_stream)
   2884                 self._test(tester, parser_text)
   2885 
   2886             def test_print_file(self, tester):
   2887                 parser = self._get_parser(tester)
   2888                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2889                 sfile = StdIOBuffer()
   2890                 print_(sfile)
   2891                 parser_text = sfile.getvalue()
   2892                 self._test(tester, parser_text)
   2893 
   2894         # add tests for {format,print}_{usage,help,version}
   2895         for func_suffix, std_name in [('usage', 'stdout'),
   2896                                       ('help', 'stdout'),
   2897                                       ('version', 'stderr')]:
   2898             AddTests(cls, func_suffix, std_name)
   2899 
   2900 bases = TestCase,
   2901 HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
   2902 
   2903 
   2904 class TestHelpBiggerOptionals(HelpTestCase):
   2905     """Make sure that argument help aligns when options are longer"""
   2906 
   2907     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   2908                            epilog='EPILOG', version='0.1')
   2909     argument_signatures = [
   2910         Sig('-x', action='store_true', help='X HELP'),
   2911         Sig('--y', help='Y HELP'),
   2912         Sig('foo', help='FOO HELP'),
   2913         Sig('bar', help='BAR HELP'),
   2914     ]
   2915     argument_group_signatures = []
   2916     usage = '''\
   2917         usage: PROG [-h] [-v] [-x] [--y Y] foo bar
   2918         '''
   2919     help = usage + '''\
   2920 
   2921         DESCRIPTION
   2922 
   2923         positional arguments:
   2924           foo            FOO HELP
   2925           bar            BAR HELP
   2926 
   2927         optional arguments:
   2928           -h, --help     show this help message and exit
   2929           -v, --version  show program's version number and exit
   2930           -x             X HELP
   2931           --y Y          Y HELP
   2932 
   2933         EPILOG
   2934     '''
   2935     version = '''\
   2936         0.1
   2937         '''
   2938 
   2939 
   2940 class TestHelpBiggerOptionalGroups(HelpTestCase):
   2941     """Make sure that argument help aligns when options are longer"""
   2942 
   2943     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   2944                            epilog='EPILOG', version='0.1')
   2945     argument_signatures = [
   2946         Sig('-x', action='store_true', help='X HELP'),
   2947         Sig('--y', help='Y HELP'),
   2948         Sig('foo', help='FOO HELP'),
   2949         Sig('bar', help='BAR HELP'),
   2950     ]
   2951     argument_group_signatures = [
   2952         (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
   2953             Sig('baz', help='BAZ HELP'),
   2954             Sig('-z', nargs='+', help='Z HELP')]),
   2955     ]
   2956     usage = '''\
   2957         usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
   2958         '''
   2959     help = usage + '''\
   2960 
   2961         DESCRIPTION
   2962 
   2963         positional arguments:
   2964           foo            FOO HELP
   2965           bar            BAR HELP
   2966 
   2967         optional arguments:
   2968           -h, --help     show this help message and exit
   2969           -v, --version  show program's version number and exit
   2970           -x             X HELP
   2971           --y Y          Y HELP
   2972 
   2973         GROUP TITLE:
   2974           GROUP DESCRIPTION
   2975 
   2976           baz            BAZ HELP
   2977           -z Z [Z ...]   Z HELP
   2978 
   2979         EPILOG
   2980     '''
   2981     version = '''\
   2982         0.1
   2983         '''
   2984 
   2985 
   2986 class TestHelpBiggerPositionals(HelpTestCase):
   2987     """Make sure that help aligns when arguments are longer"""
   2988 
   2989     parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
   2990     argument_signatures = [
   2991         Sig('-x', action='store_true', help='X HELP'),
   2992         Sig('--y', help='Y HELP'),
   2993         Sig('ekiekiekifekang', help='EKI HELP'),
   2994         Sig('bar', help='BAR HELP'),
   2995     ]
   2996     argument_group_signatures = []
   2997     usage = '''\
   2998         usage: USAGE
   2999         '''
   3000     help = usage + '''\
   3001 
   3002         DESCRIPTION
   3003 
   3004         positional arguments:
   3005           ekiekiekifekang  EKI HELP
   3006           bar              BAR HELP
   3007 
   3008         optional arguments:
   3009           -h, --help       show this help message and exit
   3010           -x               X HELP
   3011           --y Y            Y HELP
   3012         '''
   3013 
   3014     version = ''
   3015 
   3016 
   3017 class TestHelpReformatting(HelpTestCase):
   3018     """Make sure that text after short names starts on the first line"""
   3019 
   3020     parser_signature = Sig(
   3021         prog='PROG',
   3022         description='   oddly    formatted\n'
   3023                     'description\n'
   3024                     '\n'
   3025                     'that is so long that it should go onto multiple '
   3026                     'lines when wrapped')
   3027     argument_signatures = [
   3028         Sig('-x', metavar='XX', help='oddly\n'
   3029                                      '    formatted -x help'),
   3030         Sig('y', metavar='yyy', help='normal y help'),
   3031     ]
   3032     argument_group_signatures = [
   3033         (Sig('title', description='\n'
   3034                                   '    oddly formatted group\n'
   3035                                   '\n'
   3036                                   'description'),
   3037          [Sig('-a', action='store_true',
   3038               help=' oddly \n'
   3039                    'formatted    -a  help  \n'
   3040                    '    again, so long that it should be wrapped over '
   3041                    'multiple lines')]),
   3042     ]
   3043     usage = '''\
   3044         usage: PROG [-h] [-x XX] [-a] yyy
   3045         '''
   3046     help = usage + '''\
   3047 
   3048         oddly formatted description that is so long that it should go onto \
   3049 multiple
   3050         lines when wrapped
   3051 
   3052         positional arguments:
   3053           yyy         normal y help
   3054 
   3055         optional arguments:
   3056           -h, --help  show this help message and exit
   3057           -x XX       oddly formatted -x help
   3058 
   3059         title:
   3060           oddly formatted group description
   3061 
   3062           -a          oddly formatted -a help again, so long that it should \
   3063 be wrapped
   3064                       over multiple lines
   3065         '''
   3066     version = ''
   3067 
   3068 
   3069 class TestHelpWrappingShortNames(HelpTestCase):
   3070     """Make sure that text after short names starts on the first line"""
   3071 
   3072     parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
   3073     argument_signatures = [
   3074         Sig('-x', metavar='XX', help='XHH HX' * 20),
   3075         Sig('y', metavar='yyy', help='YH YH' * 20),
   3076     ]
   3077     argument_group_signatures = [
   3078         (Sig('ALPHAS'), [
   3079             Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
   3080     ]
   3081     usage = '''\
   3082         usage: PROG [-h] [-x XX] [-a] yyy
   3083         '''
   3084     help = usage + '''\
   3085 
   3086         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3087 DD DD DD
   3088         DD DD DD DD D
   3089 
   3090         positional arguments:
   3091           yyy         YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3092 YHYH YHYH
   3093                       YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3094 
   3095         optional arguments:
   3096           -h, --help  show this help message and exit
   3097           -x XX       XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
   3098 HXXHH HXXHH
   3099                       HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
   3100 
   3101         ALPHAS:
   3102           -a          AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
   3103 HHAAHHH
   3104                       HHAAHHH HHAAHHH HHA
   3105         '''
   3106     version = ''
   3107 
   3108 
   3109 class TestHelpWrappingLongNames(HelpTestCase):
   3110     """Make sure that text after long names starts on the next line"""
   3111 
   3112     parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
   3113                            version='V V'*30)
   3114     argument_signatures = [
   3115         Sig('-x', metavar='X' * 25, help='XH XH' * 20),
   3116         Sig('y', metavar='y' * 25, help='YH YH' * 20),
   3117     ]
   3118     argument_group_signatures = [
   3119         (Sig('ALPHAS'), [
   3120             Sig('-a', metavar='A' * 25, help='AH AH' * 20),
   3121             Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
   3122     ]
   3123     usage = '''\
   3124         usage: USAGE
   3125         '''
   3126     help = usage + '''\
   3127 
   3128         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3129 DD DD DD
   3130         DD DD DD DD D
   3131 
   3132         positional arguments:
   3133           yyyyyyyyyyyyyyyyyyyyyyyyy
   3134                                 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3135 YHYH YHYH
   3136                                 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3137 
   3138         optional arguments:
   3139           -h, --help            show this help message and exit
   3140           -v, --version         show program's version number and exit
   3141           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3142                                 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
   3143 XHXH XHXH
   3144                                 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
   3145 
   3146         ALPHAS:
   3147           -a AAAAAAAAAAAAAAAAAAAAAAAAA
   3148                                 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
   3149 AHAH AHAH
   3150                                 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
   3151           zzzzzzzzzzzzzzzzzzzzzzzzz
   3152                                 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
   3153 ZHZH ZHZH
   3154                                 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
   3155         '''
   3156     version = '''\
   3157         V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
   3158 VV VV VV
   3159         VV VV VV VV V
   3160         '''
   3161 
   3162 
   3163 class TestHelpUsage(HelpTestCase):
   3164     """Test basic usage messages"""
   3165 
   3166     parser_signature = Sig(prog='PROG')
   3167     argument_signatures = [
   3168         Sig('-w', nargs='+', help='w'),
   3169         Sig('-x', nargs='*', help='x'),
   3170         Sig('a', help='a'),
   3171         Sig('b', help='b', nargs=2),
   3172         Sig('c', help='c', nargs='?'),
   3173     ]
   3174     argument_group_signatures = [
   3175         (Sig('group'), [
   3176             Sig('-y', nargs='?', help='y'),
   3177             Sig('-z', nargs=3, help='z'),
   3178             Sig('d', help='d', nargs='*'),
   3179             Sig('e', help='e', nargs='+'),
   3180         ])
   3181     ]
   3182     usage = '''\
   3183         usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
   3184                     a b b [c] [d [d ...]] e [e ...]
   3185         '''
   3186     help = usage + '''\
   3187 
   3188         positional arguments:
   3189           a               a
   3190           b               b
   3191           c               c
   3192 
   3193         optional arguments:
   3194           -h, --help      show this help message and exit
   3195           -w W [W ...]    w
   3196           -x [X [X ...]]  x
   3197 
   3198         group:
   3199           -y [Y]          y
   3200           -z Z Z Z        z
   3201           d               d
   3202           e               e
   3203         '''
   3204     version = ''
   3205 
   3206 
   3207 class TestHelpOnlyUserGroups(HelpTestCase):
   3208     """Test basic usage messages"""
   3209 
   3210     parser_signature = Sig(prog='PROG', add_help=False)
   3211     argument_signatures = []
   3212     argument_group_signatures = [
   3213         (Sig('xxxx'), [
   3214             Sig('-x', help='x'),
   3215             Sig('a', help='a'),
   3216         ]),
   3217         (Sig('yyyy'), [
   3218             Sig('b', help='b'),
   3219             Sig('-y', help='y'),
   3220         ]),
   3221     ]
   3222     usage = '''\
   3223         usage: PROG [-x X] [-y Y] a b
   3224         '''
   3225     help = usage + '''\
   3226 
   3227         xxxx:
   3228           -x X  x
   3229           a     a
   3230 
   3231         yyyy:
   3232           b     b
   3233           -y Y  y
   3234         '''
   3235     version = ''
   3236 
   3237 
   3238 class TestHelpUsageLongProg(HelpTestCase):
   3239     """Test usage messages where the prog is long"""
   3240 
   3241     parser_signature = Sig(prog='P' * 60)
   3242     argument_signatures = [
   3243         Sig('-w', metavar='W'),
   3244         Sig('-x', metavar='X'),
   3245         Sig('a'),
   3246         Sig('b'),
   3247     ]
   3248     argument_group_signatures = []
   3249     usage = '''\
   3250         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3251                [-h] [-w W] [-x X] 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 W
   3262           -x X
   3263         '''
   3264     version = ''
   3265 
   3266 
   3267 class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
   3268     """Test usage messages where the prog is long and the optionals wrap"""
   3269 
   3270     parser_signature = Sig(prog='P' * 60)
   3271     argument_signatures = [
   3272         Sig('-w', metavar='W' * 25),
   3273         Sig('-x', metavar='X' * 25),
   3274         Sig('-y', metavar='Y' * 25),
   3275         Sig('-z', metavar='Z' * 25),
   3276         Sig('a'),
   3277         Sig('b'),
   3278     ]
   3279     argument_group_signatures = []
   3280     usage = '''\
   3281         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3282                [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3283 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3284                [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3285                a b
   3286         '''
   3287     help = usage + '''\
   3288 
   3289         positional arguments:
   3290           a
   3291           b
   3292 
   3293         optional arguments:
   3294           -h, --help            show this help message and exit
   3295           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3296           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3297           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3298           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3299         '''
   3300     version = ''
   3301 
   3302 
   3303 class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
   3304     """Test usage messages where the prog is long and the positionals wrap"""
   3305 
   3306     parser_signature = Sig(prog='P' * 60, add_help=False)
   3307     argument_signatures = [
   3308         Sig('a' * 25),
   3309         Sig('b' * 25),
   3310         Sig('c' * 25),
   3311     ]
   3312     argument_group_signatures = []
   3313     usage = '''\
   3314         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3315                aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3316                ccccccccccccccccccccccccc
   3317         '''
   3318     help = usage + '''\
   3319 
   3320         positional arguments:
   3321           aaaaaaaaaaaaaaaaaaaaaaaaa
   3322           bbbbbbbbbbbbbbbbbbbbbbbbb
   3323           ccccccccccccccccccccccccc
   3324         '''
   3325     version = ''
   3326 
   3327 
   3328 class TestHelpUsageOptionalsWrap(HelpTestCase):
   3329     """Test usage messages where the optionals wrap"""
   3330 
   3331     parser_signature = Sig(prog='PROG')
   3332     argument_signatures = [
   3333         Sig('-w', metavar='W' * 25),
   3334         Sig('-x', metavar='X' * 25),
   3335         Sig('-y', metavar='Y' * 25),
   3336         Sig('-z', metavar='Z' * 25),
   3337         Sig('a'),
   3338         Sig('b'),
   3339         Sig('c'),
   3340     ]
   3341     argument_group_signatures = []
   3342     usage = '''\
   3343         usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3344 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3345                     [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
   3346 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3347                     a b c
   3348         '''
   3349     help = usage + '''\
   3350 
   3351         positional arguments:
   3352           a
   3353           b
   3354           c
   3355 
   3356         optional arguments:
   3357           -h, --help            show this help message and exit
   3358           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3359           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3360           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3361           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3362         '''
   3363     version = ''
   3364 
   3365 
   3366 class TestHelpUsagePositionalsWrap(HelpTestCase):
   3367     """Test usage messages where the positionals wrap"""
   3368 
   3369     parser_signature = Sig(prog='PROG')
   3370     argument_signatures = [
   3371         Sig('-x'),
   3372         Sig('-y'),
   3373         Sig('-z'),
   3374         Sig('a' * 25),
   3375         Sig('b' * 25),
   3376         Sig('c' * 25),
   3377     ]
   3378     argument_group_signatures = []
   3379     usage = '''\
   3380         usage: PROG [-h] [-x X] [-y Y] [-z Z]
   3381                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3382                     ccccccccccccccccccccccccc
   3383         '''
   3384     help = usage + '''\
   3385 
   3386         positional arguments:
   3387           aaaaaaaaaaaaaaaaaaaaaaaaa
   3388           bbbbbbbbbbbbbbbbbbbbbbbbb
   3389           ccccccccccccccccccccccccc
   3390 
   3391         optional arguments:
   3392           -h, --help            show this help message and exit
   3393           -x X
   3394           -y Y
   3395           -z Z
   3396         '''
   3397     version = ''
   3398 
   3399 
   3400 class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
   3401     """Test usage messages where the optionals and positionals wrap"""
   3402 
   3403     parser_signature = Sig(prog='PROG')
   3404     argument_signatures = [
   3405         Sig('-x', metavar='X' * 25),
   3406         Sig('-y', metavar='Y' * 25),
   3407         Sig('-z', metavar='Z' * 25),
   3408         Sig('a' * 25),
   3409         Sig('b' * 25),
   3410         Sig('c' * 25),
   3411     ]
   3412     argument_group_signatures = []
   3413     usage = '''\
   3414         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3415 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3416                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3417                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3418                     ccccccccccccccccccccccccc
   3419         '''
   3420     help = usage + '''\
   3421 
   3422         positional arguments:
   3423           aaaaaaaaaaaaaaaaaaaaaaaaa
   3424           bbbbbbbbbbbbbbbbbbbbbbbbb
   3425           ccccccccccccccccccccccccc
   3426 
   3427         optional arguments:
   3428           -h, --help            show this help message and exit
   3429           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3430           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3431           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3432         '''
   3433     version = ''
   3434 
   3435 
   3436 class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
   3437     """Test usage messages where there are only optionals and they wrap"""
   3438 
   3439     parser_signature = Sig(prog='PROG')
   3440     argument_signatures = [
   3441         Sig('-x', metavar='X' * 25),
   3442         Sig('-y', metavar='Y' * 25),
   3443         Sig('-z', metavar='Z' * 25),
   3444     ]
   3445     argument_group_signatures = []
   3446     usage = '''\
   3447         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3448 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3449                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3450         '''
   3451     help = usage + '''\
   3452 
   3453         optional arguments:
   3454           -h, --help            show this help message and exit
   3455           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3456           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3457           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3458         '''
   3459     version = ''
   3460 
   3461 
   3462 class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
   3463     """Test usage messages where there are only positionals and they wrap"""
   3464 
   3465     parser_signature = Sig(prog='PROG', add_help=False)
   3466     argument_signatures = [
   3467         Sig('a' * 25),
   3468         Sig('b' * 25),
   3469         Sig('c' * 25),
   3470     ]
   3471     argument_group_signatures = []
   3472     usage = '''\
   3473         usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3474                     ccccccccccccccccccccccccc
   3475         '''
   3476     help = usage + '''\
   3477 
   3478         positional arguments:
   3479           aaaaaaaaaaaaaaaaaaaaaaaaa
   3480           bbbbbbbbbbbbbbbbbbbbbbbbb
   3481           ccccccccccccccccccccccccc
   3482         '''
   3483     version = ''
   3484 
   3485 
   3486 class TestHelpVariableExpansion(HelpTestCase):
   3487     """Test that variables are expanded properly in help messages"""
   3488 
   3489     parser_signature = Sig(prog='PROG')
   3490     argument_signatures = [
   3491         Sig('-x', type=int,
   3492             help='x %(prog)s %(default)s %(type)s %%'),
   3493         Sig('-y', action='store_const', default=42, const='XXX',
   3494             help='y %(prog)s %(default)s %(const)s'),
   3495         Sig('--foo', choices='abc',
   3496             help='foo %(prog)s %(default)s %(choices)s'),
   3497         Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
   3498             help='bar %(prog)s %(default)s %(dest)s'),
   3499         Sig('spam', help='spam %(prog)s %(default)s'),
   3500         Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
   3501     ]
   3502     argument_group_signatures = [
   3503         (Sig('group'), [
   3504             Sig('-a', help='a %(prog)s %(default)s'),
   3505             Sig('-b', default=-1, help='b %(prog)s %(default)s'),
   3506         ])
   3507     ]
   3508     usage = ('''\
   3509         usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
   3510                     spam badger
   3511         ''')
   3512     help = usage + '''\
   3513 
   3514         positional arguments:
   3515           spam           spam PROG None
   3516           badger         badger PROG 0.5
   3517 
   3518         optional arguments:
   3519           -h, --help     show this help message and exit
   3520           -x X           x PROG None int %
   3521           -y             y PROG 42 XXX
   3522           --foo {a,b,c}  foo PROG None a, b, c
   3523           --bar BBB      bar PROG baz bar
   3524 
   3525         group:
   3526           -a A           a PROG None
   3527           -b B           b PROG -1
   3528         '''
   3529     version = ''
   3530 
   3531 
   3532 class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
   3533     """Test that variables are expanded properly when usage= is present"""
   3534 
   3535     parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
   3536     argument_signatures = []
   3537     argument_group_signatures = []
   3538     usage = ('''\
   3539         usage: PROG FOO
   3540         ''')
   3541     help = usage + '''\
   3542 
   3543         optional arguments:
   3544           -h, --help  show this help message and exit
   3545         '''
   3546     version = ''
   3547 
   3548 
   3549 class TestHelpVariableExpansionNoArguments(HelpTestCase):
   3550     """Test that variables are expanded properly with no arguments"""
   3551 
   3552     parser_signature = Sig(prog='PROG', add_help=False)
   3553     argument_signatures = []
   3554     argument_group_signatures = []
   3555     usage = ('''\
   3556         usage: PROG
   3557         ''')
   3558     help = usage
   3559     version = ''
   3560 
   3561 
   3562 class TestHelpSuppressUsage(HelpTestCase):
   3563     """Test that items can be suppressed in usage messages"""
   3564 
   3565     parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
   3566     argument_signatures = [
   3567         Sig('--foo', help='foo help'),
   3568         Sig('spam', help='spam help'),
   3569     ]
   3570     argument_group_signatures = []
   3571     help = '''\
   3572         positional arguments:
   3573           spam        spam help
   3574 
   3575         optional arguments:
   3576           -h, --help  show this help message and exit
   3577           --foo FOO   foo help
   3578         '''
   3579     usage = ''
   3580     version = ''
   3581 
   3582 
   3583 class TestHelpSuppressOptional(HelpTestCase):
   3584     """Test that optional arguments can be suppressed in help messages"""
   3585 
   3586     parser_signature = Sig(prog='PROG', add_help=False)
   3587     argument_signatures = [
   3588         Sig('--foo', help=argparse.SUPPRESS),
   3589         Sig('spam', help='spam help'),
   3590     ]
   3591     argument_group_signatures = []
   3592     usage = '''\
   3593         usage: PROG spam
   3594         '''
   3595     help = usage + '''\
   3596 
   3597         positional arguments:
   3598           spam  spam help
   3599         '''
   3600     version = ''
   3601 
   3602 
   3603 class TestHelpSuppressOptionalGroup(HelpTestCase):
   3604     """Test that optional groups can be suppressed in help messages"""
   3605 
   3606     parser_signature = Sig(prog='PROG')
   3607     argument_signatures = [
   3608         Sig('--foo', help='foo help'),
   3609         Sig('spam', help='spam help'),
   3610     ]
   3611     argument_group_signatures = [
   3612         (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
   3613     ]
   3614     usage = '''\
   3615         usage: PROG [-h] [--foo FOO] spam
   3616         '''
   3617     help = usage + '''\
   3618 
   3619         positional arguments:
   3620           spam        spam help
   3621 
   3622         optional arguments:
   3623           -h, --help  show this help message and exit
   3624           --foo FOO   foo help
   3625         '''
   3626     version = ''
   3627 
   3628 
   3629 class TestHelpSuppressPositional(HelpTestCase):
   3630     """Test that positional arguments can be suppressed in help messages"""
   3631 
   3632     parser_signature = Sig(prog='PROG')
   3633     argument_signatures = [
   3634         Sig('--foo', help='foo help'),
   3635         Sig('spam', help=argparse.SUPPRESS),
   3636     ]
   3637     argument_group_signatures = []
   3638     usage = '''\
   3639         usage: PROG [-h] [--foo FOO]
   3640         '''
   3641     help = usage + '''\
   3642 
   3643         optional arguments:
   3644           -h, --help  show this help message and exit
   3645           --foo FOO   foo help
   3646         '''
   3647     version = ''
   3648 
   3649 
   3650 class TestHelpRequiredOptional(HelpTestCase):
   3651     """Test that required options don't look optional"""
   3652 
   3653     parser_signature = Sig(prog='PROG')
   3654     argument_signatures = [
   3655         Sig('--foo', required=True, help='foo help'),
   3656     ]
   3657     argument_group_signatures = []
   3658     usage = '''\
   3659         usage: PROG [-h] --foo FOO
   3660         '''
   3661     help = usage + '''\
   3662 
   3663         optional arguments:
   3664           -h, --help  show this help message and exit
   3665           --foo FOO   foo help
   3666         '''
   3667     version = ''
   3668 
   3669 
   3670 class TestHelpAlternatePrefixChars(HelpTestCase):
   3671     """Test that options display with different prefix characters"""
   3672 
   3673     parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
   3674     argument_signatures = [
   3675         Sig('^^foo', action='store_true', help='foo help'),
   3676         Sig(';b', ';;bar', help='bar help'),
   3677     ]
   3678     argument_group_signatures = []
   3679     usage = '''\
   3680         usage: PROG [^^foo] [;b BAR]
   3681         '''
   3682     help = usage + '''\
   3683 
   3684         optional arguments:
   3685           ^^foo              foo help
   3686           ;b BAR, ;;bar BAR  bar help
   3687         '''
   3688     version = ''
   3689 
   3690 
   3691 class TestHelpNoHelpOptional(HelpTestCase):
   3692     """Test that the --help argument can be suppressed help messages"""
   3693 
   3694     parser_signature = Sig(prog='PROG', add_help=False)
   3695     argument_signatures = [
   3696         Sig('--foo', help='foo help'),
   3697         Sig('spam', help='spam help'),
   3698     ]
   3699     argument_group_signatures = []
   3700     usage = '''\
   3701         usage: PROG [--foo FOO] spam
   3702         '''
   3703     help = usage + '''\
   3704 
   3705         positional arguments:
   3706           spam       spam help
   3707 
   3708         optional arguments:
   3709           --foo FOO  foo help
   3710         '''
   3711     version = ''
   3712 
   3713 
   3714 class TestHelpVersionOptional(HelpTestCase):
   3715     """Test that the --version argument can be suppressed help messages"""
   3716 
   3717     parser_signature = Sig(prog='PROG', version='1.0')
   3718     argument_signatures = [
   3719         Sig('--foo', help='foo help'),
   3720         Sig('spam', help='spam help'),
   3721     ]
   3722     argument_group_signatures = []
   3723     usage = '''\
   3724         usage: PROG [-h] [-v] [--foo FOO] spam
   3725         '''
   3726     help = usage + '''\
   3727 
   3728         positional arguments:
   3729           spam           spam help
   3730 
   3731         optional arguments:
   3732           -h, --help     show this help message and exit
   3733           -v, --version  show program's version number and exit
   3734           --foo FOO      foo help
   3735         '''
   3736     version = '''\
   3737         1.0
   3738         '''
   3739 
   3740 
   3741 class TestHelpNone(HelpTestCase):
   3742     """Test that no errors occur if no help is specified"""
   3743 
   3744     parser_signature = Sig(prog='PROG')
   3745     argument_signatures = [
   3746         Sig('--foo'),
   3747         Sig('spam'),
   3748     ]
   3749     argument_group_signatures = []
   3750     usage = '''\
   3751         usage: PROG [-h] [--foo FOO] spam
   3752         '''
   3753     help = usage + '''\
   3754 
   3755         positional arguments:
   3756           spam
   3757 
   3758         optional arguments:
   3759           -h, --help  show this help message and exit
   3760           --foo FOO
   3761         '''
   3762     version = ''
   3763 
   3764 
   3765 class TestHelpTupleMetavar(HelpTestCase):
   3766     """Test specifying metavar as a tuple"""
   3767 
   3768     parser_signature = Sig(prog='PROG')
   3769     argument_signatures = [
   3770         Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
   3771         Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
   3772         Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
   3773         Sig('-z', help='z', nargs='?', metavar=('Z1', )),
   3774     ]
   3775     argument_group_signatures = []
   3776     usage = '''\
   3777         usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
   3778 [-z [Z1]]
   3779         '''
   3780     help = usage + '''\
   3781 
   3782         optional arguments:
   3783           -h, --help        show this help message and exit
   3784           -w W1 [W2 ...]    w
   3785           -x [X1 [X2 ...]]  x
   3786           -y Y1 Y2 Y3       y
   3787           -z [Z1]           z
   3788         '''
   3789     version = ''
   3790 
   3791 
   3792 class TestHelpRawText(HelpTestCase):
   3793     """Test the RawTextHelpFormatter"""
   3794 
   3795     parser_signature = Sig(
   3796         prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
   3797         description='Keep the formatting\n'
   3798                     '    exactly as it is written\n'
   3799                     '\n'
   3800                     'here\n')
   3801 
   3802     argument_signatures = [
   3803         Sig('--foo', help='    foo help should also\n'
   3804                           'appear as given here'),
   3805         Sig('spam', help='spam help'),
   3806     ]
   3807     argument_group_signatures = [
   3808         (Sig('title', description='    This text\n'
   3809                                   '  should be indented\n'
   3810                                   '    exactly like it is here\n'),
   3811          [Sig('--bar', help='bar help')]),
   3812     ]
   3813     usage = '''\
   3814         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3815         '''
   3816     help = usage + '''\
   3817 
   3818         Keep the formatting
   3819             exactly as it is written
   3820 
   3821         here
   3822 
   3823         positional arguments:
   3824           spam        spam help
   3825 
   3826         optional arguments:
   3827           -h, --help  show this help message and exit
   3828           --foo FOO       foo help should also
   3829                       appear as given here
   3830 
   3831         title:
   3832               This text
   3833             should be indented
   3834               exactly like it is here
   3835 
   3836           --bar BAR   bar help
   3837         '''
   3838     version = ''
   3839 
   3840 
   3841 class TestHelpRawDescription(HelpTestCase):
   3842     """Test the RawTextHelpFormatter"""
   3843 
   3844     parser_signature = Sig(
   3845         prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
   3846         description='Keep the formatting\n'
   3847                     '    exactly as it is written\n'
   3848                     '\n'
   3849                     'here\n')
   3850 
   3851     argument_signatures = [
   3852         Sig('--foo', help='  foo help should not\n'
   3853                           '    retain this odd formatting'),
   3854         Sig('spam', help='spam help'),
   3855     ]
   3856     argument_group_signatures = [
   3857         (Sig('title', description='    This text\n'
   3858                                   '  should be indented\n'
   3859                                   '    exactly like it is here\n'),
   3860          [Sig('--bar', help='bar help')]),
   3861     ]
   3862     usage = '''\
   3863         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3864         '''
   3865     help = usage + '''\
   3866 
   3867         Keep the formatting
   3868             exactly as it is written
   3869 
   3870         here
   3871 
   3872         positional arguments:
   3873           spam        spam help
   3874 
   3875         optional arguments:
   3876           -h, --help  show this help message and exit
   3877           --foo FOO   foo help should not retain this odd formatting
   3878 
   3879         title:
   3880               This text
   3881             should be indented
   3882               exactly like it is here
   3883 
   3884           --bar BAR   bar help
   3885         '''
   3886     version = ''
   3887 
   3888 
   3889 class TestHelpArgumentDefaults(HelpTestCase):
   3890     """Test the ArgumentDefaultsHelpFormatter"""
   3891 
   3892     parser_signature = Sig(
   3893         prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
   3894         description='description')
   3895 
   3896     argument_signatures = [
   3897         Sig('--foo', help='foo help - oh and by the way, %(default)s'),
   3898         Sig('--bar', action='store_true', help='bar help'),
   3899         Sig('spam', help='spam help'),
   3900         Sig('badger', nargs='?', default='wooden', help='badger help'),
   3901     ]
   3902     argument_group_signatures = [
   3903         (Sig('title', description='description'),
   3904          [Sig('--baz', type=int, default=42, help='baz help')]),
   3905     ]
   3906     usage = '''\
   3907         usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
   3908         '''
   3909     help = usage + '''\
   3910 
   3911         description
   3912 
   3913         positional arguments:
   3914           spam        spam help
   3915           badger      badger help (default: wooden)
   3916 
   3917         optional arguments:
   3918           -h, --help  show this help message and exit
   3919           --foo FOO   foo help - oh and by the way, None
   3920           --bar       bar help (default: False)
   3921 
   3922         title:
   3923           description
   3924 
   3925           --baz BAZ   baz help (default: 42)
   3926         '''
   3927     version = ''
   3928 
   3929 class TestHelpVersionAction(HelpTestCase):
   3930     """Test the default help for the version action"""
   3931 
   3932     parser_signature = Sig(prog='PROG', description='description')
   3933     argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
   3934     argument_group_signatures = []
   3935     usage = '''\
   3936         usage: PROG [-h] [-V]
   3937         '''
   3938     help = usage + '''\
   3939 
   3940         description
   3941 
   3942         optional arguments:
   3943           -h, --help     show this help message and exit
   3944           -V, --version  show program's version number and exit
   3945         '''
   3946     version = ''
   3947 
   3948 class TestHelpSubparsersOrdering(HelpTestCase):
   3949     """Test ordering of subcommands in help matches the code"""
   3950     parser_signature = Sig(prog='PROG',
   3951                            description='display some subcommands',
   3952                            version='0.1')
   3953 
   3954     subparsers_signatures = [Sig(name=name)
   3955                              for name in ('a', 'b', 'c', 'd', 'e')]
   3956 
   3957     usage = '''\
   3958         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   3959         '''
   3960 
   3961     help = usage + '''\
   3962 
   3963         display some subcommands
   3964 
   3965         positional arguments:
   3966           {a,b,c,d,e}
   3967 
   3968         optional arguments:
   3969           -h, --help     show this help message and exit
   3970           -v, --version  show program's version number and exit
   3971         '''
   3972 
   3973     version = '''\
   3974         0.1
   3975         '''
   3976 
   3977 class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
   3978     """Test ordering of subcommands in help matches the code"""
   3979     parser_signature = Sig(prog='PROG',
   3980                            description='display some subcommands',
   3981                            version='0.1')
   3982 
   3983     subcommand_data = (('a', 'a subcommand help'),
   3984                        ('b', 'b subcommand help'),
   3985                        ('c', 'c subcommand help'),
   3986                        ('d', 'd subcommand help'),
   3987                        ('e', 'e subcommand help'),
   3988                        )
   3989 
   3990     subparsers_signatures = [Sig(name=name, help=help)
   3991                              for name, help in subcommand_data]
   3992 
   3993     usage = '''\
   3994         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   3995         '''
   3996 
   3997     help = usage + '''\
   3998 
   3999         display some subcommands
   4000 
   4001         positional arguments:
   4002           {a,b,c,d,e}
   4003             a            a subcommand help
   4004             b            b subcommand help
   4005             c            c subcommand help
   4006             d            d subcommand help
   4007             e            e subcommand help
   4008 
   4009         optional arguments:
   4010           -h, --help     show this help message and exit
   4011           -v, --version  show program's version number and exit
   4012         '''
   4013 
   4014     version = '''\
   4015         0.1
   4016         '''
   4017 
   4018 
   4019 # =====================================
   4020 # Optional/Positional constructor tests
   4021 # =====================================
   4022 
   4023 class TestInvalidArgumentConstructors(TestCase):
   4024     """Test a bunch of invalid Argument constructors"""
   4025 
   4026     def assertTypeError(self, *args, **kwargs):
   4027         parser = argparse.ArgumentParser()
   4028         self.assertRaises(TypeError, parser.add_argument,
   4029                           *args, **kwargs)
   4030 
   4031     def assertValueError(self, *args, **kwargs):
   4032         parser = argparse.ArgumentParser()
   4033         self.assertRaises(ValueError, parser.add_argument,
   4034                           *args, **kwargs)
   4035 
   4036     def test_invalid_keyword_arguments(self):
   4037         self.assertTypeError('-x', bar=None)
   4038         self.assertTypeError('-y', callback='foo')
   4039         self.assertTypeError('-y', callback_args=())
   4040         self.assertTypeError('-y', callback_kwargs={})
   4041 
   4042     def test_missing_destination(self):
   4043         self.assertTypeError()
   4044         for action in ['append', 'store']:
   4045             self.assertTypeError(action=action)
   4046 
   4047     def test_invalid_option_strings(self):
   4048         self.assertValueError('--')
   4049         self.assertValueError('---')
   4050 
   4051     def test_invalid_type(self):
   4052         self.assertValueError('--foo', type='int')
   4053         self.assertValueError('--foo', type=(int, float))
   4054 
   4055     def test_invalid_action(self):
   4056         self.assertValueError('-x', action='foo')
   4057         self.assertValueError('foo', action='baz')
   4058         self.assertValueError('--foo', action=('store', 'append'))
   4059         parser = argparse.ArgumentParser()
   4060         try:
   4061             parser.add_argument("--foo", action="store-true")
   4062         except ValueError:
   4063             e = sys.exc_info()[1]
   4064             expected = 'unknown action'
   4065             msg = 'expected %r, found %r' % (expected, e)
   4066             self.assertTrue(expected in str(e), msg)
   4067 
   4068     def test_multiple_dest(self):
   4069         parser = argparse.ArgumentParser()
   4070         parser.add_argument(dest='foo')
   4071         try:
   4072             parser.add_argument('bar', dest='baz')
   4073         except ValueError:
   4074             e = sys.exc_info()[1]
   4075             expected = 'dest supplied twice for positional argument'
   4076             msg = 'expected %r, found %r' % (expected, e)
   4077             self.assertTrue(expected in str(e), msg)
   4078 
   4079     def test_no_argument_actions(self):
   4080         for action in ['store_const', 'store_true', 'store_false',
   4081                        'append_const', 'count']:
   4082             for attrs in [dict(type=int), dict(nargs='+'),
   4083                           dict(choices='ab')]:
   4084                 self.assertTypeError('-x', action=action, **attrs)
   4085 
   4086     def test_no_argument_no_const_actions(self):
   4087         # options with zero arguments
   4088         for action in ['store_true', 'store_false', 'count']:
   4089 
   4090             # const is always disallowed
   4091             self.assertTypeError('-x', const='foo', action=action)
   4092 
   4093             # nargs is always disallowed
   4094             self.assertTypeError('-x', nargs='*', action=action)
   4095 
   4096     def test_more_than_one_argument_actions(self):
   4097         for action in ['store', 'append']:
   4098 
   4099             # nargs=0 is disallowed
   4100             self.assertValueError('-x', nargs=0, action=action)
   4101             self.assertValueError('spam', nargs=0, action=action)
   4102 
   4103             # const is disallowed with non-optional arguments
   4104             for nargs in [1, '*', '+']:
   4105                 self.assertValueError('-x', const='foo',
   4106                                       nargs=nargs, action=action)
   4107                 self.assertValueError('spam', const='foo',
   4108                                       nargs=nargs, action=action)
   4109 
   4110     def test_required_const_actions(self):
   4111         for action in ['store_const', 'append_const']:
   4112 
   4113             # nargs is always disallowed
   4114             self.assertTypeError('-x', nargs='+', action=action)
   4115 
   4116     def test_parsers_action_missing_params(self):
   4117         self.assertTypeError('command', action='parsers')
   4118         self.assertTypeError('command', action='parsers', prog='PROG')
   4119         self.assertTypeError('command', action='parsers',
   4120                              parser_class=argparse.ArgumentParser)
   4121 
   4122     def test_required_positional(self):
   4123         self.assertTypeError('foo', required=True)
   4124 
   4125     def test_user_defined_action(self):
   4126 
   4127         class Success(Exception):
   4128             pass
   4129 
   4130         class Action(object):
   4131 
   4132             def __init__(self,
   4133                          option_strings,
   4134                          dest,
   4135                          const,
   4136                          default,
   4137                          required=False):
   4138                 if dest == 'spam':
   4139                     if const is Success:
   4140                         if default is Success:
   4141                             raise Success()
   4142 
   4143             def __call__(self, *args, **kwargs):
   4144                 pass
   4145 
   4146         parser = argparse.ArgumentParser()
   4147         self.assertRaises(Success, parser.add_argument, '--spam',
   4148                           action=Action, default=Success, const=Success)
   4149         self.assertRaises(Success, parser.add_argument, 'spam',
   4150                           action=Action, default=Success, const=Success)
   4151 
   4152 # ================================
   4153 # Actions returned by add_argument
   4154 # ================================
   4155 
   4156 class TestActionsReturned(TestCase):
   4157 
   4158     def test_dest(self):
   4159         parser = argparse.ArgumentParser()
   4160         action = parser.add_argument('--foo')
   4161         self.assertEqual(action.dest, 'foo')
   4162         action = parser.add_argument('-b', '--bar')
   4163         self.assertEqual(action.dest, 'bar')
   4164         action = parser.add_argument('-x', '-y')
   4165         self.assertEqual(action.dest, 'x')
   4166 
   4167     def test_misc(self):
   4168         parser = argparse.ArgumentParser()
   4169         action = parser.add_argument('--foo', nargs='?', const=42,
   4170                                      default=84, type=int, choices=[1, 2],
   4171                                      help='FOO', metavar='BAR', dest='baz')
   4172         self.assertEqual(action.nargs, '?')
   4173         self.assertEqual(action.const, 42)
   4174         self.assertEqual(action.default, 84)
   4175         self.assertEqual(action.type, int)
   4176         self.assertEqual(action.choices, [1, 2])
   4177         self.assertEqual(action.help, 'FOO')
   4178         self.assertEqual(action.metavar, 'BAR')
   4179         self.assertEqual(action.dest, 'baz')
   4180 
   4181 
   4182 # ================================
   4183 # Argument conflict handling tests
   4184 # ================================
   4185 
   4186 class TestConflictHandling(TestCase):
   4187 
   4188     def test_bad_type(self):
   4189         self.assertRaises(ValueError, argparse.ArgumentParser,
   4190                           conflict_handler='foo')
   4191 
   4192     def test_conflict_error(self):
   4193         parser = argparse.ArgumentParser()
   4194         parser.add_argument('-x')
   4195         self.assertRaises(argparse.ArgumentError,
   4196                           parser.add_argument, '-x')
   4197         parser.add_argument('--spam')
   4198         self.assertRaises(argparse.ArgumentError,
   4199                           parser.add_argument, '--spam')
   4200 
   4201     def test_resolve_error(self):
   4202         get_parser = argparse.ArgumentParser
   4203         parser = get_parser(prog='PROG', conflict_handler='resolve')
   4204 
   4205         parser.add_argument('-x', help='OLD X')
   4206         parser.add_argument('-x', help='NEW X')
   4207         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4208             usage: PROG [-h] [-x X]
   4209 
   4210             optional arguments:
   4211               -h, --help  show this help message and exit
   4212               -x X        NEW X
   4213             '''))
   4214 
   4215         parser.add_argument('--spam', metavar='OLD_SPAM')
   4216         parser.add_argument('--spam', metavar='NEW_SPAM')
   4217         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4218             usage: PROG [-h] [-x X] [--spam NEW_SPAM]
   4219 
   4220             optional arguments:
   4221               -h, --help       show this help message and exit
   4222               -x X             NEW X
   4223               --spam NEW_SPAM
   4224             '''))
   4225 
   4226 
   4227 # =============================
   4228 # Help and Version option tests
   4229 # =============================
   4230 
   4231 class TestOptionalsHelpVersionActions(TestCase):
   4232     """Test the help and version actions"""
   4233 
   4234     def _get_error(self, func, *args, **kwargs):
   4235         try:
   4236             func(*args, **kwargs)
   4237         except ArgumentParserError:
   4238             return sys.exc_info()[1]
   4239         else:
   4240             self.assertRaises(ArgumentParserError, func, *args, **kwargs)
   4241 
   4242     def assertPrintHelpExit(self, parser, args_str):
   4243         self.assertEqual(
   4244             parser.format_help(),
   4245             self._get_error(parser.parse_args, args_str.split()).stdout)
   4246 
   4247     def assertPrintVersionExit(self, parser, args_str):
   4248         self.assertEqual(
   4249             parser.format_version(),
   4250             self._get_error(parser.parse_args, args_str.split()).stderr)
   4251 
   4252     def assertArgumentParserError(self, parser, *args):
   4253         self.assertRaises(ArgumentParserError, parser.parse_args, args)
   4254 
   4255     def test_version(self):
   4256         parser = ErrorRaisingArgumentParser(version='1.0')
   4257         self.assertPrintHelpExit(parser, '-h')
   4258         self.assertPrintHelpExit(parser, '--help')
   4259         self.assertPrintVersionExit(parser, '-v')
   4260         self.assertPrintVersionExit(parser, '--version')
   4261 
   4262     def test_version_format(self):
   4263         parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
   4264         msg = self._get_error(parser.parse_args, ['-v']).stderr
   4265         self.assertEqual('PPP 3.5\n', msg)
   4266 
   4267     def test_version_no_help(self):
   4268         parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
   4269         self.assertArgumentParserError(parser, '-h')
   4270         self.assertArgumentParserError(parser, '--help')
   4271         self.assertPrintVersionExit(parser, '-v')
   4272         self.assertPrintVersionExit(parser, '--version')
   4273 
   4274     def test_version_action(self):
   4275         parser = ErrorRaisingArgumentParser(prog='XXX')
   4276         parser.add_argument('-V', action='version', version='%(prog)s 3.7')
   4277         msg = self._get_error(parser.parse_args, ['-V']).stderr
   4278         self.assertEqual('XXX 3.7\n', msg)
   4279 
   4280     def test_no_help(self):
   4281         parser = ErrorRaisingArgumentParser(add_help=False)
   4282         self.assertArgumentParserError(parser, '-h')
   4283         self.assertArgumentParserError(parser, '--help')
   4284         self.assertArgumentParserError(parser, '-v')
   4285         self.assertArgumentParserError(parser, '--version')
   4286 
   4287     def test_alternate_help_version(self):
   4288         parser = ErrorRaisingArgumentParser()
   4289         parser.add_argument('-x', action='help')
   4290         parser.add_argument('-y', action='version')
   4291         self.assertPrintHelpExit(parser, '-x')
   4292         self.assertPrintVersionExit(parser, '-y')
   4293         self.assertArgumentParserError(parser, '-v')
   4294         self.assertArgumentParserError(parser, '--version')
   4295 
   4296     def test_help_version_extra_arguments(self):
   4297         parser = ErrorRaisingArgumentParser(version='1.0')
   4298         parser.add_argument('-x', action='store_true')
   4299         parser.add_argument('y')
   4300 
   4301         # try all combinations of valid prefixes and suffixes
   4302         valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
   4303         valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
   4304         for prefix in valid_prefixes:
   4305             for suffix in valid_suffixes:
   4306                 format = '%s %%s %s' % (prefix, suffix)
   4307             self.assertPrintHelpExit(parser, format % '-h')
   4308             self.assertPrintHelpExit(parser, format % '--help')
   4309             self.assertPrintVersionExit(parser, format % '-v')
   4310             self.assertPrintVersionExit(parser, format % '--version')
   4311 
   4312 
   4313 # ======================
   4314 # str() and repr() tests
   4315 # ======================
   4316 
   4317 class TestStrings(TestCase):
   4318     """Test str()  and repr() on Optionals and Positionals"""
   4319 
   4320     def assertStringEqual(self, obj, result_string):
   4321         for func in [str, repr]:
   4322             self.assertEqual(func(obj), result_string)
   4323 
   4324     def test_optional(self):
   4325         option = argparse.Action(
   4326             option_strings=['--foo', '-a', '-b'],
   4327             dest='b',
   4328             type='int',
   4329             nargs='+',
   4330             default=42,
   4331             choices=[1, 2, 3],
   4332             help='HELP',
   4333             metavar='METAVAR')
   4334         string = (
   4335             "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
   4336             "nargs='+', const=None, default=42, type='int', "
   4337             "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
   4338         self.assertStringEqual(option, string)
   4339 
   4340     def test_argument(self):
   4341         argument = argparse.Action(
   4342             option_strings=[],
   4343             dest='x',
   4344             type=float,
   4345             nargs='?',
   4346             default=2.5,
   4347             choices=[0.5, 1.5, 2.5],
   4348             help='H HH H',
   4349             metavar='MV MV MV')
   4350         string = (
   4351             "Action(option_strings=[], dest='x', nargs='?', "
   4352             "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
   4353             "help='H HH H', metavar='MV MV MV')" % float)
   4354         self.assertStringEqual(argument, string)
   4355 
   4356     def test_namespace(self):
   4357         ns = argparse.Namespace(foo=42, bar='spam')
   4358         string = "Namespace(bar='spam', foo=42)"
   4359         self.assertStringEqual(ns, string)
   4360 
   4361     def test_parser(self):
   4362         parser = argparse.ArgumentParser(prog='PROG')
   4363         string = (
   4364             "ArgumentParser(prog='PROG', usage=None, description=None, "
   4365             "version=None, formatter_class=%r, conflict_handler='error', "
   4366             "add_help=True)" % argparse.HelpFormatter)
   4367         self.assertStringEqual(parser, string)
   4368 
   4369 # ===============
   4370 # Namespace tests
   4371 # ===============
   4372 
   4373 class TestNamespace(TestCase):
   4374 
   4375     def test_constructor(self):
   4376         ns = argparse.Namespace()
   4377         self.assertRaises(AttributeError, getattr, ns, 'x')
   4378 
   4379         ns = argparse.Namespace(a=42, b='spam')
   4380         self.assertEqual(ns.a, 42)
   4381         self.assertEqual(ns.b, 'spam')
   4382 
   4383     def test_equality(self):
   4384         ns1 = argparse.Namespace(a=1, b=2)
   4385         ns2 = argparse.Namespace(b=2, a=1)
   4386         ns3 = argparse.Namespace(a=1)
   4387         ns4 = argparse.Namespace(b=2)
   4388 
   4389         self.assertEqual(ns1, ns2)
   4390         self.assertNotEqual(ns1, ns3)
   4391         self.assertNotEqual(ns1, ns4)
   4392         self.assertNotEqual(ns2, ns3)
   4393         self.assertNotEqual(ns2, ns4)
   4394         self.assertTrue(ns1 != ns3)
   4395         self.assertTrue(ns1 != ns4)
   4396         self.assertTrue(ns2 != ns3)
   4397         self.assertTrue(ns2 != ns4)
   4398 
   4399 
   4400 # ===================
   4401 # File encoding tests
   4402 # ===================
   4403 
   4404 class TestEncoding(TestCase):
   4405 
   4406     def _test_module_encoding(self, path):
   4407         path, _ = os.path.splitext(path)
   4408         path += ".py"
   4409         with codecs.open(path, 'r', 'utf8') as f:
   4410             f.read()
   4411 
   4412     def test_argparse_module_encoding(self):
   4413         self._test_module_encoding(argparse.__file__)
   4414 
   4415     def test_test_argparse_module_encoding(self):
   4416         self._test_module_encoding(__file__)
   4417 
   4418 # ===================
   4419 # ArgumentError tests
   4420 # ===================
   4421 
   4422 class TestArgumentError(TestCase):
   4423 
   4424     def test_argument_error(self):
   4425         msg = "my error here"
   4426         error = argparse.ArgumentError(None, msg)
   4427         self.assertEqual(str(error), msg)
   4428 
   4429 # =======================
   4430 # ArgumentTypeError tests
   4431 # =======================
   4432 
   4433 class TestArgumentTypeError(TestCase):
   4434 
   4435     def test_argument_type_error(self):
   4436 
   4437         def spam(string):
   4438             raise argparse.ArgumentTypeError('spam!')
   4439 
   4440         parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
   4441         parser.add_argument('x', type=spam)
   4442         try:
   4443             parser.parse_args(['XXX'])
   4444         except ArgumentParserError:
   4445             expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
   4446             msg = sys.exc_info()[1].stderr
   4447             self.assertEqual(expected, msg)
   4448         else:
   4449             self.fail()
   4450 
   4451 # ================================================
   4452 # Check that the type function is called only once
   4453 # ================================================
   4454 
   4455 class TestTypeFunctionCallOnlyOnce(TestCase):
   4456 
   4457     def test_type_function_call_only_once(self):
   4458         def spam(string_to_convert):
   4459             self.assertEqual(string_to_convert, 'spam!')
   4460             return 'foo_converted'
   4461 
   4462         parser = argparse.ArgumentParser()
   4463         parser.add_argument('--foo', type=spam, default='bar')
   4464         args = parser.parse_args('--foo spam!'.split())
   4465         self.assertEqual(NS(foo='foo_converted'), args)
   4466 
   4467 # ==================================================================
   4468 # Check semantics regarding the default argument and type conversion
   4469 # ==================================================================
   4470 
   4471 class TestTypeFunctionCalledOnDefault(TestCase):
   4472 
   4473     def test_type_function_call_with_non_string_default(self):
   4474         def spam(int_to_convert):
   4475             self.assertEqual(int_to_convert, 0)
   4476             return 'foo_converted'
   4477 
   4478         parser = argparse.ArgumentParser()
   4479         parser.add_argument('--foo', type=spam, default=0)
   4480         args = parser.parse_args([])
   4481         # foo should *not* be converted because its default is not a string.
   4482         self.assertEqual(NS(foo=0), args)
   4483 
   4484     def test_type_function_call_with_string_default(self):
   4485         def spam(int_to_convert):
   4486             return 'foo_converted'
   4487 
   4488         parser = argparse.ArgumentParser()
   4489         parser.add_argument('--foo', type=spam, default='0')
   4490         args = parser.parse_args([])
   4491         # foo is converted because its default is a string.
   4492         self.assertEqual(NS(foo='foo_converted'), args)
   4493 
   4494     def test_no_double_type_conversion_of_default(self):
   4495         def extend(str_to_convert):
   4496             return str_to_convert + '*'
   4497 
   4498         parser = argparse.ArgumentParser()
   4499         parser.add_argument('--test', type=extend, default='*')
   4500         args = parser.parse_args([])
   4501         # The test argument will be two stars, one coming from the default
   4502         # value and one coming from the type conversion being called exactly
   4503         # once.
   4504         self.assertEqual(NS(test='**'), args)
   4505 
   4506     def test_issue_15906(self):
   4507         # Issue #15906: When action='append', type=str, default=[] are
   4508         # providing, the dest value was the string representation "[]" when it
   4509         # should have been an empty list.
   4510         parser = argparse.ArgumentParser()
   4511         parser.add_argument('--test', dest='test', type=str,
   4512                             default=[], action='append')
   4513         args = parser.parse_args([])
   4514         self.assertEqual(args.test, [])
   4515 
   4516 # ======================
   4517 # parse_known_args tests
   4518 # ======================
   4519 
   4520 class TestParseKnownArgs(TestCase):
   4521 
   4522     def test_arguments_tuple(self):
   4523         parser = argparse.ArgumentParser()
   4524         parser.parse_args(())
   4525 
   4526     def test_arguments_list(self):
   4527         parser = argparse.ArgumentParser()
   4528         parser.parse_args([])
   4529 
   4530     def test_arguments_tuple_positional(self):
   4531         parser = argparse.ArgumentParser()
   4532         parser.add_argument('x')
   4533         parser.parse_args(('x',))
   4534 
   4535     def test_arguments_list_positional(self):
   4536         parser = argparse.ArgumentParser()
   4537         parser.add_argument('x')
   4538         parser.parse_args(['x'])
   4539 
   4540     def test_optionals(self):
   4541         parser = argparse.ArgumentParser()
   4542         parser.add_argument('--foo')
   4543         args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
   4544         self.assertEqual(NS(foo='F'), args)
   4545         self.assertEqual(['--bar', '--baz'], extras)
   4546 
   4547     def test_mixed(self):
   4548         parser = argparse.ArgumentParser()
   4549         parser.add_argument('-v', nargs='?', const=1, type=int)
   4550         parser.add_argument('--spam', action='store_false')
   4551         parser.add_argument('badger')
   4552 
   4553         argv = ["B", "C", "--foo", "-v", "3", "4"]
   4554         args, extras = parser.parse_known_args(argv)
   4555         self.assertEqual(NS(v=3, spam=True, badger="B"), args)
   4556         self.assertEqual(["C", "--foo", "4"], extras)
   4557 
   4558 # ==========================
   4559 # add_argument metavar tests
   4560 # ==========================
   4561 
   4562 class TestAddArgumentMetavar(TestCase):
   4563 
   4564     EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
   4565 
   4566     def do_test_no_exception(self, nargs, metavar):
   4567         parser = argparse.ArgumentParser()
   4568         parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4569 
   4570     def do_test_exception(self, nargs, metavar):
   4571         parser = argparse.ArgumentParser()
   4572         with self.assertRaises(ValueError) as cm:
   4573             parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4574         self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
   4575 
   4576     # Unit tests for different values of metavar when nargs=None
   4577 
   4578     def test_nargs_None_metavar_string(self):
   4579         self.do_test_no_exception(nargs=None, metavar="1")
   4580 
   4581     def test_nargs_None_metavar_length0(self):
   4582         self.do_test_exception(nargs=None, metavar=tuple())
   4583 
   4584     def test_nargs_None_metavar_length1(self):
   4585         self.do_test_no_exception(nargs=None, metavar=("1"))
   4586 
   4587     def test_nargs_None_metavar_length2(self):
   4588         self.do_test_exception(nargs=None, metavar=("1", "2"))
   4589 
   4590     def test_nargs_None_metavar_length3(self):
   4591         self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
   4592 
   4593     # Unit tests for different values of metavar when nargs=?
   4594 
   4595     def test_nargs_optional_metavar_string(self):
   4596         self.do_test_no_exception(nargs="?", metavar="1")
   4597 
   4598     def test_nargs_optional_metavar_length0(self):
   4599         self.do_test_exception(nargs="?", metavar=tuple())
   4600 
   4601     def test_nargs_optional_metavar_length1(self):
   4602         self.do_test_no_exception(nargs="?", metavar=("1"))
   4603 
   4604     def test_nargs_optional_metavar_length2(self):
   4605         self.do_test_exception(nargs="?", metavar=("1", "2"))
   4606 
   4607     def test_nargs_optional_metavar_length3(self):
   4608         self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
   4609 
   4610     # Unit tests for different values of metavar when nargs=*
   4611 
   4612     def test_nargs_zeroormore_metavar_string(self):
   4613         self.do_test_no_exception(nargs="*", metavar="1")
   4614 
   4615     def test_nargs_zeroormore_metavar_length0(self):
   4616         self.do_test_exception(nargs="*", metavar=tuple())
   4617 
   4618     def test_nargs_zeroormore_metavar_length1(self):
   4619         self.do_test_no_exception(nargs="*", metavar=("1"))
   4620 
   4621     def test_nargs_zeroormore_metavar_length2(self):
   4622         self.do_test_no_exception(nargs="*", metavar=("1", "2"))
   4623 
   4624     def test_nargs_zeroormore_metavar_length3(self):
   4625         self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
   4626 
   4627     # Unit tests for different values of metavar when nargs=+
   4628 
   4629     def test_nargs_oneormore_metavar_string(self):
   4630         self.do_test_no_exception(nargs="+", metavar="1")
   4631 
   4632     def test_nargs_oneormore_metavar_length0(self):
   4633         self.do_test_exception(nargs="+", metavar=tuple())
   4634 
   4635     def test_nargs_oneormore_metavar_length1(self):
   4636         self.do_test_no_exception(nargs="+", metavar=("1"))
   4637 
   4638     def test_nargs_oneormore_metavar_length2(self):
   4639         self.do_test_no_exception(nargs="+", metavar=("1", "2"))
   4640 
   4641     def test_nargs_oneormore_metavar_length3(self):
   4642         self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
   4643 
   4644     # Unit tests for different values of metavar when nargs=...
   4645 
   4646     def test_nargs_remainder_metavar_string(self):
   4647         self.do_test_no_exception(nargs="...", metavar="1")
   4648 
   4649     def test_nargs_remainder_metavar_length0(self):
   4650         self.do_test_no_exception(nargs="...", metavar=tuple())
   4651 
   4652     def test_nargs_remainder_metavar_length1(self):
   4653         self.do_test_no_exception(nargs="...", metavar=("1"))
   4654 
   4655     def test_nargs_remainder_metavar_length2(self):
   4656         self.do_test_no_exception(nargs="...", metavar=("1", "2"))
   4657 
   4658     def test_nargs_remainder_metavar_length3(self):
   4659         self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
   4660 
   4661     # Unit tests for different values of metavar when nargs=A...
   4662 
   4663     def test_nargs_parser_metavar_string(self):
   4664         self.do_test_no_exception(nargs="A...", metavar="1")
   4665 
   4666     def test_nargs_parser_metavar_length0(self):
   4667         self.do_test_exception(nargs="A...", metavar=tuple())
   4668 
   4669     def test_nargs_parser_metavar_length1(self):
   4670         self.do_test_no_exception(nargs="A...", metavar=("1"))
   4671 
   4672     def test_nargs_parser_metavar_length2(self):
   4673         self.do_test_exception(nargs="A...", metavar=("1", "2"))
   4674 
   4675     def test_nargs_parser_metavar_length3(self):
   4676         self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
   4677 
   4678     # Unit tests for different values of metavar when nargs=1
   4679 
   4680     def test_nargs_1_metavar_string(self):
   4681         self.do_test_no_exception(nargs=1, metavar="1")
   4682 
   4683     def test_nargs_1_metavar_length0(self):
   4684         self.do_test_exception(nargs=1, metavar=tuple())
   4685 
   4686     def test_nargs_1_metavar_length1(self):
   4687         self.do_test_no_exception(nargs=1, metavar=("1"))
   4688 
   4689     def test_nargs_1_metavar_length2(self):
   4690         self.do_test_exception(nargs=1, metavar=("1", "2"))
   4691 
   4692     def test_nargs_1_metavar_length3(self):
   4693         self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
   4694 
   4695     # Unit tests for different values of metavar when nargs=2
   4696 
   4697     def test_nargs_2_metavar_string(self):
   4698         self.do_test_no_exception(nargs=2, metavar="1")
   4699 
   4700     def test_nargs_2_metavar_length0(self):
   4701         self.do_test_exception(nargs=2, metavar=tuple())
   4702 
   4703     def test_nargs_2_metavar_length1(self):
   4704         self.do_test_no_exception(nargs=2, metavar=("1"))
   4705 
   4706     def test_nargs_2_metavar_length2(self):
   4707         self.do_test_no_exception(nargs=2, metavar=("1", "2"))
   4708 
   4709     def test_nargs_2_metavar_length3(self):
   4710         self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
   4711 
   4712     # Unit tests for different values of metavar when nargs=3
   4713 
   4714     def test_nargs_3_metavar_string(self):
   4715         self.do_test_no_exception(nargs=3, metavar="1")
   4716 
   4717     def test_nargs_3_metavar_length0(self):
   4718         self.do_test_exception(nargs=3, metavar=tuple())
   4719 
   4720     def test_nargs_3_metavar_length1(self):
   4721         self.do_test_no_exception(nargs=3, metavar=("1"))
   4722 
   4723     def test_nargs_3_metavar_length2(self):
   4724         self.do_test_exception(nargs=3, metavar=("1", "2"))
   4725 
   4726     def test_nargs_3_metavar_length3(self):
   4727         self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
   4728 
   4729 # ============================
   4730 # from argparse import * tests
   4731 # ============================
   4732 
   4733 class TestImportStar(TestCase):
   4734 
   4735     def test(self):
   4736         for name in argparse.__all__:
   4737             self.assertTrue(hasattr(argparse, name))
   4738 
   4739     def test_all_exports_everything_but_modules(self):
   4740         items = [
   4741             name
   4742             for name, value in vars(argparse).items()
   4743             if not name.startswith("_")
   4744             if not inspect.ismodule(value)
   4745         ]
   4746         self.assertEqual(sorted(items), sorted(argparse.__all__))
   4747 
   4748 def test_main():
   4749     # silence warnings about version argument - these are expected
   4750     with test_support.check_warnings(
   4751             ('The "version" argument to ArgumentParser is deprecated.',
   4752              DeprecationWarning),
   4753             ('The (format|print)_version method is deprecated',
   4754              DeprecationWarning)):
   4755         test_support.run_unittest(__name__)
   4756     # Remove global references to avoid looking like we have refleaks.
   4757     RFile.seen = {}
   4758     WFile.seen = set()
   4759 
   4760 
   4761 
   4762 if __name__ == '__main__':
   4763     test_main()
   4764