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