blob: 9cb15c78bda97bed6c7fc6d63150819aeea9edf5 [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
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001326 parser_signature = Sig(argument_default=42)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001327 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001328 Sig('--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001329 Sig('foo', nargs='?'),
1330 Sig('bar', nargs='*'),
1331 Sig('--baz', action='store_true'),
1332 ]
1333 failures = ['-x']
1334 successes = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001335 ('', NS(foo=42, bar=42, baz=42, version=42)),
1336 ('a', NS(foo='a', bar=42, baz=42, version=42)),
1337 ('a b', NS(foo='a', bar=['b'], baz=42, version=42)),
1338 ('--baz', NS(foo=42, bar=42, baz=True, version=42)),
1339 ('a --baz', NS(foo='a', bar=42, baz=True, version=42)),
1340 ('--baz a b', NS(foo='a', bar=['b'], baz=True, version=42)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001341 ]
1342
1343
1344class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
1345 """Test reading arguments from a file"""
1346
1347 def setUp(self):
1348 super(TestArgumentsFromFile, self).setUp()
1349 file_texts = [
1350 ('hello', 'hello world!\n'),
1351 ('recursive', '-a\n'
1352 'A\n'
1353 '@hello'),
1354 ('invalid', '@no-such-path\n'),
1355 ]
1356 for path, text in file_texts:
1357 file = open(path, 'w')
1358 file.write(text)
1359 file.close()
1360
1361 parser_signature = Sig(fromfile_prefix_chars='@')
1362 argument_signatures = [
1363 Sig('-a'),
1364 Sig('x'),
1365 Sig('y', nargs='+'),
1366 ]
1367 failures = ['', '-b', 'X', '@invalid', '@missing']
1368 successes = [
1369 ('X Y', NS(a=None, x='X', y=['Y'])),
1370 ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
1371 ('@hello X', NS(a=None, x='hello world!', y=['X'])),
1372 ('X @hello', NS(a=None, x='X', y=['hello world!'])),
1373 ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
1374 ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
R David Murrayb94082a2012-07-21 22:20:11 -04001375 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001376 ]
1377
1378
1379class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1380 """Test reading arguments from a file"""
1381
1382 def setUp(self):
1383 super(TestArgumentsFromFileConverter, self).setUp()
1384 file_texts = [
1385 ('hello', 'hello world!\n'),
1386 ]
1387 for path, text in file_texts:
1388 file = open(path, 'w')
1389 file.write(text)
1390 file.close()
1391
1392 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1393
1394 def convert_arg_line_to_args(self, arg_line):
1395 for arg in arg_line.split():
1396 if not arg.strip():
1397 continue
1398 yield arg
1399 parser_class = FromFileConverterArgumentParser
1400 parser_signature = Sig(fromfile_prefix_chars='@')
1401 argument_signatures = [
1402 Sig('y', nargs='+'),
1403 ]
1404 failures = []
1405 successes = [
1406 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1407 ]
1408
1409
1410# =====================
1411# Type conversion tests
1412# =====================
1413
1414class TestFileTypeRepr(TestCase):
1415
1416 def test_r(self):
1417 type = argparse.FileType('r')
1418 self.assertEqual("FileType('r')", repr(type))
1419
1420 def test_wb_1(self):
1421 type = argparse.FileType('wb', 1)
1422 self.assertEqual("FileType('wb', 1)", repr(type))
1423
1424
1425class RFile(object):
1426 seen = {}
1427
1428 def __init__(self, name):
1429 self.name = name
1430
1431 def __eq__(self, other):
1432 if other in self.seen:
1433 text = self.seen[other]
1434 else:
1435 text = self.seen[other] = other.read()
1436 other.close()
1437 if not isinstance(text, str):
1438 text = text.decode('ascii')
1439 return self.name == other.name == text
1440
1441
1442class TestFileTypeR(TempDirMixin, ParserTestCase):
1443 """Test the FileType option/argument type for reading files"""
1444
1445 def setUp(self):
1446 super(TestFileTypeR, self).setUp()
1447 for file_name in ['foo', 'bar']:
1448 file = open(os.path.join(self.temp_dir, file_name), 'w')
1449 file.write(file_name)
1450 file.close()
Steven Bethardb0270112011-01-24 21:02:50 +00001451 self.create_readonly_file('readonly')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001452
1453 argument_signatures = [
1454 Sig('-x', type=argparse.FileType()),
1455 Sig('spam', type=argparse.FileType('r')),
1456 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001457 failures = ['-x', '', 'non-existent-file.txt']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001458 successes = [
1459 ('foo', NS(x=None, spam=RFile('foo'))),
1460 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1461 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1462 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
Steven Bethardb0270112011-01-24 21:02:50 +00001463 ('readonly', NS(x=None, spam=RFile('readonly'))),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001464 ]
1465
R David Murray6fb8fb12012-08-31 22:45:20 -04001466class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
1467 """Test that a file is not created unless the default is needed"""
1468 def setUp(self):
1469 super(TestFileTypeDefaults, self).setUp()
1470 file = open(os.path.join(self.temp_dir, 'good'), 'w')
1471 file.write('good')
1472 file.close()
1473
1474 argument_signatures = [
1475 Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
1476 ]
1477 # should provoke no such file error
1478 failures = ['']
1479 # should not provoke error because default file is created
1480 successes = [('-c good', NS(c=RFile('good')))]
1481
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001482
1483class TestFileTypeRB(TempDirMixin, ParserTestCase):
1484 """Test the FileType option/argument type for reading files"""
1485
1486 def setUp(self):
1487 super(TestFileTypeRB, self).setUp()
1488 for file_name in ['foo', 'bar']:
1489 file = open(os.path.join(self.temp_dir, file_name), 'w')
1490 file.write(file_name)
1491 file.close()
1492
1493 argument_signatures = [
1494 Sig('-x', type=argparse.FileType('rb')),
1495 Sig('spam', type=argparse.FileType('rb')),
1496 ]
1497 failures = ['-x', '']
1498 successes = [
1499 ('foo', NS(x=None, spam=RFile('foo'))),
1500 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1501 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1502 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
1503 ]
1504
1505
1506class WFile(object):
1507 seen = set()
1508
1509 def __init__(self, name):
1510 self.name = name
1511
1512 def __eq__(self, other):
1513 if other not in self.seen:
1514 text = 'Check that file is writable.'
1515 if 'b' in other.mode:
1516 text = text.encode('ascii')
1517 other.write(text)
1518 other.close()
1519 self.seen.add(other)
1520 return self.name == other.name
1521
1522
Victor Stinnera04b39b2011-11-20 23:09:09 +01001523@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1524 "non-root user required")
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001525class TestFileTypeW(TempDirMixin, ParserTestCase):
1526 """Test the FileType option/argument type for writing files"""
1527
Steven Bethardb0270112011-01-24 21:02:50 +00001528 def setUp(self):
1529 super(TestFileTypeW, self).setUp()
1530 self.create_readonly_file('readonly')
1531
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001532 argument_signatures = [
1533 Sig('-x', type=argparse.FileType('w')),
1534 Sig('spam', type=argparse.FileType('w')),
1535 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001536 failures = ['-x', '', 'readonly']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001537 successes = [
1538 ('foo', NS(x=None, spam=WFile('foo'))),
1539 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1540 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1541 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1542 ]
1543
1544
1545class TestFileTypeWB(TempDirMixin, ParserTestCase):
1546
1547 argument_signatures = [
1548 Sig('-x', type=argparse.FileType('wb')),
1549 Sig('spam', type=argparse.FileType('wb')),
1550 ]
1551 failures = ['-x', '']
1552 successes = [
1553 ('foo', NS(x=None, spam=WFile('foo'))),
1554 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1555 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1556 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1557 ]
1558
1559
1560class TestTypeCallable(ParserTestCase):
1561 """Test some callables as option/argument types"""
1562
1563 argument_signatures = [
1564 Sig('--eggs', type=complex),
1565 Sig('spam', type=float),
1566 ]
1567 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1568 successes = [
1569 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1570 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1571 ('1024.675', NS(eggs=None, spam=1024.675)),
1572 ]
1573
1574
1575class TestTypeUserDefined(ParserTestCase):
1576 """Test a user-defined option/argument type"""
1577
1578 class MyType(TestCase):
1579
1580 def __init__(self, value):
1581 self.value = value
1582
1583 def __eq__(self, other):
1584 return (type(self), self.value) == (type(other), other.value)
1585
1586 argument_signatures = [
1587 Sig('-x', type=MyType),
1588 Sig('spam', type=MyType),
1589 ]
1590 failures = []
1591 successes = [
1592 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1593 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1594 ]
1595
1596
1597class TestTypeClassicClass(ParserTestCase):
1598 """Test a classic class type"""
1599
1600 class C:
1601
1602 def __init__(self, value):
1603 self.value = value
1604
1605 def __eq__(self, other):
1606 return (type(self), self.value) == (type(other), other.value)
1607
1608 argument_signatures = [
1609 Sig('-x', type=C),
1610 Sig('spam', type=C),
1611 ]
1612 failures = []
1613 successes = [
1614 ('a -x b', NS(x=C('b'), spam=C('a'))),
1615 ('-xf g', NS(x=C('f'), spam=C('g'))),
1616 ]
1617
1618
1619class TestTypeRegistration(TestCase):
1620 """Test a user-defined type by registering it"""
1621
1622 def test(self):
1623
1624 def get_my_type(string):
1625 return 'my_type{%s}' % string
1626
1627 parser = argparse.ArgumentParser()
1628 parser.register('type', 'my_type', get_my_type)
1629 parser.add_argument('-x', type='my_type')
1630 parser.add_argument('y', type='my_type')
1631
1632 self.assertEqual(parser.parse_args('1'.split()),
1633 NS(x=None, y='my_type{1}'))
1634 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1635 NS(x='my_type{1}', y='my_type{42}'))
1636
1637
1638# ============
1639# Action tests
1640# ============
1641
1642class TestActionUserDefined(ParserTestCase):
1643 """Test a user-defined option/argument action"""
1644
1645 class OptionalAction(argparse.Action):
1646
1647 def __call__(self, parser, namespace, value, option_string=None):
1648 try:
1649 # check destination and option string
1650 assert self.dest == 'spam', 'dest: %s' % self.dest
1651 assert option_string == '-s', 'flag: %s' % option_string
1652 # when option is before argument, badger=2, and when
1653 # option is after argument, badger=<whatever was set>
1654 expected_ns = NS(spam=0.25)
1655 if value in [0.125, 0.625]:
1656 expected_ns.badger = 2
1657 elif value in [2.0]:
1658 expected_ns.badger = 84
1659 else:
1660 raise AssertionError('value: %s' % value)
1661 assert expected_ns == namespace, ('expected %s, got %s' %
1662 (expected_ns, namespace))
1663 except AssertionError:
1664 e = sys.exc_info()[1]
1665 raise ArgumentParserError('opt_action failed: %s' % e)
1666 setattr(namespace, 'spam', value)
1667
1668 class PositionalAction(argparse.Action):
1669
1670 def __call__(self, parser, namespace, value, option_string=None):
1671 try:
1672 assert option_string is None, ('option_string: %s' %
1673 option_string)
1674 # check destination
1675 assert self.dest == 'badger', 'dest: %s' % self.dest
1676 # when argument is before option, spam=0.25, and when
1677 # option is after argument, spam=<whatever was set>
1678 expected_ns = NS(badger=2)
1679 if value in [42, 84]:
1680 expected_ns.spam = 0.25
1681 elif value in [1]:
1682 expected_ns.spam = 0.625
1683 elif value in [2]:
1684 expected_ns.spam = 0.125
1685 else:
1686 raise AssertionError('value: %s' % value)
1687 assert expected_ns == namespace, ('expected %s, got %s' %
1688 (expected_ns, namespace))
1689 except AssertionError:
1690 e = sys.exc_info()[1]
1691 raise ArgumentParserError('arg_action failed: %s' % e)
1692 setattr(namespace, 'badger', value)
1693
1694 argument_signatures = [
1695 Sig('-s', dest='spam', action=OptionalAction,
1696 type=float, default=0.25),
1697 Sig('badger', action=PositionalAction,
1698 type=int, nargs='?', default=2),
1699 ]
1700 failures = []
1701 successes = [
1702 ('-s0.125', NS(spam=0.125, badger=2)),
1703 ('42', NS(spam=0.25, badger=42)),
1704 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1705 ('84 -s2', NS(spam=2.0, badger=84)),
1706 ]
1707
1708
1709class TestActionRegistration(TestCase):
1710 """Test a user-defined action supplied by registering it"""
1711
1712 class MyAction(argparse.Action):
1713
1714 def __call__(self, parser, namespace, values, option_string=None):
1715 setattr(namespace, self.dest, 'foo[%s]' % values)
1716
1717 def test(self):
1718
1719 parser = argparse.ArgumentParser()
1720 parser.register('action', 'my_action', self.MyAction)
1721 parser.add_argument('badger', action='my_action')
1722
1723 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1724 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1725
1726
1727# ================
1728# Subparsers tests
1729# ================
1730
1731class TestAddSubparsers(TestCase):
1732 """Test the add_subparsers method"""
1733
1734 def assertArgumentParserError(self, *args, **kwargs):
1735 self.assertRaises(ArgumentParserError, *args, **kwargs)
1736
Steven Bethardfd311a72010-12-18 11:19:23 +00001737 def _get_parser(self, subparser_help=False, prefix_chars=None,
1738 aliases=False):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001739 # create a parser with a subparsers argument
R. David Murray88c49fe2010-08-03 17:56:09 +00001740 if prefix_chars:
1741 parser = ErrorRaisingArgumentParser(
1742 prog='PROG', description='main description', prefix_chars=prefix_chars)
1743 parser.add_argument(
1744 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1745 else:
1746 parser = ErrorRaisingArgumentParser(
1747 prog='PROG', description='main description')
1748 parser.add_argument(
1749 '--foo', action='store_true', help='foo help')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001750 parser.add_argument(
1751 'bar', type=float, help='bar help')
1752
1753 # check that only one subparsers argument can be added
Steven Bethardfd311a72010-12-18 11:19:23 +00001754 subparsers_kwargs = {}
1755 if aliases:
1756 subparsers_kwargs['metavar'] = 'COMMAND'
1757 subparsers_kwargs['title'] = 'commands'
1758 else:
1759 subparsers_kwargs['help'] = 'command help'
1760 subparsers = parser.add_subparsers(**subparsers_kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001761 self.assertArgumentParserError(parser.add_subparsers)
1762
1763 # add first sub-parser
1764 parser1_kwargs = dict(description='1 description')
1765 if subparser_help:
1766 parser1_kwargs['help'] = '1 help'
Steven Bethardfd311a72010-12-18 11:19:23 +00001767 if aliases:
1768 parser1_kwargs['aliases'] = ['1alias1', '1alias2']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001769 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1770 parser1.add_argument('-w', type=int, help='w help')
1771 parser1.add_argument('x', choices='abc', help='x help')
1772
1773 # add second sub-parser
1774 parser2_kwargs = dict(description='2 description')
1775 if subparser_help:
1776 parser2_kwargs['help'] = '2 help'
1777 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1778 parser2.add_argument('-y', choices='123', help='y help')
1779 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1780
R David Murray00528e82012-07-21 22:48:35 -04001781 # add third sub-parser
1782 parser3_kwargs = dict(description='3 description')
1783 if subparser_help:
1784 parser3_kwargs['help'] = '3 help'
1785 parser3 = subparsers.add_parser('3', **parser3_kwargs)
1786 parser3.add_argument('t', type=int, help='t help')
1787 parser3.add_argument('u', nargs='...', help='u help')
1788
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001789 # return the main parser
1790 return parser
1791
1792 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00001793 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001794 self.parser = self._get_parser()
1795 self.command_help_parser = self._get_parser(subparser_help=True)
1796
1797 def test_parse_args_failures(self):
1798 # check some failure cases:
1799 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1800 '0.5 1 -y', '0.5 2 -w']:
1801 args = args_str.split()
1802 self.assertArgumentParserError(self.parser.parse_args, args)
1803
1804 def test_parse_args(self):
1805 # check some non-failure cases:
1806 self.assertEqual(
1807 self.parser.parse_args('0.5 1 b -w 7'.split()),
1808 NS(foo=False, bar=0.5, w=7, x='b'),
1809 )
1810 self.assertEqual(
1811 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1812 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1813 )
1814 self.assertEqual(
1815 self.parser.parse_args('--foo 0.125 1 c'.split()),
1816 NS(foo=True, bar=0.125, w=None, x='c'),
1817 )
R David Murray00528e82012-07-21 22:48:35 -04001818 self.assertEqual(
1819 self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
1820 NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
1821 )
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001822
Steven Bethardfca2e8a2010-11-02 12:47:22 +00001823 def test_parse_known_args(self):
1824 self.assertEqual(
1825 self.parser.parse_known_args('0.5 1 b -w 7'.split()),
1826 (NS(foo=False, bar=0.5, w=7, x='b'), []),
1827 )
1828 self.assertEqual(
1829 self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
1830 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1831 )
1832 self.assertEqual(
1833 self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
1834 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1835 )
1836 self.assertEqual(
1837 self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
1838 (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
1839 )
1840 self.assertEqual(
1841 self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
1842 (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
1843 )
1844
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001845 def test_dest(self):
1846 parser = ErrorRaisingArgumentParser()
1847 parser.add_argument('--foo', action='store_true')
1848 subparsers = parser.add_subparsers(dest='bar')
1849 parser1 = subparsers.add_parser('1')
1850 parser1.add_argument('baz')
1851 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1852 parser.parse_args('1 2'.split()))
1853
1854 def test_help(self):
1855 self.assertEqual(self.parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001856 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001857 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001858 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001859
1860 main description
1861
1862 positional arguments:
1863 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001864 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001865
1866 optional arguments:
1867 -h, --help show this help message and exit
1868 --foo foo help
1869 '''))
1870
R. David Murray88c49fe2010-08-03 17:56:09 +00001871 def test_help_extra_prefix_chars(self):
1872 # Make sure - is still used for help if it is a non-first prefix char
1873 parser = self._get_parser(prefix_chars='+:-')
1874 self.assertEqual(parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001875 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00001876 self.assertEqual(parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001877 usage: PROG [-h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00001878
1879 main description
1880
1881 positional arguments:
1882 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001883 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00001884
1885 optional arguments:
1886 -h, --help show this help message and exit
1887 ++foo foo help
1888 '''))
1889
1890
1891 def test_help_alternate_prefix_chars(self):
1892 parser = self._get_parser(prefix_chars='+:/')
1893 self.assertEqual(parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001894 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00001895 self.assertEqual(parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001896 usage: PROG [+h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00001897
1898 main description
1899
1900 positional arguments:
1901 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001902 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00001903
1904 optional arguments:
1905 +h, ++help show this help message and exit
1906 ++foo foo help
1907 '''))
1908
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001909 def test_parser_command_help(self):
1910 self.assertEqual(self.command_help_parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001911 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001912 self.assertEqual(self.command_help_parser.format_help(),
1913 textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001914 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001915
1916 main description
1917
1918 positional arguments:
1919 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001920 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001921 1 1 help
1922 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04001923 3 3 help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001924
1925 optional arguments:
1926 -h, --help show this help message and exit
1927 --foo foo help
1928 '''))
1929
1930 def test_subparser_title_help(self):
1931 parser = ErrorRaisingArgumentParser(prog='PROG',
1932 description='main description')
1933 parser.add_argument('--foo', action='store_true', help='foo help')
1934 parser.add_argument('bar', help='bar help')
1935 subparsers = parser.add_subparsers(title='subcommands',
1936 description='command help',
1937 help='additional text')
1938 parser1 = subparsers.add_parser('1')
1939 parser2 = subparsers.add_parser('2')
1940 self.assertEqual(parser.format_usage(),
1941 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1942 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1943 usage: PROG [-h] [--foo] bar {1,2} ...
1944
1945 main description
1946
1947 positional arguments:
1948 bar bar help
1949
1950 optional arguments:
1951 -h, --help show this help message and exit
1952 --foo foo help
1953
1954 subcommands:
1955 command help
1956
1957 {1,2} additional text
1958 '''))
1959
1960 def _test_subparser_help(self, args_str, expected_help):
1961 try:
1962 self.parser.parse_args(args_str.split())
1963 except ArgumentParserError:
1964 err = sys.exc_info()[1]
1965 if err.stdout != expected_help:
1966 print(repr(expected_help))
1967 print(repr(err.stdout))
1968 self.assertEqual(err.stdout, expected_help)
1969
1970 def test_subparser1_help(self):
1971 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
1972 usage: PROG bar 1 [-h] [-w W] {a,b,c}
1973
1974 1 description
1975
1976 positional arguments:
1977 {a,b,c} x help
1978
1979 optional arguments:
1980 -h, --help show this help message and exit
1981 -w W w help
1982 '''))
1983
1984 def test_subparser2_help(self):
1985 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
1986 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
1987
1988 2 description
1989
1990 positional arguments:
1991 z z help
1992
1993 optional arguments:
1994 -h, --help show this help message and exit
1995 -y {1,2,3} y help
1996 '''))
1997
Steven Bethardfd311a72010-12-18 11:19:23 +00001998 def test_alias_invocation(self):
1999 parser = self._get_parser(aliases=True)
2000 self.assertEqual(
2001 parser.parse_known_args('0.5 1alias1 b'.split()),
2002 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2003 )
2004 self.assertEqual(
2005 parser.parse_known_args('0.5 1alias2 b'.split()),
2006 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2007 )
2008
2009 def test_error_alias_invocation(self):
2010 parser = self._get_parser(aliases=True)
2011 self.assertArgumentParserError(parser.parse_args,
2012 '0.5 1alias3 b'.split())
2013
2014 def test_alias_help(self):
2015 parser = self._get_parser(aliases=True, subparser_help=True)
2016 self.maxDiff = None
2017 self.assertEqual(parser.format_help(), textwrap.dedent("""\
2018 usage: PROG [-h] [--foo] bar COMMAND ...
2019
2020 main description
2021
2022 positional arguments:
2023 bar bar help
2024
2025 optional arguments:
2026 -h, --help show this help message and exit
2027 --foo foo help
2028
2029 commands:
2030 COMMAND
2031 1 (1alias1, 1alias2)
2032 1 help
2033 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04002034 3 3 help
Steven Bethardfd311a72010-12-18 11:19:23 +00002035 """))
2036
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002037# ============
2038# Groups tests
2039# ============
2040
2041class TestPositionalsGroups(TestCase):
2042 """Tests that order of group positionals matches construction order"""
2043
2044 def test_nongroup_first(self):
2045 parser = ErrorRaisingArgumentParser()
2046 parser.add_argument('foo')
2047 group = parser.add_argument_group('g')
2048 group.add_argument('bar')
2049 parser.add_argument('baz')
2050 expected = NS(foo='1', bar='2', baz='3')
2051 result = parser.parse_args('1 2 3'.split())
2052 self.assertEqual(expected, result)
2053
2054 def test_group_first(self):
2055 parser = ErrorRaisingArgumentParser()
2056 group = parser.add_argument_group('xxx')
2057 group.add_argument('foo')
2058 parser.add_argument('bar')
2059 parser.add_argument('baz')
2060 expected = NS(foo='1', bar='2', baz='3')
2061 result = parser.parse_args('1 2 3'.split())
2062 self.assertEqual(expected, result)
2063
2064 def test_interleaved_groups(self):
2065 parser = ErrorRaisingArgumentParser()
2066 group = parser.add_argument_group('xxx')
2067 parser.add_argument('foo')
2068 group.add_argument('bar')
2069 parser.add_argument('baz')
2070 group = parser.add_argument_group('yyy')
2071 group.add_argument('frell')
2072 expected = NS(foo='1', bar='2', baz='3', frell='4')
2073 result = parser.parse_args('1 2 3 4'.split())
2074 self.assertEqual(expected, result)
2075
2076# ===================
2077# Parent parser tests
2078# ===================
2079
2080class TestParentParsers(TestCase):
2081 """Tests that parsers can be created with parent parsers"""
2082
2083 def assertArgumentParserError(self, *args, **kwargs):
2084 self.assertRaises(ArgumentParserError, *args, **kwargs)
2085
2086 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00002087 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002088 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
2089 self.wxyz_parent.add_argument('--w')
2090 x_group = self.wxyz_parent.add_argument_group('x')
2091 x_group.add_argument('-y')
2092 self.wxyz_parent.add_argument('z')
2093
2094 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
2095 self.abcd_parent.add_argument('a')
2096 self.abcd_parent.add_argument('-b')
2097 c_group = self.abcd_parent.add_argument_group('c')
2098 c_group.add_argument('--d')
2099
2100 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2101 self.w_parent.add_argument('--w')
2102
2103 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2104 self.z_parent.add_argument('z')
2105
2106 # parents with mutually exclusive groups
2107 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2108 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2109 group.add_argument('-a', action='store_true')
2110 group.add_argument('-b', action='store_true')
2111
2112 self.main_program = os.path.basename(sys.argv[0])
2113
2114 def test_single_parent(self):
2115 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2116 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2117 NS(w='3', y='1', z='2'))
2118
2119 def test_single_parent_mutex(self):
2120 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2121 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2122 self._test_mutex_ab(parser.parse_args)
2123
2124 def test_single_granparent_mutex(self):
2125 parents = [self.ab_mutex_parent]
2126 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2127 parser = ErrorRaisingArgumentParser(parents=[parser])
2128 self._test_mutex_ab(parser.parse_args)
2129
2130 def _test_mutex_ab(self, parse_args):
2131 self.assertEqual(parse_args([]), NS(a=False, b=False))
2132 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2133 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2134 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2135 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2136 self.assertArgumentParserError(parse_args, ['-c'])
2137 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2138 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2139
2140 def test_multiple_parents(self):
2141 parents = [self.abcd_parent, self.wxyz_parent]
2142 parser = ErrorRaisingArgumentParser(parents=parents)
2143 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2144 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2145
2146 def test_multiple_parents_mutex(self):
2147 parents = [self.ab_mutex_parent, self.wxyz_parent]
2148 parser = ErrorRaisingArgumentParser(parents=parents)
2149 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2150 NS(a=True, b=False, w='2', y=None, z='3'))
2151 self.assertArgumentParserError(
2152 parser.parse_args, '-a --w 2 3 -b'.split())
2153 self.assertArgumentParserError(
2154 parser.parse_args, '-a -b --w 2 3'.split())
2155
2156 def test_conflicting_parents(self):
2157 self.assertRaises(
2158 argparse.ArgumentError,
2159 argparse.ArgumentParser,
2160 parents=[self.w_parent, self.wxyz_parent])
2161
2162 def test_conflicting_parents_mutex(self):
2163 self.assertRaises(
2164 argparse.ArgumentError,
2165 argparse.ArgumentParser,
2166 parents=[self.abcd_parent, self.ab_mutex_parent])
2167
2168 def test_same_argument_name_parents(self):
2169 parents = [self.wxyz_parent, self.z_parent]
2170 parser = ErrorRaisingArgumentParser(parents=parents)
2171 self.assertEqual(parser.parse_args('1 2'.split()),
2172 NS(w=None, y=None, z='2'))
2173
2174 def test_subparser_parents(self):
2175 parser = ErrorRaisingArgumentParser()
2176 subparsers = parser.add_subparsers()
2177 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2178 abcde_parser.add_argument('e')
2179 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2180 NS(a='3', b='1', d='2', e='4'))
2181
2182 def test_subparser_parents_mutex(self):
2183 parser = ErrorRaisingArgumentParser()
2184 subparsers = parser.add_subparsers()
2185 parents = [self.ab_mutex_parent]
2186 abc_parser = subparsers.add_parser('foo', parents=parents)
2187 c_group = abc_parser.add_argument_group('c_group')
2188 c_group.add_argument('c')
2189 parents = [self.wxyz_parent, self.ab_mutex_parent]
2190 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2191 wxyzabe_parser.add_argument('e')
2192 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2193 NS(a=True, b=False, c='4'))
2194 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2195 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2196 self.assertArgumentParserError(
2197 parser.parse_args, 'foo -a -b 4'.split())
2198 self.assertArgumentParserError(
2199 parser.parse_args, 'bar -b -a 4'.split())
2200
2201 def test_parent_help(self):
2202 parents = [self.abcd_parent, self.wxyz_parent]
2203 parser = ErrorRaisingArgumentParser(parents=parents)
2204 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002205 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002206 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002207 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002208
2209 positional arguments:
2210 a
2211 z
2212
2213 optional arguments:
2214 -h, --help show this help message and exit
2215 -b B
2216 --w W
2217
2218 c:
2219 --d D
2220
2221 x:
2222 -y Y
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002223 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002224
2225 def test_groups_parents(self):
2226 parent = ErrorRaisingArgumentParser(add_help=False)
2227 g = parent.add_argument_group(title='g', description='gd')
2228 g.add_argument('-w')
2229 g.add_argument('-x')
2230 m = parent.add_mutually_exclusive_group()
2231 m.add_argument('-y')
2232 m.add_argument('-z')
2233 parser = ErrorRaisingArgumentParser(parents=[parent])
2234
2235 self.assertRaises(ArgumentParserError, parser.parse_args,
2236 ['-y', 'Y', '-z', 'Z'])
2237
2238 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002239 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002240 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002241 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002242
2243 optional arguments:
2244 -h, --help show this help message and exit
2245 -y Y
2246 -z Z
2247
2248 g:
2249 gd
2250
2251 -w W
2252 -x X
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002253 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002254
2255# ==============================
2256# Mutually exclusive group tests
2257# ==============================
2258
2259class TestMutuallyExclusiveGroupErrors(TestCase):
2260
2261 def test_invalid_add_argument_group(self):
2262 parser = ErrorRaisingArgumentParser()
2263 raises = self.assertRaises
2264 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2265
2266 def test_invalid_add_argument(self):
2267 parser = ErrorRaisingArgumentParser()
2268 group = parser.add_mutually_exclusive_group()
2269 add_argument = group.add_argument
2270 raises = self.assertRaises
2271 raises(ValueError, add_argument, '--foo', required=True)
2272 raises(ValueError, add_argument, 'bar')
2273 raises(ValueError, add_argument, 'bar', nargs='+')
2274 raises(ValueError, add_argument, 'bar', nargs=1)
2275 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2276
Steven Bethard49998ee2010-11-01 16:29:26 +00002277 def test_help(self):
2278 parser = ErrorRaisingArgumentParser(prog='PROG')
2279 group1 = parser.add_mutually_exclusive_group()
2280 group1.add_argument('--foo', action='store_true')
2281 group1.add_argument('--bar', action='store_false')
2282 group2 = parser.add_mutually_exclusive_group()
2283 group2.add_argument('--soup', action='store_true')
2284 group2.add_argument('--nuts', action='store_false')
2285 expected = '''\
2286 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2287
2288 optional arguments:
2289 -h, --help show this help message and exit
2290 --foo
2291 --bar
2292 --soup
2293 --nuts
2294 '''
2295 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002296
2297class MEMixin(object):
2298
2299 def test_failures_when_not_required(self):
2300 parse_args = self.get_parser(required=False).parse_args
2301 error = ArgumentParserError
2302 for args_string in self.failures:
2303 self.assertRaises(error, parse_args, args_string.split())
2304
2305 def test_failures_when_required(self):
2306 parse_args = self.get_parser(required=True).parse_args
2307 error = ArgumentParserError
2308 for args_string in self.failures + ['']:
2309 self.assertRaises(error, parse_args, args_string.split())
2310
2311 def test_successes_when_not_required(self):
2312 parse_args = self.get_parser(required=False).parse_args
2313 successes = self.successes + self.successes_when_not_required
2314 for args_string, expected_ns in successes:
2315 actual_ns = parse_args(args_string.split())
2316 self.assertEqual(actual_ns, expected_ns)
2317
2318 def test_successes_when_required(self):
2319 parse_args = self.get_parser(required=True).parse_args
2320 for args_string, expected_ns in self.successes:
2321 actual_ns = parse_args(args_string.split())
2322 self.assertEqual(actual_ns, expected_ns)
2323
2324 def test_usage_when_not_required(self):
2325 format_usage = self.get_parser(required=False).format_usage
2326 expected_usage = self.usage_when_not_required
2327 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2328
2329 def test_usage_when_required(self):
2330 format_usage = self.get_parser(required=True).format_usage
2331 expected_usage = self.usage_when_required
2332 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2333
2334 def test_help_when_not_required(self):
2335 format_help = self.get_parser(required=False).format_help
2336 help = self.usage_when_not_required + self.help
2337 self.assertEqual(format_help(), textwrap.dedent(help))
2338
2339 def test_help_when_required(self):
2340 format_help = self.get_parser(required=True).format_help
2341 help = self.usage_when_required + self.help
2342 self.assertEqual(format_help(), textwrap.dedent(help))
2343
2344
2345class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2346
2347 def get_parser(self, required=None):
2348 parser = ErrorRaisingArgumentParser(prog='PROG')
2349 group = parser.add_mutually_exclusive_group(required=required)
2350 group.add_argument('--bar', help='bar help')
2351 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2352 return parser
2353
2354 failures = ['--bar X --baz Y', '--bar X --baz']
2355 successes = [
2356 ('--bar X', NS(bar='X', baz=None)),
2357 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2358 ('--baz Y', NS(bar=None, baz='Y')),
2359 ('--baz', NS(bar=None, baz='Z')),
2360 ]
2361 successes_when_not_required = [
2362 ('', NS(bar=None, baz=None)),
2363 ]
2364
2365 usage_when_not_required = '''\
2366 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2367 '''
2368 usage_when_required = '''\
2369 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2370 '''
2371 help = '''\
2372
2373 optional arguments:
2374 -h, --help show this help message and exit
2375 --bar BAR bar help
2376 --baz [BAZ] baz help
2377 '''
2378
2379
2380class TestMutuallyExclusiveLong(MEMixin, TestCase):
2381
2382 def get_parser(self, required=None):
2383 parser = ErrorRaisingArgumentParser(prog='PROG')
2384 parser.add_argument('--abcde', help='abcde help')
2385 parser.add_argument('--fghij', help='fghij help')
2386 group = parser.add_mutually_exclusive_group(required=required)
2387 group.add_argument('--klmno', help='klmno help')
2388 group.add_argument('--pqrst', help='pqrst help')
2389 return parser
2390
2391 failures = ['--klmno X --pqrst Y']
2392 successes = [
2393 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2394 ('--abcde Y --klmno X',
2395 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2396 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2397 ('--pqrst X --fghij Y',
2398 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2399 ]
2400 successes_when_not_required = [
2401 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2402 ]
2403
2404 usage_when_not_required = '''\
2405 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2406 [--klmno KLMNO | --pqrst PQRST]
2407 '''
2408 usage_when_required = '''\
2409 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2410 (--klmno KLMNO | --pqrst PQRST)
2411 '''
2412 help = '''\
2413
2414 optional arguments:
2415 -h, --help show this help message and exit
2416 --abcde ABCDE abcde help
2417 --fghij FGHIJ fghij help
2418 --klmno KLMNO klmno help
2419 --pqrst PQRST pqrst help
2420 '''
2421
2422
2423class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2424
2425 def get_parser(self, required):
2426 parser = ErrorRaisingArgumentParser(prog='PROG')
2427 group = parser.add_mutually_exclusive_group(required=required)
2428 group.add_argument('-x', help=argparse.SUPPRESS)
2429 group.add_argument('-y', action='store_false', help='y help')
2430 return parser
2431
2432 failures = ['-x X -y']
2433 successes = [
2434 ('-x X', NS(x='X', y=True)),
2435 ('-x X -x Y', NS(x='Y', y=True)),
2436 ('-y', NS(x=None, y=False)),
2437 ]
2438 successes_when_not_required = [
2439 ('', NS(x=None, y=True)),
2440 ]
2441
2442 usage_when_not_required = '''\
2443 usage: PROG [-h] [-y]
2444 '''
2445 usage_when_required = '''\
2446 usage: PROG [-h] -y
2447 '''
2448 help = '''\
2449
2450 optional arguments:
2451 -h, --help show this help message and exit
2452 -y y help
2453 '''
2454
2455
2456class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2457
2458 def get_parser(self, required):
2459 parser = ErrorRaisingArgumentParser(prog='PROG')
2460 group = parser.add_mutually_exclusive_group(required=required)
2461 add = group.add_argument
2462 add('--spam', action='store_true', help=argparse.SUPPRESS)
2463 add('--badger', action='store_false', help=argparse.SUPPRESS)
2464 add('--bladder', help=argparse.SUPPRESS)
2465 return parser
2466
2467 failures = [
2468 '--spam --badger',
2469 '--badger --bladder B',
2470 '--bladder B --spam',
2471 ]
2472 successes = [
2473 ('--spam', NS(spam=True, badger=True, bladder=None)),
2474 ('--badger', NS(spam=False, badger=False, bladder=None)),
2475 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2476 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2477 ]
2478 successes_when_not_required = [
2479 ('', NS(spam=False, badger=True, bladder=None)),
2480 ]
2481
2482 usage_when_required = usage_when_not_required = '''\
2483 usage: PROG [-h]
2484 '''
2485 help = '''\
2486
2487 optional arguments:
2488 -h, --help show this help message and exit
2489 '''
2490
2491
2492class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2493
2494 def get_parser(self, required):
2495 parser = ErrorRaisingArgumentParser(prog='PROG')
2496 group = parser.add_mutually_exclusive_group(required=required)
2497 group.add_argument('--foo', action='store_true', help='FOO')
2498 group.add_argument('--spam', help='SPAM')
2499 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2500 return parser
2501
2502 failures = [
2503 '--foo --spam S',
2504 '--spam S X',
2505 'X --foo',
2506 'X Y Z --spam S',
2507 '--foo X Y',
2508 ]
2509 successes = [
2510 ('--foo', NS(foo=True, spam=None, badger='X')),
2511 ('--spam S', NS(foo=False, spam='S', badger='X')),
2512 ('X', NS(foo=False, spam=None, badger=['X'])),
2513 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2514 ]
2515 successes_when_not_required = [
2516 ('', NS(foo=False, spam=None, badger='X')),
2517 ]
2518
2519 usage_when_not_required = '''\
2520 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2521 '''
2522 usage_when_required = '''\
2523 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2524 '''
2525 help = '''\
2526
2527 positional arguments:
2528 badger BADGER
2529
2530 optional arguments:
2531 -h, --help show this help message and exit
2532 --foo FOO
2533 --spam SPAM SPAM
2534 '''
2535
2536
2537class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2538
2539 def get_parser(self, required):
2540 parser = ErrorRaisingArgumentParser(prog='PROG')
2541 parser.add_argument('-x', action='store_true', help='x help')
2542 group = parser.add_mutually_exclusive_group(required=required)
2543 group.add_argument('-a', action='store_true', help='a help')
2544 group.add_argument('-b', action='store_true', help='b help')
2545 parser.add_argument('-y', action='store_true', help='y help')
2546 group.add_argument('-c', action='store_true', help='c help')
2547 return parser
2548
2549 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2550 successes = [
2551 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2552 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2553 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2554 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2555 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2556 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2557 ]
2558 successes_when_not_required = [
2559 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2560 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2561 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2562 ]
2563
2564 usage_when_required = usage_when_not_required = '''\
2565 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2566 '''
2567 help = '''\
2568
2569 optional arguments:
2570 -h, --help show this help message and exit
2571 -x x help
2572 -a a help
2573 -b b help
2574 -y y help
2575 -c c help
2576 '''
2577
2578
Georg Brandl0f6b47a2011-01-30 12:19:35 +00002579class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2580
2581 def get_parser(self, required=None):
2582 parser = ErrorRaisingArgumentParser(prog='PROG')
2583 titled_group = parser.add_argument_group(
2584 title='Titled group', description='Group description')
2585 mutex_group = \
2586 titled_group.add_mutually_exclusive_group(required=required)
2587 mutex_group.add_argument('--bar', help='bar help')
2588 mutex_group.add_argument('--baz', help='baz help')
2589 return parser
2590
2591 failures = ['--bar X --baz Y', '--baz X --bar Y']
2592 successes = [
2593 ('--bar X', NS(bar='X', baz=None)),
2594 ('--baz Y', NS(bar=None, baz='Y')),
2595 ]
2596 successes_when_not_required = [
2597 ('', NS(bar=None, baz=None)),
2598 ]
2599
2600 usage_when_not_required = '''\
2601 usage: PROG [-h] [--bar BAR | --baz BAZ]
2602 '''
2603 usage_when_required = '''\
2604 usage: PROG [-h] (--bar BAR | --baz BAZ)
2605 '''
2606 help = '''\
2607
2608 optional arguments:
2609 -h, --help show this help message and exit
2610
2611 Titled group:
2612 Group description
2613
2614 --bar BAR bar help
2615 --baz BAZ baz help
2616 '''
2617
2618
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002619class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2620
2621 def get_parser(self, required):
2622 parser = ErrorRaisingArgumentParser(prog='PROG')
2623 parser.add_argument('x', help='x help')
2624 parser.add_argument('-y', action='store_true', help='y help')
2625 group = parser.add_mutually_exclusive_group(required=required)
2626 group.add_argument('a', nargs='?', help='a help')
2627 group.add_argument('-b', action='store_true', help='b help')
2628 group.add_argument('-c', action='store_true', help='c help')
2629 return parser
2630
2631 failures = ['X A -b', '-b -c', '-c X A']
2632 successes = [
2633 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2634 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2635 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2636 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2637 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2638 ]
2639 successes_when_not_required = [
2640 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2641 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2642 ]
2643
2644 usage_when_required = usage_when_not_required = '''\
2645 usage: PROG [-h] [-y] [-b] [-c] x [a]
2646 '''
2647 help = '''\
2648
2649 positional arguments:
2650 x x help
2651 a a help
2652
2653 optional arguments:
2654 -h, --help show this help message and exit
2655 -y y help
2656 -b b help
2657 -c c help
2658 '''
2659
2660# =================================================
2661# Mutually exclusive group in parent parser tests
2662# =================================================
2663
2664class MEPBase(object):
2665
2666 def get_parser(self, required=None):
2667 parent = super(MEPBase, self).get_parser(required=required)
2668 parser = ErrorRaisingArgumentParser(
2669 prog=parent.prog, add_help=False, parents=[parent])
2670 return parser
2671
2672
2673class TestMutuallyExclusiveGroupErrorsParent(
2674 MEPBase, TestMutuallyExclusiveGroupErrors):
2675 pass
2676
2677
2678class TestMutuallyExclusiveSimpleParent(
2679 MEPBase, TestMutuallyExclusiveSimple):
2680 pass
2681
2682
2683class TestMutuallyExclusiveLongParent(
2684 MEPBase, TestMutuallyExclusiveLong):
2685 pass
2686
2687
2688class TestMutuallyExclusiveFirstSuppressedParent(
2689 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2690 pass
2691
2692
2693class TestMutuallyExclusiveManySuppressedParent(
2694 MEPBase, TestMutuallyExclusiveManySuppressed):
2695 pass
2696
2697
2698class TestMutuallyExclusiveOptionalAndPositionalParent(
2699 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2700 pass
2701
2702
2703class TestMutuallyExclusiveOptionalsMixedParent(
2704 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2705 pass
2706
2707
2708class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2709 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2710 pass
2711
2712# =================
2713# Set default tests
2714# =================
2715
2716class TestSetDefaults(TestCase):
2717
2718 def test_set_defaults_no_args(self):
2719 parser = ErrorRaisingArgumentParser()
2720 parser.set_defaults(x='foo')
2721 parser.set_defaults(y='bar', z=1)
2722 self.assertEqual(NS(x='foo', y='bar', z=1),
2723 parser.parse_args([]))
2724 self.assertEqual(NS(x='foo', y='bar', z=1),
2725 parser.parse_args([], NS()))
2726 self.assertEqual(NS(x='baz', y='bar', z=1),
2727 parser.parse_args([], NS(x='baz')))
2728 self.assertEqual(NS(x='baz', y='bar', z=2),
2729 parser.parse_args([], NS(x='baz', z=2)))
2730
2731 def test_set_defaults_with_args(self):
2732 parser = ErrorRaisingArgumentParser()
2733 parser.set_defaults(x='foo', y='bar')
2734 parser.add_argument('-x', default='xfoox')
2735 self.assertEqual(NS(x='xfoox', y='bar'),
2736 parser.parse_args([]))
2737 self.assertEqual(NS(x='xfoox', y='bar'),
2738 parser.parse_args([], NS()))
2739 self.assertEqual(NS(x='baz', y='bar'),
2740 parser.parse_args([], NS(x='baz')))
2741 self.assertEqual(NS(x='1', y='bar'),
2742 parser.parse_args('-x 1'.split()))
2743 self.assertEqual(NS(x='1', y='bar'),
2744 parser.parse_args('-x 1'.split(), NS()))
2745 self.assertEqual(NS(x='1', y='bar'),
2746 parser.parse_args('-x 1'.split(), NS(x='baz')))
2747
2748 def test_set_defaults_subparsers(self):
2749 parser = ErrorRaisingArgumentParser()
2750 parser.set_defaults(x='foo')
2751 subparsers = parser.add_subparsers()
2752 parser_a = subparsers.add_parser('a')
2753 parser_a.set_defaults(y='bar')
2754 self.assertEqual(NS(x='foo', y='bar'),
2755 parser.parse_args('a'.split()))
2756
2757 def test_set_defaults_parents(self):
2758 parent = ErrorRaisingArgumentParser(add_help=False)
2759 parent.set_defaults(x='foo')
2760 parser = ErrorRaisingArgumentParser(parents=[parent])
2761 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2762
2763 def test_set_defaults_same_as_add_argument(self):
2764 parser = ErrorRaisingArgumentParser()
2765 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2766 parser.add_argument('-w')
2767 parser.add_argument('-x', default='XX')
2768 parser.add_argument('y', nargs='?')
2769 parser.add_argument('z', nargs='?', default='ZZ')
2770
2771 # defaults set previously
2772 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2773 parser.parse_args([]))
2774
2775 # reset defaults
2776 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2777 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2778 parser.parse_args([]))
2779
2780 def test_set_defaults_same_as_add_argument_group(self):
2781 parser = ErrorRaisingArgumentParser()
2782 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2783 group = parser.add_argument_group('foo')
2784 group.add_argument('-w')
2785 group.add_argument('-x', default='XX')
2786 group.add_argument('y', nargs='?')
2787 group.add_argument('z', nargs='?', default='ZZ')
2788
2789
2790 # defaults set previously
2791 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2792 parser.parse_args([]))
2793
2794 # reset defaults
2795 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2796 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2797 parser.parse_args([]))
2798
2799# =================
2800# Get default tests
2801# =================
2802
2803class TestGetDefault(TestCase):
2804
2805 def test_get_default(self):
2806 parser = ErrorRaisingArgumentParser()
2807 self.assertEqual(None, parser.get_default("foo"))
2808 self.assertEqual(None, parser.get_default("bar"))
2809
2810 parser.add_argument("--foo")
2811 self.assertEqual(None, parser.get_default("foo"))
2812 self.assertEqual(None, parser.get_default("bar"))
2813
2814 parser.add_argument("--bar", type=int, default=42)
2815 self.assertEqual(None, parser.get_default("foo"))
2816 self.assertEqual(42, parser.get_default("bar"))
2817
2818 parser.set_defaults(foo="badger")
2819 self.assertEqual("badger", parser.get_default("foo"))
2820 self.assertEqual(42, parser.get_default("bar"))
2821
2822# ==========================
2823# Namespace 'contains' tests
2824# ==========================
2825
2826class TestNamespaceContainsSimple(TestCase):
2827
2828 def test_empty(self):
2829 ns = argparse.Namespace()
Ezio Melottib3aedd42010-11-20 19:04:17 +00002830 self.assertEqual('' in ns, False)
2831 self.assertEqual('' not in ns, True)
2832 self.assertEqual('x' in ns, False)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002833
2834 def test_non_empty(self):
2835 ns = argparse.Namespace(x=1, y=2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002836 self.assertEqual('x' in ns, True)
2837 self.assertEqual('x' not in ns, False)
2838 self.assertEqual('y' in ns, True)
2839 self.assertEqual('' in ns, False)
2840 self.assertEqual('xx' in ns, False)
2841 self.assertEqual('z' in ns, False)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002842
2843# =====================
2844# Help formatting tests
2845# =====================
2846
2847class TestHelpFormattingMetaclass(type):
2848
2849 def __init__(cls, name, bases, bodydict):
2850 if name == 'HelpTestCase':
2851 return
2852
2853 class AddTests(object):
2854
2855 def __init__(self, test_class, func_suffix, std_name):
2856 self.func_suffix = func_suffix
2857 self.std_name = std_name
2858
2859 for test_func in [self.test_format,
2860 self.test_print,
2861 self.test_print_file]:
2862 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2863
2864 def test_wrapper(self, test_func=test_func):
2865 test_func(self)
2866 try:
2867 test_wrapper.__name__ = test_name
2868 except TypeError:
2869 pass
2870 setattr(test_class, test_name, test_wrapper)
2871
2872 def _get_parser(self, tester):
2873 parser = argparse.ArgumentParser(
2874 *tester.parser_signature.args,
2875 **tester.parser_signature.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002876 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002877 parser.add_argument(*argument_sig.args,
2878 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002879 group_sigs = getattr(tester, 'argument_group_signatures', [])
2880 for group_sig, argument_sigs in group_sigs:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002881 group = parser.add_argument_group(*group_sig.args,
2882 **group_sig.kwargs)
2883 for argument_sig in argument_sigs:
2884 group.add_argument(*argument_sig.args,
2885 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002886 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
2887 if subparsers_sigs:
2888 subparsers = parser.add_subparsers()
2889 for subparser_sig in subparsers_sigs:
2890 subparsers.add_parser(*subparser_sig.args,
2891 **subparser_sig.kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002892 return parser
2893
2894 def _test(self, tester, parser_text):
2895 expected_text = getattr(tester, self.func_suffix)
2896 expected_text = textwrap.dedent(expected_text)
2897 if expected_text != parser_text:
2898 print(repr(expected_text))
2899 print(repr(parser_text))
2900 for char1, char2 in zip(expected_text, parser_text):
2901 if char1 != char2:
2902 print('first diff: %r %r' % (char1, char2))
2903 break
2904 tester.assertEqual(expected_text, parser_text)
2905
2906 def test_format(self, tester):
2907 parser = self._get_parser(tester)
2908 format = getattr(parser, 'format_%s' % self.func_suffix)
2909 self._test(tester, format())
2910
2911 def test_print(self, tester):
2912 parser = self._get_parser(tester)
2913 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2914 old_stream = getattr(sys, self.std_name)
Benjamin Petersonb48af542010-04-11 20:43:16 +00002915 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002916 try:
2917 print_()
2918 parser_text = getattr(sys, self.std_name).getvalue()
2919 finally:
2920 setattr(sys, self.std_name, old_stream)
2921 self._test(tester, parser_text)
2922
2923 def test_print_file(self, tester):
2924 parser = self._get_parser(tester)
2925 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Benjamin Petersonb48af542010-04-11 20:43:16 +00002926 sfile = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002927 print_(sfile)
2928 parser_text = sfile.getvalue()
2929 self._test(tester, parser_text)
2930
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002931 # add tests for {format,print}_{usage,help}
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002932 for func_suffix, std_name in [('usage', 'stdout'),
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002933 ('help', 'stdout')]:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002934 AddTests(cls, func_suffix, std_name)
2935
2936bases = TestCase,
2937HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2938
2939
2940class TestHelpBiggerOptionals(HelpTestCase):
2941 """Make sure that argument help aligns when options are longer"""
2942
2943 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002944 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002945 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002946 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002947 Sig('-x', action='store_true', help='X HELP'),
2948 Sig('--y', help='Y HELP'),
2949 Sig('foo', help='FOO HELP'),
2950 Sig('bar', help='BAR HELP'),
2951 ]
2952 argument_group_signatures = []
2953 usage = '''\
2954 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2955 '''
2956 help = usage + '''\
2957
2958 DESCRIPTION
2959
2960 positional arguments:
2961 foo FOO HELP
2962 bar BAR HELP
2963
2964 optional arguments:
2965 -h, --help show this help message and exit
2966 -v, --version show program's version number and exit
2967 -x X HELP
2968 --y Y Y HELP
2969
2970 EPILOG
2971 '''
2972 version = '''\
2973 0.1
2974 '''
2975
Serhiy Storchakaf4511122014-01-09 23:14:27 +02002976class TestShortColumns(HelpTestCase):
2977 '''Test extremely small number of columns.
2978
2979 TestCase prevents "COLUMNS" from being too small in the tests themselves,
2980 but we don't want any exceptions thrown in such case. Only ugly representation.
2981 '''
2982 def setUp(self):
2983 env = support.EnvironmentVarGuard()
2984 env.set("COLUMNS", '15')
2985 self.addCleanup(env.__exit__)
2986
2987 parser_signature = TestHelpBiggerOptionals.parser_signature
2988 argument_signatures = TestHelpBiggerOptionals.argument_signatures
2989 argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures
2990 usage = '''\
2991 usage: PROG
2992 [-h]
2993 [-v]
2994 [-x]
2995 [--y Y]
2996 foo
2997 bar
2998 '''
2999 help = usage + '''\
3000
3001 DESCRIPTION
3002
3003 positional arguments:
3004 foo
3005 FOO HELP
3006 bar
3007 BAR HELP
3008
3009 optional arguments:
3010 -h, --help
3011 show this
3012 help
3013 message and
3014 exit
3015 -v, --version
3016 show
3017 program's
3018 version
3019 number and
3020 exit
3021 -x
3022 X HELP
3023 --y Y
3024 Y HELP
3025
3026 EPILOG
3027 '''
3028 version = TestHelpBiggerOptionals.version
3029
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003030
3031class TestHelpBiggerOptionalGroups(HelpTestCase):
3032 """Make sure that argument help aligns when options are longer"""
3033
3034 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003035 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003036 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003037 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003038 Sig('-x', action='store_true', help='X HELP'),
3039 Sig('--y', help='Y HELP'),
3040 Sig('foo', help='FOO HELP'),
3041 Sig('bar', help='BAR HELP'),
3042 ]
3043 argument_group_signatures = [
3044 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
3045 Sig('baz', help='BAZ HELP'),
3046 Sig('-z', nargs='+', help='Z HELP')]),
3047 ]
3048 usage = '''\
3049 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
3050 '''
3051 help = usage + '''\
3052
3053 DESCRIPTION
3054
3055 positional arguments:
3056 foo FOO HELP
3057 bar BAR HELP
3058
3059 optional arguments:
3060 -h, --help show this help message and exit
3061 -v, --version show program's version number and exit
3062 -x X HELP
3063 --y Y Y HELP
3064
3065 GROUP TITLE:
3066 GROUP DESCRIPTION
3067
3068 baz BAZ HELP
3069 -z Z [Z ...] Z HELP
3070
3071 EPILOG
3072 '''
3073 version = '''\
3074 0.1
3075 '''
3076
3077
3078class TestHelpBiggerPositionals(HelpTestCase):
3079 """Make sure that help aligns when arguments are longer"""
3080
3081 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
3082 argument_signatures = [
3083 Sig('-x', action='store_true', help='X HELP'),
3084 Sig('--y', help='Y HELP'),
3085 Sig('ekiekiekifekang', help='EKI HELP'),
3086 Sig('bar', help='BAR HELP'),
3087 ]
3088 argument_group_signatures = []
3089 usage = '''\
3090 usage: USAGE
3091 '''
3092 help = usage + '''\
3093
3094 DESCRIPTION
3095
3096 positional arguments:
3097 ekiekiekifekang EKI HELP
3098 bar BAR HELP
3099
3100 optional arguments:
3101 -h, --help show this help message and exit
3102 -x X HELP
3103 --y Y Y HELP
3104 '''
3105
3106 version = ''
3107
3108
3109class TestHelpReformatting(HelpTestCase):
3110 """Make sure that text after short names starts on the first line"""
3111
3112 parser_signature = Sig(
3113 prog='PROG',
3114 description=' oddly formatted\n'
3115 'description\n'
3116 '\n'
3117 'that is so long that it should go onto multiple '
3118 'lines when wrapped')
3119 argument_signatures = [
3120 Sig('-x', metavar='XX', help='oddly\n'
3121 ' formatted -x help'),
3122 Sig('y', metavar='yyy', help='normal y help'),
3123 ]
3124 argument_group_signatures = [
3125 (Sig('title', description='\n'
3126 ' oddly formatted group\n'
3127 '\n'
3128 'description'),
3129 [Sig('-a', action='store_true',
3130 help=' oddly \n'
3131 'formatted -a help \n'
3132 ' again, so long that it should be wrapped over '
3133 'multiple lines')]),
3134 ]
3135 usage = '''\
3136 usage: PROG [-h] [-x XX] [-a] yyy
3137 '''
3138 help = usage + '''\
3139
3140 oddly formatted description that is so long that it should go onto \
3141multiple
3142 lines when wrapped
3143
3144 positional arguments:
3145 yyy normal y help
3146
3147 optional arguments:
3148 -h, --help show this help message and exit
3149 -x XX oddly formatted -x help
3150
3151 title:
3152 oddly formatted group description
3153
3154 -a oddly formatted -a help again, so long that it should \
3155be wrapped
3156 over multiple lines
3157 '''
3158 version = ''
3159
3160
3161class TestHelpWrappingShortNames(HelpTestCase):
3162 """Make sure that text after short names starts on the first line"""
3163
3164 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3165 argument_signatures = [
3166 Sig('-x', metavar='XX', help='XHH HX' * 20),
3167 Sig('y', metavar='yyy', help='YH YH' * 20),
3168 ]
3169 argument_group_signatures = [
3170 (Sig('ALPHAS'), [
3171 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3172 ]
3173 usage = '''\
3174 usage: PROG [-h] [-x XX] [-a] yyy
3175 '''
3176 help = usage + '''\
3177
3178 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3179DD DD DD
3180 DD DD DD DD D
3181
3182 positional arguments:
3183 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3184YHYH YHYH
3185 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3186
3187 optional arguments:
3188 -h, --help show this help message and exit
3189 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3190HXXHH HXXHH
3191 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3192
3193 ALPHAS:
3194 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3195HHAAHHH
3196 HHAAHHH HHAAHHH HHA
3197 '''
3198 version = ''
3199
3200
3201class TestHelpWrappingLongNames(HelpTestCase):
3202 """Make sure that text after long names starts on the next line"""
3203
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003204 parser_signature = Sig(usage='USAGE', description= 'D D' * 30)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003205 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003206 Sig('-v', '--version', action='version', version='V V' * 30),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003207 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3208 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3209 ]
3210 argument_group_signatures = [
3211 (Sig('ALPHAS'), [
3212 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3213 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3214 ]
3215 usage = '''\
3216 usage: USAGE
3217 '''
3218 help = usage + '''\
3219
3220 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3221DD DD DD
3222 DD DD DD DD D
3223
3224 positional arguments:
3225 yyyyyyyyyyyyyyyyyyyyyyyyy
3226 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3227YHYH YHYH
3228 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3229
3230 optional arguments:
3231 -h, --help show this help message and exit
3232 -v, --version show program's version number and exit
3233 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3234 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3235XHXH XHXH
3236 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3237
3238 ALPHAS:
3239 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3240 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3241AHAH AHAH
3242 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3243 zzzzzzzzzzzzzzzzzzzzzzzzz
3244 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3245ZHZH ZHZH
3246 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3247 '''
3248 version = '''\
3249 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3250VV VV VV
3251 VV VV VV VV V
3252 '''
3253
3254
3255class TestHelpUsage(HelpTestCase):
3256 """Test basic usage messages"""
3257
3258 parser_signature = Sig(prog='PROG')
3259 argument_signatures = [
3260 Sig('-w', nargs='+', help='w'),
3261 Sig('-x', nargs='*', help='x'),
3262 Sig('a', help='a'),
3263 Sig('b', help='b', nargs=2),
3264 Sig('c', help='c', nargs='?'),
3265 ]
3266 argument_group_signatures = [
3267 (Sig('group'), [
3268 Sig('-y', nargs='?', help='y'),
3269 Sig('-z', nargs=3, help='z'),
3270 Sig('d', help='d', nargs='*'),
3271 Sig('e', help='e', nargs='+'),
3272 ])
3273 ]
3274 usage = '''\
3275 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3276 a b b [c] [d [d ...]] e [e ...]
3277 '''
3278 help = usage + '''\
3279
3280 positional arguments:
3281 a a
3282 b b
3283 c c
3284
3285 optional arguments:
3286 -h, --help show this help message and exit
3287 -w W [W ...] w
3288 -x [X [X ...]] x
3289
3290 group:
3291 -y [Y] y
3292 -z Z Z Z z
3293 d d
3294 e e
3295 '''
3296 version = ''
3297
3298
3299class TestHelpOnlyUserGroups(HelpTestCase):
3300 """Test basic usage messages"""
3301
3302 parser_signature = Sig(prog='PROG', add_help=False)
3303 argument_signatures = []
3304 argument_group_signatures = [
3305 (Sig('xxxx'), [
3306 Sig('-x', help='x'),
3307 Sig('a', help='a'),
3308 ]),
3309 (Sig('yyyy'), [
3310 Sig('b', help='b'),
3311 Sig('-y', help='y'),
3312 ]),
3313 ]
3314 usage = '''\
3315 usage: PROG [-x X] [-y Y] a b
3316 '''
3317 help = usage + '''\
3318
3319 xxxx:
3320 -x X x
3321 a a
3322
3323 yyyy:
3324 b b
3325 -y Y y
3326 '''
3327 version = ''
3328
3329
3330class TestHelpUsageLongProg(HelpTestCase):
3331 """Test usage messages where the prog is long"""
3332
3333 parser_signature = Sig(prog='P' * 60)
3334 argument_signatures = [
3335 Sig('-w', metavar='W'),
3336 Sig('-x', metavar='X'),
3337 Sig('a'),
3338 Sig('b'),
3339 ]
3340 argument_group_signatures = []
3341 usage = '''\
3342 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3343 [-h] [-w W] [-x X] a b
3344 '''
3345 help = usage + '''\
3346
3347 positional arguments:
3348 a
3349 b
3350
3351 optional arguments:
3352 -h, --help show this help message and exit
3353 -w W
3354 -x X
3355 '''
3356 version = ''
3357
3358
3359class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3360 """Test usage messages where the prog is long and the optionals wrap"""
3361
3362 parser_signature = Sig(prog='P' * 60)
3363 argument_signatures = [
3364 Sig('-w', metavar='W' * 25),
3365 Sig('-x', metavar='X' * 25),
3366 Sig('-y', metavar='Y' * 25),
3367 Sig('-z', metavar='Z' * 25),
3368 Sig('a'),
3369 Sig('b'),
3370 ]
3371 argument_group_signatures = []
3372 usage = '''\
3373 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3374 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3375[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3376 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3377 a b
3378 '''
3379 help = usage + '''\
3380
3381 positional arguments:
3382 a
3383 b
3384
3385 optional arguments:
3386 -h, --help show this help message and exit
3387 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3388 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3389 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3390 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3391 '''
3392 version = ''
3393
3394
3395class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3396 """Test usage messages where the prog is long and the positionals wrap"""
3397
3398 parser_signature = Sig(prog='P' * 60, add_help=False)
3399 argument_signatures = [
3400 Sig('a' * 25),
3401 Sig('b' * 25),
3402 Sig('c' * 25),
3403 ]
3404 argument_group_signatures = []
3405 usage = '''\
3406 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3407 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3408 ccccccccccccccccccccccccc
3409 '''
3410 help = usage + '''\
3411
3412 positional arguments:
3413 aaaaaaaaaaaaaaaaaaaaaaaaa
3414 bbbbbbbbbbbbbbbbbbbbbbbbb
3415 ccccccccccccccccccccccccc
3416 '''
3417 version = ''
3418
3419
3420class TestHelpUsageOptionalsWrap(HelpTestCase):
3421 """Test usage messages where the optionals wrap"""
3422
3423 parser_signature = Sig(prog='PROG')
3424 argument_signatures = [
3425 Sig('-w', metavar='W' * 25),
3426 Sig('-x', metavar='X' * 25),
3427 Sig('-y', metavar='Y' * 25),
3428 Sig('-z', metavar='Z' * 25),
3429 Sig('a'),
3430 Sig('b'),
3431 Sig('c'),
3432 ]
3433 argument_group_signatures = []
3434 usage = '''\
3435 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3436[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3437 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3438[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3439 a b c
3440 '''
3441 help = usage + '''\
3442
3443 positional arguments:
3444 a
3445 b
3446 c
3447
3448 optional arguments:
3449 -h, --help show this help message and exit
3450 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3451 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3452 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3453 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3454 '''
3455 version = ''
3456
3457
3458class TestHelpUsagePositionalsWrap(HelpTestCase):
3459 """Test usage messages where the positionals wrap"""
3460
3461 parser_signature = Sig(prog='PROG')
3462 argument_signatures = [
3463 Sig('-x'),
3464 Sig('-y'),
3465 Sig('-z'),
3466 Sig('a' * 25),
3467 Sig('b' * 25),
3468 Sig('c' * 25),
3469 ]
3470 argument_group_signatures = []
3471 usage = '''\
3472 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3473 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3474 ccccccccccccccccccccccccc
3475 '''
3476 help = usage + '''\
3477
3478 positional arguments:
3479 aaaaaaaaaaaaaaaaaaaaaaaaa
3480 bbbbbbbbbbbbbbbbbbbbbbbbb
3481 ccccccccccccccccccccccccc
3482
3483 optional arguments:
3484 -h, --help show this help message and exit
3485 -x X
3486 -y Y
3487 -z Z
3488 '''
3489 version = ''
3490
3491
3492class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3493 """Test usage messages where the optionals and positionals wrap"""
3494
3495 parser_signature = Sig(prog='PROG')
3496 argument_signatures = [
3497 Sig('-x', metavar='X' * 25),
3498 Sig('-y', metavar='Y' * 25),
3499 Sig('-z', metavar='Z' * 25),
3500 Sig('a' * 25),
3501 Sig('b' * 25),
3502 Sig('c' * 25),
3503 ]
3504 argument_group_signatures = []
3505 usage = '''\
3506 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3507[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3508 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3509 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3510 ccccccccccccccccccccccccc
3511 '''
3512 help = usage + '''\
3513
3514 positional arguments:
3515 aaaaaaaaaaaaaaaaaaaaaaaaa
3516 bbbbbbbbbbbbbbbbbbbbbbbbb
3517 ccccccccccccccccccccccccc
3518
3519 optional arguments:
3520 -h, --help show this help message and exit
3521 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3522 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3523 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3524 '''
3525 version = ''
3526
3527
3528class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3529 """Test usage messages where there are only optionals and they wrap"""
3530
3531 parser_signature = Sig(prog='PROG')
3532 argument_signatures = [
3533 Sig('-x', metavar='X' * 25),
3534 Sig('-y', metavar='Y' * 25),
3535 Sig('-z', metavar='Z' * 25),
3536 ]
3537 argument_group_signatures = []
3538 usage = '''\
3539 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3540[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3541 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3542 '''
3543 help = usage + '''\
3544
3545 optional arguments:
3546 -h, --help show this help message and exit
3547 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3548 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3549 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3550 '''
3551 version = ''
3552
3553
3554class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3555 """Test usage messages where there are only positionals and they wrap"""
3556
3557 parser_signature = Sig(prog='PROG', add_help=False)
3558 argument_signatures = [
3559 Sig('a' * 25),
3560 Sig('b' * 25),
3561 Sig('c' * 25),
3562 ]
3563 argument_group_signatures = []
3564 usage = '''\
3565 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3566 ccccccccccccccccccccccccc
3567 '''
3568 help = usage + '''\
3569
3570 positional arguments:
3571 aaaaaaaaaaaaaaaaaaaaaaaaa
3572 bbbbbbbbbbbbbbbbbbbbbbbbb
3573 ccccccccccccccccccccccccc
3574 '''
3575 version = ''
3576
3577
3578class TestHelpVariableExpansion(HelpTestCase):
3579 """Test that variables are expanded properly in help messages"""
3580
3581 parser_signature = Sig(prog='PROG')
3582 argument_signatures = [
3583 Sig('-x', type=int,
3584 help='x %(prog)s %(default)s %(type)s %%'),
3585 Sig('-y', action='store_const', default=42, const='XXX',
3586 help='y %(prog)s %(default)s %(const)s'),
3587 Sig('--foo', choices='abc',
3588 help='foo %(prog)s %(default)s %(choices)s'),
3589 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3590 help='bar %(prog)s %(default)s %(dest)s'),
3591 Sig('spam', help='spam %(prog)s %(default)s'),
3592 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3593 ]
3594 argument_group_signatures = [
3595 (Sig('group'), [
3596 Sig('-a', help='a %(prog)s %(default)s'),
3597 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3598 ])
3599 ]
3600 usage = ('''\
3601 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3602 spam badger
3603 ''')
3604 help = usage + '''\
3605
3606 positional arguments:
3607 spam spam PROG None
3608 badger badger PROG 0.5
3609
3610 optional arguments:
3611 -h, --help show this help message and exit
3612 -x X x PROG None int %
3613 -y y PROG 42 XXX
3614 --foo {a,b,c} foo PROG None a, b, c
3615 --bar BBB bar PROG baz bar
3616
3617 group:
3618 -a A a PROG None
3619 -b B b PROG -1
3620 '''
3621 version = ''
3622
3623
3624class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3625 """Test that variables are expanded properly when usage= is present"""
3626
3627 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3628 argument_signatures = []
3629 argument_group_signatures = []
3630 usage = ('''\
3631 usage: PROG FOO
3632 ''')
3633 help = usage + '''\
3634
3635 optional arguments:
3636 -h, --help show this help message and exit
3637 '''
3638 version = ''
3639
3640
3641class TestHelpVariableExpansionNoArguments(HelpTestCase):
3642 """Test that variables are expanded properly with no arguments"""
3643
3644 parser_signature = Sig(prog='PROG', add_help=False)
3645 argument_signatures = []
3646 argument_group_signatures = []
3647 usage = ('''\
3648 usage: PROG
3649 ''')
3650 help = usage
3651 version = ''
3652
3653
3654class TestHelpSuppressUsage(HelpTestCase):
3655 """Test that items can be suppressed in usage messages"""
3656
3657 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3658 argument_signatures = [
3659 Sig('--foo', help='foo help'),
3660 Sig('spam', help='spam help'),
3661 ]
3662 argument_group_signatures = []
3663 help = '''\
3664 positional arguments:
3665 spam spam help
3666
3667 optional arguments:
3668 -h, --help show this help message and exit
3669 --foo FOO foo help
3670 '''
3671 usage = ''
3672 version = ''
3673
3674
3675class TestHelpSuppressOptional(HelpTestCase):
3676 """Test that optional arguments can be suppressed in help messages"""
3677
3678 parser_signature = Sig(prog='PROG', add_help=False)
3679 argument_signatures = [
3680 Sig('--foo', help=argparse.SUPPRESS),
3681 Sig('spam', help='spam help'),
3682 ]
3683 argument_group_signatures = []
3684 usage = '''\
3685 usage: PROG spam
3686 '''
3687 help = usage + '''\
3688
3689 positional arguments:
3690 spam spam help
3691 '''
3692 version = ''
3693
3694
3695class TestHelpSuppressOptionalGroup(HelpTestCase):
3696 """Test that optional groups can be suppressed in help messages"""
3697
3698 parser_signature = Sig(prog='PROG')
3699 argument_signatures = [
3700 Sig('--foo', help='foo help'),
3701 Sig('spam', help='spam help'),
3702 ]
3703 argument_group_signatures = [
3704 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3705 ]
3706 usage = '''\
3707 usage: PROG [-h] [--foo FOO] spam
3708 '''
3709 help = usage + '''\
3710
3711 positional arguments:
3712 spam spam help
3713
3714 optional arguments:
3715 -h, --help show this help message and exit
3716 --foo FOO foo help
3717 '''
3718 version = ''
3719
3720
3721class TestHelpSuppressPositional(HelpTestCase):
3722 """Test that positional arguments can be suppressed in help messages"""
3723
3724 parser_signature = Sig(prog='PROG')
3725 argument_signatures = [
3726 Sig('--foo', help='foo help'),
3727 Sig('spam', help=argparse.SUPPRESS),
3728 ]
3729 argument_group_signatures = []
3730 usage = '''\
3731 usage: PROG [-h] [--foo FOO]
3732 '''
3733 help = usage + '''\
3734
3735 optional arguments:
3736 -h, --help show this help message and exit
3737 --foo FOO foo help
3738 '''
3739 version = ''
3740
3741
3742class TestHelpRequiredOptional(HelpTestCase):
3743 """Test that required options don't look optional"""
3744
3745 parser_signature = Sig(prog='PROG')
3746 argument_signatures = [
3747 Sig('--foo', required=True, help='foo help'),
3748 ]
3749 argument_group_signatures = []
3750 usage = '''\
3751 usage: PROG [-h] --foo FOO
3752 '''
3753 help = usage + '''\
3754
3755 optional arguments:
3756 -h, --help show this help message and exit
3757 --foo FOO foo help
3758 '''
3759 version = ''
3760
3761
3762class TestHelpAlternatePrefixChars(HelpTestCase):
3763 """Test that options display with different prefix characters"""
3764
3765 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3766 argument_signatures = [
3767 Sig('^^foo', action='store_true', help='foo help'),
3768 Sig(';b', ';;bar', help='bar help'),
3769 ]
3770 argument_group_signatures = []
3771 usage = '''\
3772 usage: PROG [^^foo] [;b BAR]
3773 '''
3774 help = usage + '''\
3775
3776 optional arguments:
3777 ^^foo foo help
3778 ;b BAR, ;;bar BAR bar help
3779 '''
3780 version = ''
3781
3782
3783class TestHelpNoHelpOptional(HelpTestCase):
3784 """Test that the --help argument can be suppressed help messages"""
3785
3786 parser_signature = Sig(prog='PROG', add_help=False)
3787 argument_signatures = [
3788 Sig('--foo', help='foo help'),
3789 Sig('spam', help='spam help'),
3790 ]
3791 argument_group_signatures = []
3792 usage = '''\
3793 usage: PROG [--foo FOO] spam
3794 '''
3795 help = usage + '''\
3796
3797 positional arguments:
3798 spam spam help
3799
3800 optional arguments:
3801 --foo FOO foo help
3802 '''
3803 version = ''
3804
3805
3806class TestHelpVersionOptional(HelpTestCase):
3807 """Test that the --version argument can be suppressed help messages"""
3808
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003809 parser_signature = Sig(prog='PROG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003810 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003811 Sig('-v', '--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003812 Sig('--foo', help='foo help'),
3813 Sig('spam', help='spam help'),
3814 ]
3815 argument_group_signatures = []
3816 usage = '''\
3817 usage: PROG [-h] [-v] [--foo FOO] spam
3818 '''
3819 help = usage + '''\
3820
3821 positional arguments:
3822 spam spam help
3823
3824 optional arguments:
3825 -h, --help show this help message and exit
3826 -v, --version show program's version number and exit
3827 --foo FOO foo help
3828 '''
3829 version = '''\
3830 1.0
3831 '''
3832
3833
3834class TestHelpNone(HelpTestCase):
3835 """Test that no errors occur if no help is specified"""
3836
3837 parser_signature = Sig(prog='PROG')
3838 argument_signatures = [
3839 Sig('--foo'),
3840 Sig('spam'),
3841 ]
3842 argument_group_signatures = []
3843 usage = '''\
3844 usage: PROG [-h] [--foo FOO] spam
3845 '''
3846 help = usage + '''\
3847
3848 positional arguments:
3849 spam
3850
3851 optional arguments:
3852 -h, --help show this help message and exit
3853 --foo FOO
3854 '''
3855 version = ''
3856
3857
3858class TestHelpTupleMetavar(HelpTestCase):
3859 """Test specifying metavar as a tuple"""
3860
3861 parser_signature = Sig(prog='PROG')
3862 argument_signatures = [
3863 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3864 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3865 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3866 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3867 ]
3868 argument_group_signatures = []
3869 usage = '''\
3870 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3871[-z [Z1]]
3872 '''
3873 help = usage + '''\
3874
3875 optional arguments:
3876 -h, --help show this help message and exit
3877 -w W1 [W2 ...] w
3878 -x [X1 [X2 ...]] x
3879 -y Y1 Y2 Y3 y
3880 -z [Z1] z
3881 '''
3882 version = ''
3883
3884
3885class TestHelpRawText(HelpTestCase):
3886 """Test the RawTextHelpFormatter"""
3887
3888 parser_signature = Sig(
3889 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3890 description='Keep the formatting\n'
3891 ' exactly as it is written\n'
3892 '\n'
3893 'here\n')
3894
3895 argument_signatures = [
3896 Sig('--foo', help=' foo help should also\n'
3897 'appear as given here'),
3898 Sig('spam', help='spam help'),
3899 ]
3900 argument_group_signatures = [
3901 (Sig('title', description=' This text\n'
3902 ' should be indented\n'
3903 ' exactly like it is here\n'),
3904 [Sig('--bar', help='bar help')]),
3905 ]
3906 usage = '''\
3907 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3908 '''
3909 help = usage + '''\
3910
3911 Keep the formatting
3912 exactly as it is written
3913
3914 here
3915
3916 positional arguments:
3917 spam spam help
3918
3919 optional arguments:
3920 -h, --help show this help message and exit
3921 --foo FOO foo help should also
3922 appear as given here
3923
3924 title:
3925 This text
3926 should be indented
3927 exactly like it is here
3928
3929 --bar BAR bar help
3930 '''
3931 version = ''
3932
3933
3934class TestHelpRawDescription(HelpTestCase):
3935 """Test the RawTextHelpFormatter"""
3936
3937 parser_signature = Sig(
3938 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3939 description='Keep the formatting\n'
3940 ' exactly as it is written\n'
3941 '\n'
3942 'here\n')
3943
3944 argument_signatures = [
3945 Sig('--foo', help=' foo help should not\n'
3946 ' retain this odd formatting'),
3947 Sig('spam', help='spam help'),
3948 ]
3949 argument_group_signatures = [
3950 (Sig('title', description=' This text\n'
3951 ' should be indented\n'
3952 ' exactly like it is here\n'),
3953 [Sig('--bar', help='bar help')]),
3954 ]
3955 usage = '''\
3956 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3957 '''
3958 help = usage + '''\
3959
3960 Keep the formatting
3961 exactly as it is written
3962
3963 here
3964
3965 positional arguments:
3966 spam spam help
3967
3968 optional arguments:
3969 -h, --help show this help message and exit
3970 --foo FOO foo help should not retain this odd formatting
3971
3972 title:
3973 This text
3974 should be indented
3975 exactly like it is here
3976
3977 --bar BAR bar help
3978 '''
3979 version = ''
3980
3981
3982class TestHelpArgumentDefaults(HelpTestCase):
3983 """Test the ArgumentDefaultsHelpFormatter"""
3984
3985 parser_signature = Sig(
3986 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3987 description='description')
3988
3989 argument_signatures = [
3990 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3991 Sig('--bar', action='store_true', help='bar help'),
3992 Sig('spam', help='spam help'),
3993 Sig('badger', nargs='?', default='wooden', help='badger help'),
3994 ]
3995 argument_group_signatures = [
3996 (Sig('title', description='description'),
3997 [Sig('--baz', type=int, default=42, help='baz help')]),
3998 ]
3999 usage = '''\
4000 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
4001 '''
4002 help = usage + '''\
4003
4004 description
4005
4006 positional arguments:
4007 spam spam help
4008 badger badger help (default: wooden)
4009
4010 optional arguments:
4011 -h, --help show this help message and exit
4012 --foo FOO foo help - oh and by the way, None
4013 --bar bar help (default: False)
4014
4015 title:
4016 description
4017
4018 --baz BAZ baz help (default: 42)
4019 '''
4020 version = ''
4021
Steven Bethard50fe5932010-05-24 03:47:38 +00004022class TestHelpVersionAction(HelpTestCase):
4023 """Test the default help for the version action"""
4024
4025 parser_signature = Sig(prog='PROG', description='description')
4026 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
4027 argument_group_signatures = []
4028 usage = '''\
4029 usage: PROG [-h] [-V]
4030 '''
4031 help = usage + '''\
4032
4033 description
4034
4035 optional arguments:
4036 -h, --help show this help message and exit
4037 -V, --version show program's version number and exit
4038 '''
4039 version = ''
4040
Steven Bethard8a6a1982011-03-27 13:53:53 +02004041class TestHelpSubparsersOrdering(HelpTestCase):
4042 """Test ordering of subcommands in help matches the code"""
4043 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004044 description='display some subcommands')
4045 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004046
4047 subparsers_signatures = [Sig(name=name)
4048 for name in ('a', 'b', 'c', 'd', 'e')]
4049
4050 usage = '''\
4051 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4052 '''
4053
4054 help = usage + '''\
4055
4056 display some subcommands
4057
4058 positional arguments:
4059 {a,b,c,d,e}
4060
4061 optional arguments:
4062 -h, --help show this help message and exit
4063 -v, --version show program's version number and exit
4064 '''
4065
4066 version = '''\
4067 0.1
4068 '''
4069
4070class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4071 """Test ordering of subcommands in help matches the code"""
4072 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004073 description='display some subcommands')
4074 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004075
4076 subcommand_data = (('a', 'a subcommand help'),
4077 ('b', 'b subcommand help'),
4078 ('c', 'c subcommand help'),
4079 ('d', 'd subcommand help'),
4080 ('e', 'e subcommand help'),
4081 )
4082
4083 subparsers_signatures = [Sig(name=name, help=help)
4084 for name, help in subcommand_data]
4085
4086 usage = '''\
4087 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4088 '''
4089
4090 help = usage + '''\
4091
4092 display some subcommands
4093
4094 positional arguments:
4095 {a,b,c,d,e}
4096 a a subcommand help
4097 b b subcommand help
4098 c c subcommand help
4099 d d subcommand help
4100 e e subcommand help
4101
4102 optional arguments:
4103 -h, --help show this help message and exit
4104 -v, --version show program's version number and exit
4105 '''
4106
4107 version = '''\
4108 0.1
4109 '''
4110
4111
Steven Bethard0331e902011-03-26 14:48:04 +01004112
4113class TestHelpMetavarTypeFormatter(HelpTestCase):
4114 """"""
4115
4116 def custom_type(string):
4117 return string
4118
4119 parser_signature = Sig(prog='PROG', description='description',
4120 formatter_class=argparse.MetavarTypeHelpFormatter)
4121 argument_signatures = [Sig('a', type=int),
4122 Sig('-b', type=custom_type),
4123 Sig('-c', type=float, metavar='SOME FLOAT')]
4124 argument_group_signatures = []
4125 usage = '''\
4126 usage: PROG [-h] [-b custom_type] [-c SOME FLOAT] int
4127 '''
4128 help = usage + '''\
4129
4130 description
4131
4132 positional arguments:
4133 int
4134
4135 optional arguments:
4136 -h, --help show this help message and exit
4137 -b custom_type
4138 -c SOME FLOAT
4139 '''
4140 version = ''
4141
4142
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004143# =====================================
4144# Optional/Positional constructor tests
4145# =====================================
4146
4147class TestInvalidArgumentConstructors(TestCase):
4148 """Test a bunch of invalid Argument constructors"""
4149
4150 def assertTypeError(self, *args, **kwargs):
4151 parser = argparse.ArgumentParser()
4152 self.assertRaises(TypeError, parser.add_argument,
4153 *args, **kwargs)
4154
4155 def assertValueError(self, *args, **kwargs):
4156 parser = argparse.ArgumentParser()
4157 self.assertRaises(ValueError, parser.add_argument,
4158 *args, **kwargs)
4159
4160 def test_invalid_keyword_arguments(self):
4161 self.assertTypeError('-x', bar=None)
4162 self.assertTypeError('-y', callback='foo')
4163 self.assertTypeError('-y', callback_args=())
4164 self.assertTypeError('-y', callback_kwargs={})
4165
4166 def test_missing_destination(self):
4167 self.assertTypeError()
4168 for action in ['append', 'store']:
4169 self.assertTypeError(action=action)
4170
4171 def test_invalid_option_strings(self):
4172 self.assertValueError('--')
4173 self.assertValueError('---')
4174
4175 def test_invalid_type(self):
4176 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004177 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004178
4179 def test_invalid_action(self):
4180 self.assertValueError('-x', action='foo')
4181 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004182 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004183 parser = argparse.ArgumentParser()
4184 try:
4185 parser.add_argument("--foo", action="store-true")
4186 except ValueError:
4187 e = sys.exc_info()[1]
4188 expected = 'unknown action'
4189 msg = 'expected %r, found %r' % (expected, e)
4190 self.assertTrue(expected in str(e), msg)
4191
4192 def test_multiple_dest(self):
4193 parser = argparse.ArgumentParser()
4194 parser.add_argument(dest='foo')
4195 try:
4196 parser.add_argument('bar', dest='baz')
4197 except ValueError:
4198 e = sys.exc_info()[1]
4199 expected = 'dest supplied twice for positional argument'
4200 msg = 'expected %r, found %r' % (expected, e)
4201 self.assertTrue(expected in str(e), msg)
4202
4203 def test_no_argument_actions(self):
4204 for action in ['store_const', 'store_true', 'store_false',
4205 'append_const', 'count']:
4206 for attrs in [dict(type=int), dict(nargs='+'),
4207 dict(choices='ab')]:
4208 self.assertTypeError('-x', action=action, **attrs)
4209
4210 def test_no_argument_no_const_actions(self):
4211 # options with zero arguments
4212 for action in ['store_true', 'store_false', 'count']:
4213
4214 # const is always disallowed
4215 self.assertTypeError('-x', const='foo', action=action)
4216
4217 # nargs is always disallowed
4218 self.assertTypeError('-x', nargs='*', action=action)
4219
4220 def test_more_than_one_argument_actions(self):
4221 for action in ['store', 'append']:
4222
4223 # nargs=0 is disallowed
4224 self.assertValueError('-x', nargs=0, action=action)
4225 self.assertValueError('spam', nargs=0, action=action)
4226
4227 # const is disallowed with non-optional arguments
4228 for nargs in [1, '*', '+']:
4229 self.assertValueError('-x', const='foo',
4230 nargs=nargs, action=action)
4231 self.assertValueError('spam', const='foo',
4232 nargs=nargs, action=action)
4233
4234 def test_required_const_actions(self):
4235 for action in ['store_const', 'append_const']:
4236
4237 # nargs is always disallowed
4238 self.assertTypeError('-x', nargs='+', action=action)
4239
4240 def test_parsers_action_missing_params(self):
4241 self.assertTypeError('command', action='parsers')
4242 self.assertTypeError('command', action='parsers', prog='PROG')
4243 self.assertTypeError('command', action='parsers',
4244 parser_class=argparse.ArgumentParser)
4245
4246 def test_required_positional(self):
4247 self.assertTypeError('foo', required=True)
4248
4249 def test_user_defined_action(self):
4250
4251 class Success(Exception):
4252 pass
4253
4254 class Action(object):
4255
4256 def __init__(self,
4257 option_strings,
4258 dest,
4259 const,
4260 default,
4261 required=False):
4262 if dest == 'spam':
4263 if const is Success:
4264 if default is Success:
4265 raise Success()
4266
4267 def __call__(self, *args, **kwargs):
4268 pass
4269
4270 parser = argparse.ArgumentParser()
4271 self.assertRaises(Success, parser.add_argument, '--spam',
4272 action=Action, default=Success, const=Success)
4273 self.assertRaises(Success, parser.add_argument, 'spam',
4274 action=Action, default=Success, const=Success)
4275
4276# ================================
4277# Actions returned by add_argument
4278# ================================
4279
4280class TestActionsReturned(TestCase):
4281
4282 def test_dest(self):
4283 parser = argparse.ArgumentParser()
4284 action = parser.add_argument('--foo')
4285 self.assertEqual(action.dest, 'foo')
4286 action = parser.add_argument('-b', '--bar')
4287 self.assertEqual(action.dest, 'bar')
4288 action = parser.add_argument('-x', '-y')
4289 self.assertEqual(action.dest, 'x')
4290
4291 def test_misc(self):
4292 parser = argparse.ArgumentParser()
4293 action = parser.add_argument('--foo', nargs='?', const=42,
4294 default=84, type=int, choices=[1, 2],
4295 help='FOO', metavar='BAR', dest='baz')
4296 self.assertEqual(action.nargs, '?')
4297 self.assertEqual(action.const, 42)
4298 self.assertEqual(action.default, 84)
4299 self.assertEqual(action.type, int)
4300 self.assertEqual(action.choices, [1, 2])
4301 self.assertEqual(action.help, 'FOO')
4302 self.assertEqual(action.metavar, 'BAR')
4303 self.assertEqual(action.dest, 'baz')
4304
4305
4306# ================================
4307# Argument conflict handling tests
4308# ================================
4309
4310class TestConflictHandling(TestCase):
4311
4312 def test_bad_type(self):
4313 self.assertRaises(ValueError, argparse.ArgumentParser,
4314 conflict_handler='foo')
4315
4316 def test_conflict_error(self):
4317 parser = argparse.ArgumentParser()
4318 parser.add_argument('-x')
4319 self.assertRaises(argparse.ArgumentError,
4320 parser.add_argument, '-x')
4321 parser.add_argument('--spam')
4322 self.assertRaises(argparse.ArgumentError,
4323 parser.add_argument, '--spam')
4324
4325 def test_resolve_error(self):
4326 get_parser = argparse.ArgumentParser
4327 parser = get_parser(prog='PROG', conflict_handler='resolve')
4328
4329 parser.add_argument('-x', help='OLD X')
4330 parser.add_argument('-x', help='NEW X')
4331 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4332 usage: PROG [-h] [-x X]
4333
4334 optional arguments:
4335 -h, --help show this help message and exit
4336 -x X NEW X
4337 '''))
4338
4339 parser.add_argument('--spam', metavar='OLD_SPAM')
4340 parser.add_argument('--spam', metavar='NEW_SPAM')
4341 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4342 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4343
4344 optional arguments:
4345 -h, --help show this help message and exit
4346 -x X NEW X
4347 --spam NEW_SPAM
4348 '''))
4349
4350
4351# =============================
4352# Help and Version option tests
4353# =============================
4354
4355class TestOptionalsHelpVersionActions(TestCase):
4356 """Test the help and version actions"""
4357
4358 def _get_error(self, func, *args, **kwargs):
4359 try:
4360 func(*args, **kwargs)
4361 except ArgumentParserError:
4362 return sys.exc_info()[1]
4363 else:
4364 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4365
4366 def assertPrintHelpExit(self, parser, args_str):
4367 self.assertEqual(
4368 parser.format_help(),
4369 self._get_error(parser.parse_args, args_str.split()).stdout)
4370
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004371 def assertArgumentParserError(self, parser, *args):
4372 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4373
4374 def test_version(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004375 parser = ErrorRaisingArgumentParser()
4376 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004377 self.assertPrintHelpExit(parser, '-h')
4378 self.assertPrintHelpExit(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004379 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004380
4381 def test_version_format(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004382 parser = ErrorRaisingArgumentParser(prog='PPP')
4383 parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004384 msg = self._get_error(parser.parse_args, ['-v']).stderr
4385 self.assertEqual('PPP 3.5\n', msg)
4386
4387 def test_version_no_help(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004388 parser = ErrorRaisingArgumentParser(add_help=False)
4389 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004390 self.assertArgumentParserError(parser, '-h')
4391 self.assertArgumentParserError(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004392 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004393
4394 def test_version_action(self):
4395 parser = ErrorRaisingArgumentParser(prog='XXX')
4396 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4397 msg = self._get_error(parser.parse_args, ['-V']).stderr
4398 self.assertEqual('XXX 3.7\n', msg)
4399
4400 def test_no_help(self):
4401 parser = ErrorRaisingArgumentParser(add_help=False)
4402 self.assertArgumentParserError(parser, '-h')
4403 self.assertArgumentParserError(parser, '--help')
4404 self.assertArgumentParserError(parser, '-v')
4405 self.assertArgumentParserError(parser, '--version')
4406
4407 def test_alternate_help_version(self):
4408 parser = ErrorRaisingArgumentParser()
4409 parser.add_argument('-x', action='help')
4410 parser.add_argument('-y', action='version')
4411 self.assertPrintHelpExit(parser, '-x')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004412 self.assertArgumentParserError(parser, '-v')
4413 self.assertArgumentParserError(parser, '--version')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004414 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004415
4416 def test_help_version_extra_arguments(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004417 parser = ErrorRaisingArgumentParser()
4418 parser.add_argument('--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004419 parser.add_argument('-x', action='store_true')
4420 parser.add_argument('y')
4421
4422 # try all combinations of valid prefixes and suffixes
4423 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4424 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4425 for prefix in valid_prefixes:
4426 for suffix in valid_suffixes:
4427 format = '%s %%s %s' % (prefix, suffix)
4428 self.assertPrintHelpExit(parser, format % '-h')
4429 self.assertPrintHelpExit(parser, format % '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004430 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004431
4432
4433# ======================
4434# str() and repr() tests
4435# ======================
4436
4437class TestStrings(TestCase):
4438 """Test str() and repr() on Optionals and Positionals"""
4439
4440 def assertStringEqual(self, obj, result_string):
4441 for func in [str, repr]:
4442 self.assertEqual(func(obj), result_string)
4443
4444 def test_optional(self):
4445 option = argparse.Action(
4446 option_strings=['--foo', '-a', '-b'],
4447 dest='b',
4448 type='int',
4449 nargs='+',
4450 default=42,
4451 choices=[1, 2, 3],
4452 help='HELP',
4453 metavar='METAVAR')
4454 string = (
4455 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4456 "nargs='+', const=None, default=42, type='int', "
4457 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4458 self.assertStringEqual(option, string)
4459
4460 def test_argument(self):
4461 argument = argparse.Action(
4462 option_strings=[],
4463 dest='x',
4464 type=float,
4465 nargs='?',
4466 default=2.5,
4467 choices=[0.5, 1.5, 2.5],
4468 help='H HH H',
4469 metavar='MV MV MV')
4470 string = (
4471 "Action(option_strings=[], dest='x', nargs='?', "
4472 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4473 "help='H HH H', metavar='MV MV MV')" % float)
4474 self.assertStringEqual(argument, string)
4475
4476 def test_namespace(self):
4477 ns = argparse.Namespace(foo=42, bar='spam')
4478 string = "Namespace(bar='spam', foo=42)"
4479 self.assertStringEqual(ns, string)
4480
4481 def test_parser(self):
4482 parser = argparse.ArgumentParser(prog='PROG')
4483 string = (
4484 "ArgumentParser(prog='PROG', usage=None, description=None, "
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004485 "formatter_class=%r, conflict_handler='error', "
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004486 "add_help=True)" % argparse.HelpFormatter)
4487 self.assertStringEqual(parser, string)
4488
4489# ===============
4490# Namespace tests
4491# ===============
4492
4493class TestNamespace(TestCase):
4494
4495 def test_constructor(self):
4496 ns = argparse.Namespace()
4497 self.assertRaises(AttributeError, getattr, ns, 'x')
4498
4499 ns = argparse.Namespace(a=42, b='spam')
4500 self.assertEqual(ns.a, 42)
4501 self.assertEqual(ns.b, 'spam')
4502
4503 def test_equality(self):
4504 ns1 = argparse.Namespace(a=1, b=2)
4505 ns2 = argparse.Namespace(b=2, a=1)
4506 ns3 = argparse.Namespace(a=1)
4507 ns4 = argparse.Namespace(b=2)
4508
4509 self.assertEqual(ns1, ns2)
4510 self.assertNotEqual(ns1, ns3)
4511 self.assertNotEqual(ns1, ns4)
4512 self.assertNotEqual(ns2, ns3)
4513 self.assertNotEqual(ns2, ns4)
4514 self.assertTrue(ns1 != ns3)
4515 self.assertTrue(ns1 != ns4)
4516 self.assertTrue(ns2 != ns3)
4517 self.assertTrue(ns2 != ns4)
4518
4519
4520# ===================
4521# File encoding tests
4522# ===================
4523
4524class TestEncoding(TestCase):
4525
4526 def _test_module_encoding(self, path):
4527 path, _ = os.path.splitext(path)
4528 path += ".py"
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00004529 with codecs.open(path, 'r', 'utf-8') as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +00004530 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004531
4532 def test_argparse_module_encoding(self):
4533 self._test_module_encoding(argparse.__file__)
4534
4535 def test_test_argparse_module_encoding(self):
4536 self._test_module_encoding(__file__)
4537
4538# ===================
4539# ArgumentError tests
4540# ===================
4541
4542class TestArgumentError(TestCase):
4543
4544 def test_argument_error(self):
4545 msg = "my error here"
4546 error = argparse.ArgumentError(None, msg)
4547 self.assertEqual(str(error), msg)
4548
4549# =======================
4550# ArgumentTypeError tests
4551# =======================
4552
R. David Murray722b5fd2010-11-20 03:48:58 +00004553class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004554
4555 def test_argument_type_error(self):
4556
4557 def spam(string):
4558 raise argparse.ArgumentTypeError('spam!')
4559
4560 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4561 parser.add_argument('x', type=spam)
4562 try:
4563 parser.parse_args(['XXX'])
4564 except ArgumentParserError:
4565 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4566 msg = sys.exc_info()[1].stderr
4567 self.assertEqual(expected, msg)
4568 else:
4569 self.fail()
4570
R David Murrayf97c59a2011-06-09 12:34:07 -04004571# =========================
4572# MessageContentError tests
4573# =========================
4574
4575class TestMessageContentError(TestCase):
4576
4577 def test_missing_argument_name_in_message(self):
4578 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4579 parser.add_argument('req_pos', type=str)
4580 parser.add_argument('-req_opt', type=int, required=True)
4581 parser.add_argument('need_one', type=str, nargs='+')
4582
4583 with self.assertRaises(ArgumentParserError) as cm:
4584 parser.parse_args([])
4585 msg = str(cm.exception)
4586 self.assertRegex(msg, 'req_pos')
4587 self.assertRegex(msg, 'req_opt')
4588 self.assertRegex(msg, 'need_one')
4589 with self.assertRaises(ArgumentParserError) as cm:
4590 parser.parse_args(['myXargument'])
4591 msg = str(cm.exception)
4592 self.assertNotIn(msg, 'req_pos')
4593 self.assertRegex(msg, 'req_opt')
4594 self.assertRegex(msg, 'need_one')
4595 with self.assertRaises(ArgumentParserError) as cm:
4596 parser.parse_args(['myXargument', '-req_opt=1'])
4597 msg = str(cm.exception)
4598 self.assertNotIn(msg, 'req_pos')
4599 self.assertNotIn(msg, 'req_opt')
4600 self.assertRegex(msg, 'need_one')
4601
4602 def test_optional_optional_not_in_message(self):
4603 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4604 parser.add_argument('req_pos', type=str)
4605 parser.add_argument('--req_opt', type=int, required=True)
4606 parser.add_argument('--opt_opt', type=bool, nargs='?',
4607 default=True)
4608 with self.assertRaises(ArgumentParserError) as cm:
4609 parser.parse_args([])
4610 msg = str(cm.exception)
4611 self.assertRegex(msg, 'req_pos')
4612 self.assertRegex(msg, 'req_opt')
4613 self.assertNotIn(msg, 'opt_opt')
4614 with self.assertRaises(ArgumentParserError) as cm:
4615 parser.parse_args(['--req_opt=1'])
4616 msg = str(cm.exception)
4617 self.assertRegex(msg, 'req_pos')
4618 self.assertNotIn(msg, 'req_opt')
4619 self.assertNotIn(msg, 'opt_opt')
4620
4621 def test_optional_positional_not_in_message(self):
4622 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4623 parser.add_argument('req_pos')
4624 parser.add_argument('optional_positional', nargs='?', default='eggs')
4625 with self.assertRaises(ArgumentParserError) as cm:
4626 parser.parse_args([])
4627 msg = str(cm.exception)
4628 self.assertRegex(msg, 'req_pos')
4629 self.assertNotIn(msg, 'optional_positional')
4630
4631
R David Murray6fb8fb12012-08-31 22:45:20 -04004632# ================================================
4633# Check that the type function is called only once
4634# ================================================
4635
4636class TestTypeFunctionCallOnlyOnce(TestCase):
4637
4638 def test_type_function_call_only_once(self):
4639 def spam(string_to_convert):
4640 self.assertEqual(string_to_convert, 'spam!')
4641 return 'foo_converted'
4642
4643 parser = argparse.ArgumentParser()
4644 parser.add_argument('--foo', type=spam, default='bar')
4645 args = parser.parse_args('--foo spam!'.split())
4646 self.assertEqual(NS(foo='foo_converted'), args)
4647
Barry Warsaweaae1b72012-09-12 14:34:50 -04004648# ==================================================================
4649# Check semantics regarding the default argument and type conversion
4650# ==================================================================
R David Murray6fb8fb12012-08-31 22:45:20 -04004651
Barry Warsaweaae1b72012-09-12 14:34:50 -04004652class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray6fb8fb12012-08-31 22:45:20 -04004653
4654 def test_type_function_call_with_non_string_default(self):
4655 def spam(int_to_convert):
4656 self.assertEqual(int_to_convert, 0)
4657 return 'foo_converted'
4658
4659 parser = argparse.ArgumentParser()
4660 parser.add_argument('--foo', type=spam, default=0)
4661 args = parser.parse_args([])
Barry Warsaweaae1b72012-09-12 14:34:50 -04004662 # foo should *not* be converted because its default is not a string.
4663 self.assertEqual(NS(foo=0), args)
4664
4665 def test_type_function_call_with_string_default(self):
4666 def spam(int_to_convert):
4667 return 'foo_converted'
4668
4669 parser = argparse.ArgumentParser()
4670 parser.add_argument('--foo', type=spam, default='0')
4671 args = parser.parse_args([])
4672 # foo is converted because its default is a string.
R David Murray6fb8fb12012-08-31 22:45:20 -04004673 self.assertEqual(NS(foo='foo_converted'), args)
4674
Barry Warsaweaae1b72012-09-12 14:34:50 -04004675 def test_no_double_type_conversion_of_default(self):
4676 def extend(str_to_convert):
4677 return str_to_convert + '*'
4678
4679 parser = argparse.ArgumentParser()
4680 parser.add_argument('--test', type=extend, default='*')
4681 args = parser.parse_args([])
4682 # The test argument will be two stars, one coming from the default
4683 # value and one coming from the type conversion being called exactly
4684 # once.
4685 self.assertEqual(NS(test='**'), args)
4686
Barry Warsaw4b2f9e92012-09-11 22:38:47 -04004687 def test_issue_15906(self):
4688 # Issue #15906: When action='append', type=str, default=[] are
4689 # providing, the dest value was the string representation "[]" when it
4690 # should have been an empty list.
4691 parser = argparse.ArgumentParser()
4692 parser.add_argument('--test', dest='test', type=str,
4693 default=[], action='append')
4694 args = parser.parse_args([])
4695 self.assertEqual(args.test, [])
4696
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004697# ======================
4698# parse_known_args tests
4699# ======================
4700
4701class TestParseKnownArgs(TestCase):
4702
R David Murrayb5228282012-09-08 12:08:01 -04004703 def test_arguments_tuple(self):
4704 parser = argparse.ArgumentParser()
4705 parser.parse_args(())
4706
4707 def test_arguments_list(self):
4708 parser = argparse.ArgumentParser()
4709 parser.parse_args([])
4710
4711 def test_arguments_tuple_positional(self):
4712 parser = argparse.ArgumentParser()
4713 parser.add_argument('x')
4714 parser.parse_args(('x',))
4715
4716 def test_arguments_list_positional(self):
4717 parser = argparse.ArgumentParser()
4718 parser.add_argument('x')
4719 parser.parse_args(['x'])
4720
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004721 def test_optionals(self):
4722 parser = argparse.ArgumentParser()
4723 parser.add_argument('--foo')
4724 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4725 self.assertEqual(NS(foo='F'), args)
4726 self.assertEqual(['--bar', '--baz'], extras)
4727
4728 def test_mixed(self):
4729 parser = argparse.ArgumentParser()
4730 parser.add_argument('-v', nargs='?', const=1, type=int)
4731 parser.add_argument('--spam', action='store_false')
4732 parser.add_argument('badger')
4733
4734 argv = ["B", "C", "--foo", "-v", "3", "4"]
4735 args, extras = parser.parse_known_args(argv)
4736 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4737 self.assertEqual(["C", "--foo", "4"], extras)
4738
Steven Bethard8d9a4622011-03-26 17:33:56 +01004739# ==========================
4740# add_argument metavar tests
4741# ==========================
4742
4743class TestAddArgumentMetavar(TestCase):
4744
4745 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4746
4747 def do_test_no_exception(self, nargs, metavar):
4748 parser = argparse.ArgumentParser()
4749 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4750
4751 def do_test_exception(self, nargs, metavar):
4752 parser = argparse.ArgumentParser()
4753 with self.assertRaises(ValueError) as cm:
4754 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4755 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4756
4757 # Unit tests for different values of metavar when nargs=None
4758
4759 def test_nargs_None_metavar_string(self):
4760 self.do_test_no_exception(nargs=None, metavar="1")
4761
4762 def test_nargs_None_metavar_length0(self):
4763 self.do_test_exception(nargs=None, metavar=tuple())
4764
4765 def test_nargs_None_metavar_length1(self):
4766 self.do_test_no_exception(nargs=None, metavar=("1"))
4767
4768 def test_nargs_None_metavar_length2(self):
4769 self.do_test_exception(nargs=None, metavar=("1", "2"))
4770
4771 def test_nargs_None_metavar_length3(self):
4772 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4773
4774 # Unit tests for different values of metavar when nargs=?
4775
4776 def test_nargs_optional_metavar_string(self):
4777 self.do_test_no_exception(nargs="?", metavar="1")
4778
4779 def test_nargs_optional_metavar_length0(self):
4780 self.do_test_exception(nargs="?", metavar=tuple())
4781
4782 def test_nargs_optional_metavar_length1(self):
4783 self.do_test_no_exception(nargs="?", metavar=("1"))
4784
4785 def test_nargs_optional_metavar_length2(self):
4786 self.do_test_exception(nargs="?", metavar=("1", "2"))
4787
4788 def test_nargs_optional_metavar_length3(self):
4789 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4790
4791 # Unit tests for different values of metavar when nargs=*
4792
4793 def test_nargs_zeroormore_metavar_string(self):
4794 self.do_test_no_exception(nargs="*", metavar="1")
4795
4796 def test_nargs_zeroormore_metavar_length0(self):
4797 self.do_test_exception(nargs="*", metavar=tuple())
4798
4799 def test_nargs_zeroormore_metavar_length1(self):
4800 self.do_test_no_exception(nargs="*", metavar=("1"))
4801
4802 def test_nargs_zeroormore_metavar_length2(self):
4803 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4804
4805 def test_nargs_zeroormore_metavar_length3(self):
4806 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4807
4808 # Unit tests for different values of metavar when nargs=+
4809
4810 def test_nargs_oneormore_metavar_string(self):
4811 self.do_test_no_exception(nargs="+", metavar="1")
4812
4813 def test_nargs_oneormore_metavar_length0(self):
4814 self.do_test_exception(nargs="+", metavar=tuple())
4815
4816 def test_nargs_oneormore_metavar_length1(self):
4817 self.do_test_no_exception(nargs="+", metavar=("1"))
4818
4819 def test_nargs_oneormore_metavar_length2(self):
4820 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4821
4822 def test_nargs_oneormore_metavar_length3(self):
4823 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4824
4825 # Unit tests for different values of metavar when nargs=...
4826
4827 def test_nargs_remainder_metavar_string(self):
4828 self.do_test_no_exception(nargs="...", metavar="1")
4829
4830 def test_nargs_remainder_metavar_length0(self):
4831 self.do_test_no_exception(nargs="...", metavar=tuple())
4832
4833 def test_nargs_remainder_metavar_length1(self):
4834 self.do_test_no_exception(nargs="...", metavar=("1"))
4835
4836 def test_nargs_remainder_metavar_length2(self):
4837 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4838
4839 def test_nargs_remainder_metavar_length3(self):
4840 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4841
4842 # Unit tests for different values of metavar when nargs=A...
4843
4844 def test_nargs_parser_metavar_string(self):
4845 self.do_test_no_exception(nargs="A...", metavar="1")
4846
4847 def test_nargs_parser_metavar_length0(self):
4848 self.do_test_exception(nargs="A...", metavar=tuple())
4849
4850 def test_nargs_parser_metavar_length1(self):
4851 self.do_test_no_exception(nargs="A...", metavar=("1"))
4852
4853 def test_nargs_parser_metavar_length2(self):
4854 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4855
4856 def test_nargs_parser_metavar_length3(self):
4857 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4858
4859 # Unit tests for different values of metavar when nargs=1
4860
4861 def test_nargs_1_metavar_string(self):
4862 self.do_test_no_exception(nargs=1, metavar="1")
4863
4864 def test_nargs_1_metavar_length0(self):
4865 self.do_test_exception(nargs=1, metavar=tuple())
4866
4867 def test_nargs_1_metavar_length1(self):
4868 self.do_test_no_exception(nargs=1, metavar=("1"))
4869
4870 def test_nargs_1_metavar_length2(self):
4871 self.do_test_exception(nargs=1, metavar=("1", "2"))
4872
4873 def test_nargs_1_metavar_length3(self):
4874 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4875
4876 # Unit tests for different values of metavar when nargs=2
4877
4878 def test_nargs_2_metavar_string(self):
4879 self.do_test_no_exception(nargs=2, metavar="1")
4880
4881 def test_nargs_2_metavar_length0(self):
4882 self.do_test_exception(nargs=2, metavar=tuple())
4883
4884 def test_nargs_2_metavar_length1(self):
4885 self.do_test_no_exception(nargs=2, metavar=("1"))
4886
4887 def test_nargs_2_metavar_length2(self):
4888 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4889
4890 def test_nargs_2_metavar_length3(self):
4891 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4892
4893 # Unit tests for different values of metavar when nargs=3
4894
4895 def test_nargs_3_metavar_string(self):
4896 self.do_test_no_exception(nargs=3, metavar="1")
4897
4898 def test_nargs_3_metavar_length0(self):
4899 self.do_test_exception(nargs=3, metavar=tuple())
4900
4901 def test_nargs_3_metavar_length1(self):
4902 self.do_test_no_exception(nargs=3, metavar=("1"))
4903
4904 def test_nargs_3_metavar_length2(self):
4905 self.do_test_exception(nargs=3, metavar=("1", "2"))
4906
4907 def test_nargs_3_metavar_length3(self):
4908 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4909
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004910# ============================
4911# from argparse import * tests
4912# ============================
4913
4914class TestImportStar(TestCase):
4915
4916 def test(self):
4917 for name in argparse.__all__:
4918 self.assertTrue(hasattr(argparse, name))
4919
Steven Bethard72c55382010-11-01 15:23:12 +00004920 def test_all_exports_everything_but_modules(self):
4921 items = [
4922 name
4923 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00004924 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00004925 if not inspect.ismodule(value)
4926 ]
4927 self.assertEqual(sorted(items), sorted(argparse.__all__))
4928
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004929def test_main():
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004930 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00004931 # Remove global references to avoid looking like we have refleaks.
4932 RFile.seen = {}
4933 WFile.seen = set()
4934
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004935
4936
4937if __name__ == '__main__':
4938 test_main()