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