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