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