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