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