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