blob: 1a72a13e30deee30ab34038369f7e884ed2b70a9 [file] [log] [blame]
Steven Bethardcd4ec0e2010-03-24 23:07:31 +00001# Author: Steven J. Bethard <steven.bethard@gmail.com>.
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002
3import codecs
Steven Bethard72c55382010-11-01 15:23:12 +00004import inspect
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005import os
6import shutil
Steven Bethardb0270112011-01-24 21:02:50 +00007import stat
Benjamin Peterson698a18a2010-03-02 22:34:37 +00008import sys
9import textwrap
10import tempfile
11import unittest
Benjamin Peterson698a18a2010-03-02 22:34:37 +000012import argparse
13
Benjamin Peterson16f2fd02010-03-02 23:09:38 +000014from io import StringIO
15
Benjamin Peterson698a18a2010-03-02 22:34:37 +000016from test import support
Benjamin Petersonb48af542010-04-11 20:43:16 +000017class StdIOBuffer(StringIO):
18 pass
Benjamin Peterson698a18a2010-03-02 22:34:37 +000019
Benjamin Peterson698a18a2010-03-02 22:34:37 +000020class TestCase(unittest.TestCase):
21
22 def assertEqual(self, obj1, obj2):
23 if obj1 != obj2:
24 print('')
25 print(repr(obj1))
26 print(repr(obj2))
27 print(obj1)
28 print(obj2)
29 super(TestCase, self).assertEqual(obj1, obj2)
30
Steven Bethard1f1c2472010-11-01 13:56:09 +000031 def setUp(self):
32 # The tests assume that line wrapping occurs at 80 columns, but this
33 # behaviour can be overridden by setting the COLUMNS environment
34 # variable. To ensure that this assumption is true, unset COLUMNS.
35 env = support.EnvironmentVarGuard()
36 env.unset("COLUMNS")
37 self.addCleanup(env.__exit__)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000038
Benjamin Petersonb48af542010-04-11 20:43:16 +000039
Benjamin Peterson698a18a2010-03-02 22:34:37 +000040class TempDirMixin(object):
41
42 def setUp(self):
43 self.temp_dir = tempfile.mkdtemp()
44 self.old_dir = os.getcwd()
45 os.chdir(self.temp_dir)
46
47 def tearDown(self):
48 os.chdir(self.old_dir)
Steven Bethardb0270112011-01-24 21:02:50 +000049 shutil.rmtree(self.temp_dir, True)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000050
Steven Bethardb0270112011-01-24 21:02:50 +000051 def create_readonly_file(self, filename):
52 file_path = os.path.join(self.temp_dir, filename)
53 with open(file_path, 'w') as file:
54 file.write(filename)
55 os.chmod(file_path, stat.S_IREAD)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000056
57class Sig(object):
58
59 def __init__(self, *args, **kwargs):
60 self.args = args
61 self.kwargs = kwargs
62
63
64class NS(object):
65
66 def __init__(self, **kwargs):
67 self.__dict__.update(kwargs)
68
69 def __repr__(self):
70 sorted_items = sorted(self.__dict__.items())
71 kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
72 return '%s(%s)' % (type(self).__name__, kwarg_str)
73
74 def __eq__(self, other):
75 return vars(self) == vars(other)
76
77 def __ne__(self, other):
78 return not (self == other)
79
80
81class ArgumentParserError(Exception):
82
83 def __init__(self, message, stdout=None, stderr=None, error_code=None):
84 Exception.__init__(self, message, stdout, stderr)
85 self.message = message
86 self.stdout = stdout
87 self.stderr = stderr
88 self.error_code = error_code
89
90
91def stderr_to_parser_error(parse_args, *args, **kwargs):
92 # if this is being called recursively and stderr or stdout is already being
93 # redirected, simply call the function and let the enclosing function
94 # catch the exception
Benjamin Petersonb48af542010-04-11 20:43:16 +000095 if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
Benjamin Peterson698a18a2010-03-02 22:34:37 +000096 return parse_args(*args, **kwargs)
97
98 # if this is not being called recursively, redirect stderr and
99 # use it as the ArgumentParserError message
100 old_stdout = sys.stdout
101 old_stderr = sys.stderr
Benjamin Petersonb48af542010-04-11 20:43:16 +0000102 sys.stdout = StdIOBuffer()
103 sys.stderr = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000104 try:
105 try:
106 result = parse_args(*args, **kwargs)
107 for key in list(vars(result)):
108 if getattr(result, key) is sys.stdout:
109 setattr(result, key, old_stdout)
110 if getattr(result, key) is sys.stderr:
111 setattr(result, key, old_stderr)
112 return result
113 except SystemExit:
114 code = sys.exc_info()[1].code
115 stdout = sys.stdout.getvalue()
116 stderr = sys.stderr.getvalue()
117 raise ArgumentParserError("SystemExit", stdout, stderr, code)
118 finally:
119 sys.stdout = old_stdout
120 sys.stderr = old_stderr
121
122
123class ErrorRaisingArgumentParser(argparse.ArgumentParser):
124
125 def parse_args(self, *args, **kwargs):
126 parse_args = super(ErrorRaisingArgumentParser, self).parse_args
127 return stderr_to_parser_error(parse_args, *args, **kwargs)
128
129 def exit(self, *args, **kwargs):
130 exit = super(ErrorRaisingArgumentParser, self).exit
131 return stderr_to_parser_error(exit, *args, **kwargs)
132
133 def error(self, *args, **kwargs):
134 error = super(ErrorRaisingArgumentParser, self).error
135 return stderr_to_parser_error(error, *args, **kwargs)
136
137
138class ParserTesterMetaclass(type):
139 """Adds parser tests using the class attributes.
140
141 Classes of this type should specify the following attributes:
142
143 argument_signatures -- a list of Sig objects which specify
144 the signatures of Argument objects to be created
145 failures -- a list of args lists that should cause the parser
146 to fail
147 successes -- a list of (initial_args, options, remaining_args) tuples
148 where initial_args specifies the string args to be parsed,
149 options is a dict that should match the vars() of the options
150 parsed out of initial_args, and remaining_args should be any
151 remaining unparsed arguments
152 """
153
154 def __init__(cls, name, bases, bodydict):
155 if name == 'ParserTestCase':
156 return
157
158 # default parser signature is empty
159 if not hasattr(cls, 'parser_signature'):
160 cls.parser_signature = Sig()
161 if not hasattr(cls, 'parser_class'):
162 cls.parser_class = ErrorRaisingArgumentParser
163
164 # ---------------------------------------
165 # functions for adding optional arguments
166 # ---------------------------------------
167 def no_groups(parser, argument_signatures):
168 """Add all arguments directly to the parser"""
169 for sig in argument_signatures:
170 parser.add_argument(*sig.args, **sig.kwargs)
171
172 def one_group(parser, argument_signatures):
173 """Add all arguments under a single group in the parser"""
174 group = parser.add_argument_group('foo')
175 for sig in argument_signatures:
176 group.add_argument(*sig.args, **sig.kwargs)
177
178 def many_groups(parser, argument_signatures):
179 """Add each argument in its own group to the parser"""
180 for i, sig in enumerate(argument_signatures):
181 group = parser.add_argument_group('foo:%i' % i)
182 group.add_argument(*sig.args, **sig.kwargs)
183
184 # --------------------------
185 # functions for parsing args
186 # --------------------------
187 def listargs(parser, args):
188 """Parse the args by passing in a list"""
189 return parser.parse_args(args)
190
191 def sysargs(parser, args):
192 """Parse the args by defaulting to sys.argv"""
193 old_sys_argv = sys.argv
194 sys.argv = [old_sys_argv[0]] + args
195 try:
196 return parser.parse_args()
197 finally:
198 sys.argv = old_sys_argv
199
200 # class that holds the combination of one optional argument
201 # addition method and one arg parsing method
202 class AddTests(object):
203
204 def __init__(self, tester_cls, add_arguments, parse_args):
205 self._add_arguments = add_arguments
206 self._parse_args = parse_args
207
208 add_arguments_name = self._add_arguments.__name__
209 parse_args_name = self._parse_args.__name__
210 for test_func in [self.test_failures, self.test_successes]:
211 func_name = test_func.__name__
212 names = func_name, add_arguments_name, parse_args_name
213 test_name = '_'.join(names)
214
215 def wrapper(self, test_func=test_func):
216 test_func(self)
217 try:
218 wrapper.__name__ = test_name
219 except TypeError:
220 pass
221 setattr(tester_cls, test_name, wrapper)
222
223 def _get_parser(self, tester):
224 args = tester.parser_signature.args
225 kwargs = tester.parser_signature.kwargs
226 parser = tester.parser_class(*args, **kwargs)
227 self._add_arguments(parser, tester.argument_signatures)
228 return parser
229
230 def test_failures(self, tester):
231 parser = self._get_parser(tester)
232 for args_str in tester.failures:
233 args = args_str.split()
234 raises = tester.assertRaises
235 raises(ArgumentParserError, parser.parse_args, args)
236
237 def test_successes(self, tester):
238 parser = self._get_parser(tester)
239 for args, expected_ns in tester.successes:
240 if isinstance(args, str):
241 args = args.split()
242 result_ns = self._parse_args(parser, args)
243 tester.assertEqual(expected_ns, result_ns)
244
245 # add tests for each combination of an optionals adding method
246 # and an arg parsing method
247 for add_arguments in [no_groups, one_group, many_groups]:
248 for parse_args in [listargs, sysargs]:
249 AddTests(cls, add_arguments, parse_args)
250
251bases = TestCase,
252ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
253
254# ===============
255# Optionals tests
256# ===============
257
258class TestOptionalsSingleDash(ParserTestCase):
259 """Test an Optional with a single-dash option string"""
260
261 argument_signatures = [Sig('-x')]
262 failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
263 successes = [
264 ('', NS(x=None)),
265 ('-x a', NS(x='a')),
266 ('-xa', NS(x='a')),
267 ('-x -1', NS(x='-1')),
268 ('-x-1', NS(x='-1')),
269 ]
270
271
272class TestOptionalsSingleDashCombined(ParserTestCase):
273 """Test an Optional with a single-dash option string"""
274
275 argument_signatures = [
276 Sig('-x', action='store_true'),
277 Sig('-yyy', action='store_const', const=42),
278 Sig('-z'),
279 ]
280 failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
281 '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
282 successes = [
283 ('', NS(x=False, yyy=None, z=None)),
284 ('-x', NS(x=True, yyy=None, z=None)),
285 ('-za', NS(x=False, yyy=None, z='a')),
286 ('-z a', NS(x=False, yyy=None, z='a')),
287 ('-xza', NS(x=True, yyy=None, z='a')),
288 ('-xz a', NS(x=True, yyy=None, z='a')),
289 ('-x -za', NS(x=True, yyy=None, z='a')),
290 ('-x -z a', NS(x=True, yyy=None, z='a')),
291 ('-y', NS(x=False, yyy=42, z=None)),
292 ('-yyy', NS(x=False, yyy=42, z=None)),
293 ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
294 ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
295 ]
296
297
298class TestOptionalsSingleDashLong(ParserTestCase):
299 """Test an Optional with a multi-character single-dash option string"""
300
301 argument_signatures = [Sig('-foo')]
302 failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
303 successes = [
304 ('', NS(foo=None)),
305 ('-foo a', NS(foo='a')),
306 ('-foo -1', NS(foo='-1')),
307 ('-fo a', NS(foo='a')),
308 ('-f a', NS(foo='a')),
309 ]
310
311
312class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
313 """Test Optionals where option strings are subsets of each other"""
314
315 argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
316 failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
317 successes = [
318 ('', NS(f=None, foobar=None, foorab=None)),
319 ('-f a', NS(f='a', foobar=None, foorab=None)),
320 ('-fa', NS(f='a', foobar=None, foorab=None)),
321 ('-foa', NS(f='oa', foobar=None, foorab=None)),
322 ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
323 ('-foobar a', NS(f=None, foobar='a', foorab=None)),
324 ('-foorab a', NS(f=None, foobar=None, foorab='a')),
325 ]
326
327
328class TestOptionalsSingleDashAmbiguous(ParserTestCase):
329 """Test Optionals that partially match but are not subsets"""
330
331 argument_signatures = [Sig('-foobar'), Sig('-foorab')]
332 failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
333 successes = [
334 ('', NS(foobar=None, foorab=None)),
335 ('-foob a', NS(foobar='a', foorab=None)),
336 ('-foor a', NS(foobar=None, foorab='a')),
337 ('-fooba a', NS(foobar='a', foorab=None)),
338 ('-foora a', NS(foobar=None, foorab='a')),
339 ('-foobar a', NS(foobar='a', foorab=None)),
340 ('-foorab a', NS(foobar=None, foorab='a')),
341 ]
342
343
344class TestOptionalsNumeric(ParserTestCase):
345 """Test an Optional with a short opt string"""
346
347 argument_signatures = [Sig('-1', dest='one')]
348 failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
349 successes = [
350 ('', NS(one=None)),
351 ('-1 a', NS(one='a')),
352 ('-1a', NS(one='a')),
353 ('-1-2', NS(one='-2')),
354 ]
355
356
357class TestOptionalsDoubleDash(ParserTestCase):
358 """Test an Optional with a double-dash option string"""
359
360 argument_signatures = [Sig('--foo')]
361 failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
362 successes = [
363 ('', NS(foo=None)),
364 ('--foo a', NS(foo='a')),
365 ('--foo=a', NS(foo='a')),
366 ('--foo -2.5', NS(foo='-2.5')),
367 ('--foo=-2.5', NS(foo='-2.5')),
368 ]
369
370
371class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
372 """Tests partial matching with a double-dash option string"""
373
374 argument_signatures = [
375 Sig('--badger', action='store_true'),
376 Sig('--bat'),
377 ]
378 failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
379 successes = [
380 ('', NS(badger=False, bat=None)),
381 ('--bat X', NS(badger=False, bat='X')),
382 ('--bad', NS(badger=True, bat=None)),
383 ('--badg', NS(badger=True, bat=None)),
384 ('--badge', NS(badger=True, bat=None)),
385 ('--badger', NS(badger=True, bat=None)),
386 ]
387
388
389class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
390 """Tests when one double-dash option string is a prefix of another"""
391
392 argument_signatures = [
393 Sig('--badger', action='store_true'),
394 Sig('--ba'),
395 ]
396 failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
397 successes = [
398 ('', NS(badger=False, ba=None)),
399 ('--ba X', NS(badger=False, ba='X')),
400 ('--ba=X', NS(badger=False, ba='X')),
401 ('--bad', NS(badger=True, ba=None)),
402 ('--badg', NS(badger=True, ba=None)),
403 ('--badge', NS(badger=True, ba=None)),
404 ('--badger', NS(badger=True, ba=None)),
405 ]
406
407
408class TestOptionalsSingleDoubleDash(ParserTestCase):
409 """Test an Optional with single- and double-dash option strings"""
410
411 argument_signatures = [
412 Sig('-f', action='store_true'),
413 Sig('--bar'),
414 Sig('-baz', action='store_const', const=42),
415 ]
416 failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
417 successes = [
418 ('', NS(f=False, bar=None, baz=None)),
419 ('-f', NS(f=True, bar=None, baz=None)),
420 ('--ba B', NS(f=False, bar='B', baz=None)),
421 ('-f --bar B', NS(f=True, bar='B', baz=None)),
422 ('-f -b', NS(f=True, bar=None, baz=42)),
423 ('-ba -f', NS(f=True, bar=None, baz=42)),
424 ]
425
426
427class TestOptionalsAlternatePrefixChars(ParserTestCase):
R. David Murray88c49fe2010-08-03 17:56:09 +0000428 """Test an Optional with option strings with custom prefixes"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000429
430 parser_signature = Sig(prefix_chars='+:/', add_help=False)
431 argument_signatures = [
432 Sig('+f', action='store_true'),
433 Sig('::bar'),
434 Sig('/baz', action='store_const', const=42),
435 ]
R. David Murray88c49fe2010-08-03 17:56:09 +0000436 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
437 successes = [
438 ('', NS(f=False, bar=None, baz=None)),
439 ('+f', NS(f=True, bar=None, baz=None)),
440 ('::ba B', NS(f=False, bar='B', baz=None)),
441 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
442 ('+f /b', NS(f=True, bar=None, baz=42)),
443 ('/ba +f', NS(f=True, bar=None, baz=42)),
444 ]
445
446
447class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
448 """When ``-`` not in prefix_chars, default operators created for help
449 should use the prefix_chars in use rather than - or --
450 http://bugs.python.org/issue9444"""
451
452 parser_signature = Sig(prefix_chars='+:/', add_help=True)
453 argument_signatures = [
454 Sig('+f', action='store_true'),
455 Sig('::bar'),
456 Sig('/baz', action='store_const', const=42),
457 ]
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000458 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
459 successes = [
460 ('', NS(f=False, bar=None, baz=None)),
461 ('+f', NS(f=True, bar=None, baz=None)),
462 ('::ba B', NS(f=False, bar='B', baz=None)),
463 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
464 ('+f /b', NS(f=True, bar=None, baz=42)),
R. David Murray88c49fe2010-08-03 17:56:09 +0000465 ('/ba +f', NS(f=True, bar=None, baz=42))
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000466 ]
467
Steven Bethard1ca45a52010-11-01 15:57:36 +0000468
469class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
470 """Verify that Optionals must be called with their defined prefixes"""
471
472 parser_signature = Sig(prefix_chars='+-', add_help=False)
473 argument_signatures = [
474 Sig('-x', action='store_true'),
475 Sig('+y', action='store_true'),
476 Sig('+z', action='store_true'),
477 ]
478 failures = ['-w',
479 '-xyz',
480 '+x',
481 '-y',
482 '+xyz',
483 ]
484 successes = [
485 ('', NS(x=False, y=False, z=False)),
486 ('-x', NS(x=True, y=False, z=False)),
487 ('+y -x', NS(x=True, y=True, z=False)),
488 ('+yz -x', NS(x=True, y=True, z=True)),
489 ]
490
491
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000492class TestOptionalsShortLong(ParserTestCase):
493 """Test a combination of single- and double-dash option strings"""
494
495 argument_signatures = [
496 Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
497 ]
498 failures = ['--x --verbose', '-N', 'a', '-v x']
499 successes = [
500 ('', NS(verbose=False)),
501 ('-v', NS(verbose=True)),
502 ('--verbose', NS(verbose=True)),
503 ('-n', NS(verbose=True)),
504 ('--noisy', NS(verbose=True)),
505 ]
506
507
508class TestOptionalsDest(ParserTestCase):
509 """Tests various means of setting destination"""
510
511 argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
512 failures = ['a']
513 successes = [
514 ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
515 ('--baz g', NS(foo_bar=None, zabbaz='g')),
516 ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
517 ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
518 ]
519
520
521class TestOptionalsDefault(ParserTestCase):
522 """Tests specifying a default for an Optional"""
523
524 argument_signatures = [Sig('-x'), Sig('-y', default=42)]
525 failures = ['a']
526 successes = [
527 ('', NS(x=None, y=42)),
528 ('-xx', NS(x='x', y=42)),
529 ('-yy', NS(x=None, y='y')),
530 ]
531
532
533class TestOptionalsNargsDefault(ParserTestCase):
534 """Tests not specifying the number of args for an Optional"""
535
536 argument_signatures = [Sig('-x')]
537 failures = ['a', '-x']
538 successes = [
539 ('', NS(x=None)),
540 ('-x a', NS(x='a')),
541 ]
542
543
544class TestOptionalsNargs1(ParserTestCase):
545 """Tests specifying the 1 arg for an Optional"""
546
547 argument_signatures = [Sig('-x', nargs=1)]
548 failures = ['a', '-x']
549 successes = [
550 ('', NS(x=None)),
551 ('-x a', NS(x=['a'])),
552 ]
553
554
555class TestOptionalsNargs3(ParserTestCase):
556 """Tests specifying the 3 args for an Optional"""
557
558 argument_signatures = [Sig('-x', nargs=3)]
559 failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
560 successes = [
561 ('', NS(x=None)),
562 ('-x a b c', NS(x=['a', 'b', 'c'])),
563 ]
564
565
566class TestOptionalsNargsOptional(ParserTestCase):
567 """Tests specifying an Optional arg for an Optional"""
568
569 argument_signatures = [
570 Sig('-w', nargs='?'),
571 Sig('-x', nargs='?', const=42),
572 Sig('-y', nargs='?', default='spam'),
573 Sig('-z', nargs='?', type=int, const='42', default='84'),
574 ]
575 failures = ['2']
576 successes = [
577 ('', NS(w=None, x=None, y='spam', z=84)),
578 ('-w', NS(w=None, x=None, y='spam', z=84)),
579 ('-w 2', NS(w='2', x=None, y='spam', z=84)),
580 ('-x', NS(w=None, x=42, y='spam', z=84)),
581 ('-x 2', NS(w=None, x='2', y='spam', z=84)),
582 ('-y', NS(w=None, x=None, y=None, z=84)),
583 ('-y 2', NS(w=None, x=None, y='2', z=84)),
584 ('-z', NS(w=None, x=None, y='spam', z=42)),
585 ('-z 2', NS(w=None, x=None, y='spam', z=2)),
586 ]
587
588
589class TestOptionalsNargsZeroOrMore(ParserTestCase):
590 """Tests specifying an args for an Optional that accepts zero or more"""
591
592 argument_signatures = [
593 Sig('-x', nargs='*'),
594 Sig('-y', nargs='*', default='spam'),
595 ]
596 failures = ['a']
597 successes = [
598 ('', NS(x=None, y='spam')),
599 ('-x', NS(x=[], y='spam')),
600 ('-x a', NS(x=['a'], y='spam')),
601 ('-x a b', NS(x=['a', 'b'], y='spam')),
602 ('-y', NS(x=None, y=[])),
603 ('-y a', NS(x=None, y=['a'])),
604 ('-y a b', NS(x=None, y=['a', 'b'])),
605 ]
606
607
608class TestOptionalsNargsOneOrMore(ParserTestCase):
609 """Tests specifying an args for an Optional that accepts one or more"""
610
611 argument_signatures = [
612 Sig('-x', nargs='+'),
613 Sig('-y', nargs='+', default='spam'),
614 ]
615 failures = ['a', '-x', '-y', 'a -x', 'a -y b']
616 successes = [
617 ('', NS(x=None, y='spam')),
618 ('-x a', NS(x=['a'], y='spam')),
619 ('-x a b', NS(x=['a', 'b'], y='spam')),
620 ('-y a', NS(x=None, y=['a'])),
621 ('-y a b', NS(x=None, y=['a', 'b'])),
622 ]
623
624
625class TestOptionalsChoices(ParserTestCase):
626 """Tests specifying the choices for an Optional"""
627
628 argument_signatures = [
629 Sig('-f', choices='abc'),
630 Sig('-g', type=int, choices=range(5))]
631 failures = ['a', '-f d', '-fad', '-ga', '-g 6']
632 successes = [
633 ('', NS(f=None, g=None)),
634 ('-f a', NS(f='a', g=None)),
635 ('-f c', NS(f='c', g=None)),
636 ('-g 0', NS(f=None, g=0)),
637 ('-g 03', NS(f=None, g=3)),
638 ('-fb -g4', NS(f='b', g=4)),
639 ]
640
641
642class TestOptionalsRequired(ParserTestCase):
643 """Tests the an optional action that is required"""
644
645 argument_signatures = [
646 Sig('-x', type=int, required=True),
647 ]
648 failures = ['a', '']
649 successes = [
650 ('-x 1', NS(x=1)),
651 ('-x42', NS(x=42)),
652 ]
653
654
655class TestOptionalsActionStore(ParserTestCase):
656 """Tests the store action for an Optional"""
657
658 argument_signatures = [Sig('-x', action='store')]
659 failures = ['a', 'a -x']
660 successes = [
661 ('', NS(x=None)),
662 ('-xfoo', NS(x='foo')),
663 ]
664
665
666class TestOptionalsActionStoreConst(ParserTestCase):
667 """Tests the store_const action for an Optional"""
668
669 argument_signatures = [Sig('-y', action='store_const', const=object)]
670 failures = ['a']
671 successes = [
672 ('', NS(y=None)),
673 ('-y', NS(y=object)),
674 ]
675
676
677class TestOptionalsActionStoreFalse(ParserTestCase):
678 """Tests the store_false action for an Optional"""
679
680 argument_signatures = [Sig('-z', action='store_false')]
681 failures = ['a', '-za', '-z a']
682 successes = [
683 ('', NS(z=True)),
684 ('-z', NS(z=False)),
685 ]
686
687
688class TestOptionalsActionStoreTrue(ParserTestCase):
689 """Tests the store_true action for an Optional"""
690
691 argument_signatures = [Sig('--apple', action='store_true')]
692 failures = ['a', '--apple=b', '--apple b']
693 successes = [
694 ('', NS(apple=False)),
695 ('--apple', NS(apple=True)),
696 ]
697
698
699class TestOptionalsActionAppend(ParserTestCase):
700 """Tests the append action for an Optional"""
701
702 argument_signatures = [Sig('--baz', action='append')]
703 failures = ['a', '--baz', 'a --baz', '--baz a b']
704 successes = [
705 ('', NS(baz=None)),
706 ('--baz a', NS(baz=['a'])),
707 ('--baz a --baz b', NS(baz=['a', 'b'])),
708 ]
709
710
711class TestOptionalsActionAppendWithDefault(ParserTestCase):
712 """Tests the append action for an Optional"""
713
714 argument_signatures = [Sig('--baz', action='append', default=['X'])]
715 failures = ['a', '--baz', 'a --baz', '--baz a b']
716 successes = [
717 ('', NS(baz=['X'])),
718 ('--baz a', NS(baz=['X', 'a'])),
719 ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
720 ]
721
722
723class TestOptionalsActionAppendConst(ParserTestCase):
724 """Tests the append_const action for an Optional"""
725
726 argument_signatures = [
727 Sig('-b', action='append_const', const=Exception),
728 Sig('-c', action='append', dest='b'),
729 ]
730 failures = ['a', '-c', 'a -c', '-bx', '-b x']
731 successes = [
732 ('', NS(b=None)),
733 ('-b', NS(b=[Exception])),
734 ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
735 ]
736
737
738class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
739 """Tests the append_const action for an Optional"""
740
741 argument_signatures = [
742 Sig('-b', action='append_const', const=Exception, default=['X']),
743 Sig('-c', action='append', dest='b'),
744 ]
745 failures = ['a', '-c', 'a -c', '-bx', '-b x']
746 successes = [
747 ('', NS(b=['X'])),
748 ('-b', NS(b=['X', Exception])),
749 ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
750 ]
751
752
753class TestOptionalsActionCount(ParserTestCase):
754 """Tests the count action for an Optional"""
755
756 argument_signatures = [Sig('-x', action='count')]
757 failures = ['a', '-x a', '-x b', '-x a -x b']
758 successes = [
759 ('', NS(x=None)),
760 ('-x', NS(x=1)),
761 ]
762
763
764# ================
765# Positional tests
766# ================
767
768class TestPositionalsNargsNone(ParserTestCase):
769 """Test a Positional that doesn't specify nargs"""
770
771 argument_signatures = [Sig('foo')]
772 failures = ['', '-x', 'a b']
773 successes = [
774 ('a', NS(foo='a')),
775 ]
776
777
778class TestPositionalsNargs1(ParserTestCase):
779 """Test a Positional that specifies an nargs of 1"""
780
781 argument_signatures = [Sig('foo', nargs=1)]
782 failures = ['', '-x', 'a b']
783 successes = [
784 ('a', NS(foo=['a'])),
785 ]
786
787
788class TestPositionalsNargs2(ParserTestCase):
789 """Test a Positional that specifies an nargs of 2"""
790
791 argument_signatures = [Sig('foo', nargs=2)]
792 failures = ['', 'a', '-x', 'a b c']
793 successes = [
794 ('a b', NS(foo=['a', 'b'])),
795 ]
796
797
798class TestPositionalsNargsZeroOrMore(ParserTestCase):
799 """Test a Positional that specifies unlimited nargs"""
800
801 argument_signatures = [Sig('foo', nargs='*')]
802 failures = ['-x']
803 successes = [
804 ('', NS(foo=[])),
805 ('a', NS(foo=['a'])),
806 ('a b', NS(foo=['a', 'b'])),
807 ]
808
809
810class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
811 """Test a Positional that specifies unlimited nargs and a default"""
812
813 argument_signatures = [Sig('foo', nargs='*', default='bar')]
814 failures = ['-x']
815 successes = [
816 ('', NS(foo='bar')),
817 ('a', NS(foo=['a'])),
818 ('a b', NS(foo=['a', 'b'])),
819 ]
820
821
822class TestPositionalsNargsOneOrMore(ParserTestCase):
823 """Test a Positional that specifies one or more nargs"""
824
825 argument_signatures = [Sig('foo', nargs='+')]
826 failures = ['', '-x']
827 successes = [
828 ('a', NS(foo=['a'])),
829 ('a b', NS(foo=['a', 'b'])),
830 ]
831
832
833class TestPositionalsNargsOptional(ParserTestCase):
834 """Tests an Optional Positional"""
835
836 argument_signatures = [Sig('foo', nargs='?')]
837 failures = ['-x', 'a b']
838 successes = [
839 ('', NS(foo=None)),
840 ('a', NS(foo='a')),
841 ]
842
843
844class TestPositionalsNargsOptionalDefault(ParserTestCase):
845 """Tests an Optional Positional with a default value"""
846
847 argument_signatures = [Sig('foo', nargs='?', default=42)]
848 failures = ['-x', 'a b']
849 successes = [
850 ('', NS(foo=42)),
851 ('a', NS(foo='a')),
852 ]
853
854
855class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
856 """Tests an Optional Positional with a default value
857 that needs to be converted to the appropriate type.
858 """
859
860 argument_signatures = [
861 Sig('foo', nargs='?', type=int, default='42'),
862 ]
863 failures = ['-x', 'a b', '1 2']
864 successes = [
865 ('', NS(foo=42)),
866 ('1', NS(foo=1)),
867 ]
868
869
870class TestPositionalsNargsNoneNone(ParserTestCase):
871 """Test two Positionals that don't specify nargs"""
872
873 argument_signatures = [Sig('foo'), Sig('bar')]
874 failures = ['', '-x', 'a', 'a b c']
875 successes = [
876 ('a b', NS(foo='a', bar='b')),
877 ]
878
879
880class TestPositionalsNargsNone1(ParserTestCase):
881 """Test a Positional with no nargs followed by one with 1"""
882
883 argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
884 failures = ['', '--foo', 'a', 'a b c']
885 successes = [
886 ('a b', NS(foo='a', bar=['b'])),
887 ]
888
889
890class TestPositionalsNargs2None(ParserTestCase):
891 """Test a Positional with 2 nargs followed by one with none"""
892
893 argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
894 failures = ['', '--foo', 'a', 'a b', 'a b c d']
895 successes = [
896 ('a b c', NS(foo=['a', 'b'], bar='c')),
897 ]
898
899
900class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
901 """Test a Positional with no nargs followed by one with unlimited"""
902
903 argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
904 failures = ['', '--foo']
905 successes = [
906 ('a', NS(foo='a', bar=[])),
907 ('a b', NS(foo='a', bar=['b'])),
908 ('a b c', NS(foo='a', bar=['b', 'c'])),
909 ]
910
911
912class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
913 """Test a Positional with no nargs followed by one with one or more"""
914
915 argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
916 failures = ['', '--foo', 'a']
917 successes = [
918 ('a b', NS(foo='a', bar=['b'])),
919 ('a b c', NS(foo='a', bar=['b', 'c'])),
920 ]
921
922
923class TestPositionalsNargsNoneOptional(ParserTestCase):
924 """Test a Positional with no nargs followed by one with an Optional"""
925
926 argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
927 failures = ['', '--foo', 'a b c']
928 successes = [
929 ('a', NS(foo='a', bar=None)),
930 ('a b', NS(foo='a', bar='b')),
931 ]
932
933
934class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
935 """Test a Positional with unlimited nargs followed by one with none"""
936
937 argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
938 failures = ['', '--foo']
939 successes = [
940 ('a', NS(foo=[], bar='a')),
941 ('a b', NS(foo=['a'], bar='b')),
942 ('a b c', NS(foo=['a', 'b'], bar='c')),
943 ]
944
945
946class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
947 """Test a Positional with one or more nargs followed by one with none"""
948
949 argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
950 failures = ['', '--foo', 'a']
951 successes = [
952 ('a b', NS(foo=['a'], bar='b')),
953 ('a b c', NS(foo=['a', 'b'], bar='c')),
954 ]
955
956
957class TestPositionalsNargsOptionalNone(ParserTestCase):
958 """Test a Positional with an Optional nargs followed by one with none"""
959
960 argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
961 failures = ['', '--foo', 'a b c']
962 successes = [
963 ('a', NS(foo=42, bar='a')),
964 ('a b', NS(foo='a', bar='b')),
965 ]
966
967
968class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
969 """Test a Positional with 2 nargs followed by one with unlimited"""
970
971 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
972 failures = ['', '--foo', 'a']
973 successes = [
974 ('a b', NS(foo=['a', 'b'], bar=[])),
975 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
976 ]
977
978
979class TestPositionalsNargs2OneOrMore(ParserTestCase):
980 """Test a Positional with 2 nargs followed by one with one or more"""
981
982 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
983 failures = ['', '--foo', 'a', 'a b']
984 successes = [
985 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
986 ]
987
988
989class TestPositionalsNargs2Optional(ParserTestCase):
990 """Test a Positional with 2 nargs followed by one optional"""
991
992 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
993 failures = ['', '--foo', 'a', 'a b c d']
994 successes = [
995 ('a b', NS(foo=['a', 'b'], bar=None)),
996 ('a b c', NS(foo=['a', 'b'], bar='c')),
997 ]
998
999
1000class TestPositionalsNargsZeroOrMore1(ParserTestCase):
1001 """Test a Positional with unlimited nargs followed by one with 1"""
1002
1003 argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
1004 failures = ['', '--foo', ]
1005 successes = [
1006 ('a', NS(foo=[], bar=['a'])),
1007 ('a b', NS(foo=['a'], bar=['b'])),
1008 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1009 ]
1010
1011
1012class TestPositionalsNargsOneOrMore1(ParserTestCase):
1013 """Test a Positional with one or more nargs followed by one with 1"""
1014
1015 argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
1016 failures = ['', '--foo', 'a']
1017 successes = [
1018 ('a b', NS(foo=['a'], bar=['b'])),
1019 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1020 ]
1021
1022
1023class TestPositionalsNargsOptional1(ParserTestCase):
1024 """Test a Positional with an Optional nargs followed by one with 1"""
1025
1026 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
1027 failures = ['', '--foo', 'a b c']
1028 successes = [
1029 ('a', NS(foo=None, bar=['a'])),
1030 ('a b', NS(foo='a', bar=['b'])),
1031 ]
1032
1033
1034class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
1035 """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
1036
1037 argument_signatures = [
1038 Sig('foo'),
1039 Sig('bar', nargs='*'),
1040 Sig('baz', nargs=1),
1041 ]
1042 failures = ['', '--foo', 'a']
1043 successes = [
1044 ('a b', NS(foo='a', bar=[], baz=['b'])),
1045 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1046 ]
1047
1048
1049class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
1050 """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
1051
1052 argument_signatures = [
1053 Sig('foo'),
1054 Sig('bar', nargs='+'),
1055 Sig('baz', nargs=1),
1056 ]
1057 failures = ['', '--foo', 'a', 'b']
1058 successes = [
1059 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1060 ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
1061 ]
1062
1063
1064class TestPositionalsNargsNoneOptional1(ParserTestCase):
1065 """Test three Positionals: no nargs, optional narg and 1 nargs"""
1066
1067 argument_signatures = [
1068 Sig('foo'),
1069 Sig('bar', nargs='?', default=0.625),
1070 Sig('baz', nargs=1),
1071 ]
1072 failures = ['', '--foo', 'a']
1073 successes = [
1074 ('a b', NS(foo='a', bar=0.625, baz=['b'])),
1075 ('a b c', NS(foo='a', bar='b', baz=['c'])),
1076 ]
1077
1078
1079class TestPositionalsNargsOptionalOptional(ParserTestCase):
1080 """Test two optional nargs"""
1081
1082 argument_signatures = [
1083 Sig('foo', nargs='?'),
1084 Sig('bar', nargs='?', default=42),
1085 ]
1086 failures = ['--foo', 'a b c']
1087 successes = [
1088 ('', NS(foo=None, bar=42)),
1089 ('a', NS(foo='a', bar=42)),
1090 ('a b', NS(foo='a', bar='b')),
1091 ]
1092
1093
1094class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
1095 """Test an Optional narg followed by unlimited nargs"""
1096
1097 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
1098 failures = ['--foo']
1099 successes = [
1100 ('', NS(foo=None, bar=[])),
1101 ('a', NS(foo='a', bar=[])),
1102 ('a b', NS(foo='a', bar=['b'])),
1103 ('a b c', NS(foo='a', bar=['b', 'c'])),
1104 ]
1105
1106
1107class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
1108 """Test an Optional narg followed by one or more nargs"""
1109
1110 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
1111 failures = ['', '--foo']
1112 successes = [
1113 ('a', NS(foo=None, bar=['a'])),
1114 ('a b', NS(foo='a', bar=['b'])),
1115 ('a b c', NS(foo='a', bar=['b', 'c'])),
1116 ]
1117
1118
1119class TestPositionalsChoicesString(ParserTestCase):
1120 """Test a set of single-character choices"""
1121
1122 argument_signatures = [Sig('spam', choices=set('abcdefg'))]
1123 failures = ['', '--foo', 'h', '42', 'ef']
1124 successes = [
1125 ('a', NS(spam='a')),
1126 ('g', NS(spam='g')),
1127 ]
1128
1129
1130class TestPositionalsChoicesInt(ParserTestCase):
1131 """Test a set of integer choices"""
1132
1133 argument_signatures = [Sig('spam', type=int, choices=range(20))]
1134 failures = ['', '--foo', 'h', '42', 'ef']
1135 successes = [
1136 ('4', NS(spam=4)),
1137 ('15', NS(spam=15)),
1138 ]
1139
1140
1141class TestPositionalsActionAppend(ParserTestCase):
1142 """Test the 'append' action"""
1143
1144 argument_signatures = [
1145 Sig('spam', action='append'),
1146 Sig('spam', action='append', nargs=2),
1147 ]
1148 failures = ['', '--foo', 'a', 'a b', 'a b c d']
1149 successes = [
1150 ('a b c', NS(spam=['a', ['b', 'c']])),
1151 ]
1152
1153# ========================================
1154# Combined optionals and positionals tests
1155# ========================================
1156
1157class TestOptionalsNumericAndPositionals(ParserTestCase):
1158 """Tests negative number args when numeric options are present"""
1159
1160 argument_signatures = [
1161 Sig('x', nargs='?'),
1162 Sig('-4', dest='y', action='store_true'),
1163 ]
1164 failures = ['-2', '-315']
1165 successes = [
1166 ('', NS(x=None, y=False)),
1167 ('a', NS(x='a', y=False)),
1168 ('-4', NS(x=None, y=True)),
1169 ('-4 a', NS(x='a', y=True)),
1170 ]
1171
1172
1173class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
1174 """Tests negative number args when almost numeric options are present"""
1175
1176 argument_signatures = [
1177 Sig('x', nargs='?'),
1178 Sig('-k4', dest='y', action='store_true'),
1179 ]
1180 failures = ['-k3']
1181 successes = [
1182 ('', NS(x=None, y=False)),
1183 ('-2', NS(x='-2', y=False)),
1184 ('a', NS(x='a', y=False)),
1185 ('-k4', NS(x=None, y=True)),
1186 ('-k4 a', NS(x='a', y=True)),
1187 ]
1188
1189
1190class TestEmptyAndSpaceContainingArguments(ParserTestCase):
1191
1192 argument_signatures = [
1193 Sig('x', nargs='?'),
1194 Sig('-y', '--yyy', dest='y'),
1195 ]
1196 failures = ['-y']
1197 successes = [
1198 ([''], NS(x='', y=None)),
1199 (['a badger'], NS(x='a badger', y=None)),
1200 (['-a badger'], NS(x='-a badger', y=None)),
1201 (['-y', ''], NS(x=None, y='')),
1202 (['-y', 'a badger'], NS(x=None, y='a badger')),
1203 (['-y', '-a badger'], NS(x=None, y='-a badger')),
1204 (['--yyy=a badger'], NS(x=None, y='a badger')),
1205 (['--yyy=-a badger'], NS(x=None, y='-a badger')),
1206 ]
1207
1208
1209class TestPrefixCharacterOnlyArguments(ParserTestCase):
1210
1211 parser_signature = Sig(prefix_chars='-+')
1212 argument_signatures = [
1213 Sig('-', dest='x', nargs='?', const='badger'),
1214 Sig('+', dest='y', type=int, default=42),
1215 Sig('-+-', dest='z', action='store_true'),
1216 ]
1217 failures = ['-y', '+ -']
1218 successes = [
1219 ('', NS(x=None, y=42, z=False)),
1220 ('-', NS(x='badger', y=42, z=False)),
1221 ('- X', NS(x='X', y=42, z=False)),
1222 ('+ -3', NS(x=None, y=-3, z=False)),
1223 ('-+-', NS(x=None, y=42, z=True)),
1224 ('- ===', NS(x='===', y=42, z=False)),
1225 ]
1226
1227
1228class TestNargsZeroOrMore(ParserTestCase):
1229 """Tests specifying an args for an Optional that accepts zero or more"""
1230
1231 argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
1232 failures = []
1233 successes = [
1234 ('', NS(x=None, y=[])),
1235 ('-x', NS(x=[], y=[])),
1236 ('-x a', NS(x=['a'], y=[])),
1237 ('-x a -- b', NS(x=['a'], y=['b'])),
1238 ('a', NS(x=None, y=['a'])),
1239 ('a -x', NS(x=[], y=['a'])),
1240 ('a -x b', NS(x=['b'], y=['a'])),
1241 ]
1242
1243
1244class TestNargsRemainder(ParserTestCase):
1245 """Tests specifying a positional with nargs=REMAINDER"""
1246
1247 argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
1248 failures = ['', '-z', '-z Z']
1249 successes = [
1250 ('X', NS(x='X', y=[], z=None)),
1251 ('-z Z X', NS(x='X', y=[], z='Z')),
1252 ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
1253 ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
1254 ]
1255
1256
1257class TestOptionLike(ParserTestCase):
1258 """Tests options that may or may not be arguments"""
1259
1260 argument_signatures = [
1261 Sig('-x', type=float),
1262 Sig('-3', type=float, dest='y'),
1263 Sig('z', nargs='*'),
1264 ]
1265 failures = ['-x', '-y2.5', '-xa', '-x -a',
1266 '-x -3', '-x -3.5', '-3 -3.5',
1267 '-x -2.5', '-x -2.5 a', '-3 -.5',
1268 'a x -1', '-x -1 a', '-3 -1 a']
1269 successes = [
1270 ('', NS(x=None, y=None, z=[])),
1271 ('-x 2.5', NS(x=2.5, y=None, z=[])),
1272 ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
1273 ('-3.5', NS(x=None, y=0.5, z=[])),
1274 ('-3-.5', NS(x=None, y=-0.5, z=[])),
1275 ('-3 .5', NS(x=None, y=0.5, z=[])),
1276 ('a -3.5', NS(x=None, y=0.5, z=['a'])),
1277 ('a', NS(x=None, y=None, z=['a'])),
1278 ('a -x 1', NS(x=1.0, y=None, z=['a'])),
1279 ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
1280 ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
1281 ]
1282
1283
1284class TestDefaultSuppress(ParserTestCase):
1285 """Test actions with suppressed defaults"""
1286
1287 argument_signatures = [
1288 Sig('foo', nargs='?', default=argparse.SUPPRESS),
1289 Sig('bar', nargs='*', default=argparse.SUPPRESS),
1290 Sig('--baz', action='store_true', default=argparse.SUPPRESS),
1291 ]
1292 failures = ['-x']
1293 successes = [
1294 ('', NS()),
1295 ('a', NS(foo='a')),
1296 ('a b', NS(foo='a', bar=['b'])),
1297 ('--baz', NS(baz=True)),
1298 ('a --baz', NS(foo='a', baz=True)),
1299 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1300 ]
1301
1302
1303class TestParserDefaultSuppress(ParserTestCase):
1304 """Test actions with a parser-level default of SUPPRESS"""
1305
1306 parser_signature = Sig(argument_default=argparse.SUPPRESS)
1307 argument_signatures = [
1308 Sig('foo', nargs='?'),
1309 Sig('bar', nargs='*'),
1310 Sig('--baz', action='store_true'),
1311 ]
1312 failures = ['-x']
1313 successes = [
1314 ('', NS()),
1315 ('a', NS(foo='a')),
1316 ('a b', NS(foo='a', bar=['b'])),
1317 ('--baz', NS(baz=True)),
1318 ('a --baz', NS(foo='a', baz=True)),
1319 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1320 ]
1321
1322
1323class TestParserDefault42(ParserTestCase):
1324 """Test actions with a parser-level default of 42"""
1325
1326 parser_signature = Sig(argument_default=42, version='1.0')
1327 argument_signatures = [
1328 Sig('foo', nargs='?'),
1329 Sig('bar', nargs='*'),
1330 Sig('--baz', action='store_true'),
1331 ]
1332 failures = ['-x']
1333 successes = [
1334 ('', NS(foo=42, bar=42, baz=42)),
1335 ('a', NS(foo='a', bar=42, baz=42)),
1336 ('a b', NS(foo='a', bar=['b'], baz=42)),
1337 ('--baz', NS(foo=42, bar=42, baz=True)),
1338 ('a --baz', NS(foo='a', bar=42, baz=True)),
1339 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1340 ]
1341
1342
1343class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
1344 """Test reading arguments from a file"""
1345
1346 def setUp(self):
1347 super(TestArgumentsFromFile, self).setUp()
1348 file_texts = [
1349 ('hello', 'hello world!\n'),
1350 ('recursive', '-a\n'
1351 'A\n'
1352 '@hello'),
1353 ('invalid', '@no-such-path\n'),
1354 ]
1355 for path, text in file_texts:
1356 file = open(path, 'w')
1357 file.write(text)
1358 file.close()
1359
1360 parser_signature = Sig(fromfile_prefix_chars='@')
1361 argument_signatures = [
1362 Sig('-a'),
1363 Sig('x'),
1364 Sig('y', nargs='+'),
1365 ]
1366 failures = ['', '-b', 'X', '@invalid', '@missing']
1367 successes = [
1368 ('X Y', NS(a=None, x='X', y=['Y'])),
1369 ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
1370 ('@hello X', NS(a=None, x='hello world!', y=['X'])),
1371 ('X @hello', NS(a=None, x='X', y=['hello world!'])),
1372 ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
1373 ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
R David Murrayb94082a2012-07-21 22:20:11 -04001374 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001375 ]
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
2900 # add tests for {format,print}_{usage,help,version}
2901 for func_suffix, std_name in [('usage', 'stdout'),
2902 ('help', 'stdout'),
2903 ('version', 'stderr')]:
2904 AddTests(cls, func_suffix, std_name)
2905
2906bases = TestCase,
2907HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2908
2909
2910class TestHelpBiggerOptionals(HelpTestCase):
2911 """Make sure that argument help aligns when options are longer"""
2912
2913 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2914 epilog='EPILOG', version='0.1')
2915 argument_signatures = [
2916 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',
2950 epilog='EPILOG', version='0.1')
2951 argument_signatures = [
2952 Sig('-x', action='store_true', help='X HELP'),
2953 Sig('--y', help='Y HELP'),
2954 Sig('foo', help='FOO HELP'),
2955 Sig('bar', help='BAR HELP'),
2956 ]
2957 argument_group_signatures = [
2958 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2959 Sig('baz', help='BAZ HELP'),
2960 Sig('-z', nargs='+', help='Z HELP')]),
2961 ]
2962 usage = '''\
2963 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2964 '''
2965 help = usage + '''\
2966
2967 DESCRIPTION
2968
2969 positional arguments:
2970 foo FOO HELP
2971 bar BAR HELP
2972
2973 optional arguments:
2974 -h, --help show this help message and exit
2975 -v, --version show program's version number and exit
2976 -x X HELP
2977 --y Y Y HELP
2978
2979 GROUP TITLE:
2980 GROUP DESCRIPTION
2981
2982 baz BAZ HELP
2983 -z Z [Z ...] Z HELP
2984
2985 EPILOG
2986 '''
2987 version = '''\
2988 0.1
2989 '''
2990
2991
2992class TestHelpBiggerPositionals(HelpTestCase):
2993 """Make sure that help aligns when arguments are longer"""
2994
2995 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2996 argument_signatures = [
2997 Sig('-x', action='store_true', help='X HELP'),
2998 Sig('--y', help='Y HELP'),
2999 Sig('ekiekiekifekang', help='EKI HELP'),
3000 Sig('bar', help='BAR HELP'),
3001 ]
3002 argument_group_signatures = []
3003 usage = '''\
3004 usage: USAGE
3005 '''
3006 help = usage + '''\
3007
3008 DESCRIPTION
3009
3010 positional arguments:
3011 ekiekiekifekang EKI HELP
3012 bar BAR HELP
3013
3014 optional arguments:
3015 -h, --help show this help message and exit
3016 -x X HELP
3017 --y Y Y HELP
3018 '''
3019
3020 version = ''
3021
3022
3023class TestHelpReformatting(HelpTestCase):
3024 """Make sure that text after short names starts on the first line"""
3025
3026 parser_signature = Sig(
3027 prog='PROG',
3028 description=' oddly formatted\n'
3029 'description\n'
3030 '\n'
3031 'that is so long that it should go onto multiple '
3032 'lines when wrapped')
3033 argument_signatures = [
3034 Sig('-x', metavar='XX', help='oddly\n'
3035 ' formatted -x help'),
3036 Sig('y', metavar='yyy', help='normal y help'),
3037 ]
3038 argument_group_signatures = [
3039 (Sig('title', description='\n'
3040 ' oddly formatted group\n'
3041 '\n'
3042 'description'),
3043 [Sig('-a', action='store_true',
3044 help=' oddly \n'
3045 'formatted -a help \n'
3046 ' again, so long that it should be wrapped over '
3047 'multiple lines')]),
3048 ]
3049 usage = '''\
3050 usage: PROG [-h] [-x XX] [-a] yyy
3051 '''
3052 help = usage + '''\
3053
3054 oddly formatted description that is so long that it should go onto \
3055multiple
3056 lines when wrapped
3057
3058 positional arguments:
3059 yyy normal y help
3060
3061 optional arguments:
3062 -h, --help show this help message and exit
3063 -x XX oddly formatted -x help
3064
3065 title:
3066 oddly formatted group description
3067
3068 -a oddly formatted -a help again, so long that it should \
3069be wrapped
3070 over multiple lines
3071 '''
3072 version = ''
3073
3074
3075class TestHelpWrappingShortNames(HelpTestCase):
3076 """Make sure that text after short names starts on the first line"""
3077
3078 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3079 argument_signatures = [
3080 Sig('-x', metavar='XX', help='XHH HX' * 20),
3081 Sig('y', metavar='yyy', help='YH YH' * 20),
3082 ]
3083 argument_group_signatures = [
3084 (Sig('ALPHAS'), [
3085 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3086 ]
3087 usage = '''\
3088 usage: PROG [-h] [-x XX] [-a] yyy
3089 '''
3090 help = usage + '''\
3091
3092 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3093DD DD DD
3094 DD DD DD DD D
3095
3096 positional arguments:
3097 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3098YHYH YHYH
3099 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3100
3101 optional arguments:
3102 -h, --help show this help message and exit
3103 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3104HXXHH HXXHH
3105 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3106
3107 ALPHAS:
3108 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3109HHAAHHH
3110 HHAAHHH HHAAHHH HHA
3111 '''
3112 version = ''
3113
3114
3115class TestHelpWrappingLongNames(HelpTestCase):
3116 """Make sure that text after long names starts on the next line"""
3117
3118 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3119 version='V V'*30)
3120 argument_signatures = [
3121 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3122 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3123 ]
3124 argument_group_signatures = [
3125 (Sig('ALPHAS'), [
3126 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3127 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3128 ]
3129 usage = '''\
3130 usage: USAGE
3131 '''
3132 help = usage + '''\
3133
3134 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3135DD DD DD
3136 DD DD DD DD D
3137
3138 positional arguments:
3139 yyyyyyyyyyyyyyyyyyyyyyyyy
3140 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3141YHYH YHYH
3142 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3143
3144 optional arguments:
3145 -h, --help show this help message and exit
3146 -v, --version show program's version number and exit
3147 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3148 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3149XHXH XHXH
3150 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3151
3152 ALPHAS:
3153 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3154 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3155AHAH AHAH
3156 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3157 zzzzzzzzzzzzzzzzzzzzzzzzz
3158 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3159ZHZH ZHZH
3160 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3161 '''
3162 version = '''\
3163 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3164VV VV VV
3165 VV VV VV VV V
3166 '''
3167
3168
3169class TestHelpUsage(HelpTestCase):
3170 """Test basic usage messages"""
3171
3172 parser_signature = Sig(prog='PROG')
3173 argument_signatures = [
3174 Sig('-w', nargs='+', help='w'),
3175 Sig('-x', nargs='*', help='x'),
3176 Sig('a', help='a'),
3177 Sig('b', help='b', nargs=2),
3178 Sig('c', help='c', nargs='?'),
3179 ]
3180 argument_group_signatures = [
3181 (Sig('group'), [
3182 Sig('-y', nargs='?', help='y'),
3183 Sig('-z', nargs=3, help='z'),
3184 Sig('d', help='d', nargs='*'),
3185 Sig('e', help='e', nargs='+'),
3186 ])
3187 ]
3188 usage = '''\
3189 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3190 a b b [c] [d [d ...]] e [e ...]
3191 '''
3192 help = usage + '''\
3193
3194 positional arguments:
3195 a a
3196 b b
3197 c c
3198
3199 optional arguments:
3200 -h, --help show this help message and exit
3201 -w W [W ...] w
3202 -x [X [X ...]] x
3203
3204 group:
3205 -y [Y] y
3206 -z Z Z Z z
3207 d d
3208 e e
3209 '''
3210 version = ''
3211
3212
3213class TestHelpOnlyUserGroups(HelpTestCase):
3214 """Test basic usage messages"""
3215
3216 parser_signature = Sig(prog='PROG', add_help=False)
3217 argument_signatures = []
3218 argument_group_signatures = [
3219 (Sig('xxxx'), [
3220 Sig('-x', help='x'),
3221 Sig('a', help='a'),
3222 ]),
3223 (Sig('yyyy'), [
3224 Sig('b', help='b'),
3225 Sig('-y', help='y'),
3226 ]),
3227 ]
3228 usage = '''\
3229 usage: PROG [-x X] [-y Y] a b
3230 '''
3231 help = usage + '''\
3232
3233 xxxx:
3234 -x X x
3235 a a
3236
3237 yyyy:
3238 b b
3239 -y Y y
3240 '''
3241 version = ''
3242
3243
3244class TestHelpUsageLongProg(HelpTestCase):
3245 """Test usage messages where the prog is long"""
3246
3247 parser_signature = Sig(prog='P' * 60)
3248 argument_signatures = [
3249 Sig('-w', metavar='W'),
3250 Sig('-x', metavar='X'),
3251 Sig('a'),
3252 Sig('b'),
3253 ]
3254 argument_group_signatures = []
3255 usage = '''\
3256 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3257 [-h] [-w W] [-x X] a b
3258 '''
3259 help = usage + '''\
3260
3261 positional arguments:
3262 a
3263 b
3264
3265 optional arguments:
3266 -h, --help show this help message and exit
3267 -w W
3268 -x X
3269 '''
3270 version = ''
3271
3272
3273class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3274 """Test usage messages where the prog is long and the optionals wrap"""
3275
3276 parser_signature = Sig(prog='P' * 60)
3277 argument_signatures = [
3278 Sig('-w', metavar='W' * 25),
3279 Sig('-x', metavar='X' * 25),
3280 Sig('-y', metavar='Y' * 25),
3281 Sig('-z', metavar='Z' * 25),
3282 Sig('a'),
3283 Sig('b'),
3284 ]
3285 argument_group_signatures = []
3286 usage = '''\
3287 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3288 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3289[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3290 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3291 a b
3292 '''
3293 help = usage + '''\
3294
3295 positional arguments:
3296 a
3297 b
3298
3299 optional arguments:
3300 -h, --help show this help message and exit
3301 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3302 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3303 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3304 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3305 '''
3306 version = ''
3307
3308
3309class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3310 """Test usage messages where the prog is long and the positionals wrap"""
3311
3312 parser_signature = Sig(prog='P' * 60, add_help=False)
3313 argument_signatures = [
3314 Sig('a' * 25),
3315 Sig('b' * 25),
3316 Sig('c' * 25),
3317 ]
3318 argument_group_signatures = []
3319 usage = '''\
3320 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3321 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3322 ccccccccccccccccccccccccc
3323 '''
3324 help = usage + '''\
3325
3326 positional arguments:
3327 aaaaaaaaaaaaaaaaaaaaaaaaa
3328 bbbbbbbbbbbbbbbbbbbbbbbbb
3329 ccccccccccccccccccccccccc
3330 '''
3331 version = ''
3332
3333
3334class TestHelpUsageOptionalsWrap(HelpTestCase):
3335 """Test usage messages where the optionals wrap"""
3336
3337 parser_signature = Sig(prog='PROG')
3338 argument_signatures = [
3339 Sig('-w', metavar='W' * 25),
3340 Sig('-x', metavar='X' * 25),
3341 Sig('-y', metavar='Y' * 25),
3342 Sig('-z', metavar='Z' * 25),
3343 Sig('a'),
3344 Sig('b'),
3345 Sig('c'),
3346 ]
3347 argument_group_signatures = []
3348 usage = '''\
3349 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3350[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3351 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3352[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3353 a b c
3354 '''
3355 help = usage + '''\
3356
3357 positional arguments:
3358 a
3359 b
3360 c
3361
3362 optional arguments:
3363 -h, --help show this help message and exit
3364 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3365 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3366 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3367 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3368 '''
3369 version = ''
3370
3371
3372class TestHelpUsagePositionalsWrap(HelpTestCase):
3373 """Test usage messages where the positionals wrap"""
3374
3375 parser_signature = Sig(prog='PROG')
3376 argument_signatures = [
3377 Sig('-x'),
3378 Sig('-y'),
3379 Sig('-z'),
3380 Sig('a' * 25),
3381 Sig('b' * 25),
3382 Sig('c' * 25),
3383 ]
3384 argument_group_signatures = []
3385 usage = '''\
3386 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3387 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3388 ccccccccccccccccccccccccc
3389 '''
3390 help = usage + '''\
3391
3392 positional arguments:
3393 aaaaaaaaaaaaaaaaaaaaaaaaa
3394 bbbbbbbbbbbbbbbbbbbbbbbbb
3395 ccccccccccccccccccccccccc
3396
3397 optional arguments:
3398 -h, --help show this help message and exit
3399 -x X
3400 -y Y
3401 -z Z
3402 '''
3403 version = ''
3404
3405
3406class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3407 """Test usage messages where the optionals and positionals wrap"""
3408
3409 parser_signature = Sig(prog='PROG')
3410 argument_signatures = [
3411 Sig('-x', metavar='X' * 25),
3412 Sig('-y', metavar='Y' * 25),
3413 Sig('-z', metavar='Z' * 25),
3414 Sig('a' * 25),
3415 Sig('b' * 25),
3416 Sig('c' * 25),
3417 ]
3418 argument_group_signatures = []
3419 usage = '''\
3420 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3421[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3422 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3423 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3424 ccccccccccccccccccccccccc
3425 '''
3426 help = usage + '''\
3427
3428 positional arguments:
3429 aaaaaaaaaaaaaaaaaaaaaaaaa
3430 bbbbbbbbbbbbbbbbbbbbbbbbb
3431 ccccccccccccccccccccccccc
3432
3433 optional arguments:
3434 -h, --help show this help message and exit
3435 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3436 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3437 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3438 '''
3439 version = ''
3440
3441
3442class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3443 """Test usage messages where there are only optionals and they wrap"""
3444
3445 parser_signature = Sig(prog='PROG')
3446 argument_signatures = [
3447 Sig('-x', metavar='X' * 25),
3448 Sig('-y', metavar='Y' * 25),
3449 Sig('-z', metavar='Z' * 25),
3450 ]
3451 argument_group_signatures = []
3452 usage = '''\
3453 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3454[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3455 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3456 '''
3457 help = usage + '''\
3458
3459 optional arguments:
3460 -h, --help show this help message and exit
3461 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3462 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3463 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3464 '''
3465 version = ''
3466
3467
3468class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3469 """Test usage messages where there are only positionals and they wrap"""
3470
3471 parser_signature = Sig(prog='PROG', add_help=False)
3472 argument_signatures = [
3473 Sig('a' * 25),
3474 Sig('b' * 25),
3475 Sig('c' * 25),
3476 ]
3477 argument_group_signatures = []
3478 usage = '''\
3479 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3480 ccccccccccccccccccccccccc
3481 '''
3482 help = usage + '''\
3483
3484 positional arguments:
3485 aaaaaaaaaaaaaaaaaaaaaaaaa
3486 bbbbbbbbbbbbbbbbbbbbbbbbb
3487 ccccccccccccccccccccccccc
3488 '''
3489 version = ''
3490
3491
3492class TestHelpVariableExpansion(HelpTestCase):
3493 """Test that variables are expanded properly in help messages"""
3494
3495 parser_signature = Sig(prog='PROG')
3496 argument_signatures = [
3497 Sig('-x', type=int,
3498 help='x %(prog)s %(default)s %(type)s %%'),
3499 Sig('-y', action='store_const', default=42, const='XXX',
3500 help='y %(prog)s %(default)s %(const)s'),
3501 Sig('--foo', choices='abc',
3502 help='foo %(prog)s %(default)s %(choices)s'),
3503 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3504 help='bar %(prog)s %(default)s %(dest)s'),
3505 Sig('spam', help='spam %(prog)s %(default)s'),
3506 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3507 ]
3508 argument_group_signatures = [
3509 (Sig('group'), [
3510 Sig('-a', help='a %(prog)s %(default)s'),
3511 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3512 ])
3513 ]
3514 usage = ('''\
3515 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3516 spam badger
3517 ''')
3518 help = usage + '''\
3519
3520 positional arguments:
3521 spam spam PROG None
3522 badger badger PROG 0.5
3523
3524 optional arguments:
3525 -h, --help show this help message and exit
3526 -x X x PROG None int %
3527 -y y PROG 42 XXX
3528 --foo {a,b,c} foo PROG None a, b, c
3529 --bar BBB bar PROG baz bar
3530
3531 group:
3532 -a A a PROG None
3533 -b B b PROG -1
3534 '''
3535 version = ''
3536
3537
3538class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3539 """Test that variables are expanded properly when usage= is present"""
3540
3541 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3542 argument_signatures = []
3543 argument_group_signatures = []
3544 usage = ('''\
3545 usage: PROG FOO
3546 ''')
3547 help = usage + '''\
3548
3549 optional arguments:
3550 -h, --help show this help message and exit
3551 '''
3552 version = ''
3553
3554
3555class TestHelpVariableExpansionNoArguments(HelpTestCase):
3556 """Test that variables are expanded properly with no arguments"""
3557
3558 parser_signature = Sig(prog='PROG', add_help=False)
3559 argument_signatures = []
3560 argument_group_signatures = []
3561 usage = ('''\
3562 usage: PROG
3563 ''')
3564 help = usage
3565 version = ''
3566
3567
3568class TestHelpSuppressUsage(HelpTestCase):
3569 """Test that items can be suppressed in usage messages"""
3570
3571 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3572 argument_signatures = [
3573 Sig('--foo', help='foo help'),
3574 Sig('spam', help='spam help'),
3575 ]
3576 argument_group_signatures = []
3577 help = '''\
3578 positional arguments:
3579 spam spam help
3580
3581 optional arguments:
3582 -h, --help show this help message and exit
3583 --foo FOO foo help
3584 '''
3585 usage = ''
3586 version = ''
3587
3588
3589class TestHelpSuppressOptional(HelpTestCase):
3590 """Test that optional arguments can be suppressed in help messages"""
3591
3592 parser_signature = Sig(prog='PROG', add_help=False)
3593 argument_signatures = [
3594 Sig('--foo', help=argparse.SUPPRESS),
3595 Sig('spam', help='spam help'),
3596 ]
3597 argument_group_signatures = []
3598 usage = '''\
3599 usage: PROG spam
3600 '''
3601 help = usage + '''\
3602
3603 positional arguments:
3604 spam spam help
3605 '''
3606 version = ''
3607
3608
3609class TestHelpSuppressOptionalGroup(HelpTestCase):
3610 """Test that optional groups can be suppressed in help messages"""
3611
3612 parser_signature = Sig(prog='PROG')
3613 argument_signatures = [
3614 Sig('--foo', help='foo help'),
3615 Sig('spam', help='spam help'),
3616 ]
3617 argument_group_signatures = [
3618 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3619 ]
3620 usage = '''\
3621 usage: PROG [-h] [--foo FOO] spam
3622 '''
3623 help = usage + '''\
3624
3625 positional arguments:
3626 spam spam help
3627
3628 optional arguments:
3629 -h, --help show this help message and exit
3630 --foo FOO foo help
3631 '''
3632 version = ''
3633
3634
3635class TestHelpSuppressPositional(HelpTestCase):
3636 """Test that positional arguments can be suppressed in help messages"""
3637
3638 parser_signature = Sig(prog='PROG')
3639 argument_signatures = [
3640 Sig('--foo', help='foo help'),
3641 Sig('spam', help=argparse.SUPPRESS),
3642 ]
3643 argument_group_signatures = []
3644 usage = '''\
3645 usage: PROG [-h] [--foo FOO]
3646 '''
3647 help = usage + '''\
3648
3649 optional arguments:
3650 -h, --help show this help message and exit
3651 --foo FOO foo help
3652 '''
3653 version = ''
3654
3655
3656class TestHelpRequiredOptional(HelpTestCase):
3657 """Test that required options don't look optional"""
3658
3659 parser_signature = Sig(prog='PROG')
3660 argument_signatures = [
3661 Sig('--foo', required=True, help='foo help'),
3662 ]
3663 argument_group_signatures = []
3664 usage = '''\
3665 usage: PROG [-h] --foo FOO
3666 '''
3667 help = usage + '''\
3668
3669 optional arguments:
3670 -h, --help show this help message and exit
3671 --foo FOO foo help
3672 '''
3673 version = ''
3674
3675
3676class TestHelpAlternatePrefixChars(HelpTestCase):
3677 """Test that options display with different prefix characters"""
3678
3679 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3680 argument_signatures = [
3681 Sig('^^foo', action='store_true', help='foo help'),
3682 Sig(';b', ';;bar', help='bar help'),
3683 ]
3684 argument_group_signatures = []
3685 usage = '''\
3686 usage: PROG [^^foo] [;b BAR]
3687 '''
3688 help = usage + '''\
3689
3690 optional arguments:
3691 ^^foo foo help
3692 ;b BAR, ;;bar BAR bar help
3693 '''
3694 version = ''
3695
3696
3697class TestHelpNoHelpOptional(HelpTestCase):
3698 """Test that the --help argument can be suppressed help messages"""
3699
3700 parser_signature = Sig(prog='PROG', add_help=False)
3701 argument_signatures = [
3702 Sig('--foo', help='foo help'),
3703 Sig('spam', help='spam help'),
3704 ]
3705 argument_group_signatures = []
3706 usage = '''\
3707 usage: PROG [--foo FOO] spam
3708 '''
3709 help = usage + '''\
3710
3711 positional arguments:
3712 spam spam help
3713
3714 optional arguments:
3715 --foo FOO foo help
3716 '''
3717 version = ''
3718
3719
3720class TestHelpVersionOptional(HelpTestCase):
3721 """Test that the --version argument can be suppressed help messages"""
3722
3723 parser_signature = Sig(prog='PROG', version='1.0')
3724 argument_signatures = [
3725 Sig('--foo', help='foo help'),
3726 Sig('spam', help='spam help'),
3727 ]
3728 argument_group_signatures = []
3729 usage = '''\
3730 usage: PROG [-h] [-v] [--foo FOO] spam
3731 '''
3732 help = usage + '''\
3733
3734 positional arguments:
3735 spam spam help
3736
3737 optional arguments:
3738 -h, --help show this help message and exit
3739 -v, --version show program's version number and exit
3740 --foo FOO foo help
3741 '''
3742 version = '''\
3743 1.0
3744 '''
3745
3746
3747class TestHelpNone(HelpTestCase):
3748 """Test that no errors occur if no help is specified"""
3749
3750 parser_signature = Sig(prog='PROG')
3751 argument_signatures = [
3752 Sig('--foo'),
3753 Sig('spam'),
3754 ]
3755 argument_group_signatures = []
3756 usage = '''\
3757 usage: PROG [-h] [--foo FOO] spam
3758 '''
3759 help = usage + '''\
3760
3761 positional arguments:
3762 spam
3763
3764 optional arguments:
3765 -h, --help show this help message and exit
3766 --foo FOO
3767 '''
3768 version = ''
3769
3770
3771class TestHelpTupleMetavar(HelpTestCase):
3772 """Test specifying metavar as a tuple"""
3773
3774 parser_signature = Sig(prog='PROG')
3775 argument_signatures = [
3776 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3777 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3778 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3779 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3780 ]
3781 argument_group_signatures = []
3782 usage = '''\
3783 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3784[-z [Z1]]
3785 '''
3786 help = usage + '''\
3787
3788 optional arguments:
3789 -h, --help show this help message and exit
3790 -w W1 [W2 ...] w
3791 -x [X1 [X2 ...]] x
3792 -y Y1 Y2 Y3 y
3793 -z [Z1] z
3794 '''
3795 version = ''
3796
3797
3798class TestHelpRawText(HelpTestCase):
3799 """Test the RawTextHelpFormatter"""
3800
3801 parser_signature = Sig(
3802 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3803 description='Keep the formatting\n'
3804 ' exactly as it is written\n'
3805 '\n'
3806 'here\n')
3807
3808 argument_signatures = [
3809 Sig('--foo', help=' foo help should also\n'
3810 'appear as given here'),
3811 Sig('spam', help='spam help'),
3812 ]
3813 argument_group_signatures = [
3814 (Sig('title', description=' This text\n'
3815 ' should be indented\n'
3816 ' exactly like it is here\n'),
3817 [Sig('--bar', help='bar help')]),
3818 ]
3819 usage = '''\
3820 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3821 '''
3822 help = usage + '''\
3823
3824 Keep the formatting
3825 exactly as it is written
3826
3827 here
3828
3829 positional arguments:
3830 spam spam help
3831
3832 optional arguments:
3833 -h, --help show this help message and exit
3834 --foo FOO foo help should also
3835 appear as given here
3836
3837 title:
3838 This text
3839 should be indented
3840 exactly like it is here
3841
3842 --bar BAR bar help
3843 '''
3844 version = ''
3845
3846
3847class TestHelpRawDescription(HelpTestCase):
3848 """Test the RawTextHelpFormatter"""
3849
3850 parser_signature = Sig(
3851 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3852 description='Keep the formatting\n'
3853 ' exactly as it is written\n'
3854 '\n'
3855 'here\n')
3856
3857 argument_signatures = [
3858 Sig('--foo', help=' foo help should not\n'
3859 ' retain this odd formatting'),
3860 Sig('spam', help='spam help'),
3861 ]
3862 argument_group_signatures = [
3863 (Sig('title', description=' This text\n'
3864 ' should be indented\n'
3865 ' exactly like it is here\n'),
3866 [Sig('--bar', help='bar help')]),
3867 ]
3868 usage = '''\
3869 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3870 '''
3871 help = usage + '''\
3872
3873 Keep the formatting
3874 exactly as it is written
3875
3876 here
3877
3878 positional arguments:
3879 spam spam help
3880
3881 optional arguments:
3882 -h, --help show this help message and exit
3883 --foo FOO foo help should not retain this odd formatting
3884
3885 title:
3886 This text
3887 should be indented
3888 exactly like it is here
3889
3890 --bar BAR bar help
3891 '''
3892 version = ''
3893
3894
3895class TestHelpArgumentDefaults(HelpTestCase):
3896 """Test the ArgumentDefaultsHelpFormatter"""
3897
3898 parser_signature = Sig(
3899 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3900 description='description')
3901
3902 argument_signatures = [
3903 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3904 Sig('--bar', action='store_true', help='bar help'),
3905 Sig('spam', help='spam help'),
3906 Sig('badger', nargs='?', default='wooden', help='badger help'),
3907 ]
3908 argument_group_signatures = [
3909 (Sig('title', description='description'),
3910 [Sig('--baz', type=int, default=42, help='baz help')]),
3911 ]
3912 usage = '''\
3913 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3914 '''
3915 help = usage + '''\
3916
3917 description
3918
3919 positional arguments:
3920 spam spam help
3921 badger badger help (default: wooden)
3922
3923 optional arguments:
3924 -h, --help show this help message and exit
3925 --foo FOO foo help - oh and by the way, None
3926 --bar bar help (default: False)
3927
3928 title:
3929 description
3930
3931 --baz BAZ baz help (default: 42)
3932 '''
3933 version = ''
3934
Steven Bethard50fe5932010-05-24 03:47:38 +00003935class TestHelpVersionAction(HelpTestCase):
3936 """Test the default help for the version action"""
3937
3938 parser_signature = Sig(prog='PROG', description='description')
3939 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3940 argument_group_signatures = []
3941 usage = '''\
3942 usage: PROG [-h] [-V]
3943 '''
3944 help = usage + '''\
3945
3946 description
3947
3948 optional arguments:
3949 -h, --help show this help message and exit
3950 -V, --version show program's version number and exit
3951 '''
3952 version = ''
3953
Steven Bethard8a6a1982011-03-27 13:53:53 +02003954class TestHelpSubparsersOrdering(HelpTestCase):
3955 """Test ordering of subcommands in help matches the code"""
3956 parser_signature = Sig(prog='PROG',
3957 description='display some subcommands',
3958 version='0.1')
3959
3960 subparsers_signatures = [Sig(name=name)
3961 for name in ('a', 'b', 'c', 'd', 'e')]
3962
3963 usage = '''\
3964 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3965 '''
3966
3967 help = usage + '''\
3968
3969 display some subcommands
3970
3971 positional arguments:
3972 {a,b,c,d,e}
3973
3974 optional arguments:
3975 -h, --help show this help message and exit
3976 -v, --version show program's version number and exit
3977 '''
3978
3979 version = '''\
3980 0.1
3981 '''
3982
3983class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
3984 """Test ordering of subcommands in help matches the code"""
3985 parser_signature = Sig(prog='PROG',
3986 description='display some subcommands',
3987 version='0.1')
3988
3989 subcommand_data = (('a', 'a subcommand help'),
3990 ('b', 'b subcommand help'),
3991 ('c', 'c subcommand help'),
3992 ('d', 'd subcommand help'),
3993 ('e', 'e subcommand help'),
3994 )
3995
3996 subparsers_signatures = [Sig(name=name, help=help)
3997 for name, help in subcommand_data]
3998
3999 usage = '''\
4000 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4001 '''
4002
4003 help = usage + '''\
4004
4005 display some subcommands
4006
4007 positional arguments:
4008 {a,b,c,d,e}
4009 a a subcommand help
4010 b b subcommand help
4011 c c subcommand help
4012 d d subcommand help
4013 e e subcommand help
4014
4015 optional arguments:
4016 -h, --help show this help message and exit
4017 -v, --version show program's version number and exit
4018 '''
4019
4020 version = '''\
4021 0.1
4022 '''
4023
4024
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004025# =====================================
4026# Optional/Positional constructor tests
4027# =====================================
4028
4029class TestInvalidArgumentConstructors(TestCase):
4030 """Test a bunch of invalid Argument constructors"""
4031
4032 def assertTypeError(self, *args, **kwargs):
4033 parser = argparse.ArgumentParser()
4034 self.assertRaises(TypeError, parser.add_argument,
4035 *args, **kwargs)
4036
4037 def assertValueError(self, *args, **kwargs):
4038 parser = argparse.ArgumentParser()
4039 self.assertRaises(ValueError, parser.add_argument,
4040 *args, **kwargs)
4041
4042 def test_invalid_keyword_arguments(self):
4043 self.assertTypeError('-x', bar=None)
4044 self.assertTypeError('-y', callback='foo')
4045 self.assertTypeError('-y', callback_args=())
4046 self.assertTypeError('-y', callback_kwargs={})
4047
4048 def test_missing_destination(self):
4049 self.assertTypeError()
4050 for action in ['append', 'store']:
4051 self.assertTypeError(action=action)
4052
4053 def test_invalid_option_strings(self):
4054 self.assertValueError('--')
4055 self.assertValueError('---')
4056
4057 def test_invalid_type(self):
4058 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004059 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004060
4061 def test_invalid_action(self):
4062 self.assertValueError('-x', action='foo')
4063 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004064 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004065 parser = argparse.ArgumentParser()
4066 try:
4067 parser.add_argument("--foo", action="store-true")
4068 except ValueError:
4069 e = sys.exc_info()[1]
4070 expected = 'unknown action'
4071 msg = 'expected %r, found %r' % (expected, e)
4072 self.assertTrue(expected in str(e), msg)
4073
4074 def test_multiple_dest(self):
4075 parser = argparse.ArgumentParser()
4076 parser.add_argument(dest='foo')
4077 try:
4078 parser.add_argument('bar', dest='baz')
4079 except ValueError:
4080 e = sys.exc_info()[1]
4081 expected = 'dest supplied twice for positional argument'
4082 msg = 'expected %r, found %r' % (expected, e)
4083 self.assertTrue(expected in str(e), msg)
4084
4085 def test_no_argument_actions(self):
4086 for action in ['store_const', 'store_true', 'store_false',
4087 'append_const', 'count']:
4088 for attrs in [dict(type=int), dict(nargs='+'),
4089 dict(choices='ab')]:
4090 self.assertTypeError('-x', action=action, **attrs)
4091
4092 def test_no_argument_no_const_actions(self):
4093 # options with zero arguments
4094 for action in ['store_true', 'store_false', 'count']:
4095
4096 # const is always disallowed
4097 self.assertTypeError('-x', const='foo', action=action)
4098
4099 # nargs is always disallowed
4100 self.assertTypeError('-x', nargs='*', action=action)
4101
4102 def test_more_than_one_argument_actions(self):
4103 for action in ['store', 'append']:
4104
4105 # nargs=0 is disallowed
4106 self.assertValueError('-x', nargs=0, action=action)
4107 self.assertValueError('spam', nargs=0, action=action)
4108
4109 # const is disallowed with non-optional arguments
4110 for nargs in [1, '*', '+']:
4111 self.assertValueError('-x', const='foo',
4112 nargs=nargs, action=action)
4113 self.assertValueError('spam', const='foo',
4114 nargs=nargs, action=action)
4115
4116 def test_required_const_actions(self):
4117 for action in ['store_const', 'append_const']:
4118
4119 # nargs is always disallowed
4120 self.assertTypeError('-x', nargs='+', action=action)
4121
4122 def test_parsers_action_missing_params(self):
4123 self.assertTypeError('command', action='parsers')
4124 self.assertTypeError('command', action='parsers', prog='PROG')
4125 self.assertTypeError('command', action='parsers',
4126 parser_class=argparse.ArgumentParser)
4127
4128 def test_required_positional(self):
4129 self.assertTypeError('foo', required=True)
4130
4131 def test_user_defined_action(self):
4132
4133 class Success(Exception):
4134 pass
4135
4136 class Action(object):
4137
4138 def __init__(self,
4139 option_strings,
4140 dest,
4141 const,
4142 default,
4143 required=False):
4144 if dest == 'spam':
4145 if const is Success:
4146 if default is Success:
4147 raise Success()
4148
4149 def __call__(self, *args, **kwargs):
4150 pass
4151
4152 parser = argparse.ArgumentParser()
4153 self.assertRaises(Success, parser.add_argument, '--spam',
4154 action=Action, default=Success, const=Success)
4155 self.assertRaises(Success, parser.add_argument, 'spam',
4156 action=Action, default=Success, const=Success)
4157
4158# ================================
4159# Actions returned by add_argument
4160# ================================
4161
4162class TestActionsReturned(TestCase):
4163
4164 def test_dest(self):
4165 parser = argparse.ArgumentParser()
4166 action = parser.add_argument('--foo')
4167 self.assertEqual(action.dest, 'foo')
4168 action = parser.add_argument('-b', '--bar')
4169 self.assertEqual(action.dest, 'bar')
4170 action = parser.add_argument('-x', '-y')
4171 self.assertEqual(action.dest, 'x')
4172
4173 def test_misc(self):
4174 parser = argparse.ArgumentParser()
4175 action = parser.add_argument('--foo', nargs='?', const=42,
4176 default=84, type=int, choices=[1, 2],
4177 help='FOO', metavar='BAR', dest='baz')
4178 self.assertEqual(action.nargs, '?')
4179 self.assertEqual(action.const, 42)
4180 self.assertEqual(action.default, 84)
4181 self.assertEqual(action.type, int)
4182 self.assertEqual(action.choices, [1, 2])
4183 self.assertEqual(action.help, 'FOO')
4184 self.assertEqual(action.metavar, 'BAR')
4185 self.assertEqual(action.dest, 'baz')
4186
4187
4188# ================================
4189# Argument conflict handling tests
4190# ================================
4191
4192class TestConflictHandling(TestCase):
4193
4194 def test_bad_type(self):
4195 self.assertRaises(ValueError, argparse.ArgumentParser,
4196 conflict_handler='foo')
4197
4198 def test_conflict_error(self):
4199 parser = argparse.ArgumentParser()
4200 parser.add_argument('-x')
4201 self.assertRaises(argparse.ArgumentError,
4202 parser.add_argument, '-x')
4203 parser.add_argument('--spam')
4204 self.assertRaises(argparse.ArgumentError,
4205 parser.add_argument, '--spam')
4206
4207 def test_resolve_error(self):
4208 get_parser = argparse.ArgumentParser
4209 parser = get_parser(prog='PROG', conflict_handler='resolve')
4210
4211 parser.add_argument('-x', help='OLD X')
4212 parser.add_argument('-x', help='NEW X')
4213 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4214 usage: PROG [-h] [-x X]
4215
4216 optional arguments:
4217 -h, --help show this help message and exit
4218 -x X NEW X
4219 '''))
4220
4221 parser.add_argument('--spam', metavar='OLD_SPAM')
4222 parser.add_argument('--spam', metavar='NEW_SPAM')
4223 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4224 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4225
4226 optional arguments:
4227 -h, --help show this help message and exit
4228 -x X NEW X
4229 --spam NEW_SPAM
4230 '''))
4231
4232
4233# =============================
4234# Help and Version option tests
4235# =============================
4236
4237class TestOptionalsHelpVersionActions(TestCase):
4238 """Test the help and version actions"""
4239
4240 def _get_error(self, func, *args, **kwargs):
4241 try:
4242 func(*args, **kwargs)
4243 except ArgumentParserError:
4244 return sys.exc_info()[1]
4245 else:
4246 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4247
4248 def assertPrintHelpExit(self, parser, args_str):
4249 self.assertEqual(
4250 parser.format_help(),
4251 self._get_error(parser.parse_args, args_str.split()).stdout)
4252
4253 def assertPrintVersionExit(self, parser, args_str):
4254 self.assertEqual(
4255 parser.format_version(),
4256 self._get_error(parser.parse_args, args_str.split()).stderr)
4257
4258 def assertArgumentParserError(self, parser, *args):
4259 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4260
4261 def test_version(self):
4262 parser = ErrorRaisingArgumentParser(version='1.0')
4263 self.assertPrintHelpExit(parser, '-h')
4264 self.assertPrintHelpExit(parser, '--help')
4265 self.assertPrintVersionExit(parser, '-v')
4266 self.assertPrintVersionExit(parser, '--version')
4267
4268 def test_version_format(self):
4269 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4270 msg = self._get_error(parser.parse_args, ['-v']).stderr
4271 self.assertEqual('PPP 3.5\n', msg)
4272
4273 def test_version_no_help(self):
4274 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4275 self.assertArgumentParserError(parser, '-h')
4276 self.assertArgumentParserError(parser, '--help')
4277 self.assertPrintVersionExit(parser, '-v')
4278 self.assertPrintVersionExit(parser, '--version')
4279
4280 def test_version_action(self):
4281 parser = ErrorRaisingArgumentParser(prog='XXX')
4282 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4283 msg = self._get_error(parser.parse_args, ['-V']).stderr
4284 self.assertEqual('XXX 3.7\n', msg)
4285
4286 def test_no_help(self):
4287 parser = ErrorRaisingArgumentParser(add_help=False)
4288 self.assertArgumentParserError(parser, '-h')
4289 self.assertArgumentParserError(parser, '--help')
4290 self.assertArgumentParserError(parser, '-v')
4291 self.assertArgumentParserError(parser, '--version')
4292
4293 def test_alternate_help_version(self):
4294 parser = ErrorRaisingArgumentParser()
4295 parser.add_argument('-x', action='help')
4296 parser.add_argument('-y', action='version')
4297 self.assertPrintHelpExit(parser, '-x')
4298 self.assertPrintVersionExit(parser, '-y')
4299 self.assertArgumentParserError(parser, '-v')
4300 self.assertArgumentParserError(parser, '--version')
4301
4302 def test_help_version_extra_arguments(self):
4303 parser = ErrorRaisingArgumentParser(version='1.0')
4304 parser.add_argument('-x', action='store_true')
4305 parser.add_argument('y')
4306
4307 # try all combinations of valid prefixes and suffixes
4308 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4309 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4310 for prefix in valid_prefixes:
4311 for suffix in valid_suffixes:
4312 format = '%s %%s %s' % (prefix, suffix)
4313 self.assertPrintHelpExit(parser, format % '-h')
4314 self.assertPrintHelpExit(parser, format % '--help')
4315 self.assertPrintVersionExit(parser, format % '-v')
4316 self.assertPrintVersionExit(parser, format % '--version')
4317
4318
4319# ======================
4320# str() and repr() tests
4321# ======================
4322
4323class TestStrings(TestCase):
4324 """Test str() and repr() on Optionals and Positionals"""
4325
4326 def assertStringEqual(self, obj, result_string):
4327 for func in [str, repr]:
4328 self.assertEqual(func(obj), result_string)
4329
4330 def test_optional(self):
4331 option = argparse.Action(
4332 option_strings=['--foo', '-a', '-b'],
4333 dest='b',
4334 type='int',
4335 nargs='+',
4336 default=42,
4337 choices=[1, 2, 3],
4338 help='HELP',
4339 metavar='METAVAR')
4340 string = (
4341 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4342 "nargs='+', const=None, default=42, type='int', "
4343 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4344 self.assertStringEqual(option, string)
4345
4346 def test_argument(self):
4347 argument = argparse.Action(
4348 option_strings=[],
4349 dest='x',
4350 type=float,
4351 nargs='?',
4352 default=2.5,
4353 choices=[0.5, 1.5, 2.5],
4354 help='H HH H',
4355 metavar='MV MV MV')
4356 string = (
4357 "Action(option_strings=[], dest='x', nargs='?', "
4358 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4359 "help='H HH H', metavar='MV MV MV')" % float)
4360 self.assertStringEqual(argument, string)
4361
4362 def test_namespace(self):
4363 ns = argparse.Namespace(foo=42, bar='spam')
4364 string = "Namespace(bar='spam', foo=42)"
4365 self.assertStringEqual(ns, string)
4366
4367 def test_parser(self):
4368 parser = argparse.ArgumentParser(prog='PROG')
4369 string = (
4370 "ArgumentParser(prog='PROG', usage=None, description=None, "
4371 "version=None, formatter_class=%r, conflict_handler='error', "
4372 "add_help=True)" % argparse.HelpFormatter)
4373 self.assertStringEqual(parser, string)
4374
4375# ===============
4376# Namespace tests
4377# ===============
4378
4379class TestNamespace(TestCase):
4380
4381 def test_constructor(self):
4382 ns = argparse.Namespace()
4383 self.assertRaises(AttributeError, getattr, ns, 'x')
4384
4385 ns = argparse.Namespace(a=42, b='spam')
4386 self.assertEqual(ns.a, 42)
4387 self.assertEqual(ns.b, 'spam')
4388
4389 def test_equality(self):
4390 ns1 = argparse.Namespace(a=1, b=2)
4391 ns2 = argparse.Namespace(b=2, a=1)
4392 ns3 = argparse.Namespace(a=1)
4393 ns4 = argparse.Namespace(b=2)
4394
4395 self.assertEqual(ns1, ns2)
4396 self.assertNotEqual(ns1, ns3)
4397 self.assertNotEqual(ns1, ns4)
4398 self.assertNotEqual(ns2, ns3)
4399 self.assertNotEqual(ns2, ns4)
4400 self.assertTrue(ns1 != ns3)
4401 self.assertTrue(ns1 != ns4)
4402 self.assertTrue(ns2 != ns3)
4403 self.assertTrue(ns2 != ns4)
4404
4405
4406# ===================
4407# File encoding tests
4408# ===================
4409
4410class TestEncoding(TestCase):
4411
4412 def _test_module_encoding(self, path):
4413 path, _ = os.path.splitext(path)
4414 path += ".py"
Antoine Pitroub86680e2010-10-14 21:15:17 +00004415 with codecs.open(path, 'r', 'utf8') as f:
4416 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004417
4418 def test_argparse_module_encoding(self):
4419 self._test_module_encoding(argparse.__file__)
4420
4421 def test_test_argparse_module_encoding(self):
4422 self._test_module_encoding(__file__)
4423
4424# ===================
4425# ArgumentError tests
4426# ===================
4427
4428class TestArgumentError(TestCase):
4429
4430 def test_argument_error(self):
4431 msg = "my error here"
4432 error = argparse.ArgumentError(None, msg)
4433 self.assertEqual(str(error), msg)
4434
4435# =======================
4436# ArgumentTypeError tests
4437# =======================
4438
R. David Murray722b5fd2010-11-20 03:48:58 +00004439class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004440
4441 def test_argument_type_error(self):
4442
4443 def spam(string):
4444 raise argparse.ArgumentTypeError('spam!')
4445
4446 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4447 parser.add_argument('x', type=spam)
4448 try:
4449 parser.parse_args(['XXX'])
4450 except ArgumentParserError:
4451 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4452 msg = sys.exc_info()[1].stderr
4453 self.assertEqual(expected, msg)
4454 else:
4455 self.fail()
4456
4457# ======================
4458# parse_known_args tests
4459# ======================
4460
4461class TestParseKnownArgs(TestCase):
4462
4463 def test_optionals(self):
4464 parser = argparse.ArgumentParser()
4465 parser.add_argument('--foo')
4466 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4467 self.assertEqual(NS(foo='F'), args)
4468 self.assertEqual(['--bar', '--baz'], extras)
4469
4470 def test_mixed(self):
4471 parser = argparse.ArgumentParser()
4472 parser.add_argument('-v', nargs='?', const=1, type=int)
4473 parser.add_argument('--spam', action='store_false')
4474 parser.add_argument('badger')
4475
4476 argv = ["B", "C", "--foo", "-v", "3", "4"]
4477 args, extras = parser.parse_known_args(argv)
4478 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4479 self.assertEqual(["C", "--foo", "4"], extras)
4480
Steven Bethard8d9a4622011-03-26 17:33:56 +01004481# ==========================
4482# add_argument metavar tests
4483# ==========================
4484
4485class TestAddArgumentMetavar(TestCase):
4486
4487 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4488
4489 def do_test_no_exception(self, nargs, metavar):
4490 parser = argparse.ArgumentParser()
4491 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4492
4493 def do_test_exception(self, nargs, metavar):
4494 parser = argparse.ArgumentParser()
4495 with self.assertRaises(ValueError) as cm:
4496 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4497 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4498
4499 # Unit tests for different values of metavar when nargs=None
4500
4501 def test_nargs_None_metavar_string(self):
4502 self.do_test_no_exception(nargs=None, metavar="1")
4503
4504 def test_nargs_None_metavar_length0(self):
4505 self.do_test_exception(nargs=None, metavar=tuple())
4506
4507 def test_nargs_None_metavar_length1(self):
4508 self.do_test_no_exception(nargs=None, metavar=("1"))
4509
4510 def test_nargs_None_metavar_length2(self):
4511 self.do_test_exception(nargs=None, metavar=("1", "2"))
4512
4513 def test_nargs_None_metavar_length3(self):
4514 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4515
4516 # Unit tests for different values of metavar when nargs=?
4517
4518 def test_nargs_optional_metavar_string(self):
4519 self.do_test_no_exception(nargs="?", metavar="1")
4520
4521 def test_nargs_optional_metavar_length0(self):
4522 self.do_test_exception(nargs="?", metavar=tuple())
4523
4524 def test_nargs_optional_metavar_length1(self):
4525 self.do_test_no_exception(nargs="?", metavar=("1"))
4526
4527 def test_nargs_optional_metavar_length2(self):
4528 self.do_test_exception(nargs="?", metavar=("1", "2"))
4529
4530 def test_nargs_optional_metavar_length3(self):
4531 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4532
4533 # Unit tests for different values of metavar when nargs=*
4534
4535 def test_nargs_zeroormore_metavar_string(self):
4536 self.do_test_no_exception(nargs="*", metavar="1")
4537
4538 def test_nargs_zeroormore_metavar_length0(self):
4539 self.do_test_exception(nargs="*", metavar=tuple())
4540
4541 def test_nargs_zeroormore_metavar_length1(self):
4542 self.do_test_no_exception(nargs="*", metavar=("1"))
4543
4544 def test_nargs_zeroormore_metavar_length2(self):
4545 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4546
4547 def test_nargs_zeroormore_metavar_length3(self):
4548 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4549
4550 # Unit tests for different values of metavar when nargs=+
4551
4552 def test_nargs_oneormore_metavar_string(self):
4553 self.do_test_no_exception(nargs="+", metavar="1")
4554
4555 def test_nargs_oneormore_metavar_length0(self):
4556 self.do_test_exception(nargs="+", metavar=tuple())
4557
4558 def test_nargs_oneormore_metavar_length1(self):
4559 self.do_test_no_exception(nargs="+", metavar=("1"))
4560
4561 def test_nargs_oneormore_metavar_length2(self):
4562 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4563
4564 def test_nargs_oneormore_metavar_length3(self):
4565 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4566
4567 # Unit tests for different values of metavar when nargs=...
4568
4569 def test_nargs_remainder_metavar_string(self):
4570 self.do_test_no_exception(nargs="...", metavar="1")
4571
4572 def test_nargs_remainder_metavar_length0(self):
4573 self.do_test_no_exception(nargs="...", metavar=tuple())
4574
4575 def test_nargs_remainder_metavar_length1(self):
4576 self.do_test_no_exception(nargs="...", metavar=("1"))
4577
4578 def test_nargs_remainder_metavar_length2(self):
4579 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4580
4581 def test_nargs_remainder_metavar_length3(self):
4582 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4583
4584 # Unit tests for different values of metavar when nargs=A...
4585
4586 def test_nargs_parser_metavar_string(self):
4587 self.do_test_no_exception(nargs="A...", metavar="1")
4588
4589 def test_nargs_parser_metavar_length0(self):
4590 self.do_test_exception(nargs="A...", metavar=tuple())
4591
4592 def test_nargs_parser_metavar_length1(self):
4593 self.do_test_no_exception(nargs="A...", metavar=("1"))
4594
4595 def test_nargs_parser_metavar_length2(self):
4596 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4597
4598 def test_nargs_parser_metavar_length3(self):
4599 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4600
4601 # Unit tests for different values of metavar when nargs=1
4602
4603 def test_nargs_1_metavar_string(self):
4604 self.do_test_no_exception(nargs=1, metavar="1")
4605
4606 def test_nargs_1_metavar_length0(self):
4607 self.do_test_exception(nargs=1, metavar=tuple())
4608
4609 def test_nargs_1_metavar_length1(self):
4610 self.do_test_no_exception(nargs=1, metavar=("1"))
4611
4612 def test_nargs_1_metavar_length2(self):
4613 self.do_test_exception(nargs=1, metavar=("1", "2"))
4614
4615 def test_nargs_1_metavar_length3(self):
4616 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4617
4618 # Unit tests for different values of metavar when nargs=2
4619
4620 def test_nargs_2_metavar_string(self):
4621 self.do_test_no_exception(nargs=2, metavar="1")
4622
4623 def test_nargs_2_metavar_length0(self):
4624 self.do_test_exception(nargs=2, metavar=tuple())
4625
4626 def test_nargs_2_metavar_length1(self):
4627 self.do_test_no_exception(nargs=2, metavar=("1"))
4628
4629 def test_nargs_2_metavar_length2(self):
4630 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4631
4632 def test_nargs_2_metavar_length3(self):
4633 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4634
4635 # Unit tests for different values of metavar when nargs=3
4636
4637 def test_nargs_3_metavar_string(self):
4638 self.do_test_no_exception(nargs=3, metavar="1")
4639
4640 def test_nargs_3_metavar_length0(self):
4641 self.do_test_exception(nargs=3, metavar=tuple())
4642
4643 def test_nargs_3_metavar_length1(self):
4644 self.do_test_no_exception(nargs=3, metavar=("1"))
4645
4646 def test_nargs_3_metavar_length2(self):
4647 self.do_test_exception(nargs=3, metavar=("1", "2"))
4648
4649 def test_nargs_3_metavar_length3(self):
4650 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4651
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004652# ============================
4653# from argparse import * tests
4654# ============================
4655
4656class TestImportStar(TestCase):
4657
4658 def test(self):
4659 for name in argparse.__all__:
4660 self.assertTrue(hasattr(argparse, name))
4661
Steven Bethard72c55382010-11-01 15:23:12 +00004662 def test_all_exports_everything_but_modules(self):
4663 items = [
4664 name
4665 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00004666 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00004667 if not inspect.ismodule(value)
4668 ]
4669 self.assertEqual(sorted(items), sorted(argparse.__all__))
4670
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004671def test_main():
Florent Xicluna41fe6152010-04-02 18:52:12 +00004672 # silence warnings about version argument - these are expected
4673 with support.check_warnings(
4674 ('The "version" argument to ArgumentParser is deprecated.',
4675 DeprecationWarning),
4676 ('The (format|print)_version method is deprecated',
4677 DeprecationWarning)):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004678 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00004679 # Remove global references to avoid looking like we have refleaks.
4680 RFile.seen = {}
4681 WFile.seen = set()
4682
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004683
4684
4685if __name__ == '__main__':
4686 test_main()