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