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