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