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