blob: 777a4af13f9400f163b3de41488360bd469f2b2b [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
1787 def test_dest(self):
1788 parser = ErrorRaisingArgumentParser()
1789 parser.add_argument('--foo', action='store_true')
1790 subparsers = parser.add_subparsers(dest='bar')
1791 parser1 = subparsers.add_parser('1')
1792 parser1.add_argument('baz')
1793 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1794 parser.parse_args('1 2'.split()))
1795
1796 def test_help(self):
1797 self.assertEqual(self.parser.format_usage(),
1798 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1799 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
1800 usage: PROG [-h] [--foo] bar {1,2} ...
1801
1802 main description
1803
1804 positional arguments:
1805 bar bar help
1806 {1,2} command help
1807
1808 optional arguments:
1809 -h, --help show this help message and exit
1810 --foo foo help
1811 '''))
1812
R. David Murray1cbf78e2010-08-03 18:14:01 +00001813 def test_help_extra_prefix_chars(self):
1814 # Make sure - is still used for help if it is a non-first prefix char
1815 parser = self._get_parser(prefix_chars='+:-')
1816 self.assertEqual(parser.format_usage(),
1817 'usage: PROG [-h] [++foo] bar {1,2} ...\n')
1818 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1819 usage: PROG [-h] [++foo] bar {1,2} ...
1820
1821 main description
1822
1823 positional arguments:
1824 bar bar help
1825 {1,2} command help
1826
1827 optional arguments:
1828 -h, --help show this help message and exit
1829 ++foo foo help
1830 '''))
1831
1832
1833 def test_help_alternate_prefix_chars(self):
1834 parser = self._get_parser(prefix_chars='+:/')
1835 self.assertEqual(parser.format_usage(),
1836 'usage: PROG [+h] [++foo] bar {1,2} ...\n')
1837 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1838 usage: PROG [+h] [++foo] bar {1,2} ...
1839
1840 main description
1841
1842 positional arguments:
1843 bar bar help
1844 {1,2} command help
1845
1846 optional arguments:
1847 +h, ++help show this help message and exit
1848 ++foo foo help
1849 '''))
1850
Benjamin Petersona39e9662010-03-02 22:05:59 +00001851 def test_parser_command_help(self):
1852 self.assertEqual(self.command_help_parser.format_usage(),
1853 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1854 self.assertEqual(self.command_help_parser.format_help(),
1855 textwrap.dedent('''\
1856 usage: PROG [-h] [--foo] bar {1,2} ...
1857
1858 main description
1859
1860 positional arguments:
1861 bar bar help
1862 {1,2} command help
1863 1 1 help
1864 2 2 help
1865
1866 optional arguments:
1867 -h, --help show this help message and exit
1868 --foo foo help
1869 '''))
1870
1871 def test_subparser_title_help(self):
1872 parser = ErrorRaisingArgumentParser(prog='PROG',
1873 description='main description')
1874 parser.add_argument('--foo', action='store_true', help='foo help')
1875 parser.add_argument('bar', help='bar help')
1876 subparsers = parser.add_subparsers(title='subcommands',
1877 description='command help',
1878 help='additional text')
1879 parser1 = subparsers.add_parser('1')
1880 parser2 = subparsers.add_parser('2')
1881 self.assertEqual(parser.format_usage(),
1882 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1883 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1884 usage: PROG [-h] [--foo] bar {1,2} ...
1885
1886 main description
1887
1888 positional arguments:
1889 bar bar help
1890
1891 optional arguments:
1892 -h, --help show this help message and exit
1893 --foo foo help
1894
1895 subcommands:
1896 command help
1897
1898 {1,2} additional text
1899 '''))
1900
1901 def _test_subparser_help(self, args_str, expected_help):
1902 try:
1903 self.parser.parse_args(args_str.split())
1904 except ArgumentParserError:
1905 err = sys.exc_info()[1]
1906 if err.stdout != expected_help:
1907 print(repr(expected_help))
1908 print(repr(err.stdout))
1909 self.assertEqual(err.stdout, expected_help)
1910
1911 def test_subparser1_help(self):
1912 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
1913 usage: PROG bar 1 [-h] [-w W] {a,b,c}
1914
1915 1 description
1916
1917 positional arguments:
1918 {a,b,c} x help
1919
1920 optional arguments:
1921 -h, --help show this help message and exit
1922 -w W w help
1923 '''))
1924
1925 def test_subparser2_help(self):
1926 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
1927 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
1928
1929 2 description
1930
1931 positional arguments:
1932 z z help
1933
1934 optional arguments:
1935 -h, --help show this help message and exit
1936 -y {1,2,3} y help
1937 '''))
1938
1939# ============
1940# Groups tests
1941# ============
1942
1943class TestPositionalsGroups(TestCase):
1944 """Tests that order of group positionals matches construction order"""
1945
1946 def test_nongroup_first(self):
1947 parser = ErrorRaisingArgumentParser()
1948 parser.add_argument('foo')
1949 group = parser.add_argument_group('g')
1950 group.add_argument('bar')
1951 parser.add_argument('baz')
1952 expected = NS(foo='1', bar='2', baz='3')
1953 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001954 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001955
1956 def test_group_first(self):
1957 parser = ErrorRaisingArgumentParser()
1958 group = parser.add_argument_group('xxx')
1959 group.add_argument('foo')
1960 parser.add_argument('bar')
1961 parser.add_argument('baz')
1962 expected = NS(foo='1', bar='2', baz='3')
1963 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001964 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001965
1966 def test_interleaved_groups(self):
1967 parser = ErrorRaisingArgumentParser()
1968 group = parser.add_argument_group('xxx')
1969 parser.add_argument('foo')
1970 group.add_argument('bar')
1971 parser.add_argument('baz')
1972 group = parser.add_argument_group('yyy')
1973 group.add_argument('frell')
1974 expected = NS(foo='1', bar='2', baz='3', frell='4')
1975 result = parser.parse_args('1 2 3 4'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001976 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001977
1978# ===================
1979# Parent parser tests
1980# ===================
1981
1982class TestParentParsers(TestCase):
1983 """Tests that parsers can be created with parent parsers"""
1984
1985 def assertArgumentParserError(self, *args, **kwargs):
1986 self.assertRaises(ArgumentParserError, *args, **kwargs)
1987
1988 def setUp(self):
Steven Bethardabacccc2010-11-01 14:09:21 +00001989 super(TestParentParsers, self).setUp()
Benjamin Petersona39e9662010-03-02 22:05:59 +00001990 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
1991 self.wxyz_parent.add_argument('--w')
1992 x_group = self.wxyz_parent.add_argument_group('x')
1993 x_group.add_argument('-y')
1994 self.wxyz_parent.add_argument('z')
1995
1996 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
1997 self.abcd_parent.add_argument('a')
1998 self.abcd_parent.add_argument('-b')
1999 c_group = self.abcd_parent.add_argument_group('c')
2000 c_group.add_argument('--d')
2001
2002 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2003 self.w_parent.add_argument('--w')
2004
2005 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2006 self.z_parent.add_argument('z')
2007
2008 # parents with mutually exclusive groups
2009 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2010 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2011 group.add_argument('-a', action='store_true')
2012 group.add_argument('-b', action='store_true')
2013
Benjamin Peterson036fae32010-03-02 22:20:10 +00002014 self.main_program = os.path.basename(sys.argv[0])
2015
Benjamin Petersona39e9662010-03-02 22:05:59 +00002016 def test_single_parent(self):
2017 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2018 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2019 NS(w='3', y='1', z='2'))
2020
2021 def test_single_parent_mutex(self):
2022 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2023 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2024 self._test_mutex_ab(parser.parse_args)
2025
2026 def test_single_granparent_mutex(self):
2027 parents = [self.ab_mutex_parent]
2028 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2029 parser = ErrorRaisingArgumentParser(parents=[parser])
2030 self._test_mutex_ab(parser.parse_args)
2031
2032 def _test_mutex_ab(self, parse_args):
2033 self.assertEqual(parse_args([]), NS(a=False, b=False))
2034 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2035 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2036 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2037 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2038 self.assertArgumentParserError(parse_args, ['-c'])
2039 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2040 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2041
2042 def test_multiple_parents(self):
2043 parents = [self.abcd_parent, self.wxyz_parent]
2044 parser = ErrorRaisingArgumentParser(parents=parents)
2045 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2046 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2047
2048 def test_multiple_parents_mutex(self):
2049 parents = [self.ab_mutex_parent, self.wxyz_parent]
2050 parser = ErrorRaisingArgumentParser(parents=parents)
2051 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2052 NS(a=True, b=False, w='2', y=None, z='3'))
2053 self.assertArgumentParserError(
2054 parser.parse_args, '-a --w 2 3 -b'.split())
2055 self.assertArgumentParserError(
2056 parser.parse_args, '-a -b --w 2 3'.split())
2057
2058 def test_conflicting_parents(self):
2059 self.assertRaises(
2060 argparse.ArgumentError,
2061 argparse.ArgumentParser,
2062 parents=[self.w_parent, self.wxyz_parent])
2063
2064 def test_conflicting_parents_mutex(self):
2065 self.assertRaises(
2066 argparse.ArgumentError,
2067 argparse.ArgumentParser,
2068 parents=[self.abcd_parent, self.ab_mutex_parent])
2069
2070 def test_same_argument_name_parents(self):
2071 parents = [self.wxyz_parent, self.z_parent]
2072 parser = ErrorRaisingArgumentParser(parents=parents)
2073 self.assertEqual(parser.parse_args('1 2'.split()),
2074 NS(w=None, y=None, z='2'))
2075
2076 def test_subparser_parents(self):
2077 parser = ErrorRaisingArgumentParser()
2078 subparsers = parser.add_subparsers()
2079 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2080 abcde_parser.add_argument('e')
2081 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2082 NS(a='3', b='1', d='2', e='4'))
2083
2084 def test_subparser_parents_mutex(self):
2085 parser = ErrorRaisingArgumentParser()
2086 subparsers = parser.add_subparsers()
2087 parents = [self.ab_mutex_parent]
2088 abc_parser = subparsers.add_parser('foo', parents=parents)
2089 c_group = abc_parser.add_argument_group('c_group')
2090 c_group.add_argument('c')
2091 parents = [self.wxyz_parent, self.ab_mutex_parent]
2092 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2093 wxyzabe_parser.add_argument('e')
2094 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2095 NS(a=True, b=False, c='4'))
2096 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2097 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2098 self.assertArgumentParserError(
2099 parser.parse_args, 'foo -a -b 4'.split())
2100 self.assertArgumentParserError(
2101 parser.parse_args, 'bar -b -a 4'.split())
2102
2103 def test_parent_help(self):
2104 parents = [self.abcd_parent, self.wxyz_parent]
2105 parser = ErrorRaisingArgumentParser(parents=parents)
2106 parser_help = parser.format_help()
2107 self.assertEqual(parser_help, textwrap.dedent('''\
Benjamin Peterson036fae32010-03-02 22:20:10 +00002108 usage: {} [-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Petersona39e9662010-03-02 22:05:59 +00002109
2110 positional arguments:
2111 a
2112 z
2113
2114 optional arguments:
2115 -h, --help show this help message and exit
2116 -b B
2117 --w W
2118
2119 c:
2120 --d D
2121
2122 x:
2123 -y Y
Benjamin Peterson036fae32010-03-02 22:20:10 +00002124 '''.format(self.main_program)))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002125
2126 def test_groups_parents(self):
2127 parent = ErrorRaisingArgumentParser(add_help=False)
2128 g = parent.add_argument_group(title='g', description='gd')
2129 g.add_argument('-w')
2130 g.add_argument('-x')
2131 m = parent.add_mutually_exclusive_group()
2132 m.add_argument('-y')
2133 m.add_argument('-z')
2134 parser = ErrorRaisingArgumentParser(parents=[parent])
2135
2136 self.assertRaises(ArgumentParserError, parser.parse_args,
2137 ['-y', 'Y', '-z', 'Z'])
2138
2139 parser_help = parser.format_help()
2140 self.assertEqual(parser_help, textwrap.dedent('''\
Benjamin Peterson036fae32010-03-02 22:20:10 +00002141 usage: {} [-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Petersona39e9662010-03-02 22:05:59 +00002142
2143 optional arguments:
2144 -h, --help show this help message and exit
2145 -y Y
2146 -z Z
2147
2148 g:
2149 gd
2150
2151 -w W
2152 -x X
Benjamin Peterson036fae32010-03-02 22:20:10 +00002153 '''.format(self.main_program)))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002154
2155# ==============================
2156# Mutually exclusive group tests
2157# ==============================
2158
2159class TestMutuallyExclusiveGroupErrors(TestCase):
2160
2161 def test_invalid_add_argument_group(self):
2162 parser = ErrorRaisingArgumentParser()
2163 raises = self.assertRaises
2164 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2165
2166 def test_invalid_add_argument(self):
2167 parser = ErrorRaisingArgumentParser()
2168 group = parser.add_mutually_exclusive_group()
2169 add_argument = group.add_argument
2170 raises = self.assertRaises
2171 raises(ValueError, add_argument, '--foo', required=True)
2172 raises(ValueError, add_argument, 'bar')
2173 raises(ValueError, add_argument, 'bar', nargs='+')
2174 raises(ValueError, add_argument, 'bar', nargs=1)
2175 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2176
Steven Bethard68c36782010-11-01 16:30:24 +00002177 def test_help(self):
2178 parser = ErrorRaisingArgumentParser(prog='PROG')
2179 group1 = parser.add_mutually_exclusive_group()
2180 group1.add_argument('--foo', action='store_true')
2181 group1.add_argument('--bar', action='store_false')
2182 group2 = parser.add_mutually_exclusive_group()
2183 group2.add_argument('--soup', action='store_true')
2184 group2.add_argument('--nuts', action='store_false')
2185 expected = '''\
2186 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2187
2188 optional arguments:
2189 -h, --help show this help message and exit
2190 --foo
2191 --bar
2192 --soup
2193 --nuts
2194 '''
2195 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002196
2197class MEMixin(object):
2198
2199 def test_failures_when_not_required(self):
2200 parse_args = self.get_parser(required=False).parse_args
2201 error = ArgumentParserError
2202 for args_string in self.failures:
2203 self.assertRaises(error, parse_args, args_string.split())
2204
2205 def test_failures_when_required(self):
2206 parse_args = self.get_parser(required=True).parse_args
2207 error = ArgumentParserError
2208 for args_string in self.failures + ['']:
2209 self.assertRaises(error, parse_args, args_string.split())
2210
2211 def test_successes_when_not_required(self):
2212 parse_args = self.get_parser(required=False).parse_args
2213 successes = self.successes + self.successes_when_not_required
2214 for args_string, expected_ns in successes:
2215 actual_ns = parse_args(args_string.split())
2216 self.assertEqual(actual_ns, expected_ns)
2217
2218 def test_successes_when_required(self):
2219 parse_args = self.get_parser(required=True).parse_args
2220 for args_string, expected_ns in self.successes:
2221 actual_ns = parse_args(args_string.split())
2222 self.assertEqual(actual_ns, expected_ns)
2223
2224 def test_usage_when_not_required(self):
2225 format_usage = self.get_parser(required=False).format_usage
2226 expected_usage = self.usage_when_not_required
2227 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2228
2229 def test_usage_when_required(self):
2230 format_usage = self.get_parser(required=True).format_usage
2231 expected_usage = self.usage_when_required
2232 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2233
2234 def test_help_when_not_required(self):
2235 format_help = self.get_parser(required=False).format_help
2236 help = self.usage_when_not_required + self.help
2237 self.assertEqual(format_help(), textwrap.dedent(help))
2238
2239 def test_help_when_required(self):
2240 format_help = self.get_parser(required=True).format_help
2241 help = self.usage_when_required + self.help
2242 self.assertEqual(format_help(), textwrap.dedent(help))
2243
2244
2245class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2246
2247 def get_parser(self, required=None):
2248 parser = ErrorRaisingArgumentParser(prog='PROG')
2249 group = parser.add_mutually_exclusive_group(required=required)
2250 group.add_argument('--bar', help='bar help')
2251 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2252 return parser
2253
2254 failures = ['--bar X --baz Y', '--bar X --baz']
2255 successes = [
2256 ('--bar X', NS(bar='X', baz=None)),
2257 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2258 ('--baz Y', NS(bar=None, baz='Y')),
2259 ('--baz', NS(bar=None, baz='Z')),
2260 ]
2261 successes_when_not_required = [
2262 ('', NS(bar=None, baz=None)),
2263 ]
2264
2265 usage_when_not_required = '''\
2266 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2267 '''
2268 usage_when_required = '''\
2269 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2270 '''
2271 help = '''\
2272
2273 optional arguments:
2274 -h, --help show this help message and exit
2275 --bar BAR bar help
2276 --baz [BAZ] baz help
2277 '''
2278
2279
2280class TestMutuallyExclusiveLong(MEMixin, TestCase):
2281
2282 def get_parser(self, required=None):
2283 parser = ErrorRaisingArgumentParser(prog='PROG')
2284 parser.add_argument('--abcde', help='abcde help')
2285 parser.add_argument('--fghij', help='fghij help')
2286 group = parser.add_mutually_exclusive_group(required=required)
2287 group.add_argument('--klmno', help='klmno help')
2288 group.add_argument('--pqrst', help='pqrst help')
2289 return parser
2290
2291 failures = ['--klmno X --pqrst Y']
2292 successes = [
2293 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2294 ('--abcde Y --klmno X',
2295 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2296 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2297 ('--pqrst X --fghij Y',
2298 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2299 ]
2300 successes_when_not_required = [
2301 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2302 ]
2303
2304 usage_when_not_required = '''\
2305 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2306 [--klmno KLMNO | --pqrst PQRST]
2307 '''
2308 usage_when_required = '''\
2309 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2310 (--klmno KLMNO | --pqrst PQRST)
2311 '''
2312 help = '''\
2313
2314 optional arguments:
2315 -h, --help show this help message and exit
2316 --abcde ABCDE abcde help
2317 --fghij FGHIJ fghij help
2318 --klmno KLMNO klmno help
2319 --pqrst PQRST pqrst help
2320 '''
2321
2322
2323class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2324
2325 def get_parser(self, required):
2326 parser = ErrorRaisingArgumentParser(prog='PROG')
2327 group = parser.add_mutually_exclusive_group(required=required)
2328 group.add_argument('-x', help=argparse.SUPPRESS)
2329 group.add_argument('-y', action='store_false', help='y help')
2330 return parser
2331
2332 failures = ['-x X -y']
2333 successes = [
2334 ('-x X', NS(x='X', y=True)),
2335 ('-x X -x Y', NS(x='Y', y=True)),
2336 ('-y', NS(x=None, y=False)),
2337 ]
2338 successes_when_not_required = [
2339 ('', NS(x=None, y=True)),
2340 ]
2341
2342 usage_when_not_required = '''\
2343 usage: PROG [-h] [-y]
2344 '''
2345 usage_when_required = '''\
2346 usage: PROG [-h] -y
2347 '''
2348 help = '''\
2349
2350 optional arguments:
2351 -h, --help show this help message and exit
2352 -y y help
2353 '''
2354
2355
2356class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2357
2358 def get_parser(self, required):
2359 parser = ErrorRaisingArgumentParser(prog='PROG')
2360 group = parser.add_mutually_exclusive_group(required=required)
2361 add = group.add_argument
2362 add('--spam', action='store_true', help=argparse.SUPPRESS)
2363 add('--badger', action='store_false', help=argparse.SUPPRESS)
2364 add('--bladder', help=argparse.SUPPRESS)
2365 return parser
2366
2367 failures = [
2368 '--spam --badger',
2369 '--badger --bladder B',
2370 '--bladder B --spam',
2371 ]
2372 successes = [
2373 ('--spam', NS(spam=True, badger=True, bladder=None)),
2374 ('--badger', NS(spam=False, badger=False, bladder=None)),
2375 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2376 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2377 ]
2378 successes_when_not_required = [
2379 ('', NS(spam=False, badger=True, bladder=None)),
2380 ]
2381
2382 usage_when_required = usage_when_not_required = '''\
2383 usage: PROG [-h]
2384 '''
2385 help = '''\
2386
2387 optional arguments:
2388 -h, --help show this help message and exit
2389 '''
2390
2391
2392class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2393
2394 def get_parser(self, required):
2395 parser = ErrorRaisingArgumentParser(prog='PROG')
2396 group = parser.add_mutually_exclusive_group(required=required)
2397 group.add_argument('--foo', action='store_true', help='FOO')
2398 group.add_argument('--spam', help='SPAM')
2399 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2400 return parser
2401
2402 failures = [
2403 '--foo --spam S',
2404 '--spam S X',
2405 'X --foo',
2406 'X Y Z --spam S',
2407 '--foo X Y',
2408 ]
2409 successes = [
2410 ('--foo', NS(foo=True, spam=None, badger='X')),
2411 ('--spam S', NS(foo=False, spam='S', badger='X')),
2412 ('X', NS(foo=False, spam=None, badger=['X'])),
2413 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2414 ]
2415 successes_when_not_required = [
2416 ('', NS(foo=False, spam=None, badger='X')),
2417 ]
2418
2419 usage_when_not_required = '''\
2420 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2421 '''
2422 usage_when_required = '''\
2423 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2424 '''
2425 help = '''\
2426
2427 positional arguments:
2428 badger BADGER
2429
2430 optional arguments:
2431 -h, --help show this help message and exit
2432 --foo FOO
2433 --spam SPAM SPAM
2434 '''
2435
2436
2437class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2438
2439 def get_parser(self, required):
2440 parser = ErrorRaisingArgumentParser(prog='PROG')
2441 parser.add_argument('-x', action='store_true', help='x help')
2442 group = parser.add_mutually_exclusive_group(required=required)
2443 group.add_argument('-a', action='store_true', help='a help')
2444 group.add_argument('-b', action='store_true', help='b help')
2445 parser.add_argument('-y', action='store_true', help='y help')
2446 group.add_argument('-c', action='store_true', help='c help')
2447 return parser
2448
2449 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2450 successes = [
2451 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2452 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2453 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2454 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2455 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2456 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2457 ]
2458 successes_when_not_required = [
2459 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2460 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2461 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2462 ]
2463
2464 usage_when_required = usage_when_not_required = '''\
2465 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2466 '''
2467 help = '''\
2468
2469 optional arguments:
2470 -h, --help show this help message and exit
2471 -x x help
2472 -a a help
2473 -b b help
2474 -y y help
2475 -c c help
2476 '''
2477
2478
2479class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2480
2481 def get_parser(self, required):
2482 parser = ErrorRaisingArgumentParser(prog='PROG')
2483 parser.add_argument('x', help='x help')
2484 parser.add_argument('-y', action='store_true', help='y help')
2485 group = parser.add_mutually_exclusive_group(required=required)
2486 group.add_argument('a', nargs='?', help='a help')
2487 group.add_argument('-b', action='store_true', help='b help')
2488 group.add_argument('-c', action='store_true', help='c help')
2489 return parser
2490
2491 failures = ['X A -b', '-b -c', '-c X A']
2492 successes = [
2493 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2494 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2495 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2496 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2497 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2498 ]
2499 successes_when_not_required = [
2500 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2501 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2502 ]
2503
2504 usage_when_required = usage_when_not_required = '''\
2505 usage: PROG [-h] [-y] [-b] [-c] x [a]
2506 '''
2507 help = '''\
2508
2509 positional arguments:
2510 x x help
2511 a a help
2512
2513 optional arguments:
2514 -h, --help show this help message and exit
2515 -y y help
2516 -b b help
2517 -c c help
2518 '''
2519
2520# =================================================
2521# Mutually exclusive group in parent parser tests
2522# =================================================
2523
2524class MEPBase(object):
2525
2526 def get_parser(self, required=None):
2527 parent = super(MEPBase, self).get_parser(required=required)
2528 parser = ErrorRaisingArgumentParser(
2529 prog=parent.prog, add_help=False, parents=[parent])
2530 return parser
2531
2532
2533class TestMutuallyExclusiveGroupErrorsParent(
2534 MEPBase, TestMutuallyExclusiveGroupErrors):
2535 pass
2536
2537
2538class TestMutuallyExclusiveSimpleParent(
2539 MEPBase, TestMutuallyExclusiveSimple):
2540 pass
2541
2542
2543class TestMutuallyExclusiveLongParent(
2544 MEPBase, TestMutuallyExclusiveLong):
2545 pass
2546
2547
2548class TestMutuallyExclusiveFirstSuppressedParent(
2549 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2550 pass
2551
2552
2553class TestMutuallyExclusiveManySuppressedParent(
2554 MEPBase, TestMutuallyExclusiveManySuppressed):
2555 pass
2556
2557
2558class TestMutuallyExclusiveOptionalAndPositionalParent(
2559 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2560 pass
2561
2562
2563class TestMutuallyExclusiveOptionalsMixedParent(
2564 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2565 pass
2566
2567
2568class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2569 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2570 pass
2571
2572# =================
2573# Set default tests
2574# =================
2575
2576class TestSetDefaults(TestCase):
2577
2578 def test_set_defaults_no_args(self):
2579 parser = ErrorRaisingArgumentParser()
2580 parser.set_defaults(x='foo')
2581 parser.set_defaults(y='bar', z=1)
2582 self.assertEqual(NS(x='foo', y='bar', z=1),
2583 parser.parse_args([]))
2584 self.assertEqual(NS(x='foo', y='bar', z=1),
2585 parser.parse_args([], NS()))
2586 self.assertEqual(NS(x='baz', y='bar', z=1),
2587 parser.parse_args([], NS(x='baz')))
2588 self.assertEqual(NS(x='baz', y='bar', z=2),
2589 parser.parse_args([], NS(x='baz', z=2)))
2590
2591 def test_set_defaults_with_args(self):
2592 parser = ErrorRaisingArgumentParser()
2593 parser.set_defaults(x='foo', y='bar')
2594 parser.add_argument('-x', default='xfoox')
2595 self.assertEqual(NS(x='xfoox', y='bar'),
2596 parser.parse_args([]))
2597 self.assertEqual(NS(x='xfoox', y='bar'),
2598 parser.parse_args([], NS()))
2599 self.assertEqual(NS(x='baz', y='bar'),
2600 parser.parse_args([], NS(x='baz')))
2601 self.assertEqual(NS(x='1', y='bar'),
2602 parser.parse_args('-x 1'.split()))
2603 self.assertEqual(NS(x='1', y='bar'),
2604 parser.parse_args('-x 1'.split(), NS()))
2605 self.assertEqual(NS(x='1', y='bar'),
2606 parser.parse_args('-x 1'.split(), NS(x='baz')))
2607
2608 def test_set_defaults_subparsers(self):
2609 parser = ErrorRaisingArgumentParser()
2610 parser.set_defaults(x='foo')
2611 subparsers = parser.add_subparsers()
2612 parser_a = subparsers.add_parser('a')
2613 parser_a.set_defaults(y='bar')
2614 self.assertEqual(NS(x='foo', y='bar'),
2615 parser.parse_args('a'.split()))
2616
2617 def test_set_defaults_parents(self):
2618 parent = ErrorRaisingArgumentParser(add_help=False)
2619 parent.set_defaults(x='foo')
2620 parser = ErrorRaisingArgumentParser(parents=[parent])
2621 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2622
2623 def test_set_defaults_same_as_add_argument(self):
2624 parser = ErrorRaisingArgumentParser()
2625 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2626 parser.add_argument('-w')
2627 parser.add_argument('-x', default='XX')
2628 parser.add_argument('y', nargs='?')
2629 parser.add_argument('z', nargs='?', default='ZZ')
2630
2631 # defaults set previously
2632 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2633 parser.parse_args([]))
2634
2635 # reset defaults
2636 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2637 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2638 parser.parse_args([]))
2639
2640 def test_set_defaults_same_as_add_argument_group(self):
2641 parser = ErrorRaisingArgumentParser()
2642 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2643 group = parser.add_argument_group('foo')
2644 group.add_argument('-w')
2645 group.add_argument('-x', default='XX')
2646 group.add_argument('y', nargs='?')
2647 group.add_argument('z', nargs='?', default='ZZ')
2648
2649
2650 # defaults set previously
2651 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2652 parser.parse_args([]))
2653
2654 # reset defaults
2655 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2656 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2657 parser.parse_args([]))
2658
2659# =================
2660# Get default tests
2661# =================
2662
2663class TestGetDefault(TestCase):
2664
2665 def test_get_default(self):
2666 parser = ErrorRaisingArgumentParser()
2667 self.assertEqual(None, parser.get_default("foo"))
2668 self.assertEqual(None, parser.get_default("bar"))
2669
2670 parser.add_argument("--foo")
2671 self.assertEqual(None, parser.get_default("foo"))
2672 self.assertEqual(None, parser.get_default("bar"))
2673
2674 parser.add_argument("--bar", type=int, default=42)
2675 self.assertEqual(None, parser.get_default("foo"))
2676 self.assertEqual(42, parser.get_default("bar"))
2677
2678 parser.set_defaults(foo="badger")
2679 self.assertEqual("badger", parser.get_default("foo"))
2680 self.assertEqual(42, parser.get_default("bar"))
2681
2682# ==========================
2683# Namespace 'contains' tests
2684# ==========================
2685
2686class TestNamespaceContainsSimple(TestCase):
2687
2688 def test_empty(self):
2689 ns = argparse.Namespace()
2690 self.assertEquals('' in ns, False)
2691 self.assertEquals('' not in ns, True)
2692 self.assertEquals('x' in ns, False)
2693
2694 def test_non_empty(self):
2695 ns = argparse.Namespace(x=1, y=2)
2696 self.assertEquals('x' in ns, True)
2697 self.assertEquals('x' not in ns, False)
2698 self.assertEquals('y' in ns, True)
2699 self.assertEquals('' in ns, False)
2700 self.assertEquals('xx' in ns, False)
2701 self.assertEquals('z' in ns, False)
2702
2703# =====================
2704# Help formatting tests
2705# =====================
2706
2707class TestHelpFormattingMetaclass(type):
2708
2709 def __init__(cls, name, bases, bodydict):
2710 if name == 'HelpTestCase':
2711 return
2712
2713 class AddTests(object):
2714
2715 def __init__(self, test_class, func_suffix, std_name):
2716 self.func_suffix = func_suffix
2717 self.std_name = std_name
2718
2719 for test_func in [self.test_format,
2720 self.test_print,
2721 self.test_print_file]:
2722 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2723
2724 def test_wrapper(self, test_func=test_func):
2725 test_func(self)
2726 try:
2727 test_wrapper.__name__ = test_name
2728 except TypeError:
2729 pass
2730 setattr(test_class, test_name, test_wrapper)
2731
2732 def _get_parser(self, tester):
2733 parser = argparse.ArgumentParser(
2734 *tester.parser_signature.args,
2735 **tester.parser_signature.kwargs)
2736 for argument_sig in tester.argument_signatures:
2737 parser.add_argument(*argument_sig.args,
2738 **argument_sig.kwargs)
2739 group_signatures = tester.argument_group_signatures
2740 for group_sig, argument_sigs in group_signatures:
2741 group = parser.add_argument_group(*group_sig.args,
2742 **group_sig.kwargs)
2743 for argument_sig in argument_sigs:
2744 group.add_argument(*argument_sig.args,
2745 **argument_sig.kwargs)
2746 return parser
2747
2748 def _test(self, tester, parser_text):
2749 expected_text = getattr(tester, self.func_suffix)
2750 expected_text = textwrap.dedent(expected_text)
2751 if expected_text != parser_text:
2752 print(repr(expected_text))
2753 print(repr(parser_text))
2754 for char1, char2 in zip(expected_text, parser_text):
2755 if char1 != char2:
2756 print('first diff: %r %r' % (char1, char2))
2757 break
2758 tester.assertEqual(expected_text, parser_text)
2759
2760 def test_format(self, tester):
2761 parser = self._get_parser(tester)
2762 format = getattr(parser, 'format_%s' % self.func_suffix)
2763 self._test(tester, format())
2764
2765 def test_print(self, tester):
2766 parser = self._get_parser(tester)
2767 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2768 old_stream = getattr(sys, self.std_name)
Michael Foord91a2c892010-04-08 00:04:24 +00002769 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Petersona39e9662010-03-02 22:05:59 +00002770 try:
2771 print_()
2772 parser_text = getattr(sys, self.std_name).getvalue()
2773 finally:
2774 setattr(sys, self.std_name, old_stream)
2775 self._test(tester, parser_text)
2776
2777 def test_print_file(self, tester):
2778 parser = self._get_parser(tester)
2779 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Michael Foord91a2c892010-04-08 00:04:24 +00002780 sfile = StdIOBuffer()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002781 print_(sfile)
2782 parser_text = sfile.getvalue()
2783 self._test(tester, parser_text)
2784
2785 # add tests for {format,print}_{usage,help,version}
2786 for func_suffix, std_name in [('usage', 'stdout'),
2787 ('help', 'stdout'),
2788 ('version', 'stderr')]:
2789 AddTests(cls, func_suffix, std_name)
2790
2791bases = TestCase,
2792HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2793
2794
2795class TestHelpBiggerOptionals(HelpTestCase):
2796 """Make sure that argument help aligns when options are longer"""
2797
2798 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2799 epilog='EPILOG', version='0.1')
2800 argument_signatures = [
2801 Sig('-x', action='store_true', help='X HELP'),
2802 Sig('--y', help='Y HELP'),
2803 Sig('foo', help='FOO HELP'),
2804 Sig('bar', help='BAR HELP'),
2805 ]
2806 argument_group_signatures = []
2807 usage = '''\
2808 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2809 '''
2810 help = usage + '''\
2811
2812 DESCRIPTION
2813
2814 positional arguments:
2815 foo FOO HELP
2816 bar BAR HELP
2817
2818 optional arguments:
2819 -h, --help show this help message and exit
2820 -v, --version show program's version number and exit
2821 -x X HELP
2822 --y Y Y HELP
2823
2824 EPILOG
2825 '''
2826 version = '''\
2827 0.1
2828 '''
2829
2830
2831class TestHelpBiggerOptionalGroups(HelpTestCase):
2832 """Make sure that argument help aligns when options are longer"""
2833
2834 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2835 epilog='EPILOG', version='0.1')
2836 argument_signatures = [
2837 Sig('-x', action='store_true', help='X HELP'),
2838 Sig('--y', help='Y HELP'),
2839 Sig('foo', help='FOO HELP'),
2840 Sig('bar', help='BAR HELP'),
2841 ]
2842 argument_group_signatures = [
2843 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2844 Sig('baz', help='BAZ HELP'),
2845 Sig('-z', nargs='+', help='Z HELP')]),
2846 ]
2847 usage = '''\
2848 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2849 '''
2850 help = usage + '''\
2851
2852 DESCRIPTION
2853
2854 positional arguments:
2855 foo FOO HELP
2856 bar BAR HELP
2857
2858 optional arguments:
2859 -h, --help show this help message and exit
2860 -v, --version show program's version number and exit
2861 -x X HELP
2862 --y Y Y HELP
2863
2864 GROUP TITLE:
2865 GROUP DESCRIPTION
2866
2867 baz BAZ HELP
2868 -z Z [Z ...] Z HELP
2869
2870 EPILOG
2871 '''
2872 version = '''\
2873 0.1
2874 '''
2875
2876
2877class TestHelpBiggerPositionals(HelpTestCase):
2878 """Make sure that help aligns when arguments are longer"""
2879
2880 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2881 argument_signatures = [
2882 Sig('-x', action='store_true', help='X HELP'),
2883 Sig('--y', help='Y HELP'),
2884 Sig('ekiekiekifekang', help='EKI HELP'),
2885 Sig('bar', help='BAR HELP'),
2886 ]
2887 argument_group_signatures = []
2888 usage = '''\
2889 usage: USAGE
2890 '''
2891 help = usage + '''\
2892
2893 DESCRIPTION
2894
2895 positional arguments:
2896 ekiekiekifekang EKI HELP
2897 bar BAR HELP
2898
2899 optional arguments:
2900 -h, --help show this help message and exit
2901 -x X HELP
2902 --y Y Y HELP
2903 '''
2904
2905 version = ''
2906
2907
2908class TestHelpReformatting(HelpTestCase):
2909 """Make sure that text after short names starts on the first line"""
2910
2911 parser_signature = Sig(
2912 prog='PROG',
2913 description=' oddly formatted\n'
2914 'description\n'
2915 '\n'
2916 'that is so long that it should go onto multiple '
2917 'lines when wrapped')
2918 argument_signatures = [
2919 Sig('-x', metavar='XX', help='oddly\n'
2920 ' formatted -x help'),
2921 Sig('y', metavar='yyy', help='normal y help'),
2922 ]
2923 argument_group_signatures = [
2924 (Sig('title', description='\n'
2925 ' oddly formatted group\n'
2926 '\n'
2927 'description'),
2928 [Sig('-a', action='store_true',
2929 help=' oddly \n'
2930 'formatted -a help \n'
2931 ' again, so long that it should be wrapped over '
2932 'multiple lines')]),
2933 ]
2934 usage = '''\
2935 usage: PROG [-h] [-x XX] [-a] yyy
2936 '''
2937 help = usage + '''\
2938
2939 oddly formatted description that is so long that it should go onto \
2940multiple
2941 lines when wrapped
2942
2943 positional arguments:
2944 yyy normal y help
2945
2946 optional arguments:
2947 -h, --help show this help message and exit
2948 -x XX oddly formatted -x help
2949
2950 title:
2951 oddly formatted group description
2952
2953 -a oddly formatted -a help again, so long that it should \
2954be wrapped
2955 over multiple lines
2956 '''
2957 version = ''
2958
2959
2960class TestHelpWrappingShortNames(HelpTestCase):
2961 """Make sure that text after short names starts on the first line"""
2962
2963 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
2964 argument_signatures = [
2965 Sig('-x', metavar='XX', help='XHH HX' * 20),
2966 Sig('y', metavar='yyy', help='YH YH' * 20),
2967 ]
2968 argument_group_signatures = [
2969 (Sig('ALPHAS'), [
2970 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
2971 ]
2972 usage = '''\
2973 usage: PROG [-h] [-x XX] [-a] yyy
2974 '''
2975 help = usage + '''\
2976
2977 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
2978DD DD DD
2979 DD DD DD DD D
2980
2981 positional arguments:
2982 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
2983YHYH YHYH
2984 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
2985
2986 optional arguments:
2987 -h, --help show this help message and exit
2988 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
2989HXXHH HXXHH
2990 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
2991
2992 ALPHAS:
2993 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
2994HHAAHHH
2995 HHAAHHH HHAAHHH HHA
2996 '''
2997 version = ''
2998
2999
3000class TestHelpWrappingLongNames(HelpTestCase):
3001 """Make sure that text after long names starts on the next line"""
3002
3003 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3004 version='V V'*30)
3005 argument_signatures = [
3006 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3007 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3008 ]
3009 argument_group_signatures = [
3010 (Sig('ALPHAS'), [
3011 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3012 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3013 ]
3014 usage = '''\
3015 usage: USAGE
3016 '''
3017 help = usage + '''\
3018
3019 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3020DD DD DD
3021 DD DD DD DD D
3022
3023 positional arguments:
3024 yyyyyyyyyyyyyyyyyyyyyyyyy
3025 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3026YHYH YHYH
3027 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3028
3029 optional arguments:
3030 -h, --help show this help message and exit
3031 -v, --version show program's version number and exit
3032 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3033 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3034XHXH XHXH
3035 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3036
3037 ALPHAS:
3038 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3039 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3040AHAH AHAH
3041 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3042 zzzzzzzzzzzzzzzzzzzzzzzzz
3043 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3044ZHZH ZHZH
3045 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3046 '''
3047 version = '''\
3048 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3049VV VV VV
3050 VV VV VV VV V
3051 '''
3052
3053
3054class TestHelpUsage(HelpTestCase):
3055 """Test basic usage messages"""
3056
3057 parser_signature = Sig(prog='PROG')
3058 argument_signatures = [
3059 Sig('-w', nargs='+', help='w'),
3060 Sig('-x', nargs='*', help='x'),
3061 Sig('a', help='a'),
3062 Sig('b', help='b', nargs=2),
3063 Sig('c', help='c', nargs='?'),
3064 ]
3065 argument_group_signatures = [
3066 (Sig('group'), [
3067 Sig('-y', nargs='?', help='y'),
3068 Sig('-z', nargs=3, help='z'),
3069 Sig('d', help='d', nargs='*'),
3070 Sig('e', help='e', nargs='+'),
3071 ])
3072 ]
3073 usage = '''\
3074 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3075 a b b [c] [d [d ...]] e [e ...]
3076 '''
3077 help = usage + '''\
3078
3079 positional arguments:
3080 a a
3081 b b
3082 c c
3083
3084 optional arguments:
3085 -h, --help show this help message and exit
3086 -w W [W ...] w
3087 -x [X [X ...]] x
3088
3089 group:
3090 -y [Y] y
3091 -z Z Z Z z
3092 d d
3093 e e
3094 '''
3095 version = ''
3096
3097
3098class TestHelpOnlyUserGroups(HelpTestCase):
3099 """Test basic usage messages"""
3100
3101 parser_signature = Sig(prog='PROG', add_help=False)
3102 argument_signatures = []
3103 argument_group_signatures = [
3104 (Sig('xxxx'), [
3105 Sig('-x', help='x'),
3106 Sig('a', help='a'),
3107 ]),
3108 (Sig('yyyy'), [
3109 Sig('b', help='b'),
3110 Sig('-y', help='y'),
3111 ]),
3112 ]
3113 usage = '''\
3114 usage: PROG [-x X] [-y Y] a b
3115 '''
3116 help = usage + '''\
3117
3118 xxxx:
3119 -x X x
3120 a a
3121
3122 yyyy:
3123 b b
3124 -y Y y
3125 '''
3126 version = ''
3127
3128
3129class TestHelpUsageLongProg(HelpTestCase):
3130 """Test usage messages where the prog is long"""
3131
3132 parser_signature = Sig(prog='P' * 60)
3133 argument_signatures = [
3134 Sig('-w', metavar='W'),
3135 Sig('-x', metavar='X'),
3136 Sig('a'),
3137 Sig('b'),
3138 ]
3139 argument_group_signatures = []
3140 usage = '''\
3141 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3142 [-h] [-w W] [-x X] a b
3143 '''
3144 help = usage + '''\
3145
3146 positional arguments:
3147 a
3148 b
3149
3150 optional arguments:
3151 -h, --help show this help message and exit
3152 -w W
3153 -x X
3154 '''
3155 version = ''
3156
3157
3158class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3159 """Test usage messages where the prog is long and the optionals wrap"""
3160
3161 parser_signature = Sig(prog='P' * 60)
3162 argument_signatures = [
3163 Sig('-w', metavar='W' * 25),
3164 Sig('-x', metavar='X' * 25),
3165 Sig('-y', metavar='Y' * 25),
3166 Sig('-z', metavar='Z' * 25),
3167 Sig('a'),
3168 Sig('b'),
3169 ]
3170 argument_group_signatures = []
3171 usage = '''\
3172 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3173 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3174[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3175 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3176 a b
3177 '''
3178 help = usage + '''\
3179
3180 positional arguments:
3181 a
3182 b
3183
3184 optional arguments:
3185 -h, --help show this help message and exit
3186 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3187 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3188 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3189 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3190 '''
3191 version = ''
3192
3193
3194class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3195 """Test usage messages where the prog is long and the positionals wrap"""
3196
3197 parser_signature = Sig(prog='P' * 60, add_help=False)
3198 argument_signatures = [
3199 Sig('a' * 25),
3200 Sig('b' * 25),
3201 Sig('c' * 25),
3202 ]
3203 argument_group_signatures = []
3204 usage = '''\
3205 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3206 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3207 ccccccccccccccccccccccccc
3208 '''
3209 help = usage + '''\
3210
3211 positional arguments:
3212 aaaaaaaaaaaaaaaaaaaaaaaaa
3213 bbbbbbbbbbbbbbbbbbbbbbbbb
3214 ccccccccccccccccccccccccc
3215 '''
3216 version = ''
3217
3218
3219class TestHelpUsageOptionalsWrap(HelpTestCase):
3220 """Test usage messages where the optionals wrap"""
3221
3222 parser_signature = Sig(prog='PROG')
3223 argument_signatures = [
3224 Sig('-w', metavar='W' * 25),
3225 Sig('-x', metavar='X' * 25),
3226 Sig('-y', metavar='Y' * 25),
3227 Sig('-z', metavar='Z' * 25),
3228 Sig('a'),
3229 Sig('b'),
3230 Sig('c'),
3231 ]
3232 argument_group_signatures = []
3233 usage = '''\
3234 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3235[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3236 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3237[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3238 a b c
3239 '''
3240 help = usage + '''\
3241
3242 positional arguments:
3243 a
3244 b
3245 c
3246
3247 optional arguments:
3248 -h, --help show this help message and exit
3249 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3250 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3251 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3252 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3253 '''
3254 version = ''
3255
3256
3257class TestHelpUsagePositionalsWrap(HelpTestCase):
3258 """Test usage messages where the positionals wrap"""
3259
3260 parser_signature = Sig(prog='PROG')
3261 argument_signatures = [
3262 Sig('-x'),
3263 Sig('-y'),
3264 Sig('-z'),
3265 Sig('a' * 25),
3266 Sig('b' * 25),
3267 Sig('c' * 25),
3268 ]
3269 argument_group_signatures = []
3270 usage = '''\
3271 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3272 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3273 ccccccccccccccccccccccccc
3274 '''
3275 help = usage + '''\
3276
3277 positional arguments:
3278 aaaaaaaaaaaaaaaaaaaaaaaaa
3279 bbbbbbbbbbbbbbbbbbbbbbbbb
3280 ccccccccccccccccccccccccc
3281
3282 optional arguments:
3283 -h, --help show this help message and exit
3284 -x X
3285 -y Y
3286 -z Z
3287 '''
3288 version = ''
3289
3290
3291class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3292 """Test usage messages where the optionals and positionals wrap"""
3293
3294 parser_signature = Sig(prog='PROG')
3295 argument_signatures = [
3296 Sig('-x', metavar='X' * 25),
3297 Sig('-y', metavar='Y' * 25),
3298 Sig('-z', metavar='Z' * 25),
3299 Sig('a' * 25),
3300 Sig('b' * 25),
3301 Sig('c' * 25),
3302 ]
3303 argument_group_signatures = []
3304 usage = '''\
3305 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3306[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3307 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3308 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3309 ccccccccccccccccccccccccc
3310 '''
3311 help = usage + '''\
3312
3313 positional arguments:
3314 aaaaaaaaaaaaaaaaaaaaaaaaa
3315 bbbbbbbbbbbbbbbbbbbbbbbbb
3316 ccccccccccccccccccccccccc
3317
3318 optional arguments:
3319 -h, --help show this help message and exit
3320 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3321 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3322 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3323 '''
3324 version = ''
3325
3326
3327class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3328 """Test usage messages where there are only optionals and they wrap"""
3329
3330 parser_signature = Sig(prog='PROG')
3331 argument_signatures = [
3332 Sig('-x', metavar='X' * 25),
3333 Sig('-y', metavar='Y' * 25),
3334 Sig('-z', metavar='Z' * 25),
3335 ]
3336 argument_group_signatures = []
3337 usage = '''\
3338 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3339[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3340 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3341 '''
3342 help = usage + '''\
3343
3344 optional arguments:
3345 -h, --help show this help message and exit
3346 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3347 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3348 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3349 '''
3350 version = ''
3351
3352
3353class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3354 """Test usage messages where there are only positionals and they wrap"""
3355
3356 parser_signature = Sig(prog='PROG', add_help=False)
3357 argument_signatures = [
3358 Sig('a' * 25),
3359 Sig('b' * 25),
3360 Sig('c' * 25),
3361 ]
3362 argument_group_signatures = []
3363 usage = '''\
3364 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3365 ccccccccccccccccccccccccc
3366 '''
3367 help = usage + '''\
3368
3369 positional arguments:
3370 aaaaaaaaaaaaaaaaaaaaaaaaa
3371 bbbbbbbbbbbbbbbbbbbbbbbbb
3372 ccccccccccccccccccccccccc
3373 '''
3374 version = ''
3375
3376
3377class TestHelpVariableExpansion(HelpTestCase):
3378 """Test that variables are expanded properly in help messages"""
3379
3380 parser_signature = Sig(prog='PROG')
3381 argument_signatures = [
3382 Sig('-x', type=int,
3383 help='x %(prog)s %(default)s %(type)s %%'),
3384 Sig('-y', action='store_const', default=42, const='XXX',
3385 help='y %(prog)s %(default)s %(const)s'),
3386 Sig('--foo', choices='abc',
3387 help='foo %(prog)s %(default)s %(choices)s'),
3388 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3389 help='bar %(prog)s %(default)s %(dest)s'),
3390 Sig('spam', help='spam %(prog)s %(default)s'),
3391 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3392 ]
3393 argument_group_signatures = [
3394 (Sig('group'), [
3395 Sig('-a', help='a %(prog)s %(default)s'),
3396 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3397 ])
3398 ]
3399 usage = ('''\
3400 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3401 spam badger
3402 ''')
3403 help = usage + '''\
3404
3405 positional arguments:
3406 spam spam PROG None
3407 badger badger PROG 0.5
3408
3409 optional arguments:
3410 -h, --help show this help message and exit
3411 -x X x PROG None int %
3412 -y y PROG 42 XXX
3413 --foo {a,b,c} foo PROG None a, b, c
3414 --bar BBB bar PROG baz bar
3415
3416 group:
3417 -a A a PROG None
3418 -b B b PROG -1
3419 '''
3420 version = ''
3421
3422
3423class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3424 """Test that variables are expanded properly when usage= is present"""
3425
3426 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3427 argument_signatures = []
3428 argument_group_signatures = []
3429 usage = ('''\
3430 usage: PROG FOO
3431 ''')
3432 help = usage + '''\
3433
3434 optional arguments:
3435 -h, --help show this help message and exit
3436 '''
3437 version = ''
3438
3439
3440class TestHelpVariableExpansionNoArguments(HelpTestCase):
3441 """Test that variables are expanded properly with no arguments"""
3442
3443 parser_signature = Sig(prog='PROG', add_help=False)
3444 argument_signatures = []
3445 argument_group_signatures = []
3446 usage = ('''\
3447 usage: PROG
3448 ''')
3449 help = usage
3450 version = ''
3451
3452
3453class TestHelpSuppressUsage(HelpTestCase):
3454 """Test that items can be suppressed in usage messages"""
3455
3456 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3457 argument_signatures = [
3458 Sig('--foo', help='foo help'),
3459 Sig('spam', help='spam help'),
3460 ]
3461 argument_group_signatures = []
3462 help = '''\
3463 positional arguments:
3464 spam spam help
3465
3466 optional arguments:
3467 -h, --help show this help message and exit
3468 --foo FOO foo help
3469 '''
3470 usage = ''
3471 version = ''
3472
3473
3474class TestHelpSuppressOptional(HelpTestCase):
3475 """Test that optional arguments can be suppressed in help messages"""
3476
3477 parser_signature = Sig(prog='PROG', add_help=False)
3478 argument_signatures = [
3479 Sig('--foo', help=argparse.SUPPRESS),
3480 Sig('spam', help='spam help'),
3481 ]
3482 argument_group_signatures = []
3483 usage = '''\
3484 usage: PROG spam
3485 '''
3486 help = usage + '''\
3487
3488 positional arguments:
3489 spam spam help
3490 '''
3491 version = ''
3492
3493
3494class TestHelpSuppressOptionalGroup(HelpTestCase):
3495 """Test that optional groups can be suppressed in help messages"""
3496
3497 parser_signature = Sig(prog='PROG')
3498 argument_signatures = [
3499 Sig('--foo', help='foo help'),
3500 Sig('spam', help='spam help'),
3501 ]
3502 argument_group_signatures = [
3503 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3504 ]
3505 usage = '''\
3506 usage: PROG [-h] [--foo FOO] spam
3507 '''
3508 help = usage + '''\
3509
3510 positional arguments:
3511 spam spam help
3512
3513 optional arguments:
3514 -h, --help show this help message and exit
3515 --foo FOO foo help
3516 '''
3517 version = ''
3518
3519
3520class TestHelpSuppressPositional(HelpTestCase):
3521 """Test that positional arguments can be suppressed in help messages"""
3522
3523 parser_signature = Sig(prog='PROG')
3524 argument_signatures = [
3525 Sig('--foo', help='foo help'),
3526 Sig('spam', help=argparse.SUPPRESS),
3527 ]
3528 argument_group_signatures = []
3529 usage = '''\
3530 usage: PROG [-h] [--foo FOO]
3531 '''
3532 help = usage + '''\
3533
3534 optional arguments:
3535 -h, --help show this help message and exit
3536 --foo FOO foo help
3537 '''
3538 version = ''
3539
3540
3541class TestHelpRequiredOptional(HelpTestCase):
3542 """Test that required options don't look optional"""
3543
3544 parser_signature = Sig(prog='PROG')
3545 argument_signatures = [
3546 Sig('--foo', required=True, help='foo help'),
3547 ]
3548 argument_group_signatures = []
3549 usage = '''\
3550 usage: PROG [-h] --foo FOO
3551 '''
3552 help = usage + '''\
3553
3554 optional arguments:
3555 -h, --help show this help message and exit
3556 --foo FOO foo help
3557 '''
3558 version = ''
3559
3560
3561class TestHelpAlternatePrefixChars(HelpTestCase):
3562 """Test that options display with different prefix characters"""
3563
3564 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3565 argument_signatures = [
3566 Sig('^^foo', action='store_true', help='foo help'),
3567 Sig(';b', ';;bar', help='bar help'),
3568 ]
3569 argument_group_signatures = []
3570 usage = '''\
3571 usage: PROG [^^foo] [;b BAR]
3572 '''
3573 help = usage + '''\
3574
3575 optional arguments:
3576 ^^foo foo help
3577 ;b BAR, ;;bar BAR bar help
3578 '''
3579 version = ''
3580
3581
3582class TestHelpNoHelpOptional(HelpTestCase):
3583 """Test that the --help argument can be suppressed help messages"""
3584
3585 parser_signature = Sig(prog='PROG', add_help=False)
3586 argument_signatures = [
3587 Sig('--foo', help='foo help'),
3588 Sig('spam', help='spam help'),
3589 ]
3590 argument_group_signatures = []
3591 usage = '''\
3592 usage: PROG [--foo FOO] spam
3593 '''
3594 help = usage + '''\
3595
3596 positional arguments:
3597 spam spam help
3598
3599 optional arguments:
3600 --foo FOO foo help
3601 '''
3602 version = ''
3603
3604
3605class TestHelpVersionOptional(HelpTestCase):
3606 """Test that the --version argument can be suppressed help messages"""
3607
3608 parser_signature = Sig(prog='PROG', version='1.0')
3609 argument_signatures = [
3610 Sig('--foo', help='foo help'),
3611 Sig('spam', help='spam help'),
3612 ]
3613 argument_group_signatures = []
3614 usage = '''\
3615 usage: PROG [-h] [-v] [--foo FOO] spam
3616 '''
3617 help = usage + '''\
3618
3619 positional arguments:
3620 spam spam help
3621
3622 optional arguments:
3623 -h, --help show this help message and exit
3624 -v, --version show program's version number and exit
3625 --foo FOO foo help
3626 '''
3627 version = '''\
3628 1.0
3629 '''
3630
3631
3632class TestHelpNone(HelpTestCase):
3633 """Test that no errors occur if no help is specified"""
3634
3635 parser_signature = Sig(prog='PROG')
3636 argument_signatures = [
3637 Sig('--foo'),
3638 Sig('spam'),
3639 ]
3640 argument_group_signatures = []
3641 usage = '''\
3642 usage: PROG [-h] [--foo FOO] spam
3643 '''
3644 help = usage + '''\
3645
3646 positional arguments:
3647 spam
3648
3649 optional arguments:
3650 -h, --help show this help message and exit
3651 --foo FOO
3652 '''
3653 version = ''
3654
3655
3656class TestHelpTupleMetavar(HelpTestCase):
3657 """Test specifying metavar as a tuple"""
3658
3659 parser_signature = Sig(prog='PROG')
3660 argument_signatures = [
3661 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3662 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3663 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3664 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3665 ]
3666 argument_group_signatures = []
3667 usage = '''\
3668 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3669[-z [Z1]]
3670 '''
3671 help = usage + '''\
3672
3673 optional arguments:
3674 -h, --help show this help message and exit
3675 -w W1 [W2 ...] w
3676 -x [X1 [X2 ...]] x
3677 -y Y1 Y2 Y3 y
3678 -z [Z1] z
3679 '''
3680 version = ''
3681
3682
3683class TestHelpRawText(HelpTestCase):
3684 """Test the RawTextHelpFormatter"""
3685
3686 parser_signature = Sig(
3687 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3688 description='Keep the formatting\n'
3689 ' exactly as it is written\n'
3690 '\n'
3691 'here\n')
3692
3693 argument_signatures = [
3694 Sig('--foo', help=' foo help should also\n'
3695 'appear as given here'),
3696 Sig('spam', help='spam help'),
3697 ]
3698 argument_group_signatures = [
3699 (Sig('title', description=' This text\n'
3700 ' should be indented\n'
3701 ' exactly like it is here\n'),
3702 [Sig('--bar', help='bar help')]),
3703 ]
3704 usage = '''\
3705 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3706 '''
3707 help = usage + '''\
3708
3709 Keep the formatting
3710 exactly as it is written
3711
3712 here
3713
3714 positional arguments:
3715 spam spam help
3716
3717 optional arguments:
3718 -h, --help show this help message and exit
3719 --foo FOO foo help should also
3720 appear as given here
3721
3722 title:
3723 This text
3724 should be indented
3725 exactly like it is here
3726
3727 --bar BAR bar help
3728 '''
3729 version = ''
3730
3731
3732class TestHelpRawDescription(HelpTestCase):
3733 """Test the RawTextHelpFormatter"""
3734
3735 parser_signature = Sig(
3736 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3737 description='Keep the formatting\n'
3738 ' exactly as it is written\n'
3739 '\n'
3740 'here\n')
3741
3742 argument_signatures = [
3743 Sig('--foo', help=' foo help should not\n'
3744 ' retain this odd formatting'),
3745 Sig('spam', help='spam help'),
3746 ]
3747 argument_group_signatures = [
3748 (Sig('title', description=' This text\n'
3749 ' should be indented\n'
3750 ' exactly like it is here\n'),
3751 [Sig('--bar', help='bar help')]),
3752 ]
3753 usage = '''\
3754 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3755 '''
3756 help = usage + '''\
3757
3758 Keep the formatting
3759 exactly as it is written
3760
3761 here
3762
3763 positional arguments:
3764 spam spam help
3765
3766 optional arguments:
3767 -h, --help show this help message and exit
3768 --foo FOO foo help should not retain this odd formatting
3769
3770 title:
3771 This text
3772 should be indented
3773 exactly like it is here
3774
3775 --bar BAR bar help
3776 '''
3777 version = ''
3778
3779
3780class TestHelpArgumentDefaults(HelpTestCase):
3781 """Test the ArgumentDefaultsHelpFormatter"""
3782
3783 parser_signature = Sig(
3784 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3785 description='description')
3786
3787 argument_signatures = [
3788 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3789 Sig('--bar', action='store_true', help='bar help'),
3790 Sig('spam', help='spam help'),
3791 Sig('badger', nargs='?', default='wooden', help='badger help'),
3792 ]
3793 argument_group_signatures = [
3794 (Sig('title', description='description'),
3795 [Sig('--baz', type=int, default=42, help='baz help')]),
3796 ]
3797 usage = '''\
3798 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3799 '''
3800 help = usage + '''\
3801
3802 description
3803
3804 positional arguments:
3805 spam spam help
3806 badger badger help (default: wooden)
3807
3808 optional arguments:
3809 -h, --help show this help message and exit
3810 --foo FOO foo help - oh and by the way, None
3811 --bar bar help (default: False)
3812
3813 title:
3814 description
3815
3816 --baz BAZ baz help (default: 42)
3817 '''
3818 version = ''
3819
Steven Betharddce6e1b2010-05-24 03:45:26 +00003820class TestHelpVersionAction(HelpTestCase):
3821 """Test the default help for the version action"""
3822
3823 parser_signature = Sig(prog='PROG', description='description')
3824 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3825 argument_group_signatures = []
3826 usage = '''\
3827 usage: PROG [-h] [-V]
3828 '''
3829 help = usage + '''\
3830
3831 description
3832
3833 optional arguments:
3834 -h, --help show this help message and exit
3835 -V, --version show program's version number and exit
3836 '''
3837 version = ''
3838
Benjamin Petersona39e9662010-03-02 22:05:59 +00003839# =====================================
3840# Optional/Positional constructor tests
3841# =====================================
3842
3843class TestInvalidArgumentConstructors(TestCase):
3844 """Test a bunch of invalid Argument constructors"""
3845
3846 def assertTypeError(self, *args, **kwargs):
3847 parser = argparse.ArgumentParser()
3848 self.assertRaises(TypeError, parser.add_argument,
3849 *args, **kwargs)
3850
3851 def assertValueError(self, *args, **kwargs):
3852 parser = argparse.ArgumentParser()
3853 self.assertRaises(ValueError, parser.add_argument,
3854 *args, **kwargs)
3855
3856 def test_invalid_keyword_arguments(self):
3857 self.assertTypeError('-x', bar=None)
3858 self.assertTypeError('-y', callback='foo')
3859 self.assertTypeError('-y', callback_args=())
3860 self.assertTypeError('-y', callback_kwargs={})
3861
3862 def test_missing_destination(self):
3863 self.assertTypeError()
3864 for action in ['append', 'store']:
3865 self.assertTypeError(action=action)
3866
3867 def test_invalid_option_strings(self):
3868 self.assertValueError('--')
3869 self.assertValueError('---')
3870
3871 def test_invalid_type(self):
3872 self.assertValueError('--foo', type='int')
3873
3874 def test_invalid_action(self):
3875 self.assertValueError('-x', action='foo')
3876 self.assertValueError('foo', action='baz')
3877 parser = argparse.ArgumentParser()
3878 try:
3879 parser.add_argument("--foo", action="store-true")
3880 except ValueError:
3881 e = sys.exc_info()[1]
3882 expected = 'unknown action'
3883 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00003884 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00003885
3886 def test_multiple_dest(self):
3887 parser = argparse.ArgumentParser()
3888 parser.add_argument(dest='foo')
3889 try:
3890 parser.add_argument('bar', dest='baz')
3891 except ValueError:
3892 e = sys.exc_info()[1]
3893 expected = 'dest supplied twice for positional argument'
3894 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00003895 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00003896
3897 def test_no_argument_actions(self):
3898 for action in ['store_const', 'store_true', 'store_false',
3899 'append_const', 'count']:
3900 for attrs in [dict(type=int), dict(nargs='+'),
3901 dict(choices='ab')]:
3902 self.assertTypeError('-x', action=action, **attrs)
3903
3904 def test_no_argument_no_const_actions(self):
3905 # options with zero arguments
3906 for action in ['store_true', 'store_false', 'count']:
3907
3908 # const is always disallowed
3909 self.assertTypeError('-x', const='foo', action=action)
3910
3911 # nargs is always disallowed
3912 self.assertTypeError('-x', nargs='*', action=action)
3913
3914 def test_more_than_one_argument_actions(self):
3915 for action in ['store', 'append']:
3916
3917 # nargs=0 is disallowed
3918 self.assertValueError('-x', nargs=0, action=action)
3919 self.assertValueError('spam', nargs=0, action=action)
3920
3921 # const is disallowed with non-optional arguments
3922 for nargs in [1, '*', '+']:
3923 self.assertValueError('-x', const='foo',
3924 nargs=nargs, action=action)
3925 self.assertValueError('spam', const='foo',
3926 nargs=nargs, action=action)
3927
3928 def test_required_const_actions(self):
3929 for action in ['store_const', 'append_const']:
3930
3931 # nargs is always disallowed
3932 self.assertTypeError('-x', nargs='+', action=action)
3933
3934 def test_parsers_action_missing_params(self):
3935 self.assertTypeError('command', action='parsers')
3936 self.assertTypeError('command', action='parsers', prog='PROG')
3937 self.assertTypeError('command', action='parsers',
3938 parser_class=argparse.ArgumentParser)
3939
3940 def test_required_positional(self):
3941 self.assertTypeError('foo', required=True)
3942
3943 def test_user_defined_action(self):
3944
3945 class Success(Exception):
3946 pass
3947
3948 class Action(object):
3949
3950 def __init__(self,
3951 option_strings,
3952 dest,
3953 const,
3954 default,
3955 required=False):
3956 if dest == 'spam':
3957 if const is Success:
3958 if default is Success:
3959 raise Success()
3960
3961 def __call__(self, *args, **kwargs):
3962 pass
3963
3964 parser = argparse.ArgumentParser()
3965 self.assertRaises(Success, parser.add_argument, '--spam',
3966 action=Action, default=Success, const=Success)
3967 self.assertRaises(Success, parser.add_argument, 'spam',
3968 action=Action, default=Success, const=Success)
3969
3970# ================================
3971# Actions returned by add_argument
3972# ================================
3973
3974class TestActionsReturned(TestCase):
3975
3976 def test_dest(self):
3977 parser = argparse.ArgumentParser()
3978 action = parser.add_argument('--foo')
3979 self.assertEqual(action.dest, 'foo')
3980 action = parser.add_argument('-b', '--bar')
3981 self.assertEqual(action.dest, 'bar')
3982 action = parser.add_argument('-x', '-y')
3983 self.assertEqual(action.dest, 'x')
3984
3985 def test_misc(self):
3986 parser = argparse.ArgumentParser()
3987 action = parser.add_argument('--foo', nargs='?', const=42,
3988 default=84, type=int, choices=[1, 2],
3989 help='FOO', metavar='BAR', dest='baz')
3990 self.assertEqual(action.nargs, '?')
3991 self.assertEqual(action.const, 42)
3992 self.assertEqual(action.default, 84)
3993 self.assertEqual(action.type, int)
3994 self.assertEqual(action.choices, [1, 2])
3995 self.assertEqual(action.help, 'FOO')
3996 self.assertEqual(action.metavar, 'BAR')
3997 self.assertEqual(action.dest, 'baz')
3998
3999
4000# ================================
4001# Argument conflict handling tests
4002# ================================
4003
4004class TestConflictHandling(TestCase):
4005
4006 def test_bad_type(self):
4007 self.assertRaises(ValueError, argparse.ArgumentParser,
4008 conflict_handler='foo')
4009
4010 def test_conflict_error(self):
4011 parser = argparse.ArgumentParser()
4012 parser.add_argument('-x')
4013 self.assertRaises(argparse.ArgumentError,
4014 parser.add_argument, '-x')
4015 parser.add_argument('--spam')
4016 self.assertRaises(argparse.ArgumentError,
4017 parser.add_argument, '--spam')
4018
4019 def test_resolve_error(self):
4020 get_parser = argparse.ArgumentParser
4021 parser = get_parser(prog='PROG', conflict_handler='resolve')
4022
4023 parser.add_argument('-x', help='OLD X')
4024 parser.add_argument('-x', help='NEW X')
4025 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4026 usage: PROG [-h] [-x X]
4027
4028 optional arguments:
4029 -h, --help show this help message and exit
4030 -x X NEW X
4031 '''))
4032
4033 parser.add_argument('--spam', metavar='OLD_SPAM')
4034 parser.add_argument('--spam', metavar='NEW_SPAM')
4035 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4036 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4037
4038 optional arguments:
4039 -h, --help show this help message and exit
4040 -x X NEW X
4041 --spam NEW_SPAM
4042 '''))
4043
4044
4045# =============================
4046# Help and Version option tests
4047# =============================
4048
4049class TestOptionalsHelpVersionActions(TestCase):
4050 """Test the help and version actions"""
4051
4052 def _get_error(self, func, *args, **kwargs):
4053 try:
4054 func(*args, **kwargs)
4055 except ArgumentParserError:
4056 return sys.exc_info()[1]
4057 else:
4058 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4059
4060 def assertPrintHelpExit(self, parser, args_str):
4061 self.assertEqual(
4062 parser.format_help(),
4063 self._get_error(parser.parse_args, args_str.split()).stdout)
4064
4065 def assertPrintVersionExit(self, parser, args_str):
4066 self.assertEqual(
4067 parser.format_version(),
4068 self._get_error(parser.parse_args, args_str.split()).stderr)
4069
4070 def assertArgumentParserError(self, parser, *args):
4071 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4072
4073 def test_version(self):
4074 parser = ErrorRaisingArgumentParser(version='1.0')
4075 self.assertPrintHelpExit(parser, '-h')
4076 self.assertPrintHelpExit(parser, '--help')
4077 self.assertPrintVersionExit(parser, '-v')
4078 self.assertPrintVersionExit(parser, '--version')
4079
4080 def test_version_format(self):
4081 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4082 msg = self._get_error(parser.parse_args, ['-v']).stderr
4083 self.assertEqual('PPP 3.5\n', msg)
4084
4085 def test_version_no_help(self):
4086 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4087 self.assertArgumentParserError(parser, '-h')
4088 self.assertArgumentParserError(parser, '--help')
4089 self.assertPrintVersionExit(parser, '-v')
4090 self.assertPrintVersionExit(parser, '--version')
4091
4092 def test_version_action(self):
4093 parser = ErrorRaisingArgumentParser(prog='XXX')
4094 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4095 msg = self._get_error(parser.parse_args, ['-V']).stderr
4096 self.assertEqual('XXX 3.7\n', msg)
4097
4098 def test_no_help(self):
4099 parser = ErrorRaisingArgumentParser(add_help=False)
4100 self.assertArgumentParserError(parser, '-h')
4101 self.assertArgumentParserError(parser, '--help')
4102 self.assertArgumentParserError(parser, '-v')
4103 self.assertArgumentParserError(parser, '--version')
4104
4105 def test_alternate_help_version(self):
4106 parser = ErrorRaisingArgumentParser()
4107 parser.add_argument('-x', action='help')
4108 parser.add_argument('-y', action='version')
4109 self.assertPrintHelpExit(parser, '-x')
4110 self.assertPrintVersionExit(parser, '-y')
4111 self.assertArgumentParserError(parser, '-v')
4112 self.assertArgumentParserError(parser, '--version')
4113
4114 def test_help_version_extra_arguments(self):
4115 parser = ErrorRaisingArgumentParser(version='1.0')
4116 parser.add_argument('-x', action='store_true')
4117 parser.add_argument('y')
4118
4119 # try all combinations of valid prefixes and suffixes
4120 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4121 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4122 for prefix in valid_prefixes:
4123 for suffix in valid_suffixes:
4124 format = '%s %%s %s' % (prefix, suffix)
4125 self.assertPrintHelpExit(parser, format % '-h')
4126 self.assertPrintHelpExit(parser, format % '--help')
4127 self.assertPrintVersionExit(parser, format % '-v')
4128 self.assertPrintVersionExit(parser, format % '--version')
4129
4130
4131# ======================
4132# str() and repr() tests
4133# ======================
4134
4135class TestStrings(TestCase):
4136 """Test str() and repr() on Optionals and Positionals"""
4137
4138 def assertStringEqual(self, obj, result_string):
4139 for func in [str, repr]:
4140 self.assertEqual(func(obj), result_string)
4141
4142 def test_optional(self):
4143 option = argparse.Action(
4144 option_strings=['--foo', '-a', '-b'],
4145 dest='b',
4146 type='int',
4147 nargs='+',
4148 default=42,
4149 choices=[1, 2, 3],
4150 help='HELP',
4151 metavar='METAVAR')
4152 string = (
4153 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4154 "nargs='+', const=None, default=42, type='int', "
4155 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4156 self.assertStringEqual(option, string)
4157
4158 def test_argument(self):
4159 argument = argparse.Action(
4160 option_strings=[],
4161 dest='x',
4162 type=float,
4163 nargs='?',
4164 default=2.5,
4165 choices=[0.5, 1.5, 2.5],
4166 help='H HH H',
4167 metavar='MV MV MV')
4168 string = (
4169 "Action(option_strings=[], dest='x', nargs='?', "
4170 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4171 "help='H HH H', metavar='MV MV MV')" % float)
4172 self.assertStringEqual(argument, string)
4173
4174 def test_namespace(self):
4175 ns = argparse.Namespace(foo=42, bar='spam')
4176 string = "Namespace(bar='spam', foo=42)"
4177 self.assertStringEqual(ns, string)
4178
4179 def test_parser(self):
4180 parser = argparse.ArgumentParser(prog='PROG')
4181 string = (
4182 "ArgumentParser(prog='PROG', usage=None, description=None, "
4183 "version=None, formatter_class=%r, conflict_handler='error', "
4184 "add_help=True)" % argparse.HelpFormatter)
4185 self.assertStringEqual(parser, string)
4186
4187# ===============
4188# Namespace tests
4189# ===============
4190
4191class TestNamespace(TestCase):
4192
4193 def test_constructor(self):
4194 ns = argparse.Namespace()
4195 self.assertRaises(AttributeError, getattr, ns, 'x')
4196
4197 ns = argparse.Namespace(a=42, b='spam')
4198 self.assertEqual(ns.a, 42)
4199 self.assertEqual(ns.b, 'spam')
4200
4201 def test_equality(self):
4202 ns1 = argparse.Namespace(a=1, b=2)
4203 ns2 = argparse.Namespace(b=2, a=1)
4204 ns3 = argparse.Namespace(a=1)
4205 ns4 = argparse.Namespace(b=2)
4206
4207 self.assertEqual(ns1, ns2)
4208 self.assertNotEqual(ns1, ns3)
4209 self.assertNotEqual(ns1, ns4)
4210 self.assertNotEqual(ns2, ns3)
4211 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004212 self.assertTrue(ns1 != ns3)
4213 self.assertTrue(ns1 != ns4)
4214 self.assertTrue(ns2 != ns3)
4215 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004216
4217
4218# ===================
4219# File encoding tests
4220# ===================
4221
4222class TestEncoding(TestCase):
4223
4224 def _test_module_encoding(self, path):
4225 path, _ = os.path.splitext(path)
4226 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004227 with codecs.open(path, 'r', 'utf8') as f:
4228 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004229
4230 def test_argparse_module_encoding(self):
4231 self._test_module_encoding(argparse.__file__)
4232
4233 def test_test_argparse_module_encoding(self):
4234 self._test_module_encoding(__file__)
4235
4236# ===================
4237# ArgumentError tests
4238# ===================
4239
4240class TestArgumentError(TestCase):
4241
4242 def test_argument_error(self):
4243 msg = "my error here"
4244 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004245 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004246
4247# =======================
4248# ArgumentTypeError tests
4249# =======================
4250
4251class TestArgumentError(TestCase):
4252
4253 def test_argument_type_error(self):
4254
4255 def spam(string):
4256 raise argparse.ArgumentTypeError('spam!')
4257
4258 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4259 parser.add_argument('x', type=spam)
4260 try:
4261 parser.parse_args(['XXX'])
4262 except ArgumentParserError:
4263 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4264 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004265 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004266 else:
4267 self.fail()
4268
4269# ======================
4270# parse_known_args tests
4271# ======================
4272
4273class TestParseKnownArgs(TestCase):
4274
4275 def test_optionals(self):
4276 parser = argparse.ArgumentParser()
4277 parser.add_argument('--foo')
4278 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004279 self.assertEqual(NS(foo='F'), args)
4280 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004281
4282 def test_mixed(self):
4283 parser = argparse.ArgumentParser()
4284 parser.add_argument('-v', nargs='?', const=1, type=int)
4285 parser.add_argument('--spam', action='store_false')
4286 parser.add_argument('badger')
4287
4288 argv = ["B", "C", "--foo", "-v", "3", "4"]
4289 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004290 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4291 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004292
4293# ============================
4294# from argparse import * tests
4295# ============================
4296
4297class TestImportStar(TestCase):
4298
4299 def test(self):
4300 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004301 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004302
Steven Bethard931906a2010-11-01 15:24:42 +00004303 def test_all_exports_everything_but_modules(self):
4304 items = [
4305 name
4306 for name, value in vars(argparse).items()
4307 if not name.startswith("_")
4308 if not inspect.ismodule(value)
4309 ]
4310 self.assertEqual(sorted(items), sorted(argparse.__all__))
4311
Benjamin Peterson036fae32010-03-02 22:20:10 +00004312def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004313 # silence warnings about version argument - these are expected
4314 with test_support.check_warnings(
4315 ('The "version" argument to ArgumentParser is deprecated.',
4316 DeprecationWarning),
4317 ('The (format|print)_version method is deprecated',
4318 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004319 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004320 # Remove global references to avoid looking like we have refleaks.
4321 RFile.seen = {}
4322 WFile.seen = set()
4323
Benjamin Peterson036fae32010-03-02 22:20:10 +00004324
Benjamin Petersona39e9662010-03-02 22:05:59 +00004325
4326if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004327 test_main()