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