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