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         for root, dirs, files in os.walk(self.temp_dir, topdown=False):
     51             for name in files:
     52                 os.chmod(os.path.join(self.temp_dir, name), stat.S_IWRITE)
     53         shutil.rmtree(self.temp_dir, True)
     54 
     55     def create_readonly_file(self, filename):
     56         file_path = os.path.join(self.temp_dir, filename)
     57         with open(file_path, 'w') as file:
     58             file.write(filename)
     59         os.chmod(file_path, stat.S_IREAD)
     60 
     61 class Sig(object):
     62 
     63     def __init__(self, *args, **kwargs):
     64         self.args = args
     65         self.kwargs = kwargs
     66 
     67 
     68 class NS(object):
     69 
     70     def __init__(self, **kwargs):
     71         self.__dict__.update(kwargs)
     72 
     73     def __repr__(self):
     74         sorted_items = sorted(self.__dict__.items())
     75         kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
     76         return '%s(%s)' % (type(self).__name__, kwarg_str)
     77 
     78     __hash__ = None
     79 
     80     def __eq__(self, other):
     81         return vars(self) == vars(other)
     82 
     83     def __ne__(self, other):
     84         return not (self == other)
     85 
     86 
     87 class ArgumentParserError(Exception):
     88 
     89     def __init__(self, message, stdout=None, stderr=None, error_code=None):
     90         Exception.__init__(self, message, stdout, stderr)
     91         self.message = message
     92         self.stdout = stdout
     93         self.stderr = stderr
     94         self.error_code = error_code
     95 
     96 
     97 def stderr_to_parser_error(parse_args, *args, **kwargs):
     98     # if this is being called recursively and stderr or stdout is already being
     99     # redirected, simply call the function and let the enclosing function
    100     # catch the exception
    101     if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
    102         return parse_args(*args, **kwargs)
    103 
    104     # if this is not being called recursively, redirect stderr and
    105     # use it as the ArgumentParserError message
    106     old_stdout = sys.stdout
    107     old_stderr = sys.stderr
    108     sys.stdout = StdIOBuffer()
    109     sys.stderr = StdIOBuffer()
    110     try:
    111         try:
    112             result = parse_args(*args, **kwargs)
    113             for key in list(vars(result)):
    114                 if getattr(result, key) is sys.stdout:
    115                     setattr(result, key, old_stdout)
    116                 if getattr(result, key) is sys.stderr:
    117                     setattr(result, key, old_stderr)
    118             return result
    119         except SystemExit:
    120             code = sys.exc_info()[1].code
    121             stdout = sys.stdout.getvalue()
    122             stderr = sys.stderr.getvalue()
    123             raise ArgumentParserError("SystemExit", stdout, stderr, code)
    124     finally:
    125         sys.stdout = old_stdout
    126         sys.stderr = old_stderr
    127 
    128 
    129 class ErrorRaisingArgumentParser(argparse.ArgumentParser):
    130 
    131     def parse_args(self, *args, **kwargs):
    132         parse_args = super(ErrorRaisingArgumentParser, self).parse_args
    133         return stderr_to_parser_error(parse_args, *args, **kwargs)
    134 
    135     def exit(self, *args, **kwargs):
    136         exit = super(ErrorRaisingArgumentParser, self).exit
    137         return stderr_to_parser_error(exit, *args, **kwargs)
    138 
    139     def error(self, *args, **kwargs):
    140         error = super(ErrorRaisingArgumentParser, self).error
    141         return stderr_to_parser_error(error, *args, **kwargs)
    142 
    143 
    144 class ParserTesterMetaclass(type):
    145     """Adds parser tests using the class attributes.
    146 
    147     Classes of this type should specify the following attributes:
    148 
    149     argument_signatures -- a list of Sig objects which specify
    150         the signatures of Argument objects to be created
    151     failures -- a list of args lists that should cause the parser
    152         to fail
    153     successes -- a list of (initial_args, options, remaining_args) tuples
    154         where initial_args specifies the string args to be parsed,
    155         options is a dict that should match the vars() of the options
    156         parsed out of initial_args, and remaining_args should be any
    157         remaining unparsed arguments
    158     """
    159 
    160     def __init__(cls, name, bases, bodydict):
    161         if name == 'ParserTestCase':
    162             return
    163 
    164         # default parser signature is empty
    165         if not hasattr(cls, 'parser_signature'):
    166             cls.parser_signature = Sig()
    167         if not hasattr(cls, 'parser_class'):
    168             cls.parser_class = ErrorRaisingArgumentParser
    169 
    170         # ---------------------------------------
    171         # functions for adding optional arguments
    172         # ---------------------------------------
    173         def no_groups(parser, argument_signatures):
    174             """Add all arguments directly to the parser"""
    175             for sig in argument_signatures:
    176                 parser.add_argument(*sig.args, **sig.kwargs)
    177 
    178         def one_group(parser, argument_signatures):
    179             """Add all arguments under a single group in the parser"""
    180             group = parser.add_argument_group('foo')
    181             for sig in argument_signatures:
    182                 group.add_argument(*sig.args, **sig.kwargs)
    183 
    184         def many_groups(parser, argument_signatures):
    185             """Add each argument in its own group to the parser"""
    186             for i, sig in enumerate(argument_signatures):
    187                 group = parser.add_argument_group('foo:%i' % i)
    188                 group.add_argument(*sig.args, **sig.kwargs)
    189 
    190         # --------------------------
    191         # functions for parsing args
    192         # --------------------------
    193         def listargs(parser, args):
    194             """Parse the args by passing in a list"""
    195             return parser.parse_args(args)
    196 
    197         def sysargs(parser, args):
    198             """Parse the args by defaulting to sys.argv"""
    199             old_sys_argv = sys.argv
    200             sys.argv = [old_sys_argv[0]] + args
    201             try:
    202                 return parser.parse_args()
    203             finally:
    204                 sys.argv = old_sys_argv
    205 
    206         # class that holds the combination of one optional argument
    207         # addition method and one arg parsing method
    208         class AddTests(object):
    209 
    210             def __init__(self, tester_cls, add_arguments, parse_args):
    211                 self._add_arguments = add_arguments
    212                 self._parse_args = parse_args
    213 
    214                 add_arguments_name = self._add_arguments.__name__
    215                 parse_args_name = self._parse_args.__name__
    216                 for test_func in [self.test_failures, self.test_successes]:
    217                     func_name = test_func.__name__
    218                     names = func_name, add_arguments_name, parse_args_name
    219                     test_name = '_'.join(names)
    220 
    221                     def wrapper(self, test_func=test_func):
    222                         test_func(self)
    223                     try:
    224                         wrapper.__name__ = test_name
    225                     except TypeError:
    226                         pass
    227                     setattr(tester_cls, test_name, wrapper)
    228 
    229             def _get_parser(self, tester):
    230                 args = tester.parser_signature.args
    231                 kwargs = tester.parser_signature.kwargs
    232                 parser = tester.parser_class(*args, **kwargs)
    233                 self._add_arguments(parser, tester.argument_signatures)
    234                 return parser
    235 
    236             def test_failures(self, tester):
    237                 parser = self._get_parser(tester)
    238                 for args_str in tester.failures:
    239                     args = args_str.split()
    240                     raises = tester.assertRaises
    241                     raises(ArgumentParserError, parser.parse_args, args)
    242 
    243             def test_successes(self, tester):
    244                 parser = self._get_parser(tester)
    245                 for args, expected_ns in tester.successes:
    246                     if isinstance(args, str):
    247                         args = args.split()
    248                     result_ns = self._parse_args(parser, args)
    249                     tester.assertEqual(expected_ns, result_ns)
    250 
    251         # add tests for each combination of an optionals adding method
    252         # and an arg parsing method
    253         for add_arguments in [no_groups, one_group, many_groups]:
    254             for parse_args in [listargs, sysargs]:
    255                 AddTests(cls, add_arguments, parse_args)
    256 
    257 bases = TestCase,
    258 ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
    259 
    260 # ===============
    261 # Optionals tests
    262 # ===============
    263 
    264 class TestOptionalsSingleDash(ParserTestCase):
    265     """Test an Optional with a single-dash option string"""
    266 
    267     argument_signatures = [Sig('-x')]
    268     failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
    269     successes = [
    270         ('', NS(x=None)),
    271         ('-x a', NS(x='a')),
    272         ('-xa', NS(x='a')),
    273         ('-x -1', NS(x='-1')),
    274         ('-x-1', NS(x='-1')),
    275     ]
    276 
    277 
    278 class TestOptionalsSingleDashCombined(ParserTestCase):
    279     """Test an Optional with a single-dash option string"""
    280 
    281     argument_signatures = [
    282         Sig('-x', action='store_true'),
    283         Sig('-yyy', action='store_const', const=42),
    284         Sig('-z'),
    285     ]
    286     failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
    287                 '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
    288     successes = [
    289         ('', NS(x=False, yyy=None, z=None)),
    290         ('-x', NS(x=True, yyy=None, z=None)),
    291         ('-za', NS(x=False, yyy=None, z='a')),
    292         ('-z a', NS(x=False, yyy=None, z='a')),
    293         ('-xza', NS(x=True, yyy=None, z='a')),
    294         ('-xz a', NS(x=True, yyy=None, z='a')),
    295         ('-x -za', NS(x=True, yyy=None, z='a')),
    296         ('-x -z a', NS(x=True, yyy=None, z='a')),
    297         ('-y', NS(x=False, yyy=42, z=None)),
    298         ('-yyy', NS(x=False, yyy=42, z=None)),
    299         ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
    300         ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
    301     ]
    302 
    303 
    304 class TestOptionalsSingleDashLong(ParserTestCase):
    305     """Test an Optional with a multi-character single-dash option string"""
    306 
    307     argument_signatures = [Sig('-foo')]
    308     failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
    309     successes = [
    310         ('', NS(foo=None)),
    311         ('-foo a', NS(foo='a')),
    312         ('-foo -1', NS(foo='-1')),
    313         ('-fo a', NS(foo='a')),
    314         ('-f a', NS(foo='a')),
    315     ]
    316 
    317 
    318 class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
    319     """Test Optionals where option strings are subsets of each other"""
    320 
    321     argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
    322     failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
    323     successes = [
    324         ('', NS(f=None, foobar=None, foorab=None)),
    325         ('-f a', NS(f='a', foobar=None, foorab=None)),
    326         ('-fa', NS(f='a', foobar=None, foorab=None)),
    327         ('-foa', NS(f='oa', foobar=None, foorab=None)),
    328         ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
    329         ('-foobar a', NS(f=None, foobar='a', foorab=None)),
    330         ('-foorab a', NS(f=None, foobar=None, foorab='a')),
    331     ]
    332 
    333 
    334 class TestOptionalsSingleDashAmbiguous(ParserTestCase):
    335     """Test Optionals that partially match but are not subsets"""
    336 
    337     argument_signatures = [Sig('-foobar'), Sig('-foorab')]
    338     failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
    339     successes = [
    340         ('', NS(foobar=None, foorab=None)),
    341         ('-foob a', NS(foobar='a', foorab=None)),
    342         ('-foor a', NS(foobar=None, foorab='a')),
    343         ('-fooba a', NS(foobar='a', foorab=None)),
    344         ('-foora a', NS(foobar=None, foorab='a')),
    345         ('-foobar a', NS(foobar='a', foorab=None)),
    346         ('-foorab a', NS(foobar=None, foorab='a')),
    347     ]
    348 
    349 
    350 class TestOptionalsNumeric(ParserTestCase):
    351     """Test an Optional with a short opt string"""
    352 
    353     argument_signatures = [Sig('-1', dest='one')]
    354     failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
    355     successes = [
    356         ('', NS(one=None)),
    357         ('-1 a', NS(one='a')),
    358         ('-1a', NS(one='a')),
    359         ('-1-2', NS(one='-2')),
    360     ]
    361 
    362 
    363 class TestOptionalsDoubleDash(ParserTestCase):
    364     """Test an Optional with a double-dash option string"""
    365 
    366     argument_signatures = [Sig('--foo')]
    367     failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
    368     successes = [
    369         ('', NS(foo=None)),
    370         ('--foo a', NS(foo='a')),
    371         ('--foo=a', NS(foo='a')),
    372         ('--foo -2.5', NS(foo='-2.5')),
    373         ('--foo=-2.5', NS(foo='-2.5')),
    374     ]
    375 
    376 
    377 class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
    378     """Tests partial matching with a double-dash option string"""
    379 
    380     argument_signatures = [
    381         Sig('--badger', action='store_true'),
    382         Sig('--bat'),
    383     ]
    384     failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
    385     successes = [
    386         ('', NS(badger=False, bat=None)),
    387         ('--bat X', NS(badger=False, bat='X')),
    388         ('--bad', NS(badger=True, bat=None)),
    389         ('--badg', NS(badger=True, bat=None)),
    390         ('--badge', NS(badger=True, bat=None)),
    391         ('--badger', NS(badger=True, bat=None)),
    392     ]
    393 
    394 
    395 class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
    396     """Tests when one double-dash option string is a prefix of another"""
    397 
    398     argument_signatures = [
    399         Sig('--badger', action='store_true'),
    400         Sig('--ba'),
    401     ]
    402     failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
    403     successes = [
    404         ('', NS(badger=False, ba=None)),
    405         ('--ba X', NS(badger=False, ba='X')),
    406         ('--ba=X', NS(badger=False, ba='X')),
    407         ('--bad', NS(badger=True, ba=None)),
    408         ('--badg', NS(badger=True, ba=None)),
    409         ('--badge', NS(badger=True, ba=None)),
    410         ('--badger', NS(badger=True, ba=None)),
    411     ]
    412 
    413 
    414 class TestOptionalsSingleDoubleDash(ParserTestCase):
    415     """Test an Optional with single- and double-dash option strings"""
    416 
    417     argument_signatures = [
    418         Sig('-f', action='store_true'),
    419         Sig('--bar'),
    420         Sig('-baz', action='store_const', const=42),
    421     ]
    422     failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
    423     successes = [
    424         ('', NS(f=False, bar=None, baz=None)),
    425         ('-f', NS(f=True, bar=None, baz=None)),
    426         ('--ba B', NS(f=False, bar='B', baz=None)),
    427         ('-f --bar B', NS(f=True, bar='B', baz=None)),
    428         ('-f -b', NS(f=True, bar=None, baz=42)),
    429         ('-ba -f', NS(f=True, bar=None, baz=42)),
    430     ]
    431 
    432 
    433 class TestOptionalsAlternatePrefixChars(ParserTestCase):
    434     """Test an Optional with option strings with custom prefixes"""
    435 
    436     parser_signature = Sig(prefix_chars='+:/', add_help=False)
    437     argument_signatures = [
    438         Sig('+f', action='store_true'),
    439         Sig('::bar'),
    440         Sig('/baz', action='store_const', const=42),
    441     ]
    442     failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
    443     successes = [
    444         ('', NS(f=False, bar=None, baz=None)),
    445         ('+f', NS(f=True, bar=None, baz=None)),
    446         ('::ba B', NS(f=False, bar='B', baz=None)),
    447         ('+f ::bar B', NS(f=True, bar='B', baz=None)),
    448         ('+f /b', NS(f=True, bar=None, baz=42)),
    449         ('/ba +f', NS(f=True, bar=None, baz=42)),
    450     ]
    451 
    452 
    453 class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
    454     """When ``-`` not in prefix_chars, default operators created for help
    455        should use the prefix_chars in use rather than - or --
    456        http://bugs.python.org/issue9444"""
    457 
    458     parser_signature = Sig(prefix_chars='+:/', add_help=True)
    459     argument_signatures = [
    460         Sig('+f', action='store_true'),
    461         Sig('::bar'),
    462         Sig('/baz', action='store_const', const=42),
    463     ]
    464     failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
    465     successes = [
    466         ('', NS(f=False, bar=None, baz=None)),
    467         ('+f', NS(f=True, bar=None, baz=None)),
    468         ('::ba B', NS(f=False, bar='B', baz=None)),
    469         ('+f ::bar B', NS(f=True, bar='B', baz=None)),
    470         ('+f /b', NS(f=True, bar=None, baz=42)),
    471         ('/ba +f', NS(f=True, bar=None, baz=42))
    472     ]
    473 
    474 
    475 class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
    476     """Verify that Optionals must be called with their defined prefixes"""
    477 
    478     parser_signature = Sig(prefix_chars='+-', add_help=False)
    479     argument_signatures = [
    480         Sig('-x', action='store_true'),
    481         Sig('+y', action='store_true'),
    482         Sig('+z', action='store_true'),
    483     ]
    484     failures = ['-w',
    485                 '-xyz',
    486                 '+x',
    487                 '-y',
    488                 '+xyz',
    489     ]
    490     successes = [
    491         ('', NS(x=False, y=False, z=False)),
    492         ('-x', NS(x=True, y=False, z=False)),
    493         ('+y -x', NS(x=True, y=True, z=False)),
    494         ('+yz -x', NS(x=True, y=True, z=True)),
    495     ]
    496 
    497 
    498 class TestOptionalsShortLong(ParserTestCase):
    499     """Test a combination of single- and double-dash option strings"""
    500 
    501     argument_signatures = [
    502         Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
    503     ]
    504     failures = ['--x --verbose', '-N', 'a', '-v x']
    505     successes = [
    506         ('', NS(verbose=False)),
    507         ('-v', NS(verbose=True)),
    508         ('--verbose', NS(verbose=True)),
    509         ('-n', NS(verbose=True)),
    510         ('--noisy', NS(verbose=True)),
    511     ]
    512 
    513 
    514 class TestOptionalsDest(ParserTestCase):
    515     """Tests various means of setting destination"""
    516 
    517     argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
    518     failures = ['a']
    519     successes = [
    520         ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
    521         ('--baz g', NS(foo_bar=None, zabbaz='g')),
    522         ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
    523         ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
    524     ]
    525 
    526 
    527 class TestOptionalsDefault(ParserTestCase):
    528     """Tests specifying a default for an Optional"""
    529 
    530     argument_signatures = [Sig('-x'), Sig('-y', default=42)]
    531     failures = ['a']
    532     successes = [
    533         ('', NS(x=None, y=42)),
    534         ('-xx', NS(x='x', y=42)),
    535         ('-yy', NS(x=None, y='y')),
    536     ]
    537 
    538 
    539 class TestOptionalsNargsDefault(ParserTestCase):
    540     """Tests not specifying the number of args for an Optional"""
    541 
    542     argument_signatures = [Sig('-x')]
    543     failures = ['a', '-x']
    544     successes = [
    545         ('', NS(x=None)),
    546         ('-x a', NS(x='a')),
    547     ]
    548 
    549 
    550 class TestOptionalsNargs1(ParserTestCase):
    551     """Tests specifying 1 arg for an Optional"""
    552 
    553     argument_signatures = [Sig('-x', nargs=1)]
    554     failures = ['a', '-x']
    555     successes = [
    556         ('', NS(x=None)),
    557         ('-x a', NS(x=['a'])),
    558     ]
    559 
    560 
    561 class TestOptionalsNargs3(ParserTestCase):
    562     """Tests specifying 3 args for an Optional"""
    563 
    564     argument_signatures = [Sig('-x', nargs=3)]
    565     failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
    566     successes = [
    567         ('', NS(x=None)),
    568         ('-x a b c', NS(x=['a', 'b', 'c'])),
    569     ]
    570 
    571 
    572 class TestOptionalsNargsOptional(ParserTestCase):
    573     """Tests specifying an Optional arg for an Optional"""
    574 
    575     argument_signatures = [
    576         Sig('-w', nargs='?'),
    577         Sig('-x', nargs='?', const=42),
    578         Sig('-y', nargs='?', default='spam'),
    579         Sig('-z', nargs='?', type=int, const='42', default='84'),
    580     ]
    581     failures = ['2']
    582     successes = [
    583         ('', NS(w=None, x=None, y='spam', z=84)),
    584         ('-w', NS(w=None, x=None, y='spam', z=84)),
    585         ('-w 2', NS(w='2', x=None, y='spam', z=84)),
    586         ('-x', NS(w=None, x=42, y='spam', z=84)),
    587         ('-x 2', NS(w=None, x='2', y='spam', z=84)),
    588         ('-y', NS(w=None, x=None, y=None, z=84)),
    589         ('-y 2', NS(w=None, x=None, y='2', z=84)),
    590         ('-z', NS(w=None, x=None, y='spam', z=42)),
    591         ('-z 2', NS(w=None, x=None, y='spam', z=2)),
    592     ]
    593 
    594 
    595 class TestOptionalsNargsZeroOrMore(ParserTestCase):
    596     """Tests specifying args for an Optional that accepts zero or more"""
    597 
    598     argument_signatures = [
    599         Sig('-x', nargs='*'),
    600         Sig('-y', nargs='*', default='spam'),
    601     ]
    602     failures = ['a']
    603     successes = [
    604         ('', NS(x=None, y='spam')),
    605         ('-x', NS(x=[], y='spam')),
    606         ('-x a', NS(x=['a'], y='spam')),
    607         ('-x a b', NS(x=['a', 'b'], y='spam')),
    608         ('-y', NS(x=None, y=[])),
    609         ('-y a', NS(x=None, y=['a'])),
    610         ('-y a b', NS(x=None, y=['a', 'b'])),
    611     ]
    612 
    613 
    614 class TestOptionalsNargsOneOrMore(ParserTestCase):
    615     """Tests specifying args for an Optional that accepts one or more"""
    616 
    617     argument_signatures = [
    618         Sig('-x', nargs='+'),
    619         Sig('-y', nargs='+', default='spam'),
    620     ]
    621     failures = ['a', '-x', '-y', 'a -x', 'a -y b']
    622     successes = [
    623         ('', NS(x=None, y='spam')),
    624         ('-x a', NS(x=['a'], y='spam')),
    625         ('-x a b', NS(x=['a', 'b'], y='spam')),
    626         ('-y a', NS(x=None, y=['a'])),
    627         ('-y a b', NS(x=None, y=['a', 'b'])),
    628     ]
    629 
    630 
    631 class TestOptionalsChoices(ParserTestCase):
    632     """Tests specifying the choices for an Optional"""
    633 
    634     argument_signatures = [
    635         Sig('-f', choices='abc'),
    636         Sig('-g', type=int, choices=range(5))]
    637     failures = ['a', '-f d', '-fad', '-ga', '-g 6']
    638     successes = [
    639         ('', NS(f=None, g=None)),
    640         ('-f a', NS(f='a', g=None)),
    641         ('-f c', NS(f='c', g=None)),
    642         ('-g 0', NS(f=None, g=0)),
    643         ('-g 03', NS(f=None, g=3)),
    644         ('-fb -g4', NS(f='b', g=4)),
    645     ]
    646 
    647 
    648 class TestOptionalsRequired(ParserTestCase):
    649     """Tests an optional action that is required"""
    650 
    651     argument_signatures = [
    652         Sig('-x', type=int, required=True),
    653     ]
    654     failures = ['a', '']
    655     successes = [
    656         ('-x 1', NS(x=1)),
    657         ('-x42', NS(x=42)),
    658     ]
    659 
    660 
    661 class TestOptionalsActionStore(ParserTestCase):
    662     """Tests the store action for an Optional"""
    663 
    664     argument_signatures = [Sig('-x', action='store')]
    665     failures = ['a', 'a -x']
    666     successes = [
    667         ('', NS(x=None)),
    668         ('-xfoo', NS(x='foo')),
    669     ]
    670 
    671 
    672 class TestOptionalsActionStoreConst(ParserTestCase):
    673     """Tests the store_const action for an Optional"""
    674 
    675     argument_signatures = [Sig('-y', action='store_const', const=object)]
    676     failures = ['a']
    677     successes = [
    678         ('', NS(y=None)),
    679         ('-y', NS(y=object)),
    680     ]
    681 
    682 
    683 class TestOptionalsActionStoreFalse(ParserTestCase):
    684     """Tests the store_false action for an Optional"""
    685 
    686     argument_signatures = [Sig('-z', action='store_false')]
    687     failures = ['a', '-za', '-z a']
    688     successes = [
    689         ('', NS(z=True)),
    690         ('-z', NS(z=False)),
    691     ]
    692 
    693 
    694 class TestOptionalsActionStoreTrue(ParserTestCase):
    695     """Tests the store_true action for an Optional"""
    696 
    697     argument_signatures = [Sig('--apple', action='store_true')]
    698     failures = ['a', '--apple=b', '--apple b']
    699     successes = [
    700         ('', NS(apple=False)),
    701         ('--apple', NS(apple=True)),
    702     ]
    703 
    704 
    705 class TestOptionalsActionAppend(ParserTestCase):
    706     """Tests the append action for an Optional"""
    707 
    708     argument_signatures = [Sig('--baz', action='append')]
    709     failures = ['a', '--baz', 'a --baz', '--baz a b']
    710     successes = [
    711         ('', NS(baz=None)),
    712         ('--baz a', NS(baz=['a'])),
    713         ('--baz a --baz b', NS(baz=['a', 'b'])),
    714     ]
    715 
    716 
    717 class TestOptionalsActionAppendWithDefault(ParserTestCase):
    718     """Tests the append action for an Optional"""
    719 
    720     argument_signatures = [Sig('--baz', action='append', default=['X'])]
    721     failures = ['a', '--baz', 'a --baz', '--baz a b']
    722     successes = [
    723         ('', NS(baz=['X'])),
    724         ('--baz a', NS(baz=['X', 'a'])),
    725         ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
    726     ]
    727 
    728 
    729 class TestOptionalsActionAppendConst(ParserTestCase):
    730     """Tests the append_const action for an Optional"""
    731 
    732     argument_signatures = [
    733         Sig('-b', action='append_const', const=Exception),
    734         Sig('-c', action='append', dest='b'),
    735     ]
    736     failures = ['a', '-c', 'a -c', '-bx', '-b x']
    737     successes = [
    738         ('', NS(b=None)),
    739         ('-b', NS(b=[Exception])),
    740         ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
    741     ]
    742 
    743 
    744 class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
    745     """Tests the append_const action for an Optional"""
    746 
    747     argument_signatures = [
    748         Sig('-b', action='append_const', const=Exception, default=['X']),
    749         Sig('-c', action='append', dest='b'),
    750     ]
    751     failures = ['a', '-c', 'a -c', '-bx', '-b x']
    752     successes = [
    753         ('', NS(b=['X'])),
    754         ('-b', NS(b=['X', Exception])),
    755         ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
    756     ]
    757 
    758 
    759 class TestOptionalsActionCount(ParserTestCase):
    760     """Tests the count action for an Optional"""
    761 
    762     argument_signatures = [Sig('-x', action='count')]
    763     failures = ['a', '-x a', '-x b', '-x a -x b']
    764     successes = [
    765         ('', NS(x=None)),
    766         ('-x', NS(x=1)),
    767     ]
    768 
    769 
    770 # ================
    771 # Positional tests
    772 # ================
    773 
    774 class TestPositionalsNargsNone(ParserTestCase):
    775     """Test a Positional that doesn't specify nargs"""
    776 
    777     argument_signatures = [Sig('foo')]
    778     failures = ['', '-x', 'a b']
    779     successes = [
    780         ('a', NS(foo='a')),
    781     ]
    782 
    783 
    784 class TestPositionalsNargs1(ParserTestCase):
    785     """Test a Positional that specifies an nargs of 1"""
    786 
    787     argument_signatures = [Sig('foo', nargs=1)]
    788     failures = ['', '-x', 'a b']
    789     successes = [
    790         ('a', NS(foo=['a'])),
    791     ]
    792 
    793 
    794 class TestPositionalsNargs2(ParserTestCase):
    795     """Test a Positional that specifies an nargs of 2"""
    796 
    797     argument_signatures = [Sig('foo', nargs=2)]
    798     failures = ['', 'a', '-x', 'a b c']
    799     successes = [
    800         ('a b', NS(foo=['a', 'b'])),
    801     ]
    802 
    803 
    804 class TestPositionalsNargsZeroOrMore(ParserTestCase):
    805     """Test a Positional that specifies unlimited nargs"""
    806 
    807     argument_signatures = [Sig('foo', nargs='*')]
    808     failures = ['-x']
    809     successes = [
    810         ('', NS(foo=[])),
    811         ('a', NS(foo=['a'])),
    812         ('a b', NS(foo=['a', 'b'])),
    813     ]
    814 
    815 
    816 class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
    817     """Test a Positional that specifies unlimited nargs and a default"""
    818 
    819     argument_signatures = [Sig('foo', nargs='*', default='bar')]
    820     failures = ['-x']
    821     successes = [
    822         ('', NS(foo='bar')),
    823         ('a', NS(foo=['a'])),
    824         ('a b', NS(foo=['a', 'b'])),
    825     ]
    826 
    827 
    828 class TestPositionalsNargsOneOrMore(ParserTestCase):
    829     """Test a Positional that specifies one or more nargs"""
    830 
    831     argument_signatures = [Sig('foo', nargs='+')]
    832     failures = ['', '-x']
    833     successes = [
    834         ('a', NS(foo=['a'])),
    835         ('a b', NS(foo=['a', 'b'])),
    836     ]
    837 
    838 
    839 class TestPositionalsNargsOptional(ParserTestCase):
    840     """Tests an Optional Positional"""
    841 
    842     argument_signatures = [Sig('foo', nargs='?')]
    843     failures = ['-x', 'a b']
    844     successes = [
    845         ('', NS(foo=None)),
    846         ('a', NS(foo='a')),
    847     ]
    848 
    849 
    850 class TestPositionalsNargsOptionalDefault(ParserTestCase):
    851     """Tests an Optional Positional with a default value"""
    852 
    853     argument_signatures = [Sig('foo', nargs='?', default=42)]
    854     failures = ['-x', 'a b']
    855     successes = [
    856         ('', NS(foo=42)),
    857         ('a', NS(foo='a')),
    858     ]
    859 
    860 
    861 class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
    862     """Tests an Optional Positional with a default value
    863     that needs to be converted to the appropriate type.
    864     """
    865 
    866     argument_signatures = [
    867         Sig('foo', nargs='?', type=int, default='42'),
    868     ]
    869     failures = ['-x', 'a b', '1 2']
    870     successes = [
    871         ('', NS(foo=42)),
    872         ('1', NS(foo=1)),
    873     ]
    874 
    875 
    876 class TestPositionalsNargsNoneNone(ParserTestCase):
    877     """Test two Positionals that don't specify nargs"""
    878 
    879     argument_signatures = [Sig('foo'), Sig('bar')]
    880     failures = ['', '-x', 'a', 'a b c']
    881     successes = [
    882         ('a b', NS(foo='a', bar='b')),
    883     ]
    884 
    885 
    886 class TestPositionalsNargsNone1(ParserTestCase):
    887     """Test a Positional with no nargs followed by one with 1"""
    888 
    889     argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
    890     failures = ['', '--foo', 'a', 'a b c']
    891     successes = [
    892         ('a b', NS(foo='a', bar=['b'])),
    893     ]
    894 
    895 
    896 class TestPositionalsNargs2None(ParserTestCase):
    897     """Test a Positional with 2 nargs followed by one with none"""
    898 
    899     argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
    900     failures = ['', '--foo', 'a', 'a b', 'a b c d']
    901     successes = [
    902         ('a b c', NS(foo=['a', 'b'], bar='c')),
    903     ]
    904 
    905 
    906 class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
    907     """Test a Positional with no nargs followed by one with unlimited"""
    908 
    909     argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
    910     failures = ['', '--foo']
    911     successes = [
    912         ('a', NS(foo='a', bar=[])),
    913         ('a b', NS(foo='a', bar=['b'])),
    914         ('a b c', NS(foo='a', bar=['b', 'c'])),
    915     ]
    916 
    917 
    918 class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
    919     """Test a Positional with no nargs followed by one with one or more"""
    920 
    921     argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
    922     failures = ['', '--foo', 'a']
    923     successes = [
    924         ('a b', NS(foo='a', bar=['b'])),
    925         ('a b c', NS(foo='a', bar=['b', 'c'])),
    926     ]
    927 
    928 
    929 class TestPositionalsNargsNoneOptional(ParserTestCase):
    930     """Test a Positional with no nargs followed by one with an Optional"""
    931 
    932     argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
    933     failures = ['', '--foo', 'a b c']
    934     successes = [
    935         ('a', NS(foo='a', bar=None)),
    936         ('a b', NS(foo='a', bar='b')),
    937     ]
    938 
    939 
    940 class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
    941     """Test a Positional with unlimited nargs followed by one with none"""
    942 
    943     argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
    944     failures = ['', '--foo']
    945     successes = [
    946         ('a', NS(foo=[], bar='a')),
    947         ('a b', NS(foo=['a'], bar='b')),
    948         ('a b c', NS(foo=['a', 'b'], bar='c')),
    949     ]
    950 
    951 
    952 class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
    953     """Test a Positional with one or more nargs followed by one with none"""
    954 
    955     argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
    956     failures = ['', '--foo', 'a']
    957     successes = [
    958         ('a b', NS(foo=['a'], bar='b')),
    959         ('a b c', NS(foo=['a', 'b'], bar='c')),
    960     ]
    961 
    962 
    963 class TestPositionalsNargsOptionalNone(ParserTestCase):
    964     """Test a Positional with an Optional nargs followed by one with none"""
    965 
    966     argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
    967     failures = ['', '--foo', 'a b c']
    968     successes = [
    969         ('a', NS(foo=42, bar='a')),
    970         ('a b', NS(foo='a', bar='b')),
    971     ]
    972 
    973 
    974 class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
    975     """Test a Positional with 2 nargs followed by one with unlimited"""
    976 
    977     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
    978     failures = ['', '--foo', 'a']
    979     successes = [
    980         ('a b', NS(foo=['a', 'b'], bar=[])),
    981         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
    982     ]
    983 
    984 
    985 class TestPositionalsNargs2OneOrMore(ParserTestCase):
    986     """Test a Positional with 2 nargs followed by one with one or more"""
    987 
    988     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
    989     failures = ['', '--foo', 'a', 'a b']
    990     successes = [
    991         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
    992     ]
    993 
    994 
    995 class TestPositionalsNargs2Optional(ParserTestCase):
    996     """Test a Positional with 2 nargs followed by one optional"""
    997 
    998     argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
    999     failures = ['', '--foo', 'a', 'a b c d']
   1000     successes = [
   1001         ('a b', NS(foo=['a', 'b'], bar=None)),
   1002         ('a b c', NS(foo=['a', 'b'], bar='c')),
   1003     ]
   1004 
   1005 
   1006 class TestPositionalsNargsZeroOrMore1(ParserTestCase):
   1007     """Test a Positional with unlimited nargs followed by one with 1"""
   1008 
   1009     argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
   1010     failures = ['', '--foo', ]
   1011     successes = [
   1012         ('a', NS(foo=[], bar=['a'])),
   1013         ('a b', NS(foo=['a'], bar=['b'])),
   1014         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
   1015     ]
   1016 
   1017 
   1018 class TestPositionalsNargsOneOrMore1(ParserTestCase):
   1019     """Test a Positional with one or more nargs followed by one with 1"""
   1020 
   1021     argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
   1022     failures = ['', '--foo', 'a']
   1023     successes = [
   1024         ('a b', NS(foo=['a'], bar=['b'])),
   1025         ('a b c', NS(foo=['a', 'b'], bar=['c'])),
   1026     ]
   1027 
   1028 
   1029 class TestPositionalsNargsOptional1(ParserTestCase):
   1030     """Test a Positional with an Optional nargs followed by one with 1"""
   1031 
   1032     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
   1033     failures = ['', '--foo', 'a b c']
   1034     successes = [
   1035         ('a', NS(foo=None, bar=['a'])),
   1036         ('a b', NS(foo='a', bar=['b'])),
   1037     ]
   1038 
   1039 
   1040 class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
   1041     """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
   1042 
   1043     argument_signatures = [
   1044         Sig('foo'),
   1045         Sig('bar', nargs='*'),
   1046         Sig('baz', nargs=1),
   1047     ]
   1048     failures = ['', '--foo', 'a']
   1049     successes = [
   1050         ('a b', NS(foo='a', bar=[], baz=['b'])),
   1051         ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
   1052     ]
   1053 
   1054 
   1055 class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
   1056     """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
   1057 
   1058     argument_signatures = [
   1059         Sig('foo'),
   1060         Sig('bar', nargs='+'),
   1061         Sig('baz', nargs=1),
   1062     ]
   1063     failures = ['', '--foo', 'a', 'b']
   1064     successes = [
   1065         ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
   1066         ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
   1067     ]
   1068 
   1069 
   1070 class TestPositionalsNargsNoneOptional1(ParserTestCase):
   1071     """Test three Positionals: no nargs, optional narg and 1 nargs"""
   1072 
   1073     argument_signatures = [
   1074         Sig('foo'),
   1075         Sig('bar', nargs='?', default=0.625),
   1076         Sig('baz', nargs=1),
   1077     ]
   1078     failures = ['', '--foo', 'a']
   1079     successes = [
   1080         ('a b', NS(foo='a', bar=0.625, baz=['b'])),
   1081         ('a b c', NS(foo='a', bar='b', baz=['c'])),
   1082     ]
   1083 
   1084 
   1085 class TestPositionalsNargsOptionalOptional(ParserTestCase):
   1086     """Test two optional nargs"""
   1087 
   1088     argument_signatures = [
   1089         Sig('foo', nargs='?'),
   1090         Sig('bar', nargs='?', default=42),
   1091     ]
   1092     failures = ['--foo', 'a b c']
   1093     successes = [
   1094         ('', NS(foo=None, bar=42)),
   1095         ('a', NS(foo='a', bar=42)),
   1096         ('a b', NS(foo='a', bar='b')),
   1097     ]
   1098 
   1099 
   1100 class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
   1101     """Test an Optional narg followed by unlimited nargs"""
   1102 
   1103     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
   1104     failures = ['--foo']
   1105     successes = [
   1106         ('', NS(foo=None, bar=[])),
   1107         ('a', NS(foo='a', bar=[])),
   1108         ('a b', NS(foo='a', bar=['b'])),
   1109         ('a b c', NS(foo='a', bar=['b', 'c'])),
   1110     ]
   1111 
   1112 
   1113 class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
   1114     """Test an Optional narg followed by one or more nargs"""
   1115 
   1116     argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
   1117     failures = ['', '--foo']
   1118     successes = [
   1119         ('a', NS(foo=None, bar=['a'])),
   1120         ('a b', NS(foo='a', bar=['b'])),
   1121         ('a b c', NS(foo='a', bar=['b', 'c'])),
   1122     ]
   1123 
   1124 
   1125 class TestPositionalsChoicesString(ParserTestCase):
   1126     """Test a set of single-character choices"""
   1127 
   1128     argument_signatures = [Sig('spam', choices=set('abcdefg'))]
   1129     failures = ['', '--foo', 'h', '42', 'ef']
   1130     successes = [
   1131         ('a', NS(spam='a')),
   1132         ('g', NS(spam='g')),
   1133     ]
   1134 
   1135 
   1136 class TestPositionalsChoicesInt(ParserTestCase):
   1137     """Test a set of integer choices"""
   1138 
   1139     argument_signatures = [Sig('spam', type=int, choices=range(20))]
   1140     failures = ['', '--foo', 'h', '42', 'ef']
   1141     successes = [
   1142         ('4', NS(spam=4)),
   1143         ('15', NS(spam=15)),
   1144     ]
   1145 
   1146 
   1147 class TestPositionalsActionAppend(ParserTestCase):
   1148     """Test the 'append' action"""
   1149 
   1150     argument_signatures = [
   1151         Sig('spam', action='append'),
   1152         Sig('spam', action='append', nargs=2),
   1153     ]
   1154     failures = ['', '--foo', 'a', 'a b', 'a b c d']
   1155     successes = [
   1156         ('a b c', NS(spam=['a', ['b', 'c']])),
   1157     ]
   1158 
   1159 # ========================================
   1160 # Combined optionals and positionals tests
   1161 # ========================================
   1162 
   1163 class TestOptionalsNumericAndPositionals(ParserTestCase):
   1164     """Tests negative number args when numeric options are present"""
   1165 
   1166     argument_signatures = [
   1167         Sig('x', nargs='?'),
   1168         Sig('-4', dest='y', action='store_true'),
   1169     ]
   1170     failures = ['-2', '-315']
   1171     successes = [
   1172         ('', NS(x=None, y=False)),
   1173         ('a', NS(x='a', y=False)),
   1174         ('-4', NS(x=None, y=True)),
   1175         ('-4 a', NS(x='a', y=True)),
   1176     ]
   1177 
   1178 
   1179 class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
   1180     """Tests negative number args when almost numeric options are present"""
   1181 
   1182     argument_signatures = [
   1183         Sig('x', nargs='?'),
   1184         Sig('-k4', dest='y', action='store_true'),
   1185     ]
   1186     failures = ['-k3']
   1187     successes = [
   1188         ('', NS(x=None, y=False)),
   1189         ('-2', NS(x='-2', y=False)),
   1190         ('a', NS(x='a', y=False)),
   1191         ('-k4', NS(x=None, y=True)),
   1192         ('-k4 a', NS(x='a', y=True)),
   1193     ]
   1194 
   1195 
   1196 class TestEmptyAndSpaceContainingArguments(ParserTestCase):
   1197 
   1198     argument_signatures = [
   1199         Sig('x', nargs='?'),
   1200         Sig('-y', '--yyy', dest='y'),
   1201     ]
   1202     failures = ['-y']
   1203     successes = [
   1204         ([''], NS(x='', y=None)),
   1205         (['a badger'], NS(x='a badger', y=None)),
   1206         (['-a badger'], NS(x='-a badger', y=None)),
   1207         (['-y', ''], NS(x=None, y='')),
   1208         (['-y', 'a badger'], NS(x=None, y='a badger')),
   1209         (['-y', '-a badger'], NS(x=None, y='-a badger')),
   1210         (['--yyy=a badger'], NS(x=None, y='a badger')),
   1211         (['--yyy=-a badger'], NS(x=None, y='-a badger')),
   1212     ]
   1213 
   1214 
   1215 class TestPrefixCharacterOnlyArguments(ParserTestCase):
   1216 
   1217     parser_signature = Sig(prefix_chars='-+')
   1218     argument_signatures = [
   1219         Sig('-', dest='x', nargs='?', const='badger'),
   1220         Sig('+', dest='y', type=int, default=42),
   1221         Sig('-+-', dest='z', action='store_true'),
   1222     ]
   1223     failures = ['-y', '+ -']
   1224     successes = [
   1225         ('', NS(x=None, y=42, z=False)),
   1226         ('-', NS(x='badger', y=42, z=False)),
   1227         ('- X', NS(x='X', y=42, z=False)),
   1228         ('+ -3', NS(x=None, y=-3, z=False)),
   1229         ('-+-', NS(x=None, y=42, z=True)),
   1230         ('- ===', NS(x='===', y=42, z=False)),
   1231     ]
   1232 
   1233 
   1234 class TestNargsZeroOrMore(ParserTestCase):
   1235     """Tests specifying args for an Optional that accepts zero or more"""
   1236 
   1237     argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
   1238     failures = []
   1239     successes = [
   1240         ('', NS(x=None, y=[])),
   1241         ('-x', NS(x=[], y=[])),
   1242         ('-x a', NS(x=['a'], y=[])),
   1243         ('-x a -- b', NS(x=['a'], y=['b'])),
   1244         ('a', NS(x=None, y=['a'])),
   1245         ('a -x', NS(x=[], y=['a'])),
   1246         ('a -x b', NS(x=['b'], y=['a'])),
   1247     ]
   1248 
   1249 
   1250 class TestNargsRemainder(ParserTestCase):
   1251     """Tests specifying a positional with nargs=REMAINDER"""
   1252 
   1253     argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
   1254     failures = ['', '-z', '-z Z']
   1255     successes = [
   1256         ('X', NS(x='X', y=[], z=None)),
   1257         ('-z Z X', NS(x='X', y=[], z='Z')),
   1258         ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
   1259         ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
   1260     ]
   1261 
   1262 
   1263 class TestOptionLike(ParserTestCase):
   1264     """Tests options that may or may not be arguments"""
   1265 
   1266     argument_signatures = [
   1267         Sig('-x', type=float),
   1268         Sig('-3', type=float, dest='y'),
   1269         Sig('z', nargs='*'),
   1270     ]
   1271     failures = ['-x', '-y2.5', '-xa', '-x -a',
   1272                 '-x -3', '-x -3.5', '-3 -3.5',
   1273                 '-x -2.5', '-x -2.5 a', '-3 -.5',
   1274                 'a x -1', '-x -1 a', '-3 -1 a']
   1275     successes = [
   1276         ('', NS(x=None, y=None, z=[])),
   1277         ('-x 2.5', NS(x=2.5, y=None, z=[])),
   1278         ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
   1279         ('-3.5', NS(x=None, y=0.5, z=[])),
   1280         ('-3-.5', NS(x=None, y=-0.5, z=[])),
   1281         ('-3 .5', NS(x=None, y=0.5, z=[])),
   1282         ('a -3.5', NS(x=None, y=0.5, z=['a'])),
   1283         ('a', NS(x=None, y=None, z=['a'])),
   1284         ('a -x 1', NS(x=1.0, y=None, z=['a'])),
   1285         ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
   1286         ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
   1287     ]
   1288 
   1289 
   1290 class TestDefaultSuppress(ParserTestCase):
   1291     """Test actions with suppressed defaults"""
   1292 
   1293     argument_signatures = [
   1294         Sig('foo', nargs='?', default=argparse.SUPPRESS),
   1295         Sig('bar', nargs='*', default=argparse.SUPPRESS),
   1296         Sig('--baz', action='store_true', default=argparse.SUPPRESS),
   1297     ]
   1298     failures = ['-x']
   1299     successes = [
   1300         ('', NS()),
   1301         ('a', NS(foo='a')),
   1302         ('a b', NS(foo='a', bar=['b'])),
   1303         ('--baz', NS(baz=True)),
   1304         ('a --baz', NS(foo='a', baz=True)),
   1305         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1306     ]
   1307 
   1308 
   1309 class TestParserDefaultSuppress(ParserTestCase):
   1310     """Test actions with a parser-level default of SUPPRESS"""
   1311 
   1312     parser_signature = Sig(argument_default=argparse.SUPPRESS)
   1313     argument_signatures = [
   1314         Sig('foo', nargs='?'),
   1315         Sig('bar', nargs='*'),
   1316         Sig('--baz', action='store_true'),
   1317     ]
   1318     failures = ['-x']
   1319     successes = [
   1320         ('', NS()),
   1321         ('a', NS(foo='a')),
   1322         ('a b', NS(foo='a', bar=['b'])),
   1323         ('--baz', NS(baz=True)),
   1324         ('a --baz', NS(foo='a', baz=True)),
   1325         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1326     ]
   1327 
   1328 
   1329 class TestParserDefault42(ParserTestCase):
   1330     """Test actions with a parser-level default of 42"""
   1331 
   1332     parser_signature = Sig(argument_default=42, version='1.0')
   1333     argument_signatures = [
   1334         Sig('foo', nargs='?'),
   1335         Sig('bar', nargs='*'),
   1336         Sig('--baz', action='store_true'),
   1337     ]
   1338     failures = ['-x']
   1339     successes = [
   1340         ('', NS(foo=42, bar=42, baz=42)),
   1341         ('a', NS(foo='a', bar=42, baz=42)),
   1342         ('a b', NS(foo='a', bar=['b'], baz=42)),
   1343         ('--baz', NS(foo=42, bar=42, baz=True)),
   1344         ('a --baz', NS(foo='a', bar=42, baz=True)),
   1345         ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
   1346     ]
   1347 
   1348 
   1349 class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
   1350     """Test reading arguments from a file"""
   1351 
   1352     def setUp(self):
   1353         super(TestArgumentsFromFile, self).setUp()
   1354         file_texts = [
   1355             ('hello', 'hello world!\n'),
   1356             ('recursive', '-a\n'
   1357                           'A\n'
   1358                           '@hello'),
   1359             ('invalid', '@no-such-path\n'),
   1360         ]
   1361         for path, text in file_texts:
   1362             file = open(path, 'w')
   1363             file.write(text)
   1364             file.close()
   1365 
   1366     parser_signature = Sig(fromfile_prefix_chars='@')
   1367     argument_signatures = [
   1368         Sig('-a'),
   1369         Sig('x'),
   1370         Sig('y', nargs='+'),
   1371     ]
   1372     failures = ['', '-b', 'X', '@invalid', '@missing']
   1373     successes = [
   1374         ('X Y', NS(a=None, x='X', y=['Y'])),
   1375         ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
   1376         ('@hello X', NS(a=None, x='hello world!', y=['X'])),
   1377         ('X @hello', NS(a=None, x='X', y=['hello world!'])),
   1378         ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
   1379         ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
   1380         (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
   1381     ]
   1382 
   1383 
   1384 class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
   1385     """Test reading arguments from a file"""
   1386 
   1387     def setUp(self):
   1388         super(TestArgumentsFromFileConverter, self).setUp()
   1389         file_texts = [
   1390             ('hello', 'hello world!\n'),
   1391         ]
   1392         for path, text in file_texts:
   1393             file = open(path, 'w')
   1394             file.write(text)
   1395             file.close()
   1396 
   1397     class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
   1398 
   1399         def convert_arg_line_to_args(self, arg_line):
   1400             for arg in arg_line.split():
   1401                 if not arg.strip():
   1402                     continue
   1403                 yield arg
   1404     parser_class = FromFileConverterArgumentParser
   1405     parser_signature = Sig(fromfile_prefix_chars='@')
   1406     argument_signatures = [
   1407         Sig('y', nargs='+'),
   1408     ]
   1409     failures = []
   1410     successes = [
   1411         ('@hello X', NS(y=['hello', 'world!', 'X'])),
   1412     ]
   1413 
   1414 
   1415 # =====================
   1416 # Type conversion tests
   1417 # =====================
   1418 
   1419 class TestFileTypeRepr(TestCase):
   1420 
   1421     def test_r(self):
   1422         type = argparse.FileType('r')
   1423         self.assertEqual("FileType('r')", repr(type))
   1424 
   1425     def test_wb_1(self):
   1426         type = argparse.FileType('wb', 1)
   1427         self.assertEqual("FileType('wb', 1)", repr(type))
   1428 
   1429 
   1430 class RFile(object):
   1431     seen = {}
   1432 
   1433     def __init__(self, name):
   1434         self.name = name
   1435 
   1436     __hash__ = None
   1437 
   1438     def __eq__(self, other):
   1439         if other in self.seen:
   1440             text = self.seen[other]
   1441         else:
   1442             text = self.seen[other] = other.read()
   1443             other.close()
   1444         if not isinstance(text, str):
   1445             text = text.decode('ascii')
   1446         return self.name == other.name == text
   1447 
   1448 
   1449 class TestFileTypeR(TempDirMixin, ParserTestCase):
   1450     """Test the FileType option/argument type for reading files"""
   1451 
   1452     def setUp(self):
   1453         super(TestFileTypeR, self).setUp()
   1454         for file_name in ['foo', 'bar']:
   1455             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1456             file.write(file_name)
   1457             file.close()
   1458         self.create_readonly_file('readonly')
   1459 
   1460     argument_signatures = [
   1461         Sig('-x', type=argparse.FileType()),
   1462         Sig('spam', type=argparse.FileType('r')),
   1463     ]
   1464     failures = ['-x', '-x bar', 'non-existent-file.txt']
   1465     successes = [
   1466         ('foo', NS(x=None, spam=RFile('foo'))),
   1467         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1468         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1469         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1470         ('readonly', NS(x=None, spam=RFile('readonly'))),
   1471     ]
   1472 
   1473 class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
   1474     """Test that a file is not created unless the default is needed"""
   1475     def setUp(self):
   1476         super(TestFileTypeDefaults, self).setUp()
   1477         file = open(os.path.join(self.temp_dir, 'good'), 'w')
   1478         file.write('good')
   1479         file.close()
   1480 
   1481     argument_signatures = [
   1482         Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
   1483     ]
   1484     # should provoke no such file error
   1485     failures = ['']
   1486     # should not provoke error because default file is created
   1487     successes = [('-c good', NS(c=RFile('good')))]
   1488 
   1489 
   1490 class TestFileTypeRB(TempDirMixin, ParserTestCase):
   1491     """Test the FileType option/argument type for reading files"""
   1492 
   1493     def setUp(self):
   1494         super(TestFileTypeRB, self).setUp()
   1495         for file_name in ['foo', 'bar']:
   1496             file = open(os.path.join(self.temp_dir, file_name), 'w')
   1497             file.write(file_name)
   1498             file.close()
   1499 
   1500     argument_signatures = [
   1501         Sig('-x', type=argparse.FileType('rb')),
   1502         Sig('spam', type=argparse.FileType('rb')),
   1503     ]
   1504     failures = ['-x', '-x bar']
   1505     successes = [
   1506         ('foo', NS(x=None, spam=RFile('foo'))),
   1507         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
   1508         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
   1509         ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
   1510     ]
   1511 
   1512 
   1513 class WFile(object):
   1514     seen = set()
   1515 
   1516     def __init__(self, name):
   1517         self.name = name
   1518 
   1519     __hash__ = None
   1520 
   1521     def __eq__(self, other):
   1522         if other not in self.seen:
   1523             text = 'Check that file is writable.'
   1524             if 'b' in other.mode:
   1525                 text = text.encode('ascii')
   1526             other.write(text)
   1527             other.close()
   1528             self.seen.add(other)
   1529         return self.name == other.name
   1530 
   1531 
   1532 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
   1533                  "non-root user required")
   1534 class TestFileTypeW(TempDirMixin, ParserTestCase):
   1535     """Test the FileType option/argument type for writing files"""
   1536 
   1537     def setUp(self):
   1538         super(TestFileTypeW, self).setUp()
   1539         self.create_readonly_file('readonly')
   1540 
   1541     argument_signatures = [
   1542         Sig('-x', type=argparse.FileType('w')),
   1543         Sig('spam', type=argparse.FileType('w')),
   1544     ]
   1545     failures = ['-x', '-x bar']
   1546     failures = ['-x', '-x bar', 'readonly']
   1547     successes = [
   1548         ('foo', NS(x=None, spam=WFile('foo'))),
   1549         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1550         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1551         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1552     ]
   1553 
   1554 
   1555 class TestFileTypeWB(TempDirMixin, ParserTestCase):
   1556 
   1557     argument_signatures = [
   1558         Sig('-x', type=argparse.FileType('wb')),
   1559         Sig('spam', type=argparse.FileType('wb')),
   1560     ]
   1561     failures = ['-x', '-x bar']
   1562     successes = [
   1563         ('foo', NS(x=None, spam=WFile('foo'))),
   1564         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
   1565         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
   1566         ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
   1567     ]
   1568 
   1569 
   1570 class TestTypeCallable(ParserTestCase):
   1571     """Test some callables as option/argument types"""
   1572 
   1573     argument_signatures = [
   1574         Sig('--eggs', type=complex),
   1575         Sig('spam', type=float),
   1576     ]
   1577     failures = ['a', '42j', '--eggs a', '--eggs 2i']
   1578     successes = [
   1579         ('--eggs=42 42', NS(eggs=42, spam=42.0)),
   1580         ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
   1581         ('1024.675', NS(eggs=None, spam=1024.675)),
   1582     ]
   1583 
   1584 
   1585 class TestTypeUserDefined(ParserTestCase):
   1586     """Test a user-defined option/argument type"""
   1587 
   1588     class MyType(TestCase):
   1589 
   1590         def __init__(self, value):
   1591             self.value = value
   1592 
   1593         __hash__ = None
   1594 
   1595         def __eq__(self, other):
   1596             return (type(self), self.value) == (type(other), other.value)
   1597 
   1598     argument_signatures = [
   1599         Sig('-x', type=MyType),
   1600         Sig('spam', type=MyType),
   1601     ]
   1602     failures = []
   1603     successes = [
   1604         ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
   1605         ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
   1606     ]
   1607 
   1608 
   1609 class TestTypeClassicClass(ParserTestCase):
   1610     """Test a classic class type"""
   1611 
   1612     class C:
   1613 
   1614         def __init__(self, value):
   1615             self.value = value
   1616 
   1617         __hash__ = None
   1618 
   1619         def __eq__(self, other):
   1620             return (type(self), self.value) == (type(other), other.value)
   1621 
   1622     argument_signatures = [
   1623         Sig('-x', type=C),
   1624         Sig('spam', type=C),
   1625     ]
   1626     failures = []
   1627     successes = [
   1628         ('a -x b', NS(x=C('b'), spam=C('a'))),
   1629         ('-xf g', NS(x=C('f'), spam=C('g'))),
   1630     ]
   1631 
   1632 
   1633 class TestTypeRegistration(TestCase):
   1634     """Test a user-defined type by registering it"""
   1635 
   1636     def test(self):
   1637 
   1638         def get_my_type(string):
   1639             return 'my_type{%s}' % string
   1640 
   1641         parser = argparse.ArgumentParser()
   1642         parser.register('type', 'my_type', get_my_type)
   1643         parser.add_argument('-x', type='my_type')
   1644         parser.add_argument('y', type='my_type')
   1645 
   1646         self.assertEqual(parser.parse_args('1'.split()),
   1647                          NS(x=None, y='my_type{1}'))
   1648         self.assertEqual(parser.parse_args('-x 1 42'.split()),
   1649                          NS(x='my_type{1}', y='my_type{42}'))
   1650 
   1651 
   1652 # ============
   1653 # Action tests
   1654 # ============
   1655 
   1656 class TestActionUserDefined(ParserTestCase):
   1657     """Test a user-defined option/argument action"""
   1658 
   1659     class OptionalAction(argparse.Action):
   1660 
   1661         def __call__(self, parser, namespace, value, option_string=None):
   1662             try:
   1663                 # check destination and option string
   1664                 assert self.dest == 'spam', 'dest: %s' % self.dest
   1665                 assert option_string == '-s', 'flag: %s' % option_string
   1666                 # when option is before argument, badger=2, and when
   1667                 # option is after argument, badger=<whatever was set>
   1668                 expected_ns = NS(spam=0.25)
   1669                 if value in [0.125, 0.625]:
   1670                     expected_ns.badger = 2
   1671                 elif value in [2.0]:
   1672                     expected_ns.badger = 84
   1673                 else:
   1674                     raise AssertionError('value: %s' % value)
   1675                 assert expected_ns == namespace, ('expected %s, got %s' %
   1676                                                   (expected_ns, namespace))
   1677             except AssertionError:
   1678                 e = sys.exc_info()[1]
   1679                 raise ArgumentParserError('opt_action failed: %s' % e)
   1680             setattr(namespace, 'spam', value)
   1681 
   1682     class PositionalAction(argparse.Action):
   1683 
   1684         def __call__(self, parser, namespace, value, option_string=None):
   1685             try:
   1686                 assert option_string is None, ('option_string: %s' %
   1687                                                option_string)
   1688                 # check destination
   1689                 assert self.dest == 'badger', 'dest: %s' % self.dest
   1690                 # when argument is before option, spam=0.25, and when
   1691                 # option is after argument, spam=<whatever was set>
   1692                 expected_ns = NS(badger=2)
   1693                 if value in [42, 84]:
   1694                     expected_ns.spam = 0.25
   1695                 elif value in [1]:
   1696                     expected_ns.spam = 0.625
   1697                 elif value in [2]:
   1698                     expected_ns.spam = 0.125
   1699                 else:
   1700                     raise AssertionError('value: %s' % value)
   1701                 assert expected_ns == namespace, ('expected %s, got %s' %
   1702                                                   (expected_ns, namespace))
   1703             except AssertionError:
   1704                 e = sys.exc_info()[1]
   1705                 raise ArgumentParserError('arg_action failed: %s' % e)
   1706             setattr(namespace, 'badger', value)
   1707 
   1708     argument_signatures = [
   1709         Sig('-s', dest='spam', action=OptionalAction,
   1710             type=float, default=0.25),
   1711         Sig('badger', action=PositionalAction,
   1712             type=int, nargs='?', default=2),
   1713     ]
   1714     failures = []
   1715     successes = [
   1716         ('-s0.125', NS(spam=0.125, badger=2)),
   1717         ('42', NS(spam=0.25, badger=42)),
   1718         ('-s 0.625 1', NS(spam=0.625, badger=1)),
   1719         ('84 -s2', NS(spam=2.0, badger=84)),
   1720     ]
   1721 
   1722 
   1723 class TestActionRegistration(TestCase):
   1724     """Test a user-defined action supplied by registering it"""
   1725 
   1726     class MyAction(argparse.Action):
   1727 
   1728         def __call__(self, parser, namespace, values, option_string=None):
   1729             setattr(namespace, self.dest, 'foo[%s]' % values)
   1730 
   1731     def test(self):
   1732 
   1733         parser = argparse.ArgumentParser()
   1734         parser.register('action', 'my_action', self.MyAction)
   1735         parser.add_argument('badger', action='my_action')
   1736 
   1737         self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
   1738         self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
   1739 
   1740 
   1741 # ================
   1742 # Subparsers tests
   1743 # ================
   1744 
   1745 class TestAddSubparsers(TestCase):
   1746     """Test the add_subparsers method"""
   1747 
   1748     def assertArgumentParserError(self, *args, **kwargs):
   1749         self.assertRaises(ArgumentParserError, *args, **kwargs)
   1750 
   1751     def _get_parser(self, subparser_help=False, prefix_chars=None):
   1752         # create a parser with a subparsers argument
   1753         if prefix_chars:
   1754             parser = ErrorRaisingArgumentParser(
   1755                 prog='PROG', description='main description', prefix_chars=prefix_chars)
   1756             parser.add_argument(
   1757                 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
   1758         else:
   1759             parser = ErrorRaisingArgumentParser(
   1760                 prog='PROG', description='main description')
   1761             parser.add_argument(
   1762                 '--foo', action='store_true', help='foo help')
   1763         parser.add_argument(
   1764             'bar', type=float, help='bar help')
   1765 
   1766         # check that only one subparsers argument can be added
   1767         subparsers = parser.add_subparsers(help='command help')
   1768         self.assertArgumentParserError(parser.add_subparsers)
   1769 
   1770         # add first sub-parser
   1771         parser1_kwargs = dict(description='1 description')
   1772         if subparser_help:
   1773             parser1_kwargs['help'] = '1 help'
   1774         parser1 = subparsers.add_parser('1', **parser1_kwargs)
   1775         parser1.add_argument('-w', type=int, help='w help')
   1776         parser1.add_argument('x', choices='abc', help='x help')
   1777 
   1778         # add second sub-parser
   1779         parser2_kwargs = dict(description='2 description')
   1780         if subparser_help:
   1781             parser2_kwargs['help'] = '2 help'
   1782         parser2 = subparsers.add_parser('2', **parser2_kwargs)
   1783         parser2.add_argument('-y', choices='123', help='y help')
   1784         parser2.add_argument('z', type=complex, nargs='*', help='z help')
   1785 
   1786         # add third sub-parser
   1787         parser3_kwargs = dict(description='3 description')
   1788         if subparser_help:
   1789             parser3_kwargs['help'] = '3 help'
   1790         parser3 = subparsers.add_parser('3', **parser3_kwargs)
   1791         parser3.add_argument('t', type=int, help='t help')
   1792         parser3.add_argument('u', nargs='...', help='u help')
   1793 
   1794         # return the main parser
   1795         return parser
   1796 
   1797     def setUp(self):
   1798         super(TestAddSubparsers, self).setUp()
   1799         self.parser = self._get_parser()
   1800         self.command_help_parser = self._get_parser(subparser_help=True)
   1801 
   1802     def test_parse_args_failures(self):
   1803         # check some failure cases:
   1804         for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
   1805                          '0.5 1 -y', '0.5 2 -w']:
   1806             args = args_str.split()
   1807             self.assertArgumentParserError(self.parser.parse_args, args)
   1808 
   1809     def test_parse_args(self):
   1810         # check some non-failure cases:
   1811         self.assertEqual(
   1812             self.parser.parse_args('0.5 1 b -w 7'.split()),
   1813             NS(foo=False, bar=0.5, w=7, x='b'),
   1814         )
   1815         self.assertEqual(
   1816             self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
   1817             NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
   1818         )
   1819         self.assertEqual(
   1820             self.parser.parse_args('--foo 0.125 1 c'.split()),
   1821             NS(foo=True, bar=0.125, w=None, x='c'),
   1822         )
   1823         self.assertEqual(
   1824             self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
   1825             NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
   1826         )
   1827 
   1828     def test_parse_known_args(self):
   1829         self.assertEqual(
   1830             self.parser.parse_known_args('0.5 1 b -w 7'.split()),
   1831             (NS(foo=False, bar=0.5, w=7, x='b'), []),
   1832         )
   1833         self.assertEqual(
   1834             self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
   1835             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1836         )
   1837         self.assertEqual(
   1838             self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
   1839             (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
   1840         )
   1841         self.assertEqual(
   1842             self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
   1843             (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
   1844         )
   1845         self.assertEqual(
   1846             self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
   1847             (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
   1848         )
   1849 
   1850     def test_dest(self):
   1851         parser = ErrorRaisingArgumentParser()
   1852         parser.add_argument('--foo', action='store_true')
   1853         subparsers = parser.add_subparsers(dest='bar')
   1854         parser1 = subparsers.add_parser('1')
   1855         parser1.add_argument('baz')
   1856         self.assertEqual(NS(foo=False, bar='1', baz='2'),
   1857                          parser.parse_args('1 2'.split()))
   1858 
   1859     def test_help(self):
   1860         self.assertEqual(self.parser.format_usage(),
   1861                          'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
   1862         self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
   1863             usage: PROG [-h] [--foo] bar {1,2,3} ...
   1864 
   1865             main description
   1866 
   1867             positional arguments:
   1868               bar         bar help
   1869               {1,2,3}     command help
   1870 
   1871             optional arguments:
   1872               -h, --help  show this help message and exit
   1873               --foo       foo help
   1874             '''))
   1875 
   1876     def test_help_extra_prefix_chars(self):
   1877         # Make sure - is still used for help if it is a non-first prefix char
   1878         parser = self._get_parser(prefix_chars='+:-')
   1879         self.assertEqual(parser.format_usage(),
   1880                          'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
   1881         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1882             usage: PROG [-h] [++foo] bar {1,2,3} ...
   1883 
   1884             main description
   1885 
   1886             positional arguments:
   1887               bar         bar help
   1888               {1,2,3}     command help
   1889 
   1890             optional arguments:
   1891               -h, --help  show this help message and exit
   1892               ++foo       foo help
   1893             '''))
   1894 
   1895 
   1896     def test_help_alternate_prefix_chars(self):
   1897         parser = self._get_parser(prefix_chars='+:/')
   1898         self.assertEqual(parser.format_usage(),
   1899                          'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
   1900         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1901             usage: PROG [+h] [++foo] bar {1,2,3} ...
   1902 
   1903             main description
   1904 
   1905             positional arguments:
   1906               bar         bar help
   1907               {1,2,3}     command help
   1908 
   1909             optional arguments:
   1910               +h, ++help  show this help message and exit
   1911               ++foo       foo help
   1912             '''))
   1913 
   1914     def test_parser_command_help(self):
   1915         self.assertEqual(self.command_help_parser.format_usage(),
   1916                          'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
   1917         self.assertEqual(self.command_help_parser.format_help(),
   1918                          textwrap.dedent('''\
   1919             usage: PROG [-h] [--foo] bar {1,2,3} ...
   1920 
   1921             main description
   1922 
   1923             positional arguments:
   1924               bar         bar help
   1925               {1,2,3}     command help
   1926                 1         1 help
   1927                 2         2 help
   1928                 3         3 help
   1929 
   1930             optional arguments:
   1931               -h, --help  show this help message and exit
   1932               --foo       foo help
   1933             '''))
   1934 
   1935     def test_subparser_title_help(self):
   1936         parser = ErrorRaisingArgumentParser(prog='PROG',
   1937                                             description='main description')
   1938         parser.add_argument('--foo', action='store_true', help='foo help')
   1939         parser.add_argument('bar', help='bar help')
   1940         subparsers = parser.add_subparsers(title='subcommands',
   1941                                            description='command help',
   1942                                            help='additional text')
   1943         parser1 = subparsers.add_parser('1')
   1944         parser2 = subparsers.add_parser('2')
   1945         self.assertEqual(parser.format_usage(),
   1946                          'usage: PROG [-h] [--foo] bar {1,2} ...\n')
   1947         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   1948             usage: PROG [-h] [--foo] bar {1,2} ...
   1949 
   1950             main description
   1951 
   1952             positional arguments:
   1953               bar         bar help
   1954 
   1955             optional arguments:
   1956               -h, --help  show this help message and exit
   1957               --foo       foo help
   1958 
   1959             subcommands:
   1960               command help
   1961 
   1962               {1,2}       additional text
   1963             '''))
   1964 
   1965     def _test_subparser_help(self, args_str, expected_help):
   1966         try:
   1967             self.parser.parse_args(args_str.split())
   1968         except ArgumentParserError:
   1969             err = sys.exc_info()[1]
   1970             if err.stdout != expected_help:
   1971                 print(repr(expected_help))
   1972                 print(repr(err.stdout))
   1973             self.assertEqual(err.stdout, expected_help)
   1974 
   1975     def test_subparser1_help(self):
   1976         self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
   1977             usage: PROG bar 1 [-h] [-w W] {a,b,c}
   1978 
   1979             1 description
   1980 
   1981             positional arguments:
   1982               {a,b,c}     x help
   1983 
   1984             optional arguments:
   1985               -h, --help  show this help message and exit
   1986               -w W        w help
   1987             '''))
   1988 
   1989     def test_subparser2_help(self):
   1990         self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
   1991             usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
   1992 
   1993             2 description
   1994 
   1995             positional arguments:
   1996               z           z help
   1997 
   1998             optional arguments:
   1999               -h, --help  show this help message and exit
   2000               -y {1,2,3}  y help
   2001             '''))
   2002 
   2003 # ============
   2004 # Groups tests
   2005 # ============
   2006 
   2007 class TestPositionalsGroups(TestCase):
   2008     """Tests that order of group positionals matches construction order"""
   2009 
   2010     def test_nongroup_first(self):
   2011         parser = ErrorRaisingArgumentParser()
   2012         parser.add_argument('foo')
   2013         group = parser.add_argument_group('g')
   2014         group.add_argument('bar')
   2015         parser.add_argument('baz')
   2016         expected = NS(foo='1', bar='2', baz='3')
   2017         result = parser.parse_args('1 2 3'.split())
   2018         self.assertEqual(expected, result)
   2019 
   2020     def test_group_first(self):
   2021         parser = ErrorRaisingArgumentParser()
   2022         group = parser.add_argument_group('xxx')
   2023         group.add_argument('foo')
   2024         parser.add_argument('bar')
   2025         parser.add_argument('baz')
   2026         expected = NS(foo='1', bar='2', baz='3')
   2027         result = parser.parse_args('1 2 3'.split())
   2028         self.assertEqual(expected, result)
   2029 
   2030     def test_interleaved_groups(self):
   2031         parser = ErrorRaisingArgumentParser()
   2032         group = parser.add_argument_group('xxx')
   2033         parser.add_argument('foo')
   2034         group.add_argument('bar')
   2035         parser.add_argument('baz')
   2036         group = parser.add_argument_group('yyy')
   2037         group.add_argument('frell')
   2038         expected = NS(foo='1', bar='2', baz='3', frell='4')
   2039         result = parser.parse_args('1 2 3 4'.split())
   2040         self.assertEqual(expected, result)
   2041 
   2042 # ===================
   2043 # Parent parser tests
   2044 # ===================
   2045 
   2046 class TestParentParsers(TestCase):
   2047     """Tests that parsers can be created with parent parsers"""
   2048 
   2049     def assertArgumentParserError(self, *args, **kwargs):
   2050         self.assertRaises(ArgumentParserError, *args, **kwargs)
   2051 
   2052     def setUp(self):
   2053         super(TestParentParsers, self).setUp()
   2054         self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
   2055         self.wxyz_parent.add_argument('--w')
   2056         x_group = self.wxyz_parent.add_argument_group('x')
   2057         x_group.add_argument('-y')
   2058         self.wxyz_parent.add_argument('z')
   2059 
   2060         self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
   2061         self.abcd_parent.add_argument('a')
   2062         self.abcd_parent.add_argument('-b')
   2063         c_group = self.abcd_parent.add_argument_group('c')
   2064         c_group.add_argument('--d')
   2065 
   2066         self.w_parent = ErrorRaisingArgumentParser(add_help=False)
   2067         self.w_parent.add_argument('--w')
   2068 
   2069         self.z_parent = ErrorRaisingArgumentParser(add_help=False)
   2070         self.z_parent.add_argument('z')
   2071 
   2072         # parents with mutually exclusive groups
   2073         self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
   2074         group = self.ab_mutex_parent.add_mutually_exclusive_group()
   2075         group.add_argument('-a', action='store_true')
   2076         group.add_argument('-b', action='store_true')
   2077 
   2078         self.main_program = os.path.basename(sys.argv[0])
   2079 
   2080     def test_single_parent(self):
   2081         parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
   2082         self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
   2083                          NS(w='3', y='1', z='2'))
   2084 
   2085     def test_single_parent_mutex(self):
   2086         self._test_mutex_ab(self.ab_mutex_parent.parse_args)
   2087         parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
   2088         self._test_mutex_ab(parser.parse_args)
   2089 
   2090     def test_single_granparent_mutex(self):
   2091         parents = [self.ab_mutex_parent]
   2092         parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
   2093         parser = ErrorRaisingArgumentParser(parents=[parser])
   2094         self._test_mutex_ab(parser.parse_args)
   2095 
   2096     def _test_mutex_ab(self, parse_args):
   2097         self.assertEqual(parse_args([]), NS(a=False, b=False))
   2098         self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
   2099         self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
   2100         self.assertArgumentParserError(parse_args, ['-a', '-b'])
   2101         self.assertArgumentParserError(parse_args, ['-b', '-a'])
   2102         self.assertArgumentParserError(parse_args, ['-c'])
   2103         self.assertArgumentParserError(parse_args, ['-a', '-c'])
   2104         self.assertArgumentParserError(parse_args, ['-b', '-c'])
   2105 
   2106     def test_multiple_parents(self):
   2107         parents = [self.abcd_parent, self.wxyz_parent]
   2108         parser = ErrorRaisingArgumentParser(parents=parents)
   2109         self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
   2110                          NS(a='3', b=None, d='1', w='2', y=None, z='4'))
   2111 
   2112     def test_multiple_parents_mutex(self):
   2113         parents = [self.ab_mutex_parent, self.wxyz_parent]
   2114         parser = ErrorRaisingArgumentParser(parents=parents)
   2115         self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
   2116                          NS(a=True, b=False, w='2', y=None, z='3'))
   2117         self.assertArgumentParserError(
   2118             parser.parse_args, '-a --w 2 3 -b'.split())
   2119         self.assertArgumentParserError(
   2120             parser.parse_args, '-a -b --w 2 3'.split())
   2121 
   2122     def test_conflicting_parents(self):
   2123         self.assertRaises(
   2124             argparse.ArgumentError,
   2125             argparse.ArgumentParser,
   2126             parents=[self.w_parent, self.wxyz_parent])
   2127 
   2128     def test_conflicting_parents_mutex(self):
   2129         self.assertRaises(
   2130             argparse.ArgumentError,
   2131             argparse.ArgumentParser,
   2132             parents=[self.abcd_parent, self.ab_mutex_parent])
   2133 
   2134     def test_same_argument_name_parents(self):
   2135         parents = [self.wxyz_parent, self.z_parent]
   2136         parser = ErrorRaisingArgumentParser(parents=parents)
   2137         self.assertEqual(parser.parse_args('1 2'.split()),
   2138                          NS(w=None, y=None, z='2'))
   2139 
   2140     def test_subparser_parents(self):
   2141         parser = ErrorRaisingArgumentParser()
   2142         subparsers = parser.add_subparsers()
   2143         abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
   2144         abcde_parser.add_argument('e')
   2145         self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
   2146                          NS(a='3', b='1', d='2', e='4'))
   2147 
   2148     def test_subparser_parents_mutex(self):
   2149         parser = ErrorRaisingArgumentParser()
   2150         subparsers = parser.add_subparsers()
   2151         parents = [self.ab_mutex_parent]
   2152         abc_parser = subparsers.add_parser('foo', parents=parents)
   2153         c_group = abc_parser.add_argument_group('c_group')
   2154         c_group.add_argument('c')
   2155         parents = [self.wxyz_parent, self.ab_mutex_parent]
   2156         wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
   2157         wxyzabe_parser.add_argument('e')
   2158         self.assertEqual(parser.parse_args('foo -a 4'.split()),
   2159                          NS(a=True, b=False, c='4'))
   2160         self.assertEqual(parser.parse_args('bar -b  --w 2 3 4'.split()),
   2161                          NS(a=False, b=True, w='2', y=None, z='3', e='4'))
   2162         self.assertArgumentParserError(
   2163             parser.parse_args, 'foo -a -b 4'.split())
   2164         self.assertArgumentParserError(
   2165             parser.parse_args, 'bar -b -a 4'.split())
   2166 
   2167     def test_parent_help(self):
   2168         parents = [self.abcd_parent, self.wxyz_parent]
   2169         parser = ErrorRaisingArgumentParser(parents=parents)
   2170         parser_help = parser.format_help()
   2171         progname = self.main_program
   2172         self.assertEqual(parser_help, textwrap.dedent('''\
   2173             usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
   2174 
   2175             positional arguments:
   2176               a
   2177               z
   2178 
   2179             optional arguments:
   2180               -h, --help  show this help message and exit
   2181               -b B
   2182               --w W
   2183 
   2184             c:
   2185               --d D
   2186 
   2187             x:
   2188               -y Y
   2189         '''.format(progname, ' ' if progname else '' )))
   2190 
   2191     def test_groups_parents(self):
   2192         parent = ErrorRaisingArgumentParser(add_help=False)
   2193         g = parent.add_argument_group(title='g', description='gd')
   2194         g.add_argument('-w')
   2195         g.add_argument('-x')
   2196         m = parent.add_mutually_exclusive_group()
   2197         m.add_argument('-y')
   2198         m.add_argument('-z')
   2199         parser = ErrorRaisingArgumentParser(parents=[parent])
   2200 
   2201         self.assertRaises(ArgumentParserError, parser.parse_args,
   2202             ['-y', 'Y', '-z', 'Z'])
   2203 
   2204         parser_help = parser.format_help()
   2205         progname = self.main_program
   2206         self.assertEqual(parser_help, textwrap.dedent('''\
   2207             usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
   2208 
   2209             optional arguments:
   2210               -h, --help  show this help message and exit
   2211               -y Y
   2212               -z Z
   2213 
   2214             g:
   2215               gd
   2216 
   2217               -w W
   2218               -x X
   2219         '''.format(progname, ' ' if progname else '' )))
   2220 
   2221 # ==============================
   2222 # Mutually exclusive group tests
   2223 # ==============================
   2224 
   2225 class TestMutuallyExclusiveGroupErrors(TestCase):
   2226 
   2227     def test_invalid_add_argument_group(self):
   2228         parser = ErrorRaisingArgumentParser()
   2229         raises = self.assertRaises
   2230         raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
   2231 
   2232     def test_invalid_add_argument(self):
   2233         parser = ErrorRaisingArgumentParser()
   2234         group = parser.add_mutually_exclusive_group()
   2235         add_argument = group.add_argument
   2236         raises = self.assertRaises
   2237         raises(ValueError, add_argument, '--foo', required=True)
   2238         raises(ValueError, add_argument, 'bar')
   2239         raises(ValueError, add_argument, 'bar', nargs='+')
   2240         raises(ValueError, add_argument, 'bar', nargs=1)
   2241         raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
   2242 
   2243     def test_help(self):
   2244         parser = ErrorRaisingArgumentParser(prog='PROG')
   2245         group1 = parser.add_mutually_exclusive_group()
   2246         group1.add_argument('--foo', action='store_true')
   2247         group1.add_argument('--bar', action='store_false')
   2248         group2 = parser.add_mutually_exclusive_group()
   2249         group2.add_argument('--soup', action='store_true')
   2250         group2.add_argument('--nuts', action='store_false')
   2251         expected = '''\
   2252             usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
   2253 
   2254             optional arguments:
   2255               -h, --help  show this help message and exit
   2256               --foo
   2257               --bar
   2258               --soup
   2259               --nuts
   2260               '''
   2261         self.assertEqual(parser.format_help(), textwrap.dedent(expected))
   2262 
   2263 class MEMixin(object):
   2264 
   2265     def test_failures_when_not_required(self):
   2266         parse_args = self.get_parser(required=False).parse_args
   2267         error = ArgumentParserError
   2268         for args_string in self.failures:
   2269             self.assertRaises(error, parse_args, args_string.split())
   2270 
   2271     def test_failures_when_required(self):
   2272         parse_args = self.get_parser(required=True).parse_args
   2273         error = ArgumentParserError
   2274         for args_string in self.failures + ['']:
   2275             self.assertRaises(error, parse_args, args_string.split())
   2276 
   2277     def test_successes_when_not_required(self):
   2278         parse_args = self.get_parser(required=False).parse_args
   2279         successes = self.successes + self.successes_when_not_required
   2280         for args_string, expected_ns in successes:
   2281             actual_ns = parse_args(args_string.split())
   2282             self.assertEqual(actual_ns, expected_ns)
   2283 
   2284     def test_successes_when_required(self):
   2285         parse_args = self.get_parser(required=True).parse_args
   2286         for args_string, expected_ns in self.successes:
   2287             actual_ns = parse_args(args_string.split())
   2288             self.assertEqual(actual_ns, expected_ns)
   2289 
   2290     def test_usage_when_not_required(self):
   2291         format_usage = self.get_parser(required=False).format_usage
   2292         expected_usage = self.usage_when_not_required
   2293         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2294 
   2295     def test_usage_when_required(self):
   2296         format_usage = self.get_parser(required=True).format_usage
   2297         expected_usage = self.usage_when_required
   2298         self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
   2299 
   2300     def test_help_when_not_required(self):
   2301         format_help = self.get_parser(required=False).format_help
   2302         help = self.usage_when_not_required + self.help
   2303         self.assertEqual(format_help(), textwrap.dedent(help))
   2304 
   2305     def test_help_when_required(self):
   2306         format_help = self.get_parser(required=True).format_help
   2307         help = self.usage_when_required + self.help
   2308         self.assertEqual(format_help(), textwrap.dedent(help))
   2309 
   2310 
   2311 class TestMutuallyExclusiveSimple(MEMixin, TestCase):
   2312 
   2313     def get_parser(self, required=None):
   2314         parser = ErrorRaisingArgumentParser(prog='PROG')
   2315         group = parser.add_mutually_exclusive_group(required=required)
   2316         group.add_argument('--bar', help='bar help')
   2317         group.add_argument('--baz', nargs='?', const='Z', help='baz help')
   2318         return parser
   2319 
   2320     failures = ['--bar X --baz Y', '--bar X --baz']
   2321     successes = [
   2322         ('--bar X', NS(bar='X', baz=None)),
   2323         ('--bar X --bar Z', NS(bar='Z', baz=None)),
   2324         ('--baz Y', NS(bar=None, baz='Y')),
   2325         ('--baz', NS(bar=None, baz='Z')),
   2326     ]
   2327     successes_when_not_required = [
   2328         ('', NS(bar=None, baz=None)),
   2329     ]
   2330 
   2331     usage_when_not_required = '''\
   2332         usage: PROG [-h] [--bar BAR | --baz [BAZ]]
   2333         '''
   2334     usage_when_required = '''\
   2335         usage: PROG [-h] (--bar BAR | --baz [BAZ])
   2336         '''
   2337     help = '''\
   2338 
   2339         optional arguments:
   2340           -h, --help   show this help message and exit
   2341           --bar BAR    bar help
   2342           --baz [BAZ]  baz help
   2343         '''
   2344 
   2345 
   2346 class TestMutuallyExclusiveLong(MEMixin, TestCase):
   2347 
   2348     def get_parser(self, required=None):
   2349         parser = ErrorRaisingArgumentParser(prog='PROG')
   2350         parser.add_argument('--abcde', help='abcde help')
   2351         parser.add_argument('--fghij', help='fghij help')
   2352         group = parser.add_mutually_exclusive_group(required=required)
   2353         group.add_argument('--klmno', help='klmno help')
   2354         group.add_argument('--pqrst', help='pqrst help')
   2355         return parser
   2356 
   2357     failures = ['--klmno X --pqrst Y']
   2358     successes = [
   2359         ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
   2360         ('--abcde Y --klmno X',
   2361             NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
   2362         ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
   2363         ('--pqrst X --fghij Y',
   2364             NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
   2365     ]
   2366     successes_when_not_required = [
   2367         ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
   2368     ]
   2369 
   2370     usage_when_not_required = '''\
   2371     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2372                 [--klmno KLMNO | --pqrst PQRST]
   2373     '''
   2374     usage_when_required = '''\
   2375     usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
   2376                 (--klmno KLMNO | --pqrst PQRST)
   2377     '''
   2378     help = '''\
   2379 
   2380     optional arguments:
   2381       -h, --help     show this help message and exit
   2382       --abcde ABCDE  abcde help
   2383       --fghij FGHIJ  fghij help
   2384       --klmno KLMNO  klmno help
   2385       --pqrst PQRST  pqrst help
   2386     '''
   2387 
   2388 
   2389 class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
   2390 
   2391     def get_parser(self, required):
   2392         parser = ErrorRaisingArgumentParser(prog='PROG')
   2393         group = parser.add_mutually_exclusive_group(required=required)
   2394         group.add_argument('-x', help=argparse.SUPPRESS)
   2395         group.add_argument('-y', action='store_false', help='y help')
   2396         return parser
   2397 
   2398     failures = ['-x X -y']
   2399     successes = [
   2400         ('-x X', NS(x='X', y=True)),
   2401         ('-x X -x Y', NS(x='Y', y=True)),
   2402         ('-y', NS(x=None, y=False)),
   2403     ]
   2404     successes_when_not_required = [
   2405         ('', NS(x=None, y=True)),
   2406     ]
   2407 
   2408     usage_when_not_required = '''\
   2409         usage: PROG [-h] [-y]
   2410         '''
   2411     usage_when_required = '''\
   2412         usage: PROG [-h] -y
   2413         '''
   2414     help = '''\
   2415 
   2416         optional arguments:
   2417           -h, --help  show this help message and exit
   2418           -y          y help
   2419         '''
   2420 
   2421 
   2422 class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
   2423 
   2424     def get_parser(self, required):
   2425         parser = ErrorRaisingArgumentParser(prog='PROG')
   2426         group = parser.add_mutually_exclusive_group(required=required)
   2427         add = group.add_argument
   2428         add('--spam', action='store_true', help=argparse.SUPPRESS)
   2429         add('--badger', action='store_false', help=argparse.SUPPRESS)
   2430         add('--bladder', help=argparse.SUPPRESS)
   2431         return parser
   2432 
   2433     failures = [
   2434         '--spam --badger',
   2435         '--badger --bladder B',
   2436         '--bladder B --spam',
   2437     ]
   2438     successes = [
   2439         ('--spam', NS(spam=True, badger=True, bladder=None)),
   2440         ('--badger', NS(spam=False, badger=False, bladder=None)),
   2441         ('--bladder B', NS(spam=False, badger=True, bladder='B')),
   2442         ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
   2443     ]
   2444     successes_when_not_required = [
   2445         ('', NS(spam=False, badger=True, bladder=None)),
   2446     ]
   2447 
   2448     usage_when_required = usage_when_not_required = '''\
   2449         usage: PROG [-h]
   2450         '''
   2451     help = '''\
   2452 
   2453         optional arguments:
   2454           -h, --help  show this help message and exit
   2455         '''
   2456 
   2457 
   2458 class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
   2459 
   2460     def get_parser(self, required):
   2461         parser = ErrorRaisingArgumentParser(prog='PROG')
   2462         group = parser.add_mutually_exclusive_group(required=required)
   2463         group.add_argument('--foo', action='store_true', help='FOO')
   2464         group.add_argument('--spam', help='SPAM')
   2465         group.add_argument('badger', nargs='*', default='X', help='BADGER')
   2466         return parser
   2467 
   2468     failures = [
   2469         '--foo --spam S',
   2470         '--spam S X',
   2471         'X --foo',
   2472         'X Y Z --spam S',
   2473         '--foo X Y',
   2474     ]
   2475     successes = [
   2476         ('--foo', NS(foo=True, spam=None, badger='X')),
   2477         ('--spam S', NS(foo=False, spam='S', badger='X')),
   2478         ('X', NS(foo=False, spam=None, badger=['X'])),
   2479         ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
   2480     ]
   2481     successes_when_not_required = [
   2482         ('', NS(foo=False, spam=None, badger='X')),
   2483     ]
   2484 
   2485     usage_when_not_required = '''\
   2486         usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
   2487         '''
   2488     usage_when_required = '''\
   2489         usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
   2490         '''
   2491     help = '''\
   2492 
   2493         positional arguments:
   2494           badger       BADGER
   2495 
   2496         optional arguments:
   2497           -h, --help   show this help message and exit
   2498           --foo        FOO
   2499           --spam SPAM  SPAM
   2500         '''
   2501 
   2502 
   2503 class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
   2504 
   2505     def get_parser(self, required):
   2506         parser = ErrorRaisingArgumentParser(prog='PROG')
   2507         parser.add_argument('-x', action='store_true', help='x help')
   2508         group = parser.add_mutually_exclusive_group(required=required)
   2509         group.add_argument('-a', action='store_true', help='a help')
   2510         group.add_argument('-b', action='store_true', help='b help')
   2511         parser.add_argument('-y', action='store_true', help='y help')
   2512         group.add_argument('-c', action='store_true', help='c help')
   2513         return parser
   2514 
   2515     failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
   2516     successes = [
   2517         ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
   2518         ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
   2519         ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
   2520         ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
   2521         ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
   2522         ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
   2523     ]
   2524     successes_when_not_required = [
   2525         ('', NS(a=False, b=False, c=False, x=False, y=False)),
   2526         ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
   2527         ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
   2528     ]
   2529 
   2530     usage_when_required = usage_when_not_required = '''\
   2531         usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
   2532         '''
   2533     help = '''\
   2534 
   2535         optional arguments:
   2536           -h, --help  show this help message and exit
   2537           -x          x help
   2538           -a          a help
   2539           -b          b help
   2540           -y          y help
   2541           -c          c help
   2542         '''
   2543 
   2544 
   2545 class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
   2546 
   2547     def get_parser(self, required=None):
   2548         parser = ErrorRaisingArgumentParser(prog='PROG')
   2549         titled_group = parser.add_argument_group(
   2550             title='Titled group', description='Group description')
   2551         mutex_group = \
   2552             titled_group.add_mutually_exclusive_group(required=required)
   2553         mutex_group.add_argument('--bar', help='bar help')
   2554         mutex_group.add_argument('--baz', help='baz help')
   2555         return parser
   2556 
   2557     failures = ['--bar X --baz Y', '--baz X --bar Y']
   2558     successes = [
   2559         ('--bar X', NS(bar='X', baz=None)),
   2560         ('--baz Y', NS(bar=None, baz='Y')),
   2561     ]
   2562     successes_when_not_required = [
   2563         ('', NS(bar=None, baz=None)),
   2564     ]
   2565 
   2566     usage_when_not_required = '''\
   2567         usage: PROG [-h] [--bar BAR | --baz BAZ]
   2568         '''
   2569     usage_when_required = '''\
   2570         usage: PROG [-h] (--bar BAR | --baz BAZ)
   2571         '''
   2572     help = '''\
   2573 
   2574         optional arguments:
   2575           -h, --help  show this help message and exit
   2576 
   2577         Titled group:
   2578           Group description
   2579 
   2580           --bar BAR   bar help
   2581           --baz BAZ   baz help
   2582         '''
   2583 
   2584 
   2585 class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
   2586 
   2587     def get_parser(self, required):
   2588         parser = ErrorRaisingArgumentParser(prog='PROG')
   2589         parser.add_argument('x', help='x help')
   2590         parser.add_argument('-y', action='store_true', help='y help')
   2591         group = parser.add_mutually_exclusive_group(required=required)
   2592         group.add_argument('a', nargs='?', help='a help')
   2593         group.add_argument('-b', action='store_true', help='b help')
   2594         group.add_argument('-c', action='store_true', help='c help')
   2595         return parser
   2596 
   2597     failures = ['X A -b', '-b -c', '-c X A']
   2598     successes = [
   2599         ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
   2600         ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
   2601         ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
   2602         ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
   2603         ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
   2604     ]
   2605     successes_when_not_required = [
   2606         ('X', NS(a=None, b=False, c=False, x='X', y=False)),
   2607         ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
   2608     ]
   2609 
   2610     usage_when_required = usage_when_not_required = '''\
   2611         usage: PROG [-h] [-y] [-b] [-c] x [a]
   2612         '''
   2613     help = '''\
   2614 
   2615         positional arguments:
   2616           x           x help
   2617           a           a help
   2618 
   2619         optional arguments:
   2620           -h, --help  show this help message and exit
   2621           -y          y help
   2622           -b          b help
   2623           -c          c help
   2624         '''
   2625 
   2626 # =================================================
   2627 # Mutually exclusive group in parent parser tests
   2628 # =================================================
   2629 
   2630 class MEPBase(object):
   2631 
   2632     def get_parser(self, required=None):
   2633         parent = super(MEPBase, self).get_parser(required=required)
   2634         parser = ErrorRaisingArgumentParser(
   2635             prog=parent.prog, add_help=False, parents=[parent])
   2636         return parser
   2637 
   2638 
   2639 class TestMutuallyExclusiveGroupErrorsParent(
   2640     MEPBase, TestMutuallyExclusiveGroupErrors):
   2641     pass
   2642 
   2643 
   2644 class TestMutuallyExclusiveSimpleParent(
   2645     MEPBase, TestMutuallyExclusiveSimple):
   2646     pass
   2647 
   2648 
   2649 class TestMutuallyExclusiveLongParent(
   2650     MEPBase, TestMutuallyExclusiveLong):
   2651     pass
   2652 
   2653 
   2654 class TestMutuallyExclusiveFirstSuppressedParent(
   2655     MEPBase, TestMutuallyExclusiveFirstSuppressed):
   2656     pass
   2657 
   2658 
   2659 class TestMutuallyExclusiveManySuppressedParent(
   2660     MEPBase, TestMutuallyExclusiveManySuppressed):
   2661     pass
   2662 
   2663 
   2664 class TestMutuallyExclusiveOptionalAndPositionalParent(
   2665     MEPBase, TestMutuallyExclusiveOptionalAndPositional):
   2666     pass
   2667 
   2668 
   2669 class TestMutuallyExclusiveOptionalsMixedParent(
   2670     MEPBase, TestMutuallyExclusiveOptionalsMixed):
   2671     pass
   2672 
   2673 
   2674 class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
   2675     MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
   2676     pass
   2677 
   2678 # =================
   2679 # Set default tests
   2680 # =================
   2681 
   2682 class TestSetDefaults(TestCase):
   2683 
   2684     def test_set_defaults_no_args(self):
   2685         parser = ErrorRaisingArgumentParser()
   2686         parser.set_defaults(x='foo')
   2687         parser.set_defaults(y='bar', z=1)
   2688         self.assertEqual(NS(x='foo', y='bar', z=1),
   2689                          parser.parse_args([]))
   2690         self.assertEqual(NS(x='foo', y='bar', z=1),
   2691                          parser.parse_args([], NS()))
   2692         self.assertEqual(NS(x='baz', y='bar', z=1),
   2693                          parser.parse_args([], NS(x='baz')))
   2694         self.assertEqual(NS(x='baz', y='bar', z=2),
   2695                          parser.parse_args([], NS(x='baz', z=2)))
   2696 
   2697     def test_set_defaults_with_args(self):
   2698         parser = ErrorRaisingArgumentParser()
   2699         parser.set_defaults(x='foo', y='bar')
   2700         parser.add_argument('-x', default='xfoox')
   2701         self.assertEqual(NS(x='xfoox', y='bar'),
   2702                          parser.parse_args([]))
   2703         self.assertEqual(NS(x='xfoox', y='bar'),
   2704                          parser.parse_args([], NS()))
   2705         self.assertEqual(NS(x='baz', y='bar'),
   2706                          parser.parse_args([], NS(x='baz')))
   2707         self.assertEqual(NS(x='1', y='bar'),
   2708                          parser.parse_args('-x 1'.split()))
   2709         self.assertEqual(NS(x='1', y='bar'),
   2710                          parser.parse_args('-x 1'.split(), NS()))
   2711         self.assertEqual(NS(x='1', y='bar'),
   2712                          parser.parse_args('-x 1'.split(), NS(x='baz')))
   2713 
   2714     def test_set_defaults_subparsers(self):
   2715         parser = ErrorRaisingArgumentParser()
   2716         parser.set_defaults(x='foo')
   2717         subparsers = parser.add_subparsers()
   2718         parser_a = subparsers.add_parser('a')
   2719         parser_a.set_defaults(y='bar')
   2720         self.assertEqual(NS(x='foo', y='bar'),
   2721                          parser.parse_args('a'.split()))
   2722 
   2723     def test_set_defaults_parents(self):
   2724         parent = ErrorRaisingArgumentParser(add_help=False)
   2725         parent.set_defaults(x='foo')
   2726         parser = ErrorRaisingArgumentParser(parents=[parent])
   2727         self.assertEqual(NS(x='foo'), parser.parse_args([]))
   2728 
   2729     def test_set_defaults_on_parent_and_subparser(self):
   2730         parser = argparse.ArgumentParser()
   2731         xparser = parser.add_subparsers().add_parser('X')
   2732         parser.set_defaults(foo=1)
   2733         xparser.set_defaults(foo=2)
   2734         self.assertEqual(NS(foo=2), parser.parse_args(['X']))
   2735 
   2736     def test_set_defaults_same_as_add_argument(self):
   2737         parser = ErrorRaisingArgumentParser()
   2738         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2739         parser.add_argument('-w')
   2740         parser.add_argument('-x', default='XX')
   2741         parser.add_argument('y', nargs='?')
   2742         parser.add_argument('z', nargs='?', default='ZZ')
   2743 
   2744         # defaults set previously
   2745         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2746                          parser.parse_args([]))
   2747 
   2748         # reset defaults
   2749         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2750         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2751                          parser.parse_args([]))
   2752 
   2753     def test_set_defaults_same_as_add_argument_group(self):
   2754         parser = ErrorRaisingArgumentParser()
   2755         parser.set_defaults(w='W', x='X', y='Y', z='Z')
   2756         group = parser.add_argument_group('foo')
   2757         group.add_argument('-w')
   2758         group.add_argument('-x', default='XX')
   2759         group.add_argument('y', nargs='?')
   2760         group.add_argument('z', nargs='?', default='ZZ')
   2761 
   2762 
   2763         # defaults set previously
   2764         self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
   2765                          parser.parse_args([]))
   2766 
   2767         # reset defaults
   2768         parser.set_defaults(w='WW', x='X', y='YY', z='Z')
   2769         self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
   2770                          parser.parse_args([]))
   2771 
   2772 # =================
   2773 # Get default tests
   2774 # =================
   2775 
   2776 class TestGetDefault(TestCase):
   2777 
   2778     def test_get_default(self):
   2779         parser = ErrorRaisingArgumentParser()
   2780         self.assertEqual(None, parser.get_default("foo"))
   2781         self.assertEqual(None, parser.get_default("bar"))
   2782 
   2783         parser.add_argument("--foo")
   2784         self.assertEqual(None, parser.get_default("foo"))
   2785         self.assertEqual(None, parser.get_default("bar"))
   2786 
   2787         parser.add_argument("--bar", type=int, default=42)
   2788         self.assertEqual(None, parser.get_default("foo"))
   2789         self.assertEqual(42, parser.get_default("bar"))
   2790 
   2791         parser.set_defaults(foo="badger")
   2792         self.assertEqual("badger", parser.get_default("foo"))
   2793         self.assertEqual(42, parser.get_default("bar"))
   2794 
   2795 # ==========================
   2796 # Namespace 'contains' tests
   2797 # ==========================
   2798 
   2799 class TestNamespaceContainsSimple(TestCase):
   2800 
   2801     def test_empty(self):
   2802         ns = argparse.Namespace()
   2803         self.assertEqual('' in ns, False)
   2804         self.assertEqual('' not in ns, True)
   2805         self.assertEqual('x' in ns, False)
   2806 
   2807     def test_non_empty(self):
   2808         ns = argparse.Namespace(x=1, y=2)
   2809         self.assertEqual('x' in ns, True)
   2810         self.assertEqual('x' not in ns, False)
   2811         self.assertEqual('y' in ns, True)
   2812         self.assertEqual('' in ns, False)
   2813         self.assertEqual('xx' in ns, False)
   2814         self.assertEqual('z' in ns, False)
   2815 
   2816 # =====================
   2817 # Help formatting tests
   2818 # =====================
   2819 
   2820 class TestHelpFormattingMetaclass(type):
   2821 
   2822     def __init__(cls, name, bases, bodydict):
   2823         if name == 'HelpTestCase':
   2824             return
   2825 
   2826         class AddTests(object):
   2827 
   2828             def __init__(self, test_class, func_suffix, std_name):
   2829                 self.func_suffix = func_suffix
   2830                 self.std_name = std_name
   2831 
   2832                 for test_func in [self.test_format,
   2833                                   self.test_print,
   2834                                   self.test_print_file]:
   2835                     test_name = '%s_%s' % (test_func.__name__, func_suffix)
   2836 
   2837                     def test_wrapper(self, test_func=test_func):
   2838                         test_func(self)
   2839                     try:
   2840                         test_wrapper.__name__ = test_name
   2841                     except TypeError:
   2842                         pass
   2843                     setattr(test_class, test_name, test_wrapper)
   2844 
   2845             def _get_parser(self, tester):
   2846                 parser = argparse.ArgumentParser(
   2847                     *tester.parser_signature.args,
   2848                     **tester.parser_signature.kwargs)
   2849                 for argument_sig in getattr(tester, 'argument_signatures', []):
   2850                     parser.add_argument(*argument_sig.args,
   2851                                         **argument_sig.kwargs)
   2852                 group_sigs = getattr(tester, 'argument_group_signatures', [])
   2853                 for group_sig, argument_sigs in group_sigs:
   2854                     group = parser.add_argument_group(*group_sig.args,
   2855                                                       **group_sig.kwargs)
   2856                     for argument_sig in argument_sigs:
   2857                         group.add_argument(*argument_sig.args,
   2858                                            **argument_sig.kwargs)
   2859                 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
   2860                 if subparsers_sigs:
   2861                     subparsers = parser.add_subparsers()
   2862                     for subparser_sig in subparsers_sigs:
   2863                         subparsers.add_parser(*subparser_sig.args,
   2864                                                **subparser_sig.kwargs)
   2865                 return parser
   2866 
   2867             def _test(self, tester, parser_text):
   2868                 expected_text = getattr(tester, self.func_suffix)
   2869                 expected_text = textwrap.dedent(expected_text)
   2870                 if expected_text != parser_text:
   2871                     print(repr(expected_text))
   2872                     print(repr(parser_text))
   2873                     for char1, char2 in zip(expected_text, parser_text):
   2874                         if char1 != char2:
   2875                             print('first diff: %r %r' % (char1, char2))
   2876                             break
   2877                 tester.assertEqual(expected_text, parser_text)
   2878 
   2879             def test_format(self, tester):
   2880                 parser = self._get_parser(tester)
   2881                 format = getattr(parser, 'format_%s' % self.func_suffix)
   2882                 self._test(tester, format())
   2883 
   2884             def test_print(self, tester):
   2885                 parser = self._get_parser(tester)
   2886                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2887                 old_stream = getattr(sys, self.std_name)
   2888                 setattr(sys, self.std_name, StdIOBuffer())
   2889                 try:
   2890                     print_()
   2891                     parser_text = getattr(sys, self.std_name).getvalue()
   2892                 finally:
   2893                     setattr(sys, self.std_name, old_stream)
   2894                 self._test(tester, parser_text)
   2895 
   2896             def test_print_file(self, tester):
   2897                 parser = self._get_parser(tester)
   2898                 print_ = getattr(parser, 'print_%s' % self.func_suffix)
   2899                 sfile = StdIOBuffer()
   2900                 print_(sfile)
   2901                 parser_text = sfile.getvalue()
   2902                 self._test(tester, parser_text)
   2903 
   2904         # add tests for {format,print}_{usage,help,version}
   2905         for func_suffix, std_name in [('usage', 'stdout'),
   2906                                       ('help', 'stdout'),
   2907                                       ('version', 'stderr')]:
   2908             AddTests(cls, func_suffix, std_name)
   2909 
   2910 bases = TestCase,
   2911 HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
   2912 
   2913 
   2914 class TestHelpBiggerOptionals(HelpTestCase):
   2915     """Make sure that argument help aligns when options are longer"""
   2916 
   2917     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   2918                            epilog='EPILOG', version='0.1')
   2919     argument_signatures = [
   2920         Sig('-x', action='store_true', help='X HELP'),
   2921         Sig('--y', help='Y HELP'),
   2922         Sig('foo', help='FOO HELP'),
   2923         Sig('bar', help='BAR HELP'),
   2924     ]
   2925     argument_group_signatures = []
   2926     usage = '''\
   2927         usage: PROG [-h] [-v] [-x] [--y Y] foo bar
   2928         '''
   2929     help = usage + '''\
   2930 
   2931         DESCRIPTION
   2932 
   2933         positional arguments:
   2934           foo            FOO HELP
   2935           bar            BAR HELP
   2936 
   2937         optional arguments:
   2938           -h, --help     show this help message and exit
   2939           -v, --version  show program's version number and exit
   2940           -x             X HELP
   2941           --y Y          Y HELP
   2942 
   2943         EPILOG
   2944     '''
   2945     version = '''\
   2946         0.1
   2947         '''
   2948 
   2949 class TestShortColumns(HelpTestCase):
   2950     '''Test extremely small number of columns.
   2951 
   2952     TestCase prevents "COLUMNS" from being too small in the tests themselves,
   2953     but we don't want any exceptions thrown in such case. Only ugly representation.
   2954     '''
   2955     def setUp(self):
   2956         env = test_support.EnvironmentVarGuard()
   2957         env.set("COLUMNS", '15')
   2958         self.addCleanup(env.__exit__)
   2959 
   2960     parser_signature            = TestHelpBiggerOptionals.parser_signature
   2961     argument_signatures         = TestHelpBiggerOptionals.argument_signatures
   2962     argument_group_signatures   = TestHelpBiggerOptionals.argument_group_signatures
   2963     usage = '''\
   2964         usage: PROG
   2965                [-h]
   2966                [-v]
   2967                [-x]
   2968                [--y Y]
   2969                foo
   2970                bar
   2971         '''
   2972     help = usage + '''\
   2973 
   2974         DESCRIPTION
   2975 
   2976         positional arguments:
   2977           foo
   2978             FOO HELP
   2979           bar
   2980             BAR HELP
   2981 
   2982         optional arguments:
   2983           -h, --help
   2984             show this
   2985             help
   2986             message and
   2987             exit
   2988           -v, --version
   2989             show
   2990             program's
   2991             version
   2992             number and
   2993             exit
   2994           -x
   2995             X HELP
   2996           --y Y
   2997             Y HELP
   2998 
   2999         EPILOG
   3000     '''
   3001     version                     = TestHelpBiggerOptionals.version
   3002 
   3003 
   3004 class TestHelpBiggerOptionalGroups(HelpTestCase):
   3005     """Make sure that argument help aligns when options are longer"""
   3006 
   3007     parser_signature = Sig(prog='PROG', description='DESCRIPTION',
   3008                            epilog='EPILOG', version='0.1')
   3009     argument_signatures = [
   3010         Sig('-x', action='store_true', help='X HELP'),
   3011         Sig('--y', help='Y HELP'),
   3012         Sig('foo', help='FOO HELP'),
   3013         Sig('bar', help='BAR HELP'),
   3014     ]
   3015     argument_group_signatures = [
   3016         (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
   3017             Sig('baz', help='BAZ HELP'),
   3018             Sig('-z', nargs='+', help='Z HELP')]),
   3019     ]
   3020     usage = '''\
   3021         usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
   3022         '''
   3023     help = usage + '''\
   3024 
   3025         DESCRIPTION
   3026 
   3027         positional arguments:
   3028           foo            FOO HELP
   3029           bar            BAR HELP
   3030 
   3031         optional arguments:
   3032           -h, --help     show this help message and exit
   3033           -v, --version  show program's version number and exit
   3034           -x             X HELP
   3035           --y Y          Y HELP
   3036 
   3037         GROUP TITLE:
   3038           GROUP DESCRIPTION
   3039 
   3040           baz            BAZ HELP
   3041           -z Z [Z ...]   Z HELP
   3042 
   3043         EPILOG
   3044     '''
   3045     version = '''\
   3046         0.1
   3047         '''
   3048 
   3049 
   3050 class TestHelpBiggerPositionals(HelpTestCase):
   3051     """Make sure that help aligns when arguments are longer"""
   3052 
   3053     parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
   3054     argument_signatures = [
   3055         Sig('-x', action='store_true', help='X HELP'),
   3056         Sig('--y', help='Y HELP'),
   3057         Sig('ekiekiekifekang', help='EKI HELP'),
   3058         Sig('bar', help='BAR HELP'),
   3059     ]
   3060     argument_group_signatures = []
   3061     usage = '''\
   3062         usage: USAGE
   3063         '''
   3064     help = usage + '''\
   3065 
   3066         DESCRIPTION
   3067 
   3068         positional arguments:
   3069           ekiekiekifekang  EKI HELP
   3070           bar              BAR HELP
   3071 
   3072         optional arguments:
   3073           -h, --help       show this help message and exit
   3074           -x               X HELP
   3075           --y Y            Y HELP
   3076         '''
   3077 
   3078     version = ''
   3079 
   3080 
   3081 class TestHelpReformatting(HelpTestCase):
   3082     """Make sure that text after short names starts on the first line"""
   3083 
   3084     parser_signature = Sig(
   3085         prog='PROG',
   3086         description='   oddly    formatted\n'
   3087                     'description\n'
   3088                     '\n'
   3089                     'that is so long that it should go onto multiple '
   3090                     'lines when wrapped')
   3091     argument_signatures = [
   3092         Sig('-x', metavar='XX', help='oddly\n'
   3093                                      '    formatted -x help'),
   3094         Sig('y', metavar='yyy', help='normal y help'),
   3095     ]
   3096     argument_group_signatures = [
   3097         (Sig('title', description='\n'
   3098                                   '    oddly formatted group\n'
   3099                                   '\n'
   3100                                   'description'),
   3101          [Sig('-a', action='store_true',
   3102               help=' oddly \n'
   3103                    'formatted    -a  help  \n'
   3104                    '    again, so long that it should be wrapped over '
   3105                    'multiple lines')]),
   3106     ]
   3107     usage = '''\
   3108         usage: PROG [-h] [-x XX] [-a] yyy
   3109         '''
   3110     help = usage + '''\
   3111 
   3112         oddly formatted description that is so long that it should go onto \
   3113 multiple
   3114         lines when wrapped
   3115 
   3116         positional arguments:
   3117           yyy         normal y help
   3118 
   3119         optional arguments:
   3120           -h, --help  show this help message and exit
   3121           -x XX       oddly formatted -x help
   3122 
   3123         title:
   3124           oddly formatted group description
   3125 
   3126           -a          oddly formatted -a help again, so long that it should \
   3127 be wrapped
   3128                       over multiple lines
   3129         '''
   3130     version = ''
   3131 
   3132 
   3133 class TestHelpWrappingShortNames(HelpTestCase):
   3134     """Make sure that text after short names starts on the first line"""
   3135 
   3136     parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
   3137     argument_signatures = [
   3138         Sig('-x', metavar='XX', help='XHH HX' * 20),
   3139         Sig('y', metavar='yyy', help='YH YH' * 20),
   3140     ]
   3141     argument_group_signatures = [
   3142         (Sig('ALPHAS'), [
   3143             Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
   3144     ]
   3145     usage = '''\
   3146         usage: PROG [-h] [-x XX] [-a] yyy
   3147         '''
   3148     help = usage + '''\
   3149 
   3150         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3151 DD DD DD
   3152         DD DD DD DD D
   3153 
   3154         positional arguments:
   3155           yyy         YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3156 YHYH YHYH
   3157                       YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3158 
   3159         optional arguments:
   3160           -h, --help  show this help message and exit
   3161           -x XX       XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
   3162 HXXHH HXXHH
   3163                       HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
   3164 
   3165         ALPHAS:
   3166           -a          AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
   3167 HHAAHHH
   3168                       HHAAHHH HHAAHHH HHA
   3169         '''
   3170     version = ''
   3171 
   3172 
   3173 class TestHelpWrappingLongNames(HelpTestCase):
   3174     """Make sure that text after long names starts on the next line"""
   3175 
   3176     parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
   3177                            version='V V'*30)
   3178     argument_signatures = [
   3179         Sig('-x', metavar='X' * 25, help='XH XH' * 20),
   3180         Sig('y', metavar='y' * 25, help='YH YH' * 20),
   3181     ]
   3182     argument_group_signatures = [
   3183         (Sig('ALPHAS'), [
   3184             Sig('-a', metavar='A' * 25, help='AH AH' * 20),
   3185             Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
   3186     ]
   3187     usage = '''\
   3188         usage: USAGE
   3189         '''
   3190     help = usage + '''\
   3191 
   3192         D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
   3193 DD DD DD
   3194         DD DD DD DD D
   3195 
   3196         positional arguments:
   3197           yyyyyyyyyyyyyyyyyyyyyyyyy
   3198                                 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
   3199 YHYH YHYH
   3200                                 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
   3201 
   3202         optional arguments:
   3203           -h, --help            show this help message and exit
   3204           -v, --version         show program's version number and exit
   3205           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3206                                 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
   3207 XHXH XHXH
   3208                                 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
   3209 
   3210         ALPHAS:
   3211           -a AAAAAAAAAAAAAAAAAAAAAAAAA
   3212                                 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
   3213 AHAH AHAH
   3214                                 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
   3215           zzzzzzzzzzzzzzzzzzzzzzzzz
   3216                                 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
   3217 ZHZH ZHZH
   3218                                 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
   3219         '''
   3220     version = '''\
   3221         V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
   3222 VV VV VV
   3223         VV VV VV VV V
   3224         '''
   3225 
   3226 
   3227 class TestHelpUsage(HelpTestCase):
   3228     """Test basic usage messages"""
   3229 
   3230     parser_signature = Sig(prog='PROG')
   3231     argument_signatures = [
   3232         Sig('-w', nargs='+', help='w'),
   3233         Sig('-x', nargs='*', help='x'),
   3234         Sig('a', help='a'),
   3235         Sig('b', help='b', nargs=2),
   3236         Sig('c', help='c', nargs='?'),
   3237     ]
   3238     argument_group_signatures = [
   3239         (Sig('group'), [
   3240             Sig('-y', nargs='?', help='y'),
   3241             Sig('-z', nargs=3, help='z'),
   3242             Sig('d', help='d', nargs='*'),
   3243             Sig('e', help='e', nargs='+'),
   3244         ])
   3245     ]
   3246     usage = '''\
   3247         usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
   3248                     a b b [c] [d [d ...]] e [e ...]
   3249         '''
   3250     help = usage + '''\
   3251 
   3252         positional arguments:
   3253           a               a
   3254           b               b
   3255           c               c
   3256 
   3257         optional arguments:
   3258           -h, --help      show this help message and exit
   3259           -w W [W ...]    w
   3260           -x [X [X ...]]  x
   3261 
   3262         group:
   3263           -y [Y]          y
   3264           -z Z Z Z        z
   3265           d               d
   3266           e               e
   3267         '''
   3268     version = ''
   3269 
   3270 
   3271 class TestHelpOnlyUserGroups(HelpTestCase):
   3272     """Test basic usage messages"""
   3273 
   3274     parser_signature = Sig(prog='PROG', add_help=False)
   3275     argument_signatures = []
   3276     argument_group_signatures = [
   3277         (Sig('xxxx'), [
   3278             Sig('-x', help='x'),
   3279             Sig('a', help='a'),
   3280         ]),
   3281         (Sig('yyyy'), [
   3282             Sig('b', help='b'),
   3283             Sig('-y', help='y'),
   3284         ]),
   3285     ]
   3286     usage = '''\
   3287         usage: PROG [-x X] [-y Y] a b
   3288         '''
   3289     help = usage + '''\
   3290 
   3291         xxxx:
   3292           -x X  x
   3293           a     a
   3294 
   3295         yyyy:
   3296           b     b
   3297           -y Y  y
   3298         '''
   3299     version = ''
   3300 
   3301 
   3302 class TestHelpUsageLongProg(HelpTestCase):
   3303     """Test usage messages where the prog is long"""
   3304 
   3305     parser_signature = Sig(prog='P' * 60)
   3306     argument_signatures = [
   3307         Sig('-w', metavar='W'),
   3308         Sig('-x', metavar='X'),
   3309         Sig('a'),
   3310         Sig('b'),
   3311     ]
   3312     argument_group_signatures = []
   3313     usage = '''\
   3314         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3315                [-h] [-w W] [-x X] a b
   3316         '''
   3317     help = usage + '''\
   3318 
   3319         positional arguments:
   3320           a
   3321           b
   3322 
   3323         optional arguments:
   3324           -h, --help  show this help message and exit
   3325           -w W
   3326           -x X
   3327         '''
   3328     version = ''
   3329 
   3330 
   3331 class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
   3332     """Test usage messages where the prog is long and the optionals wrap"""
   3333 
   3334     parser_signature = Sig(prog='P' * 60)
   3335     argument_signatures = [
   3336         Sig('-w', metavar='W' * 25),
   3337         Sig('-x', metavar='X' * 25),
   3338         Sig('-y', metavar='Y' * 25),
   3339         Sig('-z', metavar='Z' * 25),
   3340         Sig('a'),
   3341         Sig('b'),
   3342     ]
   3343     argument_group_signatures = []
   3344     usage = '''\
   3345         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3346                [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3347 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3348                [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3349                a b
   3350         '''
   3351     help = usage + '''\
   3352 
   3353         positional arguments:
   3354           a
   3355           b
   3356 
   3357         optional arguments:
   3358           -h, --help            show this help message and exit
   3359           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3360           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3361           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3362           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3363         '''
   3364     version = ''
   3365 
   3366 
   3367 class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
   3368     """Test usage messages where the prog is long and the positionals wrap"""
   3369 
   3370     parser_signature = Sig(prog='P' * 60, add_help=False)
   3371     argument_signatures = [
   3372         Sig('a' * 25),
   3373         Sig('b' * 25),
   3374         Sig('c' * 25),
   3375     ]
   3376     argument_group_signatures = []
   3377     usage = '''\
   3378         usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
   3379                aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3380                ccccccccccccccccccccccccc
   3381         '''
   3382     help = usage + '''\
   3383 
   3384         positional arguments:
   3385           aaaaaaaaaaaaaaaaaaaaaaaaa
   3386           bbbbbbbbbbbbbbbbbbbbbbbbb
   3387           ccccccccccccccccccccccccc
   3388         '''
   3389     version = ''
   3390 
   3391 
   3392 class TestHelpUsageOptionalsWrap(HelpTestCase):
   3393     """Test usage messages where the optionals wrap"""
   3394 
   3395     parser_signature = Sig(prog='PROG')
   3396     argument_signatures = [
   3397         Sig('-w', metavar='W' * 25),
   3398         Sig('-x', metavar='X' * 25),
   3399         Sig('-y', metavar='Y' * 25),
   3400         Sig('-z', metavar='Z' * 25),
   3401         Sig('a'),
   3402         Sig('b'),
   3403         Sig('c'),
   3404     ]
   3405     argument_group_signatures = []
   3406     usage = '''\
   3407         usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
   3408 [-x XXXXXXXXXXXXXXXXXXXXXXXXX]
   3409                     [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
   3410 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3411                     a b c
   3412         '''
   3413     help = usage + '''\
   3414 
   3415         positional arguments:
   3416           a
   3417           b
   3418           c
   3419 
   3420         optional arguments:
   3421           -h, --help            show this help message and exit
   3422           -w WWWWWWWWWWWWWWWWWWWWWWWWW
   3423           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3424           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3425           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3426         '''
   3427     version = ''
   3428 
   3429 
   3430 class TestHelpUsagePositionalsWrap(HelpTestCase):
   3431     """Test usage messages where the positionals wrap"""
   3432 
   3433     parser_signature = Sig(prog='PROG')
   3434     argument_signatures = [
   3435         Sig('-x'),
   3436         Sig('-y'),
   3437         Sig('-z'),
   3438         Sig('a' * 25),
   3439         Sig('b' * 25),
   3440         Sig('c' * 25),
   3441     ]
   3442     argument_group_signatures = []
   3443     usage = '''\
   3444         usage: PROG [-h] [-x X] [-y Y] [-z Z]
   3445                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3446                     ccccccccccccccccccccccccc
   3447         '''
   3448     help = usage + '''\
   3449 
   3450         positional arguments:
   3451           aaaaaaaaaaaaaaaaaaaaaaaaa
   3452           bbbbbbbbbbbbbbbbbbbbbbbbb
   3453           ccccccccccccccccccccccccc
   3454 
   3455         optional arguments:
   3456           -h, --help            show this help message and exit
   3457           -x X
   3458           -y Y
   3459           -z Z
   3460         '''
   3461     version = ''
   3462 
   3463 
   3464 class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
   3465     """Test usage messages where the optionals and positionals wrap"""
   3466 
   3467     parser_signature = Sig(prog='PROG')
   3468     argument_signatures = [
   3469         Sig('-x', metavar='X' * 25),
   3470         Sig('-y', metavar='Y' * 25),
   3471         Sig('-z', metavar='Z' * 25),
   3472         Sig('a' * 25),
   3473         Sig('b' * 25),
   3474         Sig('c' * 25),
   3475     ]
   3476     argument_group_signatures = []
   3477     usage = '''\
   3478         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3479 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3480                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3481                     aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3482                     ccccccccccccccccccccccccc
   3483         '''
   3484     help = usage + '''\
   3485 
   3486         positional arguments:
   3487           aaaaaaaaaaaaaaaaaaaaaaaaa
   3488           bbbbbbbbbbbbbbbbbbbbbbbbb
   3489           ccccccccccccccccccccccccc
   3490 
   3491         optional arguments:
   3492           -h, --help            show this help message and exit
   3493           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3494           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3495           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3496         '''
   3497     version = ''
   3498 
   3499 
   3500 class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
   3501     """Test usage messages where there are only optionals and they wrap"""
   3502 
   3503     parser_signature = Sig(prog='PROG')
   3504     argument_signatures = [
   3505         Sig('-x', metavar='X' * 25),
   3506         Sig('-y', metavar='Y' * 25),
   3507         Sig('-z', metavar='Z' * 25),
   3508     ]
   3509     argument_group_signatures = []
   3510     usage = '''\
   3511         usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
   3512 [-y YYYYYYYYYYYYYYYYYYYYYYYYY]
   3513                     [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
   3514         '''
   3515     help = usage + '''\
   3516 
   3517         optional arguments:
   3518           -h, --help            show this help message and exit
   3519           -x XXXXXXXXXXXXXXXXXXXXXXXXX
   3520           -y YYYYYYYYYYYYYYYYYYYYYYYYY
   3521           -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
   3522         '''
   3523     version = ''
   3524 
   3525 
   3526 class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
   3527     """Test usage messages where there are only positionals and they wrap"""
   3528 
   3529     parser_signature = Sig(prog='PROG', add_help=False)
   3530     argument_signatures = [
   3531         Sig('a' * 25),
   3532         Sig('b' * 25),
   3533         Sig('c' * 25),
   3534     ]
   3535     argument_group_signatures = []
   3536     usage = '''\
   3537         usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
   3538                     ccccccccccccccccccccccccc
   3539         '''
   3540     help = usage + '''\
   3541 
   3542         positional arguments:
   3543           aaaaaaaaaaaaaaaaaaaaaaaaa
   3544           bbbbbbbbbbbbbbbbbbbbbbbbb
   3545           ccccccccccccccccccccccccc
   3546         '''
   3547     version = ''
   3548 
   3549 
   3550 class TestHelpVariableExpansion(HelpTestCase):
   3551     """Test that variables are expanded properly in help messages"""
   3552 
   3553     parser_signature = Sig(prog='PROG')
   3554     argument_signatures = [
   3555         Sig('-x', type=int,
   3556             help='x %(prog)s %(default)s %(type)s %%'),
   3557         Sig('-y', action='store_const', default=42, const='XXX',
   3558             help='y %(prog)s %(default)s %(const)s'),
   3559         Sig('--foo', choices='abc',
   3560             help='foo %(prog)s %(default)s %(choices)s'),
   3561         Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
   3562             help='bar %(prog)s %(default)s %(dest)s'),
   3563         Sig('spam', help='spam %(prog)s %(default)s'),
   3564         Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
   3565     ]
   3566     argument_group_signatures = [
   3567         (Sig('group'), [
   3568             Sig('-a', help='a %(prog)s %(default)s'),
   3569             Sig('-b', default=-1, help='b %(prog)s %(default)s'),
   3570         ])
   3571     ]
   3572     usage = ('''\
   3573         usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
   3574                     spam badger
   3575         ''')
   3576     help = usage + '''\
   3577 
   3578         positional arguments:
   3579           spam           spam PROG None
   3580           badger         badger PROG 0.5
   3581 
   3582         optional arguments:
   3583           -h, --help     show this help message and exit
   3584           -x X           x PROG None int %
   3585           -y             y PROG 42 XXX
   3586           --foo {a,b,c}  foo PROG None a, b, c
   3587           --bar BBB      bar PROG baz bar
   3588 
   3589         group:
   3590           -a A           a PROG None
   3591           -b B           b PROG -1
   3592         '''
   3593     version = ''
   3594 
   3595 
   3596 class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
   3597     """Test that variables are expanded properly when usage= is present"""
   3598 
   3599     parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
   3600     argument_signatures = []
   3601     argument_group_signatures = []
   3602     usage = ('''\
   3603         usage: PROG FOO
   3604         ''')
   3605     help = usage + '''\
   3606 
   3607         optional arguments:
   3608           -h, --help  show this help message and exit
   3609         '''
   3610     version = ''
   3611 
   3612 
   3613 class TestHelpVariableExpansionNoArguments(HelpTestCase):
   3614     """Test that variables are expanded properly with no arguments"""
   3615 
   3616     parser_signature = Sig(prog='PROG', add_help=False)
   3617     argument_signatures = []
   3618     argument_group_signatures = []
   3619     usage = ('''\
   3620         usage: PROG
   3621         ''')
   3622     help = usage
   3623     version = ''
   3624 
   3625 
   3626 class TestHelpSuppressUsage(HelpTestCase):
   3627     """Test that items can be suppressed in usage messages"""
   3628 
   3629     parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
   3630     argument_signatures = [
   3631         Sig('--foo', help='foo help'),
   3632         Sig('spam', help='spam help'),
   3633     ]
   3634     argument_group_signatures = []
   3635     help = '''\
   3636         positional arguments:
   3637           spam        spam help
   3638 
   3639         optional arguments:
   3640           -h, --help  show this help message and exit
   3641           --foo FOO   foo help
   3642         '''
   3643     usage = ''
   3644     version = ''
   3645 
   3646 
   3647 class TestHelpSuppressOptional(HelpTestCase):
   3648     """Test that optional arguments can be suppressed in help messages"""
   3649 
   3650     parser_signature = Sig(prog='PROG', add_help=False)
   3651     argument_signatures = [
   3652         Sig('--foo', help=argparse.SUPPRESS),
   3653         Sig('spam', help='spam help'),
   3654     ]
   3655     argument_group_signatures = []
   3656     usage = '''\
   3657         usage: PROG spam
   3658         '''
   3659     help = usage + '''\
   3660 
   3661         positional arguments:
   3662           spam  spam help
   3663         '''
   3664     version = ''
   3665 
   3666 
   3667 class TestHelpSuppressOptionalGroup(HelpTestCase):
   3668     """Test that optional groups can be suppressed in help messages"""
   3669 
   3670     parser_signature = Sig(prog='PROG')
   3671     argument_signatures = [
   3672         Sig('--foo', help='foo help'),
   3673         Sig('spam', help='spam help'),
   3674     ]
   3675     argument_group_signatures = [
   3676         (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
   3677     ]
   3678     usage = '''\
   3679         usage: PROG [-h] [--foo FOO] spam
   3680         '''
   3681     help = usage + '''\
   3682 
   3683         positional arguments:
   3684           spam        spam help
   3685 
   3686         optional arguments:
   3687           -h, --help  show this help message and exit
   3688           --foo FOO   foo help
   3689         '''
   3690     version = ''
   3691 
   3692 
   3693 class TestHelpSuppressPositional(HelpTestCase):
   3694     """Test that positional arguments can be suppressed in help messages"""
   3695 
   3696     parser_signature = Sig(prog='PROG')
   3697     argument_signatures = [
   3698         Sig('--foo', help='foo help'),
   3699         Sig('spam', help=argparse.SUPPRESS),
   3700     ]
   3701     argument_group_signatures = []
   3702     usage = '''\
   3703         usage: PROG [-h] [--foo FOO]
   3704         '''
   3705     help = usage + '''\
   3706 
   3707         optional arguments:
   3708           -h, --help  show this help message and exit
   3709           --foo FOO   foo help
   3710         '''
   3711     version = ''
   3712 
   3713 
   3714 class TestHelpRequiredOptional(HelpTestCase):
   3715     """Test that required options don't look optional"""
   3716 
   3717     parser_signature = Sig(prog='PROG')
   3718     argument_signatures = [
   3719         Sig('--foo', required=True, help='foo help'),
   3720     ]
   3721     argument_group_signatures = []
   3722     usage = '''\
   3723         usage: PROG [-h] --foo FOO
   3724         '''
   3725     help = usage + '''\
   3726 
   3727         optional arguments:
   3728           -h, --help  show this help message and exit
   3729           --foo FOO   foo help
   3730         '''
   3731     version = ''
   3732 
   3733 
   3734 class TestHelpAlternatePrefixChars(HelpTestCase):
   3735     """Test that options display with different prefix characters"""
   3736 
   3737     parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
   3738     argument_signatures = [
   3739         Sig('^^foo', action='store_true', help='foo help'),
   3740         Sig(';b', ';;bar', help='bar help'),
   3741     ]
   3742     argument_group_signatures = []
   3743     usage = '''\
   3744         usage: PROG [^^foo] [;b BAR]
   3745         '''
   3746     help = usage + '''\
   3747 
   3748         optional arguments:
   3749           ^^foo              foo help
   3750           ;b BAR, ;;bar BAR  bar help
   3751         '''
   3752     version = ''
   3753 
   3754 
   3755 class TestHelpNoHelpOptional(HelpTestCase):
   3756     """Test that the --help argument can be suppressed help messages"""
   3757 
   3758     parser_signature = Sig(prog='PROG', add_help=False)
   3759     argument_signatures = [
   3760         Sig('--foo', help='foo help'),
   3761         Sig('spam', help='spam help'),
   3762     ]
   3763     argument_group_signatures = []
   3764     usage = '''\
   3765         usage: PROG [--foo FOO] spam
   3766         '''
   3767     help = usage + '''\
   3768 
   3769         positional arguments:
   3770           spam       spam help
   3771 
   3772         optional arguments:
   3773           --foo FOO  foo help
   3774         '''
   3775     version = ''
   3776 
   3777 
   3778 class TestHelpVersionOptional(HelpTestCase):
   3779     """Test that the --version argument can be suppressed help messages"""
   3780 
   3781     parser_signature = Sig(prog='PROG', version='1.0')
   3782     argument_signatures = [
   3783         Sig('--foo', help='foo help'),
   3784         Sig('spam', help='spam help'),
   3785     ]
   3786     argument_group_signatures = []
   3787     usage = '''\
   3788         usage: PROG [-h] [-v] [--foo FOO] spam
   3789         '''
   3790     help = usage + '''\
   3791 
   3792         positional arguments:
   3793           spam           spam help
   3794 
   3795         optional arguments:
   3796           -h, --help     show this help message and exit
   3797           -v, --version  show program's version number and exit
   3798           --foo FOO      foo help
   3799         '''
   3800     version = '''\
   3801         1.0
   3802         '''
   3803 
   3804 
   3805 class TestHelpNone(HelpTestCase):
   3806     """Test that no errors occur if no help is specified"""
   3807 
   3808     parser_signature = Sig(prog='PROG')
   3809     argument_signatures = [
   3810         Sig('--foo'),
   3811         Sig('spam'),
   3812     ]
   3813     argument_group_signatures = []
   3814     usage = '''\
   3815         usage: PROG [-h] [--foo FOO] spam
   3816         '''
   3817     help = usage + '''\
   3818 
   3819         positional arguments:
   3820           spam
   3821 
   3822         optional arguments:
   3823           -h, --help  show this help message and exit
   3824           --foo FOO
   3825         '''
   3826     version = ''
   3827 
   3828 
   3829 class TestHelpTupleMetavar(HelpTestCase):
   3830     """Test specifying metavar as a tuple"""
   3831 
   3832     parser_signature = Sig(prog='PROG')
   3833     argument_signatures = [
   3834         Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
   3835         Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
   3836         Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
   3837         Sig('-z', help='z', nargs='?', metavar=('Z1', )),
   3838     ]
   3839     argument_group_signatures = []
   3840     usage = '''\
   3841         usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
   3842 [-z [Z1]]
   3843         '''
   3844     help = usage + '''\
   3845 
   3846         optional arguments:
   3847           -h, --help        show this help message and exit
   3848           -w W1 [W2 ...]    w
   3849           -x [X1 [X2 ...]]  x
   3850           -y Y1 Y2 Y3       y
   3851           -z [Z1]           z
   3852         '''
   3853     version = ''
   3854 
   3855 
   3856 class TestHelpRawText(HelpTestCase):
   3857     """Test the RawTextHelpFormatter"""
   3858 
   3859     parser_signature = Sig(
   3860         prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
   3861         description='Keep the formatting\n'
   3862                     '    exactly as it is written\n'
   3863                     '\n'
   3864                     'here\n')
   3865 
   3866     argument_signatures = [
   3867         Sig('--foo', help='    foo help should also\n'
   3868                           'appear as given here'),
   3869         Sig('spam', help='spam help'),
   3870     ]
   3871     argument_group_signatures = [
   3872         (Sig('title', description='    This text\n'
   3873                                   '  should be indented\n'
   3874                                   '    exactly like it is here\n'),
   3875          [Sig('--bar', help='bar help')]),
   3876     ]
   3877     usage = '''\
   3878         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3879         '''
   3880     help = usage + '''\
   3881 
   3882         Keep the formatting
   3883             exactly as it is written
   3884 
   3885         here
   3886 
   3887         positional arguments:
   3888           spam        spam help
   3889 
   3890         optional arguments:
   3891           -h, --help  show this help message and exit
   3892           --foo FOO       foo help should also
   3893                       appear as given here
   3894 
   3895         title:
   3896               This text
   3897             should be indented
   3898               exactly like it is here
   3899 
   3900           --bar BAR   bar help
   3901         '''
   3902     version = ''
   3903 
   3904 
   3905 class TestHelpRawDescription(HelpTestCase):
   3906     """Test the RawTextHelpFormatter"""
   3907 
   3908     parser_signature = Sig(
   3909         prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
   3910         description='Keep the formatting\n'
   3911                     '    exactly as it is written\n'
   3912                     '\n'
   3913                     'here\n')
   3914 
   3915     argument_signatures = [
   3916         Sig('--foo', help='  foo help should not\n'
   3917                           '    retain this odd formatting'),
   3918         Sig('spam', help='spam help'),
   3919     ]
   3920     argument_group_signatures = [
   3921         (Sig('title', description='    This text\n'
   3922                                   '  should be indented\n'
   3923                                   '    exactly like it is here\n'),
   3924          [Sig('--bar', help='bar help')]),
   3925     ]
   3926     usage = '''\
   3927         usage: PROG [-h] [--foo FOO] [--bar BAR] spam
   3928         '''
   3929     help = usage + '''\
   3930 
   3931         Keep the formatting
   3932             exactly as it is written
   3933 
   3934         here
   3935 
   3936         positional arguments:
   3937           spam        spam help
   3938 
   3939         optional arguments:
   3940           -h, --help  show this help message and exit
   3941           --foo FOO   foo help should not retain this odd formatting
   3942 
   3943         title:
   3944               This text
   3945             should be indented
   3946               exactly like it is here
   3947 
   3948           --bar BAR   bar help
   3949         '''
   3950     version = ''
   3951 
   3952 
   3953 class TestHelpArgumentDefaults(HelpTestCase):
   3954     """Test the ArgumentDefaultsHelpFormatter"""
   3955 
   3956     parser_signature = Sig(
   3957         prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
   3958         description='description')
   3959 
   3960     argument_signatures = [
   3961         Sig('--foo', help='foo help - oh and by the way, %(default)s'),
   3962         Sig('--bar', action='store_true', help='bar help'),
   3963         Sig('spam', help='spam help'),
   3964         Sig('badger', nargs='?', default='wooden', help='badger help'),
   3965     ]
   3966     argument_group_signatures = [
   3967         (Sig('title', description='description'),
   3968          [Sig('--baz', type=int, default=42, help='baz help')]),
   3969     ]
   3970     usage = '''\
   3971         usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
   3972         '''
   3973     help = usage + '''\
   3974 
   3975         description
   3976 
   3977         positional arguments:
   3978           spam        spam help
   3979           badger      badger help (default: wooden)
   3980 
   3981         optional arguments:
   3982           -h, --help  show this help message and exit
   3983           --foo FOO   foo help - oh and by the way, None
   3984           --bar       bar help (default: False)
   3985 
   3986         title:
   3987           description
   3988 
   3989           --baz BAZ   baz help (default: 42)
   3990         '''
   3991     version = ''
   3992 
   3993 class TestHelpVersionAction(HelpTestCase):
   3994     """Test the default help for the version action"""
   3995 
   3996     parser_signature = Sig(prog='PROG', description='description')
   3997     argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
   3998     argument_group_signatures = []
   3999     usage = '''\
   4000         usage: PROG [-h] [-V]
   4001         '''
   4002     help = usage + '''\
   4003 
   4004         description
   4005 
   4006         optional arguments:
   4007           -h, --help     show this help message and exit
   4008           -V, --version  show program's version number and exit
   4009         '''
   4010     version = ''
   4011 
   4012 class TestHelpSubparsersOrdering(HelpTestCase):
   4013     """Test ordering of subcommands in help matches the code"""
   4014     parser_signature = Sig(prog='PROG',
   4015                            description='display some subcommands',
   4016                            version='0.1')
   4017 
   4018     subparsers_signatures = [Sig(name=name)
   4019                              for name in ('a', 'b', 'c', 'd', 'e')]
   4020 
   4021     usage = '''\
   4022         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   4023         '''
   4024 
   4025     help = usage + '''\
   4026 
   4027         display some subcommands
   4028 
   4029         positional arguments:
   4030           {a,b,c,d,e}
   4031 
   4032         optional arguments:
   4033           -h, --help     show this help message and exit
   4034           -v, --version  show program's version number and exit
   4035         '''
   4036 
   4037     version = '''\
   4038         0.1
   4039         '''
   4040 
   4041 class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
   4042     """Test ordering of subcommands in help matches the code"""
   4043     parser_signature = Sig(prog='PROG',
   4044                            description='display some subcommands',
   4045                            version='0.1')
   4046 
   4047     subcommand_data = (('a', 'a subcommand help'),
   4048                        ('b', 'b subcommand help'),
   4049                        ('c', 'c subcommand help'),
   4050                        ('d', 'd subcommand help'),
   4051                        ('e', 'e subcommand help'),
   4052                        )
   4053 
   4054     subparsers_signatures = [Sig(name=name, help=help)
   4055                              for name, help in subcommand_data]
   4056 
   4057     usage = '''\
   4058         usage: PROG [-h] [-v] {a,b,c,d,e} ...
   4059         '''
   4060 
   4061     help = usage + '''\
   4062 
   4063         display some subcommands
   4064 
   4065         positional arguments:
   4066           {a,b,c,d,e}
   4067             a            a subcommand help
   4068             b            b subcommand help
   4069             c            c subcommand help
   4070             d            d subcommand help
   4071             e            e subcommand help
   4072 
   4073         optional arguments:
   4074           -h, --help     show this help message and exit
   4075           -v, --version  show program's version number and exit
   4076         '''
   4077 
   4078     version = '''\
   4079         0.1
   4080         '''
   4081 
   4082 
   4083 # =====================================
   4084 # Optional/Positional constructor tests
   4085 # =====================================
   4086 
   4087 class TestInvalidArgumentConstructors(TestCase):
   4088     """Test a bunch of invalid Argument constructors"""
   4089 
   4090     def assertTypeError(self, *args, **kwargs):
   4091         parser = argparse.ArgumentParser()
   4092         self.assertRaises(TypeError, parser.add_argument,
   4093                           *args, **kwargs)
   4094 
   4095     def assertValueError(self, *args, **kwargs):
   4096         parser = argparse.ArgumentParser()
   4097         self.assertRaises(ValueError, parser.add_argument,
   4098                           *args, **kwargs)
   4099 
   4100     def test_invalid_keyword_arguments(self):
   4101         self.assertTypeError('-x', bar=None)
   4102         self.assertTypeError('-y', callback='foo')
   4103         self.assertTypeError('-y', callback_args=())
   4104         self.assertTypeError('-y', callback_kwargs={})
   4105 
   4106     def test_missing_destination(self):
   4107         self.assertTypeError()
   4108         for action in ['append', 'store']:
   4109             self.assertTypeError(action=action)
   4110 
   4111     def test_invalid_option_strings(self):
   4112         self.assertValueError('--')
   4113         self.assertValueError('---')
   4114 
   4115     def test_invalid_type(self):
   4116         self.assertValueError('--foo', type='int')
   4117         self.assertValueError('--foo', type=(int, float))
   4118 
   4119     def test_invalid_action(self):
   4120         self.assertValueError('-x', action='foo')
   4121         self.assertValueError('foo', action='baz')
   4122         self.assertValueError('--foo', action=('store', 'append'))
   4123         parser = argparse.ArgumentParser()
   4124         try:
   4125             parser.add_argument("--foo", action="store-true")
   4126         except ValueError:
   4127             e = sys.exc_info()[1]
   4128             expected = 'unknown action'
   4129             msg = 'expected %r, found %r' % (expected, e)
   4130             self.assertTrue(expected in str(e), msg)
   4131 
   4132     def test_multiple_dest(self):
   4133         parser = argparse.ArgumentParser()
   4134         parser.add_argument(dest='foo')
   4135         try:
   4136             parser.add_argument('bar', dest='baz')
   4137         except ValueError:
   4138             e = sys.exc_info()[1]
   4139             expected = 'dest supplied twice for positional argument'
   4140             msg = 'expected %r, found %r' % (expected, e)
   4141             self.assertTrue(expected in str(e), msg)
   4142 
   4143     def test_no_argument_actions(self):
   4144         for action in ['store_const', 'store_true', 'store_false',
   4145                        'append_const', 'count']:
   4146             for attrs in [dict(type=int), dict(nargs='+'),
   4147                           dict(choices='ab')]:
   4148                 self.assertTypeError('-x', action=action, **attrs)
   4149 
   4150     def test_no_argument_no_const_actions(self):
   4151         # options with zero arguments
   4152         for action in ['store_true', 'store_false', 'count']:
   4153 
   4154             # const is always disallowed
   4155             self.assertTypeError('-x', const='foo', action=action)
   4156 
   4157             # nargs is always disallowed
   4158             self.assertTypeError('-x', nargs='*', action=action)
   4159 
   4160     def test_more_than_one_argument_actions(self):
   4161         for action in ['store', 'append']:
   4162 
   4163             # nargs=0 is disallowed
   4164             self.assertValueError('-x', nargs=0, action=action)
   4165             self.assertValueError('spam', nargs=0, action=action)
   4166 
   4167             # const is disallowed with non-optional arguments
   4168             for nargs in [1, '*', '+']:
   4169                 self.assertValueError('-x', const='foo',
   4170                                       nargs=nargs, action=action)
   4171                 self.assertValueError('spam', const='foo',
   4172                                       nargs=nargs, action=action)
   4173 
   4174     def test_required_const_actions(self):
   4175         for action in ['store_const', 'append_const']:
   4176 
   4177             # nargs is always disallowed
   4178             self.assertTypeError('-x', nargs='+', action=action)
   4179 
   4180     def test_parsers_action_missing_params(self):
   4181         self.assertTypeError('command', action='parsers')
   4182         self.assertTypeError('command', action='parsers', prog='PROG')
   4183         self.assertTypeError('command', action='parsers',
   4184                              parser_class=argparse.ArgumentParser)
   4185 
   4186     def test_required_positional(self):
   4187         self.assertTypeError('foo', required=True)
   4188 
   4189     def test_user_defined_action(self):
   4190 
   4191         class Success(Exception):
   4192             pass
   4193 
   4194         class Action(object):
   4195 
   4196             def __init__(self,
   4197                          option_strings,
   4198                          dest,
   4199                          const,
   4200                          default,
   4201                          required=False):
   4202                 if dest == 'spam':
   4203                     if const is Success:
   4204                         if default is Success:
   4205                             raise Success()
   4206 
   4207             def __call__(self, *args, **kwargs):
   4208                 pass
   4209 
   4210         parser = argparse.ArgumentParser()
   4211         self.assertRaises(Success, parser.add_argument, '--spam',
   4212                           action=Action, default=Success, const=Success)
   4213         self.assertRaises(Success, parser.add_argument, 'spam',
   4214                           action=Action, default=Success, const=Success)
   4215 
   4216 # ================================
   4217 # Actions returned by add_argument
   4218 # ================================
   4219 
   4220 class TestActionsReturned(TestCase):
   4221 
   4222     def test_dest(self):
   4223         parser = argparse.ArgumentParser()
   4224         action = parser.add_argument('--foo')
   4225         self.assertEqual(action.dest, 'foo')
   4226         action = parser.add_argument('-b', '--bar')
   4227         self.assertEqual(action.dest, 'bar')
   4228         action = parser.add_argument('-x', '-y')
   4229         self.assertEqual(action.dest, 'x')
   4230 
   4231     def test_misc(self):
   4232         parser = argparse.ArgumentParser()
   4233         action = parser.add_argument('--foo', nargs='?', const=42,
   4234                                      default=84, type=int, choices=[1, 2],
   4235                                      help='FOO', metavar='BAR', dest='baz')
   4236         self.assertEqual(action.nargs, '?')
   4237         self.assertEqual(action.const, 42)
   4238         self.assertEqual(action.default, 84)
   4239         self.assertEqual(action.type, int)
   4240         self.assertEqual(action.choices, [1, 2])
   4241         self.assertEqual(action.help, 'FOO')
   4242         self.assertEqual(action.metavar, 'BAR')
   4243         self.assertEqual(action.dest, 'baz')
   4244 
   4245 
   4246 # ================================
   4247 # Argument conflict handling tests
   4248 # ================================
   4249 
   4250 class TestConflictHandling(TestCase):
   4251 
   4252     def test_bad_type(self):
   4253         self.assertRaises(ValueError, argparse.ArgumentParser,
   4254                           conflict_handler='foo')
   4255 
   4256     def test_conflict_error(self):
   4257         parser = argparse.ArgumentParser()
   4258         parser.add_argument('-x')
   4259         self.assertRaises(argparse.ArgumentError,
   4260                           parser.add_argument, '-x')
   4261         parser.add_argument('--spam')
   4262         self.assertRaises(argparse.ArgumentError,
   4263                           parser.add_argument, '--spam')
   4264 
   4265     def test_resolve_error(self):
   4266         get_parser = argparse.ArgumentParser
   4267         parser = get_parser(prog='PROG', conflict_handler='resolve')
   4268 
   4269         parser.add_argument('-x', help='OLD X')
   4270         parser.add_argument('-x', help='NEW X')
   4271         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4272             usage: PROG [-h] [-x X]
   4273 
   4274             optional arguments:
   4275               -h, --help  show this help message and exit
   4276               -x X        NEW X
   4277             '''))
   4278 
   4279         parser.add_argument('--spam', metavar='OLD_SPAM')
   4280         parser.add_argument('--spam', metavar='NEW_SPAM')
   4281         self.assertEqual(parser.format_help(), textwrap.dedent('''\
   4282             usage: PROG [-h] [-x X] [--spam NEW_SPAM]
   4283 
   4284             optional arguments:
   4285               -h, --help       show this help message and exit
   4286               -x X             NEW X
   4287               --spam NEW_SPAM
   4288             '''))
   4289 
   4290 
   4291 # =============================
   4292 # Help and Version option tests
   4293 # =============================
   4294 
   4295 class TestOptionalsHelpVersionActions(TestCase):
   4296     """Test the help and version actions"""
   4297 
   4298     def _get_error(self, func, *args, **kwargs):
   4299         try:
   4300             func(*args, **kwargs)
   4301         except ArgumentParserError:
   4302             return sys.exc_info()[1]
   4303         else:
   4304             self.assertRaises(ArgumentParserError, func, *args, **kwargs)
   4305 
   4306     def assertPrintHelpExit(self, parser, args_str):
   4307         self.assertEqual(
   4308             parser.format_help(),
   4309             self._get_error(parser.parse_args, args_str.split()).stdout)
   4310 
   4311     def assertPrintVersionExit(self, parser, args_str):
   4312         self.assertEqual(
   4313             parser.format_version(),
   4314             self._get_error(parser.parse_args, args_str.split()).stderr)
   4315 
   4316     def assertArgumentParserError(self, parser, *args):
   4317         self.assertRaises(ArgumentParserError, parser.parse_args, args)
   4318 
   4319     def test_version(self):
   4320         parser = ErrorRaisingArgumentParser(version='1.0')
   4321         self.assertPrintHelpExit(parser, '-h')
   4322         self.assertPrintHelpExit(parser, '--help')
   4323         self.assertPrintVersionExit(parser, '-v')
   4324         self.assertPrintVersionExit(parser, '--version')
   4325 
   4326     def test_version_format(self):
   4327         parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
   4328         msg = self._get_error(parser.parse_args, ['-v']).stderr
   4329         self.assertEqual('PPP 3.5\n', msg)
   4330 
   4331     def test_version_no_help(self):
   4332         parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
   4333         self.assertArgumentParserError(parser, '-h')
   4334         self.assertArgumentParserError(parser, '--help')
   4335         self.assertPrintVersionExit(parser, '-v')
   4336         self.assertPrintVersionExit(parser, '--version')
   4337 
   4338     def test_version_action(self):
   4339         parser = ErrorRaisingArgumentParser(prog='XXX')
   4340         parser.add_argument('-V', action='version', version='%(prog)s 3.7')
   4341         msg = self._get_error(parser.parse_args, ['-V']).stderr
   4342         self.assertEqual('XXX 3.7\n', msg)
   4343 
   4344     def test_no_help(self):
   4345         parser = ErrorRaisingArgumentParser(add_help=False)
   4346         self.assertArgumentParserError(parser, '-h')
   4347         self.assertArgumentParserError(parser, '--help')
   4348         self.assertArgumentParserError(parser, '-v')
   4349         self.assertArgumentParserError(parser, '--version')
   4350 
   4351     def test_alternate_help_version(self):
   4352         parser = ErrorRaisingArgumentParser()
   4353         parser.add_argument('-x', action='help')
   4354         parser.add_argument('-y', action='version')
   4355         self.assertPrintHelpExit(parser, '-x')
   4356         self.assertPrintVersionExit(parser, '-y')
   4357         self.assertArgumentParserError(parser, '-v')
   4358         self.assertArgumentParserError(parser, '--version')
   4359 
   4360     def test_help_version_extra_arguments(self):
   4361         parser = ErrorRaisingArgumentParser(version='1.0')
   4362         parser.add_argument('-x', action='store_true')
   4363         parser.add_argument('y')
   4364 
   4365         # try all combinations of valid prefixes and suffixes
   4366         valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
   4367         valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
   4368         for prefix in valid_prefixes:
   4369             for suffix in valid_suffixes:
   4370                 format = '%s %%s %s' % (prefix, suffix)
   4371             self.assertPrintHelpExit(parser, format % '-h')
   4372             self.assertPrintHelpExit(parser, format % '--help')
   4373             self.assertPrintVersionExit(parser, format % '-v')
   4374             self.assertPrintVersionExit(parser, format % '--version')
   4375 
   4376 
   4377 # ======================
   4378 # str() and repr() tests
   4379 # ======================
   4380 
   4381 class TestStrings(TestCase):
   4382     """Test str()  and repr() on Optionals and Positionals"""
   4383 
   4384     def assertStringEqual(self, obj, result_string):
   4385         for func in [str, repr]:
   4386             self.assertEqual(func(obj), result_string)
   4387 
   4388     def test_optional(self):
   4389         option = argparse.Action(
   4390             option_strings=['--foo', '-a', '-b'],
   4391             dest='b',
   4392             type='int',
   4393             nargs='+',
   4394             default=42,
   4395             choices=[1, 2, 3],
   4396             help='HELP',
   4397             metavar='METAVAR')
   4398         string = (
   4399             "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
   4400             "nargs='+', const=None, default=42, type='int', "
   4401             "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
   4402         self.assertStringEqual(option, string)
   4403 
   4404     def test_argument(self):
   4405         argument = argparse.Action(
   4406             option_strings=[],
   4407             dest='x',
   4408             type=float,
   4409             nargs='?',
   4410             default=2.5,
   4411             choices=[0.5, 1.5, 2.5],
   4412             help='H HH H',
   4413             metavar='MV MV MV')
   4414         string = (
   4415             "Action(option_strings=[], dest='x', nargs='?', "
   4416             "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
   4417             "help='H HH H', metavar='MV MV MV')" % float)
   4418         self.assertStringEqual(argument, string)
   4419 
   4420     def test_namespace(self):
   4421         ns = argparse.Namespace(foo=42, bar='spam')
   4422         string = "Namespace(bar='spam', foo=42)"
   4423         self.assertStringEqual(ns, string)
   4424 
   4425     def test_parser(self):
   4426         parser = argparse.ArgumentParser(prog='PROG')
   4427         string = (
   4428             "ArgumentParser(prog='PROG', usage=None, description=None, "
   4429             "version=None, formatter_class=%r, conflict_handler='error', "
   4430             "add_help=True)" % argparse.HelpFormatter)
   4431         self.assertStringEqual(parser, string)
   4432 
   4433 # ===============
   4434 # Namespace tests
   4435 # ===============
   4436 
   4437 class TestNamespace(TestCase):
   4438 
   4439     def test_constructor(self):
   4440         ns = argparse.Namespace()
   4441         self.assertRaises(AttributeError, getattr, ns, 'x')
   4442 
   4443         ns = argparse.Namespace(a=42, b='spam')
   4444         self.assertEqual(ns.a, 42)
   4445         self.assertEqual(ns.b, 'spam')
   4446 
   4447     def test_equality(self):
   4448         ns1 = argparse.Namespace(a=1, b=2)
   4449         ns2 = argparse.Namespace(b=2, a=1)
   4450         ns3 = argparse.Namespace(a=1)
   4451         ns4 = argparse.Namespace(b=2)
   4452 
   4453         self.assertEqual(ns1, ns2)
   4454         self.assertNotEqual(ns1, ns3)
   4455         self.assertNotEqual(ns1, ns4)
   4456         self.assertNotEqual(ns2, ns3)
   4457         self.assertNotEqual(ns2, ns4)
   4458         self.assertTrue(ns1 != ns3)
   4459         self.assertTrue(ns1 != ns4)
   4460         self.assertTrue(ns2 != ns3)
   4461         self.assertTrue(ns2 != ns4)
   4462 
   4463     def test_equality_returns_notimplemeted(self):
   4464         # See issue 21481
   4465         ns = argparse.Namespace(a=1, b=2)
   4466         self.assertIs(ns.__eq__(None), NotImplemented)
   4467         self.assertIs(ns.__ne__(None), NotImplemented)
   4468 
   4469 
   4470 # ===================
   4471 # File encoding tests
   4472 # ===================
   4473 
   4474 class TestEncoding(TestCase):
   4475 
   4476     def _test_module_encoding(self, path):
   4477         path, _ = os.path.splitext(path)
   4478         path += ".py"
   4479         with codecs.open(path, 'r', 'utf8') as f:
   4480             f.read()
   4481 
   4482     def test_argparse_module_encoding(self):
   4483         self._test_module_encoding(argparse.__file__)
   4484 
   4485     def test_test_argparse_module_encoding(self):
   4486         self._test_module_encoding(__file__)
   4487 
   4488 # ===================
   4489 # ArgumentError tests
   4490 # ===================
   4491 
   4492 class TestArgumentError(TestCase):
   4493 
   4494     def test_argument_error(self):
   4495         msg = "my error here"
   4496         error = argparse.ArgumentError(None, msg)
   4497         self.assertEqual(str(error), msg)
   4498 
   4499 # =======================
   4500 # ArgumentTypeError tests
   4501 # =======================
   4502 
   4503 class TestArgumentTypeError(TestCase):
   4504 
   4505     def test_argument_type_error(self):
   4506 
   4507         def spam(string):
   4508             raise argparse.ArgumentTypeError('spam!')
   4509 
   4510         parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
   4511         parser.add_argument('x', type=spam)
   4512         try:
   4513             parser.parse_args(['XXX'])
   4514         except ArgumentParserError:
   4515             expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
   4516             msg = sys.exc_info()[1].stderr
   4517             self.assertEqual(expected, msg)
   4518         else:
   4519             self.fail()
   4520 
   4521 # ================================================
   4522 # Check that the type function is called only once
   4523 # ================================================
   4524 
   4525 class TestTypeFunctionCallOnlyOnce(TestCase):
   4526 
   4527     def test_type_function_call_only_once(self):
   4528         def spam(string_to_convert):
   4529             self.assertEqual(string_to_convert, 'spam!')
   4530             return 'foo_converted'
   4531 
   4532         parser = argparse.ArgumentParser()
   4533         parser.add_argument('--foo', type=spam, default='bar')
   4534         args = parser.parse_args('--foo spam!'.split())
   4535         self.assertEqual(NS(foo='foo_converted'), args)
   4536 
   4537 # ==================================================================
   4538 # Check semantics regarding the default argument and type conversion
   4539 # ==================================================================
   4540 
   4541 class TestTypeFunctionCalledOnDefault(TestCase):
   4542 
   4543     def test_type_function_call_with_non_string_default(self):
   4544         def spam(int_to_convert):
   4545             self.assertEqual(int_to_convert, 0)
   4546             return 'foo_converted'
   4547 
   4548         parser = argparse.ArgumentParser()
   4549         parser.add_argument('--foo', type=spam, default=0)
   4550         args = parser.parse_args([])
   4551         # foo should *not* be converted because its default is not a string.
   4552         self.assertEqual(NS(foo=0), args)
   4553 
   4554     def test_type_function_call_with_string_default(self):
   4555         def spam(int_to_convert):
   4556             return 'foo_converted'
   4557 
   4558         parser = argparse.ArgumentParser()
   4559         parser.add_argument('--foo', type=spam, default='0')
   4560         args = parser.parse_args([])
   4561         # foo is converted because its default is a string.
   4562         self.assertEqual(NS(foo='foo_converted'), args)
   4563 
   4564     def test_no_double_type_conversion_of_default(self):
   4565         def extend(str_to_convert):
   4566             return str_to_convert + '*'
   4567 
   4568         parser = argparse.ArgumentParser()
   4569         parser.add_argument('--test', type=extend, default='*')
   4570         args = parser.parse_args([])
   4571         # The test argument will be two stars, one coming from the default
   4572         # value and one coming from the type conversion being called exactly
   4573         # once.
   4574         self.assertEqual(NS(test='**'), args)
   4575 
   4576     def test_issue_15906(self):
   4577         # Issue #15906: When action='append', type=str, default=[] are
   4578         # providing, the dest value was the string representation "[]" when it
   4579         # should have been an empty list.
   4580         parser = argparse.ArgumentParser()
   4581         parser.add_argument('--test', dest='test', type=str,
   4582                             default=[], action='append')
   4583         args = parser.parse_args([])
   4584         self.assertEqual(args.test, [])
   4585 
   4586 # ======================
   4587 # parse_known_args tests
   4588 # ======================
   4589 
   4590 class TestParseKnownArgs(TestCase):
   4591 
   4592     def test_arguments_tuple(self):
   4593         parser = argparse.ArgumentParser()
   4594         parser.parse_args(())
   4595 
   4596     def test_arguments_list(self):
   4597         parser = argparse.ArgumentParser()
   4598         parser.parse_args([])
   4599 
   4600     def test_arguments_tuple_positional(self):
   4601         parser = argparse.ArgumentParser()
   4602         parser.add_argument('x')
   4603         parser.parse_args(('x',))
   4604 
   4605     def test_arguments_list_positional(self):
   4606         parser = argparse.ArgumentParser()
   4607         parser.add_argument('x')
   4608         parser.parse_args(['x'])
   4609 
   4610     def test_optionals(self):
   4611         parser = argparse.ArgumentParser()
   4612         parser.add_argument('--foo')
   4613         args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
   4614         self.assertEqual(NS(foo='F'), args)
   4615         self.assertEqual(['--bar', '--baz'], extras)
   4616 
   4617     def test_mixed(self):
   4618         parser = argparse.ArgumentParser()
   4619         parser.add_argument('-v', nargs='?', const=1, type=int)
   4620         parser.add_argument('--spam', action='store_false')
   4621         parser.add_argument('badger')
   4622 
   4623         argv = ["B", "C", "--foo", "-v", "3", "4"]
   4624         args, extras = parser.parse_known_args(argv)
   4625         self.assertEqual(NS(v=3, spam=True, badger="B"), args)
   4626         self.assertEqual(["C", "--foo", "4"], extras)
   4627 
   4628 # ==========================
   4629 # add_argument metavar tests
   4630 # ==========================
   4631 
   4632 class TestAddArgumentMetavar(TestCase):
   4633 
   4634     EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
   4635 
   4636     def do_test_no_exception(self, nargs, metavar):
   4637         parser = argparse.ArgumentParser()
   4638         parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4639 
   4640     def do_test_exception(self, nargs, metavar):
   4641         parser = argparse.ArgumentParser()
   4642         with self.assertRaises(ValueError) as cm:
   4643             parser.add_argument("--foo", nargs=nargs, metavar=metavar)
   4644         self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
   4645 
   4646     # Unit tests for different values of metavar when nargs=None
   4647 
   4648     def test_nargs_None_metavar_string(self):
   4649         self.do_test_no_exception(nargs=None, metavar="1")
   4650 
   4651     def test_nargs_None_metavar_length0(self):
   4652         self.do_test_exception(nargs=None, metavar=tuple())
   4653 
   4654     def test_nargs_None_metavar_length1(self):
   4655         self.do_test_no_exception(nargs=None, metavar=("1",))
   4656 
   4657     def test_nargs_None_metavar_length2(self):
   4658         self.do_test_exception(nargs=None, metavar=("1", "2"))
   4659 
   4660     def test_nargs_None_metavar_length3(self):
   4661         self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
   4662 
   4663     # Unit tests for different values of metavar when nargs=?
   4664 
   4665     def test_nargs_optional_metavar_string(self):
   4666         self.do_test_no_exception(nargs="?", metavar="1")
   4667 
   4668     def test_nargs_optional_metavar_length0(self):
   4669         self.do_test_exception(nargs="?", metavar=tuple())
   4670 
   4671     def test_nargs_optional_metavar_length1(self):
   4672         self.do_test_no_exception(nargs="?", metavar=("1",))
   4673 
   4674     def test_nargs_optional_metavar_length2(self):
   4675         self.do_test_exception(nargs="?", metavar=("1", "2"))
   4676 
   4677     def test_nargs_optional_metavar_length3(self):
   4678         self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
   4679 
   4680     # Unit tests for different values of metavar when nargs=*
   4681 
   4682     def test_nargs_zeroormore_metavar_string(self):
   4683         self.do_test_no_exception(nargs="*", metavar="1")
   4684 
   4685     def test_nargs_zeroormore_metavar_length0(self):
   4686         self.do_test_exception(nargs="*", metavar=tuple())
   4687 
   4688     def test_nargs_zeroormore_metavar_length1(self):
   4689         self.do_test_exception(nargs="*", metavar=("1",))
   4690 
   4691     def test_nargs_zeroormore_metavar_length2(self):
   4692         self.do_test_no_exception(nargs="*", metavar=("1", "2"))
   4693 
   4694     def test_nargs_zeroormore_metavar_length3(self):
   4695         self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
   4696 
   4697     # Unit tests for different values of metavar when nargs=+
   4698 
   4699     def test_nargs_oneormore_metavar_string(self):
   4700         self.do_test_no_exception(nargs="+", metavar="1")
   4701 
   4702     def test_nargs_oneormore_metavar_length0(self):
   4703         self.do_test_exception(nargs="+", metavar=tuple())
   4704 
   4705     def test_nargs_oneormore_metavar_length1(self):
   4706         self.do_test_exception(nargs="+", metavar=("1",))
   4707 
   4708     def test_nargs_oneormore_metavar_length2(self):
   4709         self.do_test_no_exception(nargs="+", metavar=("1", "2"))
   4710 
   4711     def test_nargs_oneormore_metavar_length3(self):
   4712         self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
   4713 
   4714     # Unit tests for different values of metavar when nargs=...
   4715 
   4716     def test_nargs_remainder_metavar_string(self):
   4717         self.do_test_no_exception(nargs="...", metavar="1")
   4718 
   4719     def test_nargs_remainder_metavar_length0(self):
   4720         self.do_test_no_exception(nargs="...", metavar=tuple())
   4721 
   4722     def test_nargs_remainder_metavar_length1(self):
   4723         self.do_test_no_exception(nargs="...", metavar=("1",))
   4724 
   4725     def test_nargs_remainder_metavar_length2(self):
   4726         self.do_test_no_exception(nargs="...", metavar=("1", "2"))
   4727 
   4728     def test_nargs_remainder_metavar_length3(self):
   4729         self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
   4730 
   4731     # Unit tests for different values of metavar when nargs=A...
   4732 
   4733     def test_nargs_parser_metavar_string(self):
   4734         self.do_test_no_exception(nargs="A...", metavar="1")
   4735 
   4736     def test_nargs_parser_metavar_length0(self):
   4737         self.do_test_exception(nargs="A...", metavar=tuple())
   4738 
   4739     def test_nargs_parser_metavar_length1(self):
   4740         self.do_test_no_exception(nargs="A...", metavar=("1",))
   4741 
   4742     def test_nargs_parser_metavar_length2(self):
   4743         self.do_test_exception(nargs="A...", metavar=("1", "2"))
   4744 
   4745     def test_nargs_parser_metavar_length3(self):
   4746         self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
   4747 
   4748     # Unit tests for different values of metavar when nargs=1
   4749 
   4750     def test_nargs_1_metavar_string(self):
   4751         self.do_test_no_exception(nargs=1, metavar="1")
   4752 
   4753     def test_nargs_1_metavar_length0(self):
   4754         self.do_test_exception(nargs=1, metavar=tuple())
   4755 
   4756     def test_nargs_1_metavar_length1(self):
   4757         self.do_test_no_exception(nargs=1, metavar=("1",))
   4758 
   4759     def test_nargs_1_metavar_length2(self):
   4760         self.do_test_exception(nargs=1, metavar=("1", "2"))
   4761 
   4762     def test_nargs_1_metavar_length3(self):
   4763         self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
   4764 
   4765     # Unit tests for different values of metavar when nargs=2
   4766 
   4767     def test_nargs_2_metavar_string(self):
   4768         self.do_test_no_exception(nargs=2, metavar="1")
   4769 
   4770     def test_nargs_2_metavar_length0(self):
   4771         self.do_test_exception(nargs=2, metavar=tuple())
   4772 
   4773     def test_nargs_2_metavar_length1(self):
   4774         self.do_test_exception(nargs=2, metavar=("1",))
   4775 
   4776     def test_nargs_2_metavar_length2(self):
   4777         self.do_test_no_exception(nargs=2, metavar=("1", "2"))
   4778 
   4779     def test_nargs_2_metavar_length3(self):
   4780         self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
   4781 
   4782     # Unit tests for different values of metavar when nargs=3
   4783 
   4784     def test_nargs_3_metavar_string(self):
   4785         self.do_test_no_exception(nargs=3, metavar="1")
   4786 
   4787     def test_nargs_3_metavar_length0(self):
   4788         self.do_test_exception(nargs=3, metavar=tuple())
   4789 
   4790     def test_nargs_3_metavar_length1(self):
   4791         self.do_test_exception(nargs=3, metavar=("1",))
   4792 
   4793     def test_nargs_3_metavar_length2(self):
   4794         self.do_test_exception(nargs=3, metavar=("1", "2"))
   4795 
   4796     def test_nargs_3_metavar_length3(self):
   4797         self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
   4798 
   4799 # ============================
   4800 # from argparse import * tests
   4801 # ============================
   4802 
   4803 class TestImportStar(TestCase):
   4804 
   4805     def test(self):
   4806         for name in argparse.__all__:
   4807             self.assertTrue(hasattr(argparse, name))
   4808 
   4809     def test_all_exports_everything_but_modules(self):
   4810         items = [
   4811             name
   4812             for name, value in vars(argparse).items()
   4813             if not name.startswith("_")
   4814             if not inspect.ismodule(value)
   4815         ]
   4816         self.assertEqual(sorted(items), sorted(argparse.__all__))
   4817 
   4818 
   4819 class TestWrappingMetavar(TestCase):
   4820 
   4821     def setUp(self):
   4822         self.parser = ErrorRaisingArgumentParser(
   4823             'this_is_spammy_prog_with_a_long_name_sorry_about_the_name'
   4824         )
   4825         # this metavar was triggering library assertion errors due to usage
   4826         # message formatting incorrectly splitting on the ] chars within
   4827         metavar = '<http[s]://example:1234>'
   4828         self.parser.add_argument('--proxy', metavar=metavar)
   4829 
   4830     def test_help_with_metavar(self):
   4831         help_text = self.parser.format_help()
   4832         self.assertEqual(help_text, textwrap.dedent('''\
   4833             usage: this_is_spammy_prog_with_a_long_name_sorry_about_the_name
   4834                    [-h] [--proxy <http[s]://example:1234>]
   4835 
   4836             optional arguments:
   4837               -h, --help            show this help message and exit
   4838               --proxy <http[s]://example:1234>
   4839             '''))
   4840 
   4841 
   4842 def test_main():
   4843     # silence warnings about version argument - these are expected
   4844     with test_support.check_warnings(
   4845             ('The "version" argument to ArgumentParser is deprecated.',
   4846              DeprecationWarning),
   4847             ('The (format|print)_version method is deprecated',
   4848              DeprecationWarning)):
   4849         test_support.run_unittest(__name__)
   4850     # Remove global references to avoid looking like we have refleaks.
   4851     RFile.seen = {}
   4852     WFile.seen = set()
   4853 
   4854 
   4855 
   4856 if __name__ == '__main__':
   4857     test_main()
   4858