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