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