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