blob: c06c940bf2d62dcccbc4bdb3de3fbf8f1192d2fe [file] [log] [blame]
Steven Bethardcd4ec0e2010-03-24 23:07:31 +00001# Author: Steven J. Bethard <steven.bethard@gmail.com>.
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002
3import codecs
Steven Bethard72c55382010-11-01 15:23:12 +00004import inspect
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005import os
6import shutil
Steven Bethardb0270112011-01-24 21:02:50 +00007import stat
Benjamin Peterson698a18a2010-03-02 22:34:37 +00008import sys
9import textwrap
10import tempfile
11import unittest
Benjamin Peterson698a18a2010-03-02 22:34:37 +000012import argparse
13
Benjamin Peterson16f2fd02010-03-02 23:09:38 +000014from io import StringIO
15
Benjamin Peterson698a18a2010-03-02 22:34:37 +000016from test import support
Benjamin Petersonb48af542010-04-11 20:43:16 +000017class StdIOBuffer(StringIO):
18 pass
Benjamin Peterson698a18a2010-03-02 22:34:37 +000019
Benjamin Peterson698a18a2010-03-02 22:34:37 +000020class TestCase(unittest.TestCase):
21
22 def assertEqual(self, obj1, obj2):
23 if obj1 != obj2:
24 print('')
25 print(repr(obj1))
26 print(repr(obj2))
27 print(obj1)
28 print(obj2)
29 super(TestCase, self).assertEqual(obj1, obj2)
30
Steven Bethard1f1c2472010-11-01 13:56:09 +000031 def setUp(self):
32 # The tests assume that line wrapping occurs at 80 columns, but this
33 # behaviour can be overridden by setting the COLUMNS environment
34 # variable. To ensure that this assumption is true, unset COLUMNS.
35 env = support.EnvironmentVarGuard()
36 env.unset("COLUMNS")
37 self.addCleanup(env.__exit__)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000038
Benjamin Petersonb48af542010-04-11 20:43:16 +000039
Benjamin Peterson698a18a2010-03-02 22:34:37 +000040class TempDirMixin(object):
41
42 def setUp(self):
43 self.temp_dir = tempfile.mkdtemp()
44 self.old_dir = os.getcwd()
45 os.chdir(self.temp_dir)
46
47 def tearDown(self):
48 os.chdir(self.old_dir)
Steven Bethardb0270112011-01-24 21:02:50 +000049 shutil.rmtree(self.temp_dir, True)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000050
Steven Bethardb0270112011-01-24 21:02:50 +000051 def create_readonly_file(self, filename):
52 file_path = os.path.join(self.temp_dir, filename)
53 with open(file_path, 'w') as file:
54 file.write(filename)
55 os.chmod(file_path, stat.S_IREAD)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000056
57class Sig(object):
58
59 def __init__(self, *args, **kwargs):
60 self.args = args
61 self.kwargs = kwargs
62
63
64class NS(object):
65
66 def __init__(self, **kwargs):
67 self.__dict__.update(kwargs)
68
69 def __repr__(self):
70 sorted_items = sorted(self.__dict__.items())
71 kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
72 return '%s(%s)' % (type(self).__name__, kwarg_str)
73
74 def __eq__(self, other):
75 return vars(self) == vars(other)
76
77 def __ne__(self, other):
78 return not (self == other)
79
80
81class ArgumentParserError(Exception):
82
83 def __init__(self, message, stdout=None, stderr=None, error_code=None):
84 Exception.__init__(self, message, stdout, stderr)
85 self.message = message
86 self.stdout = stdout
87 self.stderr = stderr
88 self.error_code = error_code
89
90
91def stderr_to_parser_error(parse_args, *args, **kwargs):
92 # if this is being called recursively and stderr or stdout is already being
93 # redirected, simply call the function and let the enclosing function
94 # catch the exception
Benjamin Petersonb48af542010-04-11 20:43:16 +000095 if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
Benjamin Peterson698a18a2010-03-02 22:34:37 +000096 return parse_args(*args, **kwargs)
97
98 # if this is not being called recursively, redirect stderr and
99 # use it as the ArgumentParserError message
100 old_stdout = sys.stdout
101 old_stderr = sys.stderr
Benjamin Petersonb48af542010-04-11 20:43:16 +0000102 sys.stdout = StdIOBuffer()
103 sys.stderr = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000104 try:
105 try:
106 result = parse_args(*args, **kwargs)
107 for key in list(vars(result)):
108 if getattr(result, key) is sys.stdout:
109 setattr(result, key, old_stdout)
110 if getattr(result, key) is sys.stderr:
111 setattr(result, key, old_stderr)
112 return result
113 except SystemExit:
114 code = sys.exc_info()[1].code
115 stdout = sys.stdout.getvalue()
116 stderr = sys.stderr.getvalue()
117 raise ArgumentParserError("SystemExit", stdout, stderr, code)
118 finally:
119 sys.stdout = old_stdout
120 sys.stderr = old_stderr
121
122
123class ErrorRaisingArgumentParser(argparse.ArgumentParser):
124
125 def parse_args(self, *args, **kwargs):
126 parse_args = super(ErrorRaisingArgumentParser, self).parse_args
127 return stderr_to_parser_error(parse_args, *args, **kwargs)
128
129 def exit(self, *args, **kwargs):
130 exit = super(ErrorRaisingArgumentParser, self).exit
131 return stderr_to_parser_error(exit, *args, **kwargs)
132
133 def error(self, *args, **kwargs):
134 error = super(ErrorRaisingArgumentParser, self).error
135 return stderr_to_parser_error(error, *args, **kwargs)
136
137
138class ParserTesterMetaclass(type):
139 """Adds parser tests using the class attributes.
140
141 Classes of this type should specify the following attributes:
142
143 argument_signatures -- a list of Sig objects which specify
144 the signatures of Argument objects to be created
145 failures -- a list of args lists that should cause the parser
146 to fail
147 successes -- a list of (initial_args, options, remaining_args) tuples
148 where initial_args specifies the string args to be parsed,
149 options is a dict that should match the vars() of the options
150 parsed out of initial_args, and remaining_args should be any
151 remaining unparsed arguments
152 """
153
154 def __init__(cls, name, bases, bodydict):
155 if name == 'ParserTestCase':
156 return
157
158 # default parser signature is empty
159 if not hasattr(cls, 'parser_signature'):
160 cls.parser_signature = Sig()
161 if not hasattr(cls, 'parser_class'):
162 cls.parser_class = ErrorRaisingArgumentParser
163
164 # ---------------------------------------
165 # functions for adding optional arguments
166 # ---------------------------------------
167 def no_groups(parser, argument_signatures):
168 """Add all arguments directly to the parser"""
169 for sig in argument_signatures:
170 parser.add_argument(*sig.args, **sig.kwargs)
171
172 def one_group(parser, argument_signatures):
173 """Add all arguments under a single group in the parser"""
174 group = parser.add_argument_group('foo')
175 for sig in argument_signatures:
176 group.add_argument(*sig.args, **sig.kwargs)
177
178 def many_groups(parser, argument_signatures):
179 """Add each argument in its own group to the parser"""
180 for i, sig in enumerate(argument_signatures):
181 group = parser.add_argument_group('foo:%i' % i)
182 group.add_argument(*sig.args, **sig.kwargs)
183
184 # --------------------------
185 # functions for parsing args
186 # --------------------------
187 def listargs(parser, args):
188 """Parse the args by passing in a list"""
189 return parser.parse_args(args)
190
191 def sysargs(parser, args):
192 """Parse the args by defaulting to sys.argv"""
193 old_sys_argv = sys.argv
194 sys.argv = [old_sys_argv[0]] + args
195 try:
196 return parser.parse_args()
197 finally:
198 sys.argv = old_sys_argv
199
200 # class that holds the combination of one optional argument
201 # addition method and one arg parsing method
202 class AddTests(object):
203
204 def __init__(self, tester_cls, add_arguments, parse_args):
205 self._add_arguments = add_arguments
206 self._parse_args = parse_args
207
208 add_arguments_name = self._add_arguments.__name__
209 parse_args_name = self._parse_args.__name__
210 for test_func in [self.test_failures, self.test_successes]:
211 func_name = test_func.__name__
212 names = func_name, add_arguments_name, parse_args_name
213 test_name = '_'.join(names)
214
215 def wrapper(self, test_func=test_func):
216 test_func(self)
217 try:
218 wrapper.__name__ = test_name
219 except TypeError:
220 pass
221 setattr(tester_cls, test_name, wrapper)
222
223 def _get_parser(self, tester):
224 args = tester.parser_signature.args
225 kwargs = tester.parser_signature.kwargs
226 parser = tester.parser_class(*args, **kwargs)
227 self._add_arguments(parser, tester.argument_signatures)
228 return parser
229
230 def test_failures(self, tester):
231 parser = self._get_parser(tester)
232 for args_str in tester.failures:
233 args = args_str.split()
234 raises = tester.assertRaises
235 raises(ArgumentParserError, parser.parse_args, args)
236
237 def test_successes(self, tester):
238 parser = self._get_parser(tester)
239 for args, expected_ns in tester.successes:
240 if isinstance(args, str):
241 args = args.split()
242 result_ns = self._parse_args(parser, args)
243 tester.assertEqual(expected_ns, result_ns)
244
245 # add tests for each combination of an optionals adding method
246 # and an arg parsing method
247 for add_arguments in [no_groups, one_group, many_groups]:
248 for parse_args in [listargs, sysargs]:
249 AddTests(cls, add_arguments, parse_args)
250
251bases = TestCase,
252ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
253
254# ===============
255# Optionals tests
256# ===============
257
258class TestOptionalsSingleDash(ParserTestCase):
259 """Test an Optional with a single-dash option string"""
260
261 argument_signatures = [Sig('-x')]
262 failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
263 successes = [
264 ('', NS(x=None)),
265 ('-x a', NS(x='a')),
266 ('-xa', NS(x='a')),
267 ('-x -1', NS(x='-1')),
268 ('-x-1', NS(x='-1')),
269 ]
270
271
272class TestOptionalsSingleDashCombined(ParserTestCase):
273 """Test an Optional with a single-dash option string"""
274
275 argument_signatures = [
276 Sig('-x', action='store_true'),
277 Sig('-yyy', action='store_const', const=42),
278 Sig('-z'),
279 ]
280 failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
281 '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
282 successes = [
283 ('', NS(x=False, yyy=None, z=None)),
284 ('-x', NS(x=True, yyy=None, z=None)),
285 ('-za', NS(x=False, yyy=None, z='a')),
286 ('-z a', NS(x=False, yyy=None, z='a')),
287 ('-xza', NS(x=True, yyy=None, z='a')),
288 ('-xz a', NS(x=True, yyy=None, z='a')),
289 ('-x -za', NS(x=True, yyy=None, z='a')),
290 ('-x -z a', NS(x=True, yyy=None, z='a')),
291 ('-y', NS(x=False, yyy=42, z=None)),
292 ('-yyy', NS(x=False, yyy=42, z=None)),
293 ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
294 ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
295 ]
296
297
298class TestOptionalsSingleDashLong(ParserTestCase):
299 """Test an Optional with a multi-character single-dash option string"""
300
301 argument_signatures = [Sig('-foo')]
302 failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
303 successes = [
304 ('', NS(foo=None)),
305 ('-foo a', NS(foo='a')),
306 ('-foo -1', NS(foo='-1')),
307 ('-fo a', NS(foo='a')),
308 ('-f a', NS(foo='a')),
309 ]
310
311
312class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
313 """Test Optionals where option strings are subsets of each other"""
314
315 argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
316 failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
317 successes = [
318 ('', NS(f=None, foobar=None, foorab=None)),
319 ('-f a', NS(f='a', foobar=None, foorab=None)),
320 ('-fa', NS(f='a', foobar=None, foorab=None)),
321 ('-foa', NS(f='oa', foobar=None, foorab=None)),
322 ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
323 ('-foobar a', NS(f=None, foobar='a', foorab=None)),
324 ('-foorab a', NS(f=None, foobar=None, foorab='a')),
325 ]
326
327
328class TestOptionalsSingleDashAmbiguous(ParserTestCase):
329 """Test Optionals that partially match but are not subsets"""
330
331 argument_signatures = [Sig('-foobar'), Sig('-foorab')]
332 failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
333 successes = [
334 ('', NS(foobar=None, foorab=None)),
335 ('-foob a', NS(foobar='a', foorab=None)),
336 ('-foor a', NS(foobar=None, foorab='a')),
337 ('-fooba a', NS(foobar='a', foorab=None)),
338 ('-foora a', NS(foobar=None, foorab='a')),
339 ('-foobar a', NS(foobar='a', foorab=None)),
340 ('-foorab a', NS(foobar=None, foorab='a')),
341 ]
342
343
344class TestOptionalsNumeric(ParserTestCase):
345 """Test an Optional with a short opt string"""
346
347 argument_signatures = [Sig('-1', dest='one')]
348 failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
349 successes = [
350 ('', NS(one=None)),
351 ('-1 a', NS(one='a')),
352 ('-1a', NS(one='a')),
353 ('-1-2', NS(one='-2')),
354 ]
355
356
357class TestOptionalsDoubleDash(ParserTestCase):
358 """Test an Optional with a double-dash option string"""
359
360 argument_signatures = [Sig('--foo')]
361 failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
362 successes = [
363 ('', NS(foo=None)),
364 ('--foo a', NS(foo='a')),
365 ('--foo=a', NS(foo='a')),
366 ('--foo -2.5', NS(foo='-2.5')),
367 ('--foo=-2.5', NS(foo='-2.5')),
368 ]
369
370
371class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
372 """Tests partial matching with a double-dash option string"""
373
374 argument_signatures = [
375 Sig('--badger', action='store_true'),
376 Sig('--bat'),
377 ]
378 failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
379 successes = [
380 ('', NS(badger=False, bat=None)),
381 ('--bat X', NS(badger=False, bat='X')),
382 ('--bad', NS(badger=True, bat=None)),
383 ('--badg', NS(badger=True, bat=None)),
384 ('--badge', NS(badger=True, bat=None)),
385 ('--badger', NS(badger=True, bat=None)),
386 ]
387
388
389class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
390 """Tests when one double-dash option string is a prefix of another"""
391
392 argument_signatures = [
393 Sig('--badger', action='store_true'),
394 Sig('--ba'),
395 ]
396 failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
397 successes = [
398 ('', NS(badger=False, ba=None)),
399 ('--ba X', NS(badger=False, ba='X')),
400 ('--ba=X', NS(badger=False, ba='X')),
401 ('--bad', NS(badger=True, ba=None)),
402 ('--badg', NS(badger=True, ba=None)),
403 ('--badge', NS(badger=True, ba=None)),
404 ('--badger', NS(badger=True, ba=None)),
405 ]
406
407
408class TestOptionalsSingleDoubleDash(ParserTestCase):
409 """Test an Optional with single- and double-dash option strings"""
410
411 argument_signatures = [
412 Sig('-f', action='store_true'),
413 Sig('--bar'),
414 Sig('-baz', action='store_const', const=42),
415 ]
416 failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
417 successes = [
418 ('', NS(f=False, bar=None, baz=None)),
419 ('-f', NS(f=True, bar=None, baz=None)),
420 ('--ba B', NS(f=False, bar='B', baz=None)),
421 ('-f --bar B', NS(f=True, bar='B', baz=None)),
422 ('-f -b', NS(f=True, bar=None, baz=42)),
423 ('-ba -f', NS(f=True, bar=None, baz=42)),
424 ]
425
426
427class TestOptionalsAlternatePrefixChars(ParserTestCase):
R. David Murray88c49fe2010-08-03 17:56:09 +0000428 """Test an Optional with option strings with custom prefixes"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000429
430 parser_signature = Sig(prefix_chars='+:/', add_help=False)
431 argument_signatures = [
432 Sig('+f', action='store_true'),
433 Sig('::bar'),
434 Sig('/baz', action='store_const', const=42),
435 ]
R. David Murray88c49fe2010-08-03 17:56:09 +0000436 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
437 successes = [
438 ('', NS(f=False, bar=None, baz=None)),
439 ('+f', NS(f=True, bar=None, baz=None)),
440 ('::ba B', NS(f=False, bar='B', baz=None)),
441 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
442 ('+f /b', NS(f=True, bar=None, baz=42)),
443 ('/ba +f', NS(f=True, bar=None, baz=42)),
444 ]
445
446
447class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
448 """When ``-`` not in prefix_chars, default operators created for help
449 should use the prefix_chars in use rather than - or --
450 http://bugs.python.org/issue9444"""
451
452 parser_signature = Sig(prefix_chars='+:/', add_help=True)
453 argument_signatures = [
454 Sig('+f', action='store_true'),
455 Sig('::bar'),
456 Sig('/baz', action='store_const', const=42),
457 ]
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000458 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
459 successes = [
460 ('', NS(f=False, bar=None, baz=None)),
461 ('+f', NS(f=True, bar=None, baz=None)),
462 ('::ba B', NS(f=False, bar='B', baz=None)),
463 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
464 ('+f /b', NS(f=True, bar=None, baz=42)),
R. David Murray88c49fe2010-08-03 17:56:09 +0000465 ('/ba +f', NS(f=True, bar=None, baz=42))
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000466 ]
467
Steven Bethard1ca45a52010-11-01 15:57:36 +0000468
469class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
470 """Verify that Optionals must be called with their defined prefixes"""
471
472 parser_signature = Sig(prefix_chars='+-', add_help=False)
473 argument_signatures = [
474 Sig('-x', action='store_true'),
475 Sig('+y', action='store_true'),
476 Sig('+z', action='store_true'),
477 ]
478 failures = ['-w',
479 '-xyz',
480 '+x',
481 '-y',
482 '+xyz',
483 ]
484 successes = [
485 ('', NS(x=False, y=False, z=False)),
486 ('-x', NS(x=True, y=False, z=False)),
487 ('+y -x', NS(x=True, y=True, z=False)),
488 ('+yz -x', NS(x=True, y=True, z=True)),
489 ]
490
491
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000492class TestOptionalsShortLong(ParserTestCase):
493 """Test a combination of single- and double-dash option strings"""
494
495 argument_signatures = [
496 Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
497 ]
498 failures = ['--x --verbose', '-N', 'a', '-v x']
499 successes = [
500 ('', NS(verbose=False)),
501 ('-v', NS(verbose=True)),
502 ('--verbose', NS(verbose=True)),
503 ('-n', NS(verbose=True)),
504 ('--noisy', NS(verbose=True)),
505 ]
506
507
508class TestOptionalsDest(ParserTestCase):
509 """Tests various means of setting destination"""
510
511 argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
512 failures = ['a']
513 successes = [
514 ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
515 ('--baz g', NS(foo_bar=None, zabbaz='g')),
516 ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
517 ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
518 ]
519
520
521class TestOptionalsDefault(ParserTestCase):
522 """Tests specifying a default for an Optional"""
523
524 argument_signatures = [Sig('-x'), Sig('-y', default=42)]
525 failures = ['a']
526 successes = [
527 ('', NS(x=None, y=42)),
528 ('-xx', NS(x='x', y=42)),
529 ('-yy', NS(x=None, y='y')),
530 ]
531
532
533class TestOptionalsNargsDefault(ParserTestCase):
534 """Tests not specifying the number of args for an Optional"""
535
536 argument_signatures = [Sig('-x')]
537 failures = ['a', '-x']
538 successes = [
539 ('', NS(x=None)),
540 ('-x a', NS(x='a')),
541 ]
542
543
544class TestOptionalsNargs1(ParserTestCase):
545 """Tests specifying the 1 arg for an Optional"""
546
547 argument_signatures = [Sig('-x', nargs=1)]
548 failures = ['a', '-x']
549 successes = [
550 ('', NS(x=None)),
551 ('-x a', NS(x=['a'])),
552 ]
553
554
555class TestOptionalsNargs3(ParserTestCase):
556 """Tests specifying the 3 args for an Optional"""
557
558 argument_signatures = [Sig('-x', nargs=3)]
559 failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
560 successes = [
561 ('', NS(x=None)),
562 ('-x a b c', NS(x=['a', 'b', 'c'])),
563 ]
564
565
566class TestOptionalsNargsOptional(ParserTestCase):
567 """Tests specifying an Optional arg for an Optional"""
568
569 argument_signatures = [
570 Sig('-w', nargs='?'),
571 Sig('-x', nargs='?', const=42),
572 Sig('-y', nargs='?', default='spam'),
573 Sig('-z', nargs='?', type=int, const='42', default='84'),
574 ]
575 failures = ['2']
576 successes = [
577 ('', NS(w=None, x=None, y='spam', z=84)),
578 ('-w', NS(w=None, x=None, y='spam', z=84)),
579 ('-w 2', NS(w='2', x=None, y='spam', z=84)),
580 ('-x', NS(w=None, x=42, y='spam', z=84)),
581 ('-x 2', NS(w=None, x='2', y='spam', z=84)),
582 ('-y', NS(w=None, x=None, y=None, z=84)),
583 ('-y 2', NS(w=None, x=None, y='2', z=84)),
584 ('-z', NS(w=None, x=None, y='spam', z=42)),
585 ('-z 2', NS(w=None, x=None, y='spam', z=2)),
586 ]
587
588
589class TestOptionalsNargsZeroOrMore(ParserTestCase):
590 """Tests specifying an args for an Optional that accepts zero or more"""
591
592 argument_signatures = [
593 Sig('-x', nargs='*'),
594 Sig('-y', nargs='*', default='spam'),
595 ]
596 failures = ['a']
597 successes = [
598 ('', NS(x=None, y='spam')),
599 ('-x', NS(x=[], y='spam')),
600 ('-x a', NS(x=['a'], y='spam')),
601 ('-x a b', NS(x=['a', 'b'], y='spam')),
602 ('-y', NS(x=None, y=[])),
603 ('-y a', NS(x=None, y=['a'])),
604 ('-y a b', NS(x=None, y=['a', 'b'])),
605 ]
606
607
608class TestOptionalsNargsOneOrMore(ParserTestCase):
609 """Tests specifying an args for an Optional that accepts one or more"""
610
611 argument_signatures = [
612 Sig('-x', nargs='+'),
613 Sig('-y', nargs='+', default='spam'),
614 ]
615 failures = ['a', '-x', '-y', 'a -x', 'a -y b']
616 successes = [
617 ('', NS(x=None, y='spam')),
618 ('-x a', NS(x=['a'], y='spam')),
619 ('-x a b', NS(x=['a', 'b'], y='spam')),
620 ('-y a', NS(x=None, y=['a'])),
621 ('-y a b', NS(x=None, y=['a', 'b'])),
622 ]
623
624
625class TestOptionalsChoices(ParserTestCase):
626 """Tests specifying the choices for an Optional"""
627
628 argument_signatures = [
629 Sig('-f', choices='abc'),
630 Sig('-g', type=int, choices=range(5))]
631 failures = ['a', '-f d', '-fad', '-ga', '-g 6']
632 successes = [
633 ('', NS(f=None, g=None)),
634 ('-f a', NS(f='a', g=None)),
635 ('-f c', NS(f='c', g=None)),
636 ('-g 0', NS(f=None, g=0)),
637 ('-g 03', NS(f=None, g=3)),
638 ('-fb -g4', NS(f='b', g=4)),
639 ]
640
641
642class TestOptionalsRequired(ParserTestCase):
643 """Tests the an optional action that is required"""
644
645 argument_signatures = [
646 Sig('-x', type=int, required=True),
647 ]
648 failures = ['a', '']
649 successes = [
650 ('-x 1', NS(x=1)),
651 ('-x42', NS(x=42)),
652 ]
653
654
655class TestOptionalsActionStore(ParserTestCase):
656 """Tests the store action for an Optional"""
657
658 argument_signatures = [Sig('-x', action='store')]
659 failures = ['a', 'a -x']
660 successes = [
661 ('', NS(x=None)),
662 ('-xfoo', NS(x='foo')),
663 ]
664
665
666class TestOptionalsActionStoreConst(ParserTestCase):
667 """Tests the store_const action for an Optional"""
668
669 argument_signatures = [Sig('-y', action='store_const', const=object)]
670 failures = ['a']
671 successes = [
672 ('', NS(y=None)),
673 ('-y', NS(y=object)),
674 ]
675
676
677class TestOptionalsActionStoreFalse(ParserTestCase):
678 """Tests the store_false action for an Optional"""
679
680 argument_signatures = [Sig('-z', action='store_false')]
681 failures = ['a', '-za', '-z a']
682 successes = [
683 ('', NS(z=True)),
684 ('-z', NS(z=False)),
685 ]
686
687
688class TestOptionalsActionStoreTrue(ParserTestCase):
689 """Tests the store_true action for an Optional"""
690
691 argument_signatures = [Sig('--apple', action='store_true')]
692 failures = ['a', '--apple=b', '--apple b']
693 successes = [
694 ('', NS(apple=False)),
695 ('--apple', NS(apple=True)),
696 ]
697
698
699class TestOptionalsActionAppend(ParserTestCase):
700 """Tests the append action for an Optional"""
701
702 argument_signatures = [Sig('--baz', action='append')]
703 failures = ['a', '--baz', 'a --baz', '--baz a b']
704 successes = [
705 ('', NS(baz=None)),
706 ('--baz a', NS(baz=['a'])),
707 ('--baz a --baz b', NS(baz=['a', 'b'])),
708 ]
709
710
711class TestOptionalsActionAppendWithDefault(ParserTestCase):
712 """Tests the append action for an Optional"""
713
714 argument_signatures = [Sig('--baz', action='append', default=['X'])]
715 failures = ['a', '--baz', 'a --baz', '--baz a b']
716 successes = [
717 ('', NS(baz=['X'])),
718 ('--baz a', NS(baz=['X', 'a'])),
719 ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
720 ]
721
722
723class TestOptionalsActionAppendConst(ParserTestCase):
724 """Tests the append_const action for an Optional"""
725
726 argument_signatures = [
727 Sig('-b', action='append_const', const=Exception),
728 Sig('-c', action='append', dest='b'),
729 ]
730 failures = ['a', '-c', 'a -c', '-bx', '-b x']
731 successes = [
732 ('', NS(b=None)),
733 ('-b', NS(b=[Exception])),
734 ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
735 ]
736
737
738class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
739 """Tests the append_const action for an Optional"""
740
741 argument_signatures = [
742 Sig('-b', action='append_const', const=Exception, default=['X']),
743 Sig('-c', action='append', dest='b'),
744 ]
745 failures = ['a', '-c', 'a -c', '-bx', '-b x']
746 successes = [
747 ('', NS(b=['X'])),
748 ('-b', NS(b=['X', Exception])),
749 ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
750 ]
751
752
753class TestOptionalsActionCount(ParserTestCase):
754 """Tests the count action for an Optional"""
755
756 argument_signatures = [Sig('-x', action='count')]
757 failures = ['a', '-x a', '-x b', '-x a -x b']
758 successes = [
759 ('', NS(x=None)),
760 ('-x', NS(x=1)),
761 ]
762
763
764# ================
765# Positional tests
766# ================
767
768class TestPositionalsNargsNone(ParserTestCase):
769 """Test a Positional that doesn't specify nargs"""
770
771 argument_signatures = [Sig('foo')]
772 failures = ['', '-x', 'a b']
773 successes = [
774 ('a', NS(foo='a')),
775 ]
776
777
778class TestPositionalsNargs1(ParserTestCase):
779 """Test a Positional that specifies an nargs of 1"""
780
781 argument_signatures = [Sig('foo', nargs=1)]
782 failures = ['', '-x', 'a b']
783 successes = [
784 ('a', NS(foo=['a'])),
785 ]
786
787
788class TestPositionalsNargs2(ParserTestCase):
789 """Test a Positional that specifies an nargs of 2"""
790
791 argument_signatures = [Sig('foo', nargs=2)]
792 failures = ['', 'a', '-x', 'a b c']
793 successes = [
794 ('a b', NS(foo=['a', 'b'])),
795 ]
796
797
798class TestPositionalsNargsZeroOrMore(ParserTestCase):
799 """Test a Positional that specifies unlimited nargs"""
800
801 argument_signatures = [Sig('foo', nargs='*')]
802 failures = ['-x']
803 successes = [
804 ('', NS(foo=[])),
805 ('a', NS(foo=['a'])),
806 ('a b', NS(foo=['a', 'b'])),
807 ]
808
809
810class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
811 """Test a Positional that specifies unlimited nargs and a default"""
812
813 argument_signatures = [Sig('foo', nargs='*', default='bar')]
814 failures = ['-x']
815 successes = [
816 ('', NS(foo='bar')),
817 ('a', NS(foo=['a'])),
818 ('a b', NS(foo=['a', 'b'])),
819 ]
820
821
822class TestPositionalsNargsOneOrMore(ParserTestCase):
823 """Test a Positional that specifies one or more nargs"""
824
825 argument_signatures = [Sig('foo', nargs='+')]
826 failures = ['', '-x']
827 successes = [
828 ('a', NS(foo=['a'])),
829 ('a b', NS(foo=['a', 'b'])),
830 ]
831
832
833class TestPositionalsNargsOptional(ParserTestCase):
834 """Tests an Optional Positional"""
835
836 argument_signatures = [Sig('foo', nargs='?')]
837 failures = ['-x', 'a b']
838 successes = [
839 ('', NS(foo=None)),
840 ('a', NS(foo='a')),
841 ]
842
843
844class TestPositionalsNargsOptionalDefault(ParserTestCase):
845 """Tests an Optional Positional with a default value"""
846
847 argument_signatures = [Sig('foo', nargs='?', default=42)]
848 failures = ['-x', 'a b']
849 successes = [
850 ('', NS(foo=42)),
851 ('a', NS(foo='a')),
852 ]
853
854
855class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
856 """Tests an Optional Positional with a default value
857 that needs to be converted to the appropriate type.
858 """
859
860 argument_signatures = [
861 Sig('foo', nargs='?', type=int, default='42'),
862 ]
863 failures = ['-x', 'a b', '1 2']
864 successes = [
865 ('', NS(foo=42)),
866 ('1', NS(foo=1)),
867 ]
868
869
870class TestPositionalsNargsNoneNone(ParserTestCase):
871 """Test two Positionals that don't specify nargs"""
872
873 argument_signatures = [Sig('foo'), Sig('bar')]
874 failures = ['', '-x', 'a', 'a b c']
875 successes = [
876 ('a b', NS(foo='a', bar='b')),
877 ]
878
879
880class TestPositionalsNargsNone1(ParserTestCase):
881 """Test a Positional with no nargs followed by one with 1"""
882
883 argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
884 failures = ['', '--foo', 'a', 'a b c']
885 successes = [
886 ('a b', NS(foo='a', bar=['b'])),
887 ]
888
889
890class TestPositionalsNargs2None(ParserTestCase):
891 """Test a Positional with 2 nargs followed by one with none"""
892
893 argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
894 failures = ['', '--foo', 'a', 'a b', 'a b c d']
895 successes = [
896 ('a b c', NS(foo=['a', 'b'], bar='c')),
897 ]
898
899
900class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
901 """Test a Positional with no nargs followed by one with unlimited"""
902
903 argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
904 failures = ['', '--foo']
905 successes = [
906 ('a', NS(foo='a', bar=[])),
907 ('a b', NS(foo='a', bar=['b'])),
908 ('a b c', NS(foo='a', bar=['b', 'c'])),
909 ]
910
911
912class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
913 """Test a Positional with no nargs followed by one with one or more"""
914
915 argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
916 failures = ['', '--foo', 'a']
917 successes = [
918 ('a b', NS(foo='a', bar=['b'])),
919 ('a b c', NS(foo='a', bar=['b', 'c'])),
920 ]
921
922
923class TestPositionalsNargsNoneOptional(ParserTestCase):
924 """Test a Positional with no nargs followed by one with an Optional"""
925
926 argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
927 failures = ['', '--foo', 'a b c']
928 successes = [
929 ('a', NS(foo='a', bar=None)),
930 ('a b', NS(foo='a', bar='b')),
931 ]
932
933
934class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
935 """Test a Positional with unlimited nargs followed by one with none"""
936
937 argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
938 failures = ['', '--foo']
939 successes = [
940 ('a', NS(foo=[], bar='a')),
941 ('a b', NS(foo=['a'], bar='b')),
942 ('a b c', NS(foo=['a', 'b'], bar='c')),
943 ]
944
945
946class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
947 """Test a Positional with one or more nargs followed by one with none"""
948
949 argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
950 failures = ['', '--foo', 'a']
951 successes = [
952 ('a b', NS(foo=['a'], bar='b')),
953 ('a b c', NS(foo=['a', 'b'], bar='c')),
954 ]
955
956
957class TestPositionalsNargsOptionalNone(ParserTestCase):
958 """Test a Positional with an Optional nargs followed by one with none"""
959
960 argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
961 failures = ['', '--foo', 'a b c']
962 successes = [
963 ('a', NS(foo=42, bar='a')),
964 ('a b', NS(foo='a', bar='b')),
965 ]
966
967
968class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
969 """Test a Positional with 2 nargs followed by one with unlimited"""
970
971 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
972 failures = ['', '--foo', 'a']
973 successes = [
974 ('a b', NS(foo=['a', 'b'], bar=[])),
975 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
976 ]
977
978
979class TestPositionalsNargs2OneOrMore(ParserTestCase):
980 """Test a Positional with 2 nargs followed by one with one or more"""
981
982 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
983 failures = ['', '--foo', 'a', 'a b']
984 successes = [
985 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
986 ]
987
988
989class TestPositionalsNargs2Optional(ParserTestCase):
990 """Test a Positional with 2 nargs followed by one optional"""
991
992 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
993 failures = ['', '--foo', 'a', 'a b c d']
994 successes = [
995 ('a b', NS(foo=['a', 'b'], bar=None)),
996 ('a b c', NS(foo=['a', 'b'], bar='c')),
997 ]
998
999
1000class TestPositionalsNargsZeroOrMore1(ParserTestCase):
1001 """Test a Positional with unlimited nargs followed by one with 1"""
1002
1003 argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
1004 failures = ['', '--foo', ]
1005 successes = [
1006 ('a', NS(foo=[], bar=['a'])),
1007 ('a b', NS(foo=['a'], bar=['b'])),
1008 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1009 ]
1010
1011
1012class TestPositionalsNargsOneOrMore1(ParserTestCase):
1013 """Test a Positional with one or more nargs followed by one with 1"""
1014
1015 argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
1016 failures = ['', '--foo', 'a']
1017 successes = [
1018 ('a b', NS(foo=['a'], bar=['b'])),
1019 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1020 ]
1021
1022
1023class TestPositionalsNargsOptional1(ParserTestCase):
1024 """Test a Positional with an Optional nargs followed by one with 1"""
1025
1026 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
1027 failures = ['', '--foo', 'a b c']
1028 successes = [
1029 ('a', NS(foo=None, bar=['a'])),
1030 ('a b', NS(foo='a', bar=['b'])),
1031 ]
1032
1033
1034class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
1035 """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
1036
1037 argument_signatures = [
1038 Sig('foo'),
1039 Sig('bar', nargs='*'),
1040 Sig('baz', nargs=1),
1041 ]
1042 failures = ['', '--foo', 'a']
1043 successes = [
1044 ('a b', NS(foo='a', bar=[], baz=['b'])),
1045 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1046 ]
1047
1048
1049class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
1050 """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
1051
1052 argument_signatures = [
1053 Sig('foo'),
1054 Sig('bar', nargs='+'),
1055 Sig('baz', nargs=1),
1056 ]
1057 failures = ['', '--foo', 'a', 'b']
1058 successes = [
1059 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1060 ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
1061 ]
1062
1063
1064class TestPositionalsNargsNoneOptional1(ParserTestCase):
1065 """Test three Positionals: no nargs, optional narg and 1 nargs"""
1066
1067 argument_signatures = [
1068 Sig('foo'),
1069 Sig('bar', nargs='?', default=0.625),
1070 Sig('baz', nargs=1),
1071 ]
1072 failures = ['', '--foo', 'a']
1073 successes = [
1074 ('a b', NS(foo='a', bar=0.625, baz=['b'])),
1075 ('a b c', NS(foo='a', bar='b', baz=['c'])),
1076 ]
1077
1078
1079class TestPositionalsNargsOptionalOptional(ParserTestCase):
1080 """Test two optional nargs"""
1081
1082 argument_signatures = [
1083 Sig('foo', nargs='?'),
1084 Sig('bar', nargs='?', default=42),
1085 ]
1086 failures = ['--foo', 'a b c']
1087 successes = [
1088 ('', NS(foo=None, bar=42)),
1089 ('a', NS(foo='a', bar=42)),
1090 ('a b', NS(foo='a', bar='b')),
1091 ]
1092
1093
1094class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
1095 """Test an Optional narg followed by unlimited nargs"""
1096
1097 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
1098 failures = ['--foo']
1099 successes = [
1100 ('', NS(foo=None, bar=[])),
1101 ('a', NS(foo='a', bar=[])),
1102 ('a b', NS(foo='a', bar=['b'])),
1103 ('a b c', NS(foo='a', bar=['b', 'c'])),
1104 ]
1105
1106
1107class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
1108 """Test an Optional narg followed by one or more nargs"""
1109
1110 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
1111 failures = ['', '--foo']
1112 successes = [
1113 ('a', NS(foo=None, bar=['a'])),
1114 ('a b', NS(foo='a', bar=['b'])),
1115 ('a b c', NS(foo='a', bar=['b', 'c'])),
1116 ]
1117
1118
1119class TestPositionalsChoicesString(ParserTestCase):
1120 """Test a set of single-character choices"""
1121
1122 argument_signatures = [Sig('spam', choices=set('abcdefg'))]
1123 failures = ['', '--foo', 'h', '42', 'ef']
1124 successes = [
1125 ('a', NS(spam='a')),
1126 ('g', NS(spam='g')),
1127 ]
1128
1129
1130class TestPositionalsChoicesInt(ParserTestCase):
1131 """Test a set of integer choices"""
1132
1133 argument_signatures = [Sig('spam', type=int, choices=range(20))]
1134 failures = ['', '--foo', 'h', '42', 'ef']
1135 successes = [
1136 ('4', NS(spam=4)),
1137 ('15', NS(spam=15)),
1138 ]
1139
1140
1141class TestPositionalsActionAppend(ParserTestCase):
1142 """Test the 'append' action"""
1143
1144 argument_signatures = [
1145 Sig('spam', action='append'),
1146 Sig('spam', action='append', nargs=2),
1147 ]
1148 failures = ['', '--foo', 'a', 'a b', 'a b c d']
1149 successes = [
1150 ('a b c', NS(spam=['a', ['b', 'c']])),
1151 ]
1152
1153# ========================================
1154# Combined optionals and positionals tests
1155# ========================================
1156
1157class TestOptionalsNumericAndPositionals(ParserTestCase):
1158 """Tests negative number args when numeric options are present"""
1159
1160 argument_signatures = [
1161 Sig('x', nargs='?'),
1162 Sig('-4', dest='y', action='store_true'),
1163 ]
1164 failures = ['-2', '-315']
1165 successes = [
1166 ('', NS(x=None, y=False)),
1167 ('a', NS(x='a', y=False)),
1168 ('-4', NS(x=None, y=True)),
1169 ('-4 a', NS(x='a', y=True)),
1170 ]
1171
1172
1173class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
1174 """Tests negative number args when almost numeric options are present"""
1175
1176 argument_signatures = [
1177 Sig('x', nargs='?'),
1178 Sig('-k4', dest='y', action='store_true'),
1179 ]
1180 failures = ['-k3']
1181 successes = [
1182 ('', NS(x=None, y=False)),
1183 ('-2', NS(x='-2', y=False)),
1184 ('a', NS(x='a', y=False)),
1185 ('-k4', NS(x=None, y=True)),
1186 ('-k4 a', NS(x='a', y=True)),
1187 ]
1188
1189
1190class TestEmptyAndSpaceContainingArguments(ParserTestCase):
1191
1192 argument_signatures = [
1193 Sig('x', nargs='?'),
1194 Sig('-y', '--yyy', dest='y'),
1195 ]
1196 failures = ['-y']
1197 successes = [
1198 ([''], NS(x='', y=None)),
1199 (['a badger'], NS(x='a badger', y=None)),
1200 (['-a badger'], NS(x='-a badger', y=None)),
1201 (['-y', ''], NS(x=None, y='')),
1202 (['-y', 'a badger'], NS(x=None, y='a badger')),
1203 (['-y', '-a badger'], NS(x=None, y='-a badger')),
1204 (['--yyy=a badger'], NS(x=None, y='a badger')),
1205 (['--yyy=-a badger'], NS(x=None, y='-a badger')),
1206 ]
1207
1208
1209class TestPrefixCharacterOnlyArguments(ParserTestCase):
1210
1211 parser_signature = Sig(prefix_chars='-+')
1212 argument_signatures = [
1213 Sig('-', dest='x', nargs='?', const='badger'),
1214 Sig('+', dest='y', type=int, default=42),
1215 Sig('-+-', dest='z', action='store_true'),
1216 ]
1217 failures = ['-y', '+ -']
1218 successes = [
1219 ('', NS(x=None, y=42, z=False)),
1220 ('-', NS(x='badger', y=42, z=False)),
1221 ('- X', NS(x='X', y=42, z=False)),
1222 ('+ -3', NS(x=None, y=-3, z=False)),
1223 ('-+-', NS(x=None, y=42, z=True)),
1224 ('- ===', NS(x='===', y=42, z=False)),
1225 ]
1226
1227
1228class TestNargsZeroOrMore(ParserTestCase):
1229 """Tests specifying an args for an Optional that accepts zero or more"""
1230
1231 argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
1232 failures = []
1233 successes = [
1234 ('', NS(x=None, y=[])),
1235 ('-x', NS(x=[], y=[])),
1236 ('-x a', NS(x=['a'], y=[])),
1237 ('-x a -- b', NS(x=['a'], y=['b'])),
1238 ('a', NS(x=None, y=['a'])),
1239 ('a -x', NS(x=[], y=['a'])),
1240 ('a -x b', NS(x=['b'], y=['a'])),
1241 ]
1242
1243
1244class TestNargsRemainder(ParserTestCase):
1245 """Tests specifying a positional with nargs=REMAINDER"""
1246
1247 argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
1248 failures = ['', '-z', '-z Z']
1249 successes = [
1250 ('X', NS(x='X', y=[], z=None)),
1251 ('-z Z X', NS(x='X', y=[], z='Z')),
1252 ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
1253 ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
1254 ]
1255
1256
1257class TestOptionLike(ParserTestCase):
1258 """Tests options that may or may not be arguments"""
1259
1260 argument_signatures = [
1261 Sig('-x', type=float),
1262 Sig('-3', type=float, dest='y'),
1263 Sig('z', nargs='*'),
1264 ]
1265 failures = ['-x', '-y2.5', '-xa', '-x -a',
1266 '-x -3', '-x -3.5', '-3 -3.5',
1267 '-x -2.5', '-x -2.5 a', '-3 -.5',
1268 'a x -1', '-x -1 a', '-3 -1 a']
1269 successes = [
1270 ('', NS(x=None, y=None, z=[])),
1271 ('-x 2.5', NS(x=2.5, y=None, z=[])),
1272 ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
1273 ('-3.5', NS(x=None, y=0.5, z=[])),
1274 ('-3-.5', NS(x=None, y=-0.5, z=[])),
1275 ('-3 .5', NS(x=None, y=0.5, z=[])),
1276 ('a -3.5', NS(x=None, y=0.5, z=['a'])),
1277 ('a', NS(x=None, y=None, z=['a'])),
1278 ('a -x 1', NS(x=1.0, y=None, z=['a'])),
1279 ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
1280 ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
1281 ]
1282
1283
1284class TestDefaultSuppress(ParserTestCase):
1285 """Test actions with suppressed defaults"""
1286
1287 argument_signatures = [
1288 Sig('foo', nargs='?', default=argparse.SUPPRESS),
1289 Sig('bar', nargs='*', default=argparse.SUPPRESS),
1290 Sig('--baz', action='store_true', default=argparse.SUPPRESS),
1291 ]
1292 failures = ['-x']
1293 successes = [
1294 ('', NS()),
1295 ('a', NS(foo='a')),
1296 ('a b', NS(foo='a', bar=['b'])),
1297 ('--baz', NS(baz=True)),
1298 ('a --baz', NS(foo='a', baz=True)),
1299 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1300 ]
1301
1302
1303class TestParserDefaultSuppress(ParserTestCase):
1304 """Test actions with a parser-level default of SUPPRESS"""
1305
1306 parser_signature = Sig(argument_default=argparse.SUPPRESS)
1307 argument_signatures = [
1308 Sig('foo', nargs='?'),
1309 Sig('bar', nargs='*'),
1310 Sig('--baz', action='store_true'),
1311 ]
1312 failures = ['-x']
1313 successes = [
1314 ('', NS()),
1315 ('a', NS(foo='a')),
1316 ('a b', NS(foo='a', bar=['b'])),
1317 ('--baz', NS(baz=True)),
1318 ('a --baz', NS(foo='a', baz=True)),
1319 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1320 ]
1321
1322
1323class TestParserDefault42(ParserTestCase):
1324 """Test actions with a parser-level default of 42"""
1325
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001326 parser_signature = Sig(argument_default=42)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001327 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001328 Sig('--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001329 Sig('foo', nargs='?'),
1330 Sig('bar', nargs='*'),
1331 Sig('--baz', action='store_true'),
1332 ]
1333 failures = ['-x']
1334 successes = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001335 ('', NS(foo=42, bar=42, baz=42, version=42)),
1336 ('a', NS(foo='a', bar=42, baz=42, version=42)),
1337 ('a b', NS(foo='a', bar=['b'], baz=42, version=42)),
1338 ('--baz', NS(foo=42, bar=42, baz=True, version=42)),
1339 ('a --baz', NS(foo='a', bar=42, baz=True, version=42)),
1340 ('--baz a b', NS(foo='a', bar=['b'], baz=True, version=42)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001341 ]
1342
1343
1344class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
1345 """Test reading arguments from a file"""
1346
1347 def setUp(self):
1348 super(TestArgumentsFromFile, self).setUp()
1349 file_texts = [
1350 ('hello', 'hello world!\n'),
1351 ('recursive', '-a\n'
1352 'A\n'
1353 '@hello'),
1354 ('invalid', '@no-such-path\n'),
1355 ]
1356 for path, text in file_texts:
1357 file = open(path, 'w')
1358 file.write(text)
1359 file.close()
1360
1361 parser_signature = Sig(fromfile_prefix_chars='@')
1362 argument_signatures = [
1363 Sig('-a'),
1364 Sig('x'),
1365 Sig('y', nargs='+'),
1366 ]
1367 failures = ['', '-b', 'X', '@invalid', '@missing']
1368 successes = [
1369 ('X Y', NS(a=None, x='X', y=['Y'])),
1370 ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
1371 ('@hello X', NS(a=None, x='hello world!', y=['X'])),
1372 ('X @hello', NS(a=None, x='X', y=['hello world!'])),
1373 ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
1374 ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
R David Murrayb94082a2012-07-21 22:20:11 -04001375 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001376 ]
1377
1378
1379class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1380 """Test reading arguments from a file"""
1381
1382 def setUp(self):
1383 super(TestArgumentsFromFileConverter, self).setUp()
1384 file_texts = [
1385 ('hello', 'hello world!\n'),
1386 ]
1387 for path, text in file_texts:
1388 file = open(path, 'w')
1389 file.write(text)
1390 file.close()
1391
1392 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1393
1394 def convert_arg_line_to_args(self, arg_line):
1395 for arg in arg_line.split():
1396 if not arg.strip():
1397 continue
1398 yield arg
1399 parser_class = FromFileConverterArgumentParser
1400 parser_signature = Sig(fromfile_prefix_chars='@')
1401 argument_signatures = [
1402 Sig('y', nargs='+'),
1403 ]
1404 failures = []
1405 successes = [
1406 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1407 ]
1408
1409
1410# =====================
1411# Type conversion tests
1412# =====================
1413
1414class TestFileTypeRepr(TestCase):
1415
1416 def test_r(self):
1417 type = argparse.FileType('r')
1418 self.assertEqual("FileType('r')", repr(type))
1419
1420 def test_wb_1(self):
1421 type = argparse.FileType('wb', 1)
1422 self.assertEqual("FileType('wb', 1)", repr(type))
1423
1424
1425class RFile(object):
1426 seen = {}
1427
1428 def __init__(self, name):
1429 self.name = name
1430
1431 def __eq__(self, other):
1432 if other in self.seen:
1433 text = self.seen[other]
1434 else:
1435 text = self.seen[other] = other.read()
1436 other.close()
1437 if not isinstance(text, str):
1438 text = text.decode('ascii')
1439 return self.name == other.name == text
1440
1441
1442class TestFileTypeR(TempDirMixin, ParserTestCase):
1443 """Test the FileType option/argument type for reading files"""
1444
1445 def setUp(self):
1446 super(TestFileTypeR, self).setUp()
1447 for file_name in ['foo', 'bar']:
1448 file = open(os.path.join(self.temp_dir, file_name), 'w')
1449 file.write(file_name)
1450 file.close()
Steven Bethardb0270112011-01-24 21:02:50 +00001451 self.create_readonly_file('readonly')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001452
1453 argument_signatures = [
1454 Sig('-x', type=argparse.FileType()),
1455 Sig('spam', type=argparse.FileType('r')),
1456 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001457 failures = ['-x', '', 'non-existent-file.txt']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001458 successes = [
1459 ('foo', NS(x=None, spam=RFile('foo'))),
1460 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1461 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1462 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
Steven Bethardb0270112011-01-24 21:02:50 +00001463 ('readonly', NS(x=None, spam=RFile('readonly'))),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001464 ]
1465
R David Murray6fb8fb12012-08-31 22:45:20 -04001466class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
1467 """Test that a file is not created unless the default is needed"""
1468 def setUp(self):
1469 super(TestFileTypeDefaults, self).setUp()
1470 file = open(os.path.join(self.temp_dir, 'good'), 'w')
1471 file.write('good')
1472 file.close()
1473
1474 argument_signatures = [
1475 Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
1476 ]
1477 # should provoke no such file error
1478 failures = ['']
1479 # should not provoke error because default file is created
1480 successes = [('-c good', NS(c=RFile('good')))]
1481
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001482
1483class TestFileTypeRB(TempDirMixin, ParserTestCase):
1484 """Test the FileType option/argument type for reading files"""
1485
1486 def setUp(self):
1487 super(TestFileTypeRB, self).setUp()
1488 for file_name in ['foo', 'bar']:
1489 file = open(os.path.join(self.temp_dir, file_name), 'w')
1490 file.write(file_name)
1491 file.close()
1492
1493 argument_signatures = [
1494 Sig('-x', type=argparse.FileType('rb')),
1495 Sig('spam', type=argparse.FileType('rb')),
1496 ]
1497 failures = ['-x', '']
1498 successes = [
1499 ('foo', NS(x=None, spam=RFile('foo'))),
1500 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1501 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1502 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
1503 ]
1504
1505
1506class WFile(object):
1507 seen = set()
1508
1509 def __init__(self, name):
1510 self.name = name
1511
1512 def __eq__(self, other):
1513 if other not in self.seen:
1514 text = 'Check that file is writable.'
1515 if 'b' in other.mode:
1516 text = text.encode('ascii')
1517 other.write(text)
1518 other.close()
1519 self.seen.add(other)
1520 return self.name == other.name
1521
1522
Victor Stinnera04b39b2011-11-20 23:09:09 +01001523@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1524 "non-root user required")
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001525class TestFileTypeW(TempDirMixin, ParserTestCase):
1526 """Test the FileType option/argument type for writing files"""
1527
Steven Bethardb0270112011-01-24 21:02:50 +00001528 def setUp(self):
1529 super(TestFileTypeW, self).setUp()
1530 self.create_readonly_file('readonly')
1531
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001532 argument_signatures = [
1533 Sig('-x', type=argparse.FileType('w')),
1534 Sig('spam', type=argparse.FileType('w')),
1535 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001536 failures = ['-x', '', 'readonly']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001537 successes = [
1538 ('foo', NS(x=None, spam=WFile('foo'))),
1539 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1540 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1541 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1542 ]
1543
1544
1545class TestFileTypeWB(TempDirMixin, ParserTestCase):
1546
1547 argument_signatures = [
1548 Sig('-x', type=argparse.FileType('wb')),
1549 Sig('spam', type=argparse.FileType('wb')),
1550 ]
1551 failures = ['-x', '']
1552 successes = [
1553 ('foo', NS(x=None, spam=WFile('foo'))),
1554 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1555 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1556 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1557 ]
1558
1559
1560class TestTypeCallable(ParserTestCase):
1561 """Test some callables as option/argument types"""
1562
1563 argument_signatures = [
1564 Sig('--eggs', type=complex),
1565 Sig('spam', type=float),
1566 ]
1567 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1568 successes = [
1569 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1570 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1571 ('1024.675', NS(eggs=None, spam=1024.675)),
1572 ]
1573
1574
1575class TestTypeUserDefined(ParserTestCase):
1576 """Test a user-defined option/argument type"""
1577
1578 class MyType(TestCase):
1579
1580 def __init__(self, value):
1581 self.value = value
1582
1583 def __eq__(self, other):
1584 return (type(self), self.value) == (type(other), other.value)
1585
1586 argument_signatures = [
1587 Sig('-x', type=MyType),
1588 Sig('spam', type=MyType),
1589 ]
1590 failures = []
1591 successes = [
1592 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1593 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1594 ]
1595
1596
1597class TestTypeClassicClass(ParserTestCase):
1598 """Test a classic class type"""
1599
1600 class C:
1601
1602 def __init__(self, value):
1603 self.value = value
1604
1605 def __eq__(self, other):
1606 return (type(self), self.value) == (type(other), other.value)
1607
1608 argument_signatures = [
1609 Sig('-x', type=C),
1610 Sig('spam', type=C),
1611 ]
1612 failures = []
1613 successes = [
1614 ('a -x b', NS(x=C('b'), spam=C('a'))),
1615 ('-xf g', NS(x=C('f'), spam=C('g'))),
1616 ]
1617
1618
1619class TestTypeRegistration(TestCase):
1620 """Test a user-defined type by registering it"""
1621
1622 def test(self):
1623
1624 def get_my_type(string):
1625 return 'my_type{%s}' % string
1626
1627 parser = argparse.ArgumentParser()
1628 parser.register('type', 'my_type', get_my_type)
1629 parser.add_argument('-x', type='my_type')
1630 parser.add_argument('y', type='my_type')
1631
1632 self.assertEqual(parser.parse_args('1'.split()),
1633 NS(x=None, y='my_type{1}'))
1634 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1635 NS(x='my_type{1}', y='my_type{42}'))
1636
1637
1638# ============
1639# Action tests
1640# ============
1641
1642class TestActionUserDefined(ParserTestCase):
1643 """Test a user-defined option/argument action"""
1644
1645 class OptionalAction(argparse.Action):
1646
1647 def __call__(self, parser, namespace, value, option_string=None):
1648 try:
1649 # check destination and option string
1650 assert self.dest == 'spam', 'dest: %s' % self.dest
1651 assert option_string == '-s', 'flag: %s' % option_string
1652 # when option is before argument, badger=2, and when
1653 # option is after argument, badger=<whatever was set>
1654 expected_ns = NS(spam=0.25)
1655 if value in [0.125, 0.625]:
1656 expected_ns.badger = 2
1657 elif value in [2.0]:
1658 expected_ns.badger = 84
1659 else:
1660 raise AssertionError('value: %s' % value)
1661 assert expected_ns == namespace, ('expected %s, got %s' %
1662 (expected_ns, namespace))
1663 except AssertionError:
1664 e = sys.exc_info()[1]
1665 raise ArgumentParserError('opt_action failed: %s' % e)
1666 setattr(namespace, 'spam', value)
1667
1668 class PositionalAction(argparse.Action):
1669
1670 def __call__(self, parser, namespace, value, option_string=None):
1671 try:
1672 assert option_string is None, ('option_string: %s' %
1673 option_string)
1674 # check destination
1675 assert self.dest == 'badger', 'dest: %s' % self.dest
1676 # when argument is before option, spam=0.25, and when
1677 # option is after argument, spam=<whatever was set>
1678 expected_ns = NS(badger=2)
1679 if value in [42, 84]:
1680 expected_ns.spam = 0.25
1681 elif value in [1]:
1682 expected_ns.spam = 0.625
1683 elif value in [2]:
1684 expected_ns.spam = 0.125
1685 else:
1686 raise AssertionError('value: %s' % value)
1687 assert expected_ns == namespace, ('expected %s, got %s' %
1688 (expected_ns, namespace))
1689 except AssertionError:
1690 e = sys.exc_info()[1]
1691 raise ArgumentParserError('arg_action failed: %s' % e)
1692 setattr(namespace, 'badger', value)
1693
1694 argument_signatures = [
1695 Sig('-s', dest='spam', action=OptionalAction,
1696 type=float, default=0.25),
1697 Sig('badger', action=PositionalAction,
1698 type=int, nargs='?', default=2),
1699 ]
1700 failures = []
1701 successes = [
1702 ('-s0.125', NS(spam=0.125, badger=2)),
1703 ('42', NS(spam=0.25, badger=42)),
1704 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1705 ('84 -s2', NS(spam=2.0, badger=84)),
1706 ]
1707
1708
1709class TestActionRegistration(TestCase):
1710 """Test a user-defined action supplied by registering it"""
1711
1712 class MyAction(argparse.Action):
1713
1714 def __call__(self, parser, namespace, values, option_string=None):
1715 setattr(namespace, self.dest, 'foo[%s]' % values)
1716
1717 def test(self):
1718
1719 parser = argparse.ArgumentParser()
1720 parser.register('action', 'my_action', self.MyAction)
1721 parser.add_argument('badger', action='my_action')
1722
1723 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1724 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1725
1726
1727# ================
1728# Subparsers tests
1729# ================
1730
1731class TestAddSubparsers(TestCase):
1732 """Test the add_subparsers method"""
1733
1734 def assertArgumentParserError(self, *args, **kwargs):
1735 self.assertRaises(ArgumentParserError, *args, **kwargs)
1736
Steven Bethardfd311a72010-12-18 11:19:23 +00001737 def _get_parser(self, subparser_help=False, prefix_chars=None,
1738 aliases=False):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001739 # create a parser with a subparsers argument
R. David Murray88c49fe2010-08-03 17:56:09 +00001740 if prefix_chars:
1741 parser = ErrorRaisingArgumentParser(
1742 prog='PROG', description='main description', prefix_chars=prefix_chars)
1743 parser.add_argument(
1744 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1745 else:
1746 parser = ErrorRaisingArgumentParser(
1747 prog='PROG', description='main description')
1748 parser.add_argument(
1749 '--foo', action='store_true', help='foo help')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001750 parser.add_argument(
1751 'bar', type=float, help='bar help')
1752
1753 # check that only one subparsers argument can be added
Steven Bethardfd311a72010-12-18 11:19:23 +00001754 subparsers_kwargs = {}
1755 if aliases:
1756 subparsers_kwargs['metavar'] = 'COMMAND'
1757 subparsers_kwargs['title'] = 'commands'
1758 else:
1759 subparsers_kwargs['help'] = 'command help'
1760 subparsers = parser.add_subparsers(**subparsers_kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001761 self.assertArgumentParserError(parser.add_subparsers)
1762
1763 # add first sub-parser
1764 parser1_kwargs = dict(description='1 description')
1765 if subparser_help:
1766 parser1_kwargs['help'] = '1 help'
Steven Bethardfd311a72010-12-18 11:19:23 +00001767 if aliases:
1768 parser1_kwargs['aliases'] = ['1alias1', '1alias2']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001769 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1770 parser1.add_argument('-w', type=int, help='w help')
1771 parser1.add_argument('x', choices='abc', help='x help')
1772
1773 # add second sub-parser
1774 parser2_kwargs = dict(description='2 description')
1775 if subparser_help:
1776 parser2_kwargs['help'] = '2 help'
1777 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1778 parser2.add_argument('-y', choices='123', help='y help')
1779 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1780
R David Murray00528e82012-07-21 22:48:35 -04001781 # add third sub-parser
1782 parser3_kwargs = dict(description='3 description')
1783 if subparser_help:
1784 parser3_kwargs['help'] = '3 help'
1785 parser3 = subparsers.add_parser('3', **parser3_kwargs)
1786 parser3.add_argument('t', type=int, help='t help')
1787 parser3.add_argument('u', nargs='...', help='u help')
1788
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001789 # return the main parser
1790 return parser
1791
1792 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00001793 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001794 self.parser = self._get_parser()
1795 self.command_help_parser = self._get_parser(subparser_help=True)
1796
1797 def test_parse_args_failures(self):
1798 # check some failure cases:
1799 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1800 '0.5 1 -y', '0.5 2 -w']:
1801 args = args_str.split()
1802 self.assertArgumentParserError(self.parser.parse_args, args)
1803
1804 def test_parse_args(self):
1805 # check some non-failure cases:
1806 self.assertEqual(
1807 self.parser.parse_args('0.5 1 b -w 7'.split()),
1808 NS(foo=False, bar=0.5, w=7, x='b'),
1809 )
1810 self.assertEqual(
1811 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1812 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1813 )
1814 self.assertEqual(
1815 self.parser.parse_args('--foo 0.125 1 c'.split()),
1816 NS(foo=True, bar=0.125, w=None, x='c'),
1817 )
R David Murray00528e82012-07-21 22:48:35 -04001818 self.assertEqual(
1819 self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
1820 NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
1821 )
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001822
Steven Bethardfca2e8a2010-11-02 12:47:22 +00001823 def test_parse_known_args(self):
1824 self.assertEqual(
1825 self.parser.parse_known_args('0.5 1 b -w 7'.split()),
1826 (NS(foo=False, bar=0.5, w=7, x='b'), []),
1827 )
1828 self.assertEqual(
1829 self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
1830 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1831 )
1832 self.assertEqual(
1833 self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
1834 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1835 )
1836 self.assertEqual(
1837 self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
1838 (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
1839 )
1840 self.assertEqual(
1841 self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
1842 (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
1843 )
1844
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001845 def test_dest(self):
1846 parser = ErrorRaisingArgumentParser()
1847 parser.add_argument('--foo', action='store_true')
1848 subparsers = parser.add_subparsers(dest='bar')
1849 parser1 = subparsers.add_parser('1')
1850 parser1.add_argument('baz')
1851 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1852 parser.parse_args('1 2'.split()))
1853
1854 def test_help(self):
1855 self.assertEqual(self.parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001856 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001857 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001858 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001859
1860 main description
1861
1862 positional arguments:
1863 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001864 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001865
1866 optional arguments:
1867 -h, --help show this help message and exit
1868 --foo foo help
1869 '''))
1870
R. David Murray88c49fe2010-08-03 17:56:09 +00001871 def test_help_extra_prefix_chars(self):
1872 # Make sure - is still used for help if it is a non-first prefix char
1873 parser = self._get_parser(prefix_chars='+:-')
1874 self.assertEqual(parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001875 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00001876 self.assertEqual(parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001877 usage: PROG [-h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00001878
1879 main description
1880
1881 positional arguments:
1882 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001883 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00001884
1885 optional arguments:
1886 -h, --help show this help message and exit
1887 ++foo foo help
1888 '''))
1889
1890
1891 def test_help_alternate_prefix_chars(self):
1892 parser = self._get_parser(prefix_chars='+:/')
1893 self.assertEqual(parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001894 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00001895 self.assertEqual(parser.format_help(), textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001896 usage: PROG [+h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00001897
1898 main description
1899
1900 positional arguments:
1901 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001902 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00001903
1904 optional arguments:
1905 +h, ++help show this help message and exit
1906 ++foo foo help
1907 '''))
1908
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001909 def test_parser_command_help(self):
1910 self.assertEqual(self.command_help_parser.format_usage(),
R David Murray00528e82012-07-21 22:48:35 -04001911 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001912 self.assertEqual(self.command_help_parser.format_help(),
1913 textwrap.dedent('''\
R David Murray00528e82012-07-21 22:48:35 -04001914 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001915
1916 main description
1917
1918 positional arguments:
1919 bar bar help
R David Murray00528e82012-07-21 22:48:35 -04001920 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001921 1 1 help
1922 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04001923 3 3 help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001924
1925 optional arguments:
1926 -h, --help show this help message and exit
1927 --foo foo help
1928 '''))
1929
1930 def test_subparser_title_help(self):
1931 parser = ErrorRaisingArgumentParser(prog='PROG',
1932 description='main description')
1933 parser.add_argument('--foo', action='store_true', help='foo help')
1934 parser.add_argument('bar', help='bar help')
1935 subparsers = parser.add_subparsers(title='subcommands',
1936 description='command help',
1937 help='additional text')
1938 parser1 = subparsers.add_parser('1')
1939 parser2 = subparsers.add_parser('2')
1940 self.assertEqual(parser.format_usage(),
1941 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1942 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1943 usage: PROG [-h] [--foo] bar {1,2} ...
1944
1945 main description
1946
1947 positional arguments:
1948 bar bar help
1949
1950 optional arguments:
1951 -h, --help show this help message and exit
1952 --foo foo help
1953
1954 subcommands:
1955 command help
1956
1957 {1,2} additional text
1958 '''))
1959
1960 def _test_subparser_help(self, args_str, expected_help):
1961 try:
1962 self.parser.parse_args(args_str.split())
1963 except ArgumentParserError:
1964 err = sys.exc_info()[1]
1965 if err.stdout != expected_help:
1966 print(repr(expected_help))
1967 print(repr(err.stdout))
1968 self.assertEqual(err.stdout, expected_help)
1969
1970 def test_subparser1_help(self):
1971 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
1972 usage: PROG bar 1 [-h] [-w W] {a,b,c}
1973
1974 1 description
1975
1976 positional arguments:
1977 {a,b,c} x help
1978
1979 optional arguments:
1980 -h, --help show this help message and exit
1981 -w W w help
1982 '''))
1983
1984 def test_subparser2_help(self):
1985 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
1986 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
1987
1988 2 description
1989
1990 positional arguments:
1991 z z help
1992
1993 optional arguments:
1994 -h, --help show this help message and exit
1995 -y {1,2,3} y help
1996 '''))
1997
Steven Bethardfd311a72010-12-18 11:19:23 +00001998 def test_alias_invocation(self):
1999 parser = self._get_parser(aliases=True)
2000 self.assertEqual(
2001 parser.parse_known_args('0.5 1alias1 b'.split()),
2002 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2003 )
2004 self.assertEqual(
2005 parser.parse_known_args('0.5 1alias2 b'.split()),
2006 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2007 )
2008
2009 def test_error_alias_invocation(self):
2010 parser = self._get_parser(aliases=True)
2011 self.assertArgumentParserError(parser.parse_args,
2012 '0.5 1alias3 b'.split())
2013
2014 def test_alias_help(self):
2015 parser = self._get_parser(aliases=True, subparser_help=True)
2016 self.maxDiff = None
2017 self.assertEqual(parser.format_help(), textwrap.dedent("""\
2018 usage: PROG [-h] [--foo] bar COMMAND ...
2019
2020 main description
2021
2022 positional arguments:
2023 bar bar help
2024
2025 optional arguments:
2026 -h, --help show this help message and exit
2027 --foo foo help
2028
2029 commands:
2030 COMMAND
2031 1 (1alias1, 1alias2)
2032 1 help
2033 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04002034 3 3 help
Steven Bethardfd311a72010-12-18 11:19:23 +00002035 """))
2036
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002037# ============
2038# Groups tests
2039# ============
2040
2041class TestPositionalsGroups(TestCase):
2042 """Tests that order of group positionals matches construction order"""
2043
2044 def test_nongroup_first(self):
2045 parser = ErrorRaisingArgumentParser()
2046 parser.add_argument('foo')
2047 group = parser.add_argument_group('g')
2048 group.add_argument('bar')
2049 parser.add_argument('baz')
2050 expected = NS(foo='1', bar='2', baz='3')
2051 result = parser.parse_args('1 2 3'.split())
2052 self.assertEqual(expected, result)
2053
2054 def test_group_first(self):
2055 parser = ErrorRaisingArgumentParser()
2056 group = parser.add_argument_group('xxx')
2057 group.add_argument('foo')
2058 parser.add_argument('bar')
2059 parser.add_argument('baz')
2060 expected = NS(foo='1', bar='2', baz='3')
2061 result = parser.parse_args('1 2 3'.split())
2062 self.assertEqual(expected, result)
2063
2064 def test_interleaved_groups(self):
2065 parser = ErrorRaisingArgumentParser()
2066 group = parser.add_argument_group('xxx')
2067 parser.add_argument('foo')
2068 group.add_argument('bar')
2069 parser.add_argument('baz')
2070 group = parser.add_argument_group('yyy')
2071 group.add_argument('frell')
2072 expected = NS(foo='1', bar='2', baz='3', frell='4')
2073 result = parser.parse_args('1 2 3 4'.split())
2074 self.assertEqual(expected, result)
2075
2076# ===================
2077# Parent parser tests
2078# ===================
2079
2080class TestParentParsers(TestCase):
2081 """Tests that parsers can be created with parent parsers"""
2082
2083 def assertArgumentParserError(self, *args, **kwargs):
2084 self.assertRaises(ArgumentParserError, *args, **kwargs)
2085
2086 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00002087 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002088 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
2089 self.wxyz_parent.add_argument('--w')
2090 x_group = self.wxyz_parent.add_argument_group('x')
2091 x_group.add_argument('-y')
2092 self.wxyz_parent.add_argument('z')
2093
2094 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
2095 self.abcd_parent.add_argument('a')
2096 self.abcd_parent.add_argument('-b')
2097 c_group = self.abcd_parent.add_argument_group('c')
2098 c_group.add_argument('--d')
2099
2100 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2101 self.w_parent.add_argument('--w')
2102
2103 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2104 self.z_parent.add_argument('z')
2105
2106 # parents with mutually exclusive groups
2107 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2108 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2109 group.add_argument('-a', action='store_true')
2110 group.add_argument('-b', action='store_true')
2111
2112 self.main_program = os.path.basename(sys.argv[0])
2113
2114 def test_single_parent(self):
2115 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2116 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2117 NS(w='3', y='1', z='2'))
2118
2119 def test_single_parent_mutex(self):
2120 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2121 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2122 self._test_mutex_ab(parser.parse_args)
2123
2124 def test_single_granparent_mutex(self):
2125 parents = [self.ab_mutex_parent]
2126 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2127 parser = ErrorRaisingArgumentParser(parents=[parser])
2128 self._test_mutex_ab(parser.parse_args)
2129
2130 def _test_mutex_ab(self, parse_args):
2131 self.assertEqual(parse_args([]), NS(a=False, b=False))
2132 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2133 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2134 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2135 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2136 self.assertArgumentParserError(parse_args, ['-c'])
2137 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2138 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2139
2140 def test_multiple_parents(self):
2141 parents = [self.abcd_parent, self.wxyz_parent]
2142 parser = ErrorRaisingArgumentParser(parents=parents)
2143 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2144 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2145
2146 def test_multiple_parents_mutex(self):
2147 parents = [self.ab_mutex_parent, self.wxyz_parent]
2148 parser = ErrorRaisingArgumentParser(parents=parents)
2149 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2150 NS(a=True, b=False, w='2', y=None, z='3'))
2151 self.assertArgumentParserError(
2152 parser.parse_args, '-a --w 2 3 -b'.split())
2153 self.assertArgumentParserError(
2154 parser.parse_args, '-a -b --w 2 3'.split())
2155
2156 def test_conflicting_parents(self):
2157 self.assertRaises(
2158 argparse.ArgumentError,
2159 argparse.ArgumentParser,
2160 parents=[self.w_parent, self.wxyz_parent])
2161
2162 def test_conflicting_parents_mutex(self):
2163 self.assertRaises(
2164 argparse.ArgumentError,
2165 argparse.ArgumentParser,
2166 parents=[self.abcd_parent, self.ab_mutex_parent])
2167
2168 def test_same_argument_name_parents(self):
2169 parents = [self.wxyz_parent, self.z_parent]
2170 parser = ErrorRaisingArgumentParser(parents=parents)
2171 self.assertEqual(parser.parse_args('1 2'.split()),
2172 NS(w=None, y=None, z='2'))
2173
2174 def test_subparser_parents(self):
2175 parser = ErrorRaisingArgumentParser()
2176 subparsers = parser.add_subparsers()
2177 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2178 abcde_parser.add_argument('e')
2179 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2180 NS(a='3', b='1', d='2', e='4'))
2181
2182 def test_subparser_parents_mutex(self):
2183 parser = ErrorRaisingArgumentParser()
2184 subparsers = parser.add_subparsers()
2185 parents = [self.ab_mutex_parent]
2186 abc_parser = subparsers.add_parser('foo', parents=parents)
2187 c_group = abc_parser.add_argument_group('c_group')
2188 c_group.add_argument('c')
2189 parents = [self.wxyz_parent, self.ab_mutex_parent]
2190 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2191 wxyzabe_parser.add_argument('e')
2192 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2193 NS(a=True, b=False, c='4'))
2194 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2195 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2196 self.assertArgumentParserError(
2197 parser.parse_args, 'foo -a -b 4'.split())
2198 self.assertArgumentParserError(
2199 parser.parse_args, 'bar -b -a 4'.split())
2200
2201 def test_parent_help(self):
2202 parents = [self.abcd_parent, self.wxyz_parent]
2203 parser = ErrorRaisingArgumentParser(parents=parents)
2204 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002205 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002206 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002207 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002208
2209 positional arguments:
2210 a
2211 z
2212
2213 optional arguments:
2214 -h, --help show this help message and exit
2215 -b B
2216 --w W
2217
2218 c:
2219 --d D
2220
2221 x:
2222 -y Y
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002223 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002224
2225 def test_groups_parents(self):
2226 parent = ErrorRaisingArgumentParser(add_help=False)
2227 g = parent.add_argument_group(title='g', description='gd')
2228 g.add_argument('-w')
2229 g.add_argument('-x')
2230 m = parent.add_mutually_exclusive_group()
2231 m.add_argument('-y')
2232 m.add_argument('-z')
2233 parser = ErrorRaisingArgumentParser(parents=[parent])
2234
2235 self.assertRaises(ArgumentParserError, parser.parse_args,
2236 ['-y', 'Y', '-z', 'Z'])
2237
2238 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002239 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002240 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002241 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002242
2243 optional arguments:
2244 -h, --help show this help message and exit
2245 -y Y
2246 -z Z
2247
2248 g:
2249 gd
2250
2251 -w W
2252 -x X
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002253 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002254
2255# ==============================
2256# Mutually exclusive group tests
2257# ==============================
2258
2259class TestMutuallyExclusiveGroupErrors(TestCase):
2260
2261 def test_invalid_add_argument_group(self):
2262 parser = ErrorRaisingArgumentParser()
2263 raises = self.assertRaises
2264 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2265
2266 def test_invalid_add_argument(self):
2267 parser = ErrorRaisingArgumentParser()
2268 group = parser.add_mutually_exclusive_group()
2269 add_argument = group.add_argument
2270 raises = self.assertRaises
2271 raises(ValueError, add_argument, '--foo', required=True)
2272 raises(ValueError, add_argument, 'bar')
2273 raises(ValueError, add_argument, 'bar', nargs='+')
2274 raises(ValueError, add_argument, 'bar', nargs=1)
2275 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2276
Steven Bethard49998ee2010-11-01 16:29:26 +00002277 def test_help(self):
2278 parser = ErrorRaisingArgumentParser(prog='PROG')
2279 group1 = parser.add_mutually_exclusive_group()
2280 group1.add_argument('--foo', action='store_true')
2281 group1.add_argument('--bar', action='store_false')
2282 group2 = parser.add_mutually_exclusive_group()
2283 group2.add_argument('--soup', action='store_true')
2284 group2.add_argument('--nuts', action='store_false')
2285 expected = '''\
2286 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2287
2288 optional arguments:
2289 -h, --help show this help message and exit
2290 --foo
2291 --bar
2292 --soup
2293 --nuts
2294 '''
2295 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002296
2297class MEMixin(object):
2298
2299 def test_failures_when_not_required(self):
2300 parse_args = self.get_parser(required=False).parse_args
2301 error = ArgumentParserError
2302 for args_string in self.failures:
2303 self.assertRaises(error, parse_args, args_string.split())
2304
2305 def test_failures_when_required(self):
2306 parse_args = self.get_parser(required=True).parse_args
2307 error = ArgumentParserError
2308 for args_string in self.failures + ['']:
2309 self.assertRaises(error, parse_args, args_string.split())
2310
2311 def test_successes_when_not_required(self):
2312 parse_args = self.get_parser(required=False).parse_args
2313 successes = self.successes + self.successes_when_not_required
2314 for args_string, expected_ns in successes:
2315 actual_ns = parse_args(args_string.split())
2316 self.assertEqual(actual_ns, expected_ns)
2317
2318 def test_successes_when_required(self):
2319 parse_args = self.get_parser(required=True).parse_args
2320 for args_string, expected_ns in self.successes:
2321 actual_ns = parse_args(args_string.split())
2322 self.assertEqual(actual_ns, expected_ns)
2323
2324 def test_usage_when_not_required(self):
2325 format_usage = self.get_parser(required=False).format_usage
2326 expected_usage = self.usage_when_not_required
2327 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2328
2329 def test_usage_when_required(self):
2330 format_usage = self.get_parser(required=True).format_usage
2331 expected_usage = self.usage_when_required
2332 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2333
2334 def test_help_when_not_required(self):
2335 format_help = self.get_parser(required=False).format_help
2336 help = self.usage_when_not_required + self.help
2337 self.assertEqual(format_help(), textwrap.dedent(help))
2338
2339 def test_help_when_required(self):
2340 format_help = self.get_parser(required=True).format_help
2341 help = self.usage_when_required + self.help
2342 self.assertEqual(format_help(), textwrap.dedent(help))
2343
2344
2345class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2346
2347 def get_parser(self, required=None):
2348 parser = ErrorRaisingArgumentParser(prog='PROG')
2349 group = parser.add_mutually_exclusive_group(required=required)
2350 group.add_argument('--bar', help='bar help')
2351 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2352 return parser
2353
2354 failures = ['--bar X --baz Y', '--bar X --baz']
2355 successes = [
2356 ('--bar X', NS(bar='X', baz=None)),
2357 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2358 ('--baz Y', NS(bar=None, baz='Y')),
2359 ('--baz', NS(bar=None, baz='Z')),
2360 ]
2361 successes_when_not_required = [
2362 ('', NS(bar=None, baz=None)),
2363 ]
2364
2365 usage_when_not_required = '''\
2366 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2367 '''
2368 usage_when_required = '''\
2369 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2370 '''
2371 help = '''\
2372
2373 optional arguments:
2374 -h, --help show this help message and exit
2375 --bar BAR bar help
2376 --baz [BAZ] baz help
2377 '''
2378
2379
2380class TestMutuallyExclusiveLong(MEMixin, TestCase):
2381
2382 def get_parser(self, required=None):
2383 parser = ErrorRaisingArgumentParser(prog='PROG')
2384 parser.add_argument('--abcde', help='abcde help')
2385 parser.add_argument('--fghij', help='fghij help')
2386 group = parser.add_mutually_exclusive_group(required=required)
2387 group.add_argument('--klmno', help='klmno help')
2388 group.add_argument('--pqrst', help='pqrst help')
2389 return parser
2390
2391 failures = ['--klmno X --pqrst Y']
2392 successes = [
2393 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2394 ('--abcde Y --klmno X',
2395 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2396 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2397 ('--pqrst X --fghij Y',
2398 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2399 ]
2400 successes_when_not_required = [
2401 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2402 ]
2403
2404 usage_when_not_required = '''\
2405 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2406 [--klmno KLMNO | --pqrst PQRST]
2407 '''
2408 usage_when_required = '''\
2409 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2410 (--klmno KLMNO | --pqrst PQRST)
2411 '''
2412 help = '''\
2413
2414 optional arguments:
2415 -h, --help show this help message and exit
2416 --abcde ABCDE abcde help
2417 --fghij FGHIJ fghij help
2418 --klmno KLMNO klmno help
2419 --pqrst PQRST pqrst help
2420 '''
2421
2422
2423class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2424
2425 def get_parser(self, required):
2426 parser = ErrorRaisingArgumentParser(prog='PROG')
2427 group = parser.add_mutually_exclusive_group(required=required)
2428 group.add_argument('-x', help=argparse.SUPPRESS)
2429 group.add_argument('-y', action='store_false', help='y help')
2430 return parser
2431
2432 failures = ['-x X -y']
2433 successes = [
2434 ('-x X', NS(x='X', y=True)),
2435 ('-x X -x Y', NS(x='Y', y=True)),
2436 ('-y', NS(x=None, y=False)),
2437 ]
2438 successes_when_not_required = [
2439 ('', NS(x=None, y=True)),
2440 ]
2441
2442 usage_when_not_required = '''\
2443 usage: PROG [-h] [-y]
2444 '''
2445 usage_when_required = '''\
2446 usage: PROG [-h] -y
2447 '''
2448 help = '''\
2449
2450 optional arguments:
2451 -h, --help show this help message and exit
2452 -y y help
2453 '''
2454
2455
2456class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2457
2458 def get_parser(self, required):
2459 parser = ErrorRaisingArgumentParser(prog='PROG')
2460 group = parser.add_mutually_exclusive_group(required=required)
2461 add = group.add_argument
2462 add('--spam', action='store_true', help=argparse.SUPPRESS)
2463 add('--badger', action='store_false', help=argparse.SUPPRESS)
2464 add('--bladder', help=argparse.SUPPRESS)
2465 return parser
2466
2467 failures = [
2468 '--spam --badger',
2469 '--badger --bladder B',
2470 '--bladder B --spam',
2471 ]
2472 successes = [
2473 ('--spam', NS(spam=True, badger=True, bladder=None)),
2474 ('--badger', NS(spam=False, badger=False, bladder=None)),
2475 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2476 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2477 ]
2478 successes_when_not_required = [
2479 ('', NS(spam=False, badger=True, bladder=None)),
2480 ]
2481
2482 usage_when_required = usage_when_not_required = '''\
2483 usage: PROG [-h]
2484 '''
2485 help = '''\
2486
2487 optional arguments:
2488 -h, --help show this help message and exit
2489 '''
2490
2491
2492class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2493
2494 def get_parser(self, required):
2495 parser = ErrorRaisingArgumentParser(prog='PROG')
2496 group = parser.add_mutually_exclusive_group(required=required)
2497 group.add_argument('--foo', action='store_true', help='FOO')
2498 group.add_argument('--spam', help='SPAM')
2499 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2500 return parser
2501
2502 failures = [
2503 '--foo --spam S',
2504 '--spam S X',
2505 'X --foo',
2506 'X Y Z --spam S',
2507 '--foo X Y',
2508 ]
2509 successes = [
2510 ('--foo', NS(foo=True, spam=None, badger='X')),
2511 ('--spam S', NS(foo=False, spam='S', badger='X')),
2512 ('X', NS(foo=False, spam=None, badger=['X'])),
2513 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2514 ]
2515 successes_when_not_required = [
2516 ('', NS(foo=False, spam=None, badger='X')),
2517 ]
2518
2519 usage_when_not_required = '''\
2520 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2521 '''
2522 usage_when_required = '''\
2523 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2524 '''
2525 help = '''\
2526
2527 positional arguments:
2528 badger BADGER
2529
2530 optional arguments:
2531 -h, --help show this help message and exit
2532 --foo FOO
2533 --spam SPAM SPAM
2534 '''
2535
2536
2537class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2538
2539 def get_parser(self, required):
2540 parser = ErrorRaisingArgumentParser(prog='PROG')
2541 parser.add_argument('-x', action='store_true', help='x help')
2542 group = parser.add_mutually_exclusive_group(required=required)
2543 group.add_argument('-a', action='store_true', help='a help')
2544 group.add_argument('-b', action='store_true', help='b help')
2545 parser.add_argument('-y', action='store_true', help='y help')
2546 group.add_argument('-c', action='store_true', help='c help')
2547 return parser
2548
2549 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2550 successes = [
2551 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2552 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2553 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2554 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2555 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2556 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2557 ]
2558 successes_when_not_required = [
2559 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2560 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2561 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2562 ]
2563
2564 usage_when_required = usage_when_not_required = '''\
2565 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2566 '''
2567 help = '''\
2568
2569 optional arguments:
2570 -h, --help show this help message and exit
2571 -x x help
2572 -a a help
2573 -b b help
2574 -y y help
2575 -c c help
2576 '''
2577
2578
Georg Brandl0f6b47a2011-01-30 12:19:35 +00002579class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2580
2581 def get_parser(self, required=None):
2582 parser = ErrorRaisingArgumentParser(prog='PROG')
2583 titled_group = parser.add_argument_group(
2584 title='Titled group', description='Group description')
2585 mutex_group = \
2586 titled_group.add_mutually_exclusive_group(required=required)
2587 mutex_group.add_argument('--bar', help='bar help')
2588 mutex_group.add_argument('--baz', help='baz help')
2589 return parser
2590
2591 failures = ['--bar X --baz Y', '--baz X --bar Y']
2592 successes = [
2593 ('--bar X', NS(bar='X', baz=None)),
2594 ('--baz Y', NS(bar=None, baz='Y')),
2595 ]
2596 successes_when_not_required = [
2597 ('', NS(bar=None, baz=None)),
2598 ]
2599
2600 usage_when_not_required = '''\
2601 usage: PROG [-h] [--bar BAR | --baz BAZ]
2602 '''
2603 usage_when_required = '''\
2604 usage: PROG [-h] (--bar BAR | --baz BAZ)
2605 '''
2606 help = '''\
2607
2608 optional arguments:
2609 -h, --help show this help message and exit
2610
2611 Titled group:
2612 Group description
2613
2614 --bar BAR bar help
2615 --baz BAZ baz help
2616 '''
2617
2618
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002619class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2620
2621 def get_parser(self, required):
2622 parser = ErrorRaisingArgumentParser(prog='PROG')
2623 parser.add_argument('x', help='x help')
2624 parser.add_argument('-y', action='store_true', help='y help')
2625 group = parser.add_mutually_exclusive_group(required=required)
2626 group.add_argument('a', nargs='?', help='a help')
2627 group.add_argument('-b', action='store_true', help='b help')
2628 group.add_argument('-c', action='store_true', help='c help')
2629 return parser
2630
2631 failures = ['X A -b', '-b -c', '-c X A']
2632 successes = [
2633 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2634 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2635 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2636 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2637 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2638 ]
2639 successes_when_not_required = [
2640 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2641 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2642 ]
2643
2644 usage_when_required = usage_when_not_required = '''\
2645 usage: PROG [-h] [-y] [-b] [-c] x [a]
2646 '''
2647 help = '''\
2648
2649 positional arguments:
2650 x x help
2651 a a help
2652
2653 optional arguments:
2654 -h, --help show this help message and exit
2655 -y y help
2656 -b b help
2657 -c c help
2658 '''
2659
2660# =================================================
2661# Mutually exclusive group in parent parser tests
2662# =================================================
2663
2664class MEPBase(object):
2665
2666 def get_parser(self, required=None):
2667 parent = super(MEPBase, self).get_parser(required=required)
2668 parser = ErrorRaisingArgumentParser(
2669 prog=parent.prog, add_help=False, parents=[parent])
2670 return parser
2671
2672
2673class TestMutuallyExclusiveGroupErrorsParent(
2674 MEPBase, TestMutuallyExclusiveGroupErrors):
2675 pass
2676
2677
2678class TestMutuallyExclusiveSimpleParent(
2679 MEPBase, TestMutuallyExclusiveSimple):
2680 pass
2681
2682
2683class TestMutuallyExclusiveLongParent(
2684 MEPBase, TestMutuallyExclusiveLong):
2685 pass
2686
2687
2688class TestMutuallyExclusiveFirstSuppressedParent(
2689 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2690 pass
2691
2692
2693class TestMutuallyExclusiveManySuppressedParent(
2694 MEPBase, TestMutuallyExclusiveManySuppressed):
2695 pass
2696
2697
2698class TestMutuallyExclusiveOptionalAndPositionalParent(
2699 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2700 pass
2701
2702
2703class TestMutuallyExclusiveOptionalsMixedParent(
2704 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2705 pass
2706
2707
2708class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2709 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2710 pass
2711
2712# =================
2713# Set default tests
2714# =================
2715
2716class TestSetDefaults(TestCase):
2717
2718 def test_set_defaults_no_args(self):
2719 parser = ErrorRaisingArgumentParser()
2720 parser.set_defaults(x='foo')
2721 parser.set_defaults(y='bar', z=1)
2722 self.assertEqual(NS(x='foo', y='bar', z=1),
2723 parser.parse_args([]))
2724 self.assertEqual(NS(x='foo', y='bar', z=1),
2725 parser.parse_args([], NS()))
2726 self.assertEqual(NS(x='baz', y='bar', z=1),
2727 parser.parse_args([], NS(x='baz')))
2728 self.assertEqual(NS(x='baz', y='bar', z=2),
2729 parser.parse_args([], NS(x='baz', z=2)))
2730
2731 def test_set_defaults_with_args(self):
2732 parser = ErrorRaisingArgumentParser()
2733 parser.set_defaults(x='foo', y='bar')
2734 parser.add_argument('-x', default='xfoox')
2735 self.assertEqual(NS(x='xfoox', y='bar'),
2736 parser.parse_args([]))
2737 self.assertEqual(NS(x='xfoox', y='bar'),
2738 parser.parse_args([], NS()))
2739 self.assertEqual(NS(x='baz', y='bar'),
2740 parser.parse_args([], NS(x='baz')))
2741 self.assertEqual(NS(x='1', y='bar'),
2742 parser.parse_args('-x 1'.split()))
2743 self.assertEqual(NS(x='1', y='bar'),
2744 parser.parse_args('-x 1'.split(), NS()))
2745 self.assertEqual(NS(x='1', y='bar'),
2746 parser.parse_args('-x 1'.split(), NS(x='baz')))
2747
2748 def test_set_defaults_subparsers(self):
2749 parser = ErrorRaisingArgumentParser()
2750 parser.set_defaults(x='foo')
2751 subparsers = parser.add_subparsers()
2752 parser_a = subparsers.add_parser('a')
2753 parser_a.set_defaults(y='bar')
2754 self.assertEqual(NS(x='foo', y='bar'),
2755 parser.parse_args('a'.split()))
2756
2757 def test_set_defaults_parents(self):
2758 parent = ErrorRaisingArgumentParser(add_help=False)
2759 parent.set_defaults(x='foo')
2760 parser = ErrorRaisingArgumentParser(parents=[parent])
2761 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2762
2763 def test_set_defaults_same_as_add_argument(self):
2764 parser = ErrorRaisingArgumentParser()
2765 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2766 parser.add_argument('-w')
2767 parser.add_argument('-x', default='XX')
2768 parser.add_argument('y', nargs='?')
2769 parser.add_argument('z', nargs='?', default='ZZ')
2770
2771 # defaults set previously
2772 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2773 parser.parse_args([]))
2774
2775 # reset defaults
2776 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2777 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2778 parser.parse_args([]))
2779
2780 def test_set_defaults_same_as_add_argument_group(self):
2781 parser = ErrorRaisingArgumentParser()
2782 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2783 group = parser.add_argument_group('foo')
2784 group.add_argument('-w')
2785 group.add_argument('-x', default='XX')
2786 group.add_argument('y', nargs='?')
2787 group.add_argument('z', nargs='?', default='ZZ')
2788
2789
2790 # defaults set previously
2791 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2792 parser.parse_args([]))
2793
2794 # reset defaults
2795 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2796 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2797 parser.parse_args([]))
2798
2799# =================
2800# Get default tests
2801# =================
2802
2803class TestGetDefault(TestCase):
2804
2805 def test_get_default(self):
2806 parser = ErrorRaisingArgumentParser()
2807 self.assertEqual(None, parser.get_default("foo"))
2808 self.assertEqual(None, parser.get_default("bar"))
2809
2810 parser.add_argument("--foo")
2811 self.assertEqual(None, parser.get_default("foo"))
2812 self.assertEqual(None, parser.get_default("bar"))
2813
2814 parser.add_argument("--bar", type=int, default=42)
2815 self.assertEqual(None, parser.get_default("foo"))
2816 self.assertEqual(42, parser.get_default("bar"))
2817
2818 parser.set_defaults(foo="badger")
2819 self.assertEqual("badger", parser.get_default("foo"))
2820 self.assertEqual(42, parser.get_default("bar"))
2821
2822# ==========================
2823# Namespace 'contains' tests
2824# ==========================
2825
2826class TestNamespaceContainsSimple(TestCase):
2827
2828 def test_empty(self):
2829 ns = argparse.Namespace()
Ezio Melottib3aedd42010-11-20 19:04:17 +00002830 self.assertEqual('' in ns, False)
2831 self.assertEqual('' not in ns, True)
2832 self.assertEqual('x' in ns, False)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002833
2834 def test_non_empty(self):
2835 ns = argparse.Namespace(x=1, y=2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00002836 self.assertEqual('x' in ns, True)
2837 self.assertEqual('x' not in ns, False)
2838 self.assertEqual('y' in ns, True)
2839 self.assertEqual('' in ns, False)
2840 self.assertEqual('xx' in ns, False)
2841 self.assertEqual('z' in ns, False)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002842
2843# =====================
2844# Help formatting tests
2845# =====================
2846
2847class TestHelpFormattingMetaclass(type):
2848
2849 def __init__(cls, name, bases, bodydict):
2850 if name == 'HelpTestCase':
2851 return
2852
2853 class AddTests(object):
2854
2855 def __init__(self, test_class, func_suffix, std_name):
2856 self.func_suffix = func_suffix
2857 self.std_name = std_name
2858
2859 for test_func in [self.test_format,
2860 self.test_print,
2861 self.test_print_file]:
2862 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2863
2864 def test_wrapper(self, test_func=test_func):
2865 test_func(self)
2866 try:
2867 test_wrapper.__name__ = test_name
2868 except TypeError:
2869 pass
2870 setattr(test_class, test_name, test_wrapper)
2871
2872 def _get_parser(self, tester):
2873 parser = argparse.ArgumentParser(
2874 *tester.parser_signature.args,
2875 **tester.parser_signature.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002876 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002877 parser.add_argument(*argument_sig.args,
2878 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002879 group_sigs = getattr(tester, 'argument_group_signatures', [])
2880 for group_sig, argument_sigs in group_sigs:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002881 group = parser.add_argument_group(*group_sig.args,
2882 **group_sig.kwargs)
2883 for argument_sig in argument_sigs:
2884 group.add_argument(*argument_sig.args,
2885 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02002886 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
2887 if subparsers_sigs:
2888 subparsers = parser.add_subparsers()
2889 for subparser_sig in subparsers_sigs:
2890 subparsers.add_parser(*subparser_sig.args,
2891 **subparser_sig.kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002892 return parser
2893
2894 def _test(self, tester, parser_text):
2895 expected_text = getattr(tester, self.func_suffix)
2896 expected_text = textwrap.dedent(expected_text)
2897 if expected_text != parser_text:
2898 print(repr(expected_text))
2899 print(repr(parser_text))
2900 for char1, char2 in zip(expected_text, parser_text):
2901 if char1 != char2:
2902 print('first diff: %r %r' % (char1, char2))
2903 break
2904 tester.assertEqual(expected_text, parser_text)
2905
2906 def test_format(self, tester):
2907 parser = self._get_parser(tester)
2908 format = getattr(parser, 'format_%s' % self.func_suffix)
2909 self._test(tester, format())
2910
2911 def test_print(self, tester):
2912 parser = self._get_parser(tester)
2913 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2914 old_stream = getattr(sys, self.std_name)
Benjamin Petersonb48af542010-04-11 20:43:16 +00002915 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002916 try:
2917 print_()
2918 parser_text = getattr(sys, self.std_name).getvalue()
2919 finally:
2920 setattr(sys, self.std_name, old_stream)
2921 self._test(tester, parser_text)
2922
2923 def test_print_file(self, tester):
2924 parser = self._get_parser(tester)
2925 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Benjamin Petersonb48af542010-04-11 20:43:16 +00002926 sfile = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002927 print_(sfile)
2928 parser_text = sfile.getvalue()
2929 self._test(tester, parser_text)
2930
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002931 # add tests for {format,print}_{usage,help}
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002932 for func_suffix, std_name in [('usage', 'stdout'),
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002933 ('help', 'stdout')]:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002934 AddTests(cls, func_suffix, std_name)
2935
2936bases = TestCase,
2937HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2938
2939
2940class TestHelpBiggerOptionals(HelpTestCase):
2941 """Make sure that argument help aligns when options are longer"""
2942
2943 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002944 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002945 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002946 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002947 Sig('-x', action='store_true', help='X HELP'),
2948 Sig('--y', help='Y HELP'),
2949 Sig('foo', help='FOO HELP'),
2950 Sig('bar', help='BAR HELP'),
2951 ]
2952 argument_group_signatures = []
2953 usage = '''\
2954 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2955 '''
2956 help = usage + '''\
2957
2958 DESCRIPTION
2959
2960 positional arguments:
2961 foo FOO HELP
2962 bar BAR HELP
2963
2964 optional arguments:
2965 -h, --help show this help message and exit
2966 -v, --version show program's version number and exit
2967 -x X HELP
2968 --y Y Y HELP
2969
2970 EPILOG
2971 '''
2972 version = '''\
2973 0.1
2974 '''
2975
2976
2977class TestHelpBiggerOptionalGroups(HelpTestCase):
2978 """Make sure that argument help aligns when options are longer"""
2979
2980 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002981 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002982 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02002983 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002984 Sig('-x', action='store_true', help='X HELP'),
2985 Sig('--y', help='Y HELP'),
2986 Sig('foo', help='FOO HELP'),
2987 Sig('bar', help='BAR HELP'),
2988 ]
2989 argument_group_signatures = [
2990 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2991 Sig('baz', help='BAZ HELP'),
2992 Sig('-z', nargs='+', help='Z HELP')]),
2993 ]
2994 usage = '''\
2995 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2996 '''
2997 help = usage + '''\
2998
2999 DESCRIPTION
3000
3001 positional arguments:
3002 foo FOO HELP
3003 bar BAR HELP
3004
3005 optional arguments:
3006 -h, --help show this help message and exit
3007 -v, --version show program's version number and exit
3008 -x X HELP
3009 --y Y Y HELP
3010
3011 GROUP TITLE:
3012 GROUP DESCRIPTION
3013
3014 baz BAZ HELP
3015 -z Z [Z ...] Z HELP
3016
3017 EPILOG
3018 '''
3019 version = '''\
3020 0.1
3021 '''
3022
3023
3024class TestHelpBiggerPositionals(HelpTestCase):
3025 """Make sure that help aligns when arguments are longer"""
3026
3027 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
3028 argument_signatures = [
3029 Sig('-x', action='store_true', help='X HELP'),
3030 Sig('--y', help='Y HELP'),
3031 Sig('ekiekiekifekang', help='EKI HELP'),
3032 Sig('bar', help='BAR HELP'),
3033 ]
3034 argument_group_signatures = []
3035 usage = '''\
3036 usage: USAGE
3037 '''
3038 help = usage + '''\
3039
3040 DESCRIPTION
3041
3042 positional arguments:
3043 ekiekiekifekang EKI HELP
3044 bar BAR HELP
3045
3046 optional arguments:
3047 -h, --help show this help message and exit
3048 -x X HELP
3049 --y Y Y HELP
3050 '''
3051
3052 version = ''
3053
3054
3055class TestHelpReformatting(HelpTestCase):
3056 """Make sure that text after short names starts on the first line"""
3057
3058 parser_signature = Sig(
3059 prog='PROG',
3060 description=' oddly formatted\n'
3061 'description\n'
3062 '\n'
3063 'that is so long that it should go onto multiple '
3064 'lines when wrapped')
3065 argument_signatures = [
3066 Sig('-x', metavar='XX', help='oddly\n'
3067 ' formatted -x help'),
3068 Sig('y', metavar='yyy', help='normal y help'),
3069 ]
3070 argument_group_signatures = [
3071 (Sig('title', description='\n'
3072 ' oddly formatted group\n'
3073 '\n'
3074 'description'),
3075 [Sig('-a', action='store_true',
3076 help=' oddly \n'
3077 'formatted -a help \n'
3078 ' again, so long that it should be wrapped over '
3079 'multiple lines')]),
3080 ]
3081 usage = '''\
3082 usage: PROG [-h] [-x XX] [-a] yyy
3083 '''
3084 help = usage + '''\
3085
3086 oddly formatted description that is so long that it should go onto \
3087multiple
3088 lines when wrapped
3089
3090 positional arguments:
3091 yyy normal y help
3092
3093 optional arguments:
3094 -h, --help show this help message and exit
3095 -x XX oddly formatted -x help
3096
3097 title:
3098 oddly formatted group description
3099
3100 -a oddly formatted -a help again, so long that it should \
3101be wrapped
3102 over multiple lines
3103 '''
3104 version = ''
3105
3106
3107class TestHelpWrappingShortNames(HelpTestCase):
3108 """Make sure that text after short names starts on the first line"""
3109
3110 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3111 argument_signatures = [
3112 Sig('-x', metavar='XX', help='XHH HX' * 20),
3113 Sig('y', metavar='yyy', help='YH YH' * 20),
3114 ]
3115 argument_group_signatures = [
3116 (Sig('ALPHAS'), [
3117 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3118 ]
3119 usage = '''\
3120 usage: PROG [-h] [-x XX] [-a] yyy
3121 '''
3122 help = usage + '''\
3123
3124 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3125DD DD DD
3126 DD DD DD DD D
3127
3128 positional arguments:
3129 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3130YHYH YHYH
3131 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3132
3133 optional arguments:
3134 -h, --help show this help message and exit
3135 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3136HXXHH HXXHH
3137 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3138
3139 ALPHAS:
3140 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3141HHAAHHH
3142 HHAAHHH HHAAHHH HHA
3143 '''
3144 version = ''
3145
3146
3147class TestHelpWrappingLongNames(HelpTestCase):
3148 """Make sure that text after long names starts on the next line"""
3149
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003150 parser_signature = Sig(usage='USAGE', description= 'D D' * 30)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003151 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003152 Sig('-v', '--version', action='version', version='V V' * 30),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003153 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3154 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3155 ]
3156 argument_group_signatures = [
3157 (Sig('ALPHAS'), [
3158 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3159 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3160 ]
3161 usage = '''\
3162 usage: USAGE
3163 '''
3164 help = usage + '''\
3165
3166 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3167DD DD DD
3168 DD DD DD DD D
3169
3170 positional arguments:
3171 yyyyyyyyyyyyyyyyyyyyyyyyy
3172 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3173YHYH YHYH
3174 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3175
3176 optional arguments:
3177 -h, --help show this help message and exit
3178 -v, --version show program's version number and exit
3179 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3180 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3181XHXH XHXH
3182 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3183
3184 ALPHAS:
3185 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3186 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3187AHAH AHAH
3188 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3189 zzzzzzzzzzzzzzzzzzzzzzzzz
3190 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3191ZHZH ZHZH
3192 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3193 '''
3194 version = '''\
3195 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3196VV VV VV
3197 VV VV VV VV V
3198 '''
3199
3200
3201class TestHelpUsage(HelpTestCase):
3202 """Test basic usage messages"""
3203
3204 parser_signature = Sig(prog='PROG')
3205 argument_signatures = [
3206 Sig('-w', nargs='+', help='w'),
3207 Sig('-x', nargs='*', help='x'),
3208 Sig('a', help='a'),
3209 Sig('b', help='b', nargs=2),
3210 Sig('c', help='c', nargs='?'),
3211 ]
3212 argument_group_signatures = [
3213 (Sig('group'), [
3214 Sig('-y', nargs='?', help='y'),
3215 Sig('-z', nargs=3, help='z'),
3216 Sig('d', help='d', nargs='*'),
3217 Sig('e', help='e', nargs='+'),
3218 ])
3219 ]
3220 usage = '''\
3221 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3222 a b b [c] [d [d ...]] e [e ...]
3223 '''
3224 help = usage + '''\
3225
3226 positional arguments:
3227 a a
3228 b b
3229 c c
3230
3231 optional arguments:
3232 -h, --help show this help message and exit
3233 -w W [W ...] w
3234 -x [X [X ...]] x
3235
3236 group:
3237 -y [Y] y
3238 -z Z Z Z z
3239 d d
3240 e e
3241 '''
3242 version = ''
3243
3244
3245class TestHelpOnlyUserGroups(HelpTestCase):
3246 """Test basic usage messages"""
3247
3248 parser_signature = Sig(prog='PROG', add_help=False)
3249 argument_signatures = []
3250 argument_group_signatures = [
3251 (Sig('xxxx'), [
3252 Sig('-x', help='x'),
3253 Sig('a', help='a'),
3254 ]),
3255 (Sig('yyyy'), [
3256 Sig('b', help='b'),
3257 Sig('-y', help='y'),
3258 ]),
3259 ]
3260 usage = '''\
3261 usage: PROG [-x X] [-y Y] a b
3262 '''
3263 help = usage + '''\
3264
3265 xxxx:
3266 -x X x
3267 a a
3268
3269 yyyy:
3270 b b
3271 -y Y y
3272 '''
3273 version = ''
3274
3275
3276class TestHelpUsageLongProg(HelpTestCase):
3277 """Test usage messages where the prog is long"""
3278
3279 parser_signature = Sig(prog='P' * 60)
3280 argument_signatures = [
3281 Sig('-w', metavar='W'),
3282 Sig('-x', metavar='X'),
3283 Sig('a'),
3284 Sig('b'),
3285 ]
3286 argument_group_signatures = []
3287 usage = '''\
3288 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3289 [-h] [-w W] [-x X] a b
3290 '''
3291 help = usage + '''\
3292
3293 positional arguments:
3294 a
3295 b
3296
3297 optional arguments:
3298 -h, --help show this help message and exit
3299 -w W
3300 -x X
3301 '''
3302 version = ''
3303
3304
3305class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3306 """Test usage messages where the prog is long and the optionals wrap"""
3307
3308 parser_signature = Sig(prog='P' * 60)
3309 argument_signatures = [
3310 Sig('-w', metavar='W' * 25),
3311 Sig('-x', metavar='X' * 25),
3312 Sig('-y', metavar='Y' * 25),
3313 Sig('-z', metavar='Z' * 25),
3314 Sig('a'),
3315 Sig('b'),
3316 ]
3317 argument_group_signatures = []
3318 usage = '''\
3319 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3320 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3321[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3322 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3323 a b
3324 '''
3325 help = usage + '''\
3326
3327 positional arguments:
3328 a
3329 b
3330
3331 optional arguments:
3332 -h, --help show this help message and exit
3333 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3334 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3335 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3336 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3337 '''
3338 version = ''
3339
3340
3341class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3342 """Test usage messages where the prog is long and the positionals wrap"""
3343
3344 parser_signature = Sig(prog='P' * 60, add_help=False)
3345 argument_signatures = [
3346 Sig('a' * 25),
3347 Sig('b' * 25),
3348 Sig('c' * 25),
3349 ]
3350 argument_group_signatures = []
3351 usage = '''\
3352 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3353 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3354 ccccccccccccccccccccccccc
3355 '''
3356 help = usage + '''\
3357
3358 positional arguments:
3359 aaaaaaaaaaaaaaaaaaaaaaaaa
3360 bbbbbbbbbbbbbbbbbbbbbbbbb
3361 ccccccccccccccccccccccccc
3362 '''
3363 version = ''
3364
3365
3366class TestHelpUsageOptionalsWrap(HelpTestCase):
3367 """Test usage messages where the optionals wrap"""
3368
3369 parser_signature = Sig(prog='PROG')
3370 argument_signatures = [
3371 Sig('-w', metavar='W' * 25),
3372 Sig('-x', metavar='X' * 25),
3373 Sig('-y', metavar='Y' * 25),
3374 Sig('-z', metavar='Z' * 25),
3375 Sig('a'),
3376 Sig('b'),
3377 Sig('c'),
3378 ]
3379 argument_group_signatures = []
3380 usage = '''\
3381 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3382[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3383 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3384[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3385 a b c
3386 '''
3387 help = usage + '''\
3388
3389 positional arguments:
3390 a
3391 b
3392 c
3393
3394 optional arguments:
3395 -h, --help show this help message and exit
3396 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3397 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3398 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3399 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3400 '''
3401 version = ''
3402
3403
3404class TestHelpUsagePositionalsWrap(HelpTestCase):
3405 """Test usage messages where the positionals wrap"""
3406
3407 parser_signature = Sig(prog='PROG')
3408 argument_signatures = [
3409 Sig('-x'),
3410 Sig('-y'),
3411 Sig('-z'),
3412 Sig('a' * 25),
3413 Sig('b' * 25),
3414 Sig('c' * 25),
3415 ]
3416 argument_group_signatures = []
3417 usage = '''\
3418 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3419 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3420 ccccccccccccccccccccccccc
3421 '''
3422 help = usage + '''\
3423
3424 positional arguments:
3425 aaaaaaaaaaaaaaaaaaaaaaaaa
3426 bbbbbbbbbbbbbbbbbbbbbbbbb
3427 ccccccccccccccccccccccccc
3428
3429 optional arguments:
3430 -h, --help show this help message and exit
3431 -x X
3432 -y Y
3433 -z Z
3434 '''
3435 version = ''
3436
3437
3438class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3439 """Test usage messages where the optionals and positionals wrap"""
3440
3441 parser_signature = Sig(prog='PROG')
3442 argument_signatures = [
3443 Sig('-x', metavar='X' * 25),
3444 Sig('-y', metavar='Y' * 25),
3445 Sig('-z', metavar='Z' * 25),
3446 Sig('a' * 25),
3447 Sig('b' * 25),
3448 Sig('c' * 25),
3449 ]
3450 argument_group_signatures = []
3451 usage = '''\
3452 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3453[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3454 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3455 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3456 ccccccccccccccccccccccccc
3457 '''
3458 help = usage + '''\
3459
3460 positional arguments:
3461 aaaaaaaaaaaaaaaaaaaaaaaaa
3462 bbbbbbbbbbbbbbbbbbbbbbbbb
3463 ccccccccccccccccccccccccc
3464
3465 optional arguments:
3466 -h, --help show this help message and exit
3467 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3468 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3469 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3470 '''
3471 version = ''
3472
3473
3474class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3475 """Test usage messages where there are only optionals and they wrap"""
3476
3477 parser_signature = Sig(prog='PROG')
3478 argument_signatures = [
3479 Sig('-x', metavar='X' * 25),
3480 Sig('-y', metavar='Y' * 25),
3481 Sig('-z', metavar='Z' * 25),
3482 ]
3483 argument_group_signatures = []
3484 usage = '''\
3485 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3486[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3487 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3488 '''
3489 help = usage + '''\
3490
3491 optional arguments:
3492 -h, --help show this help message and exit
3493 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3494 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3495 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3496 '''
3497 version = ''
3498
3499
3500class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3501 """Test usage messages where there are only positionals and they wrap"""
3502
3503 parser_signature = Sig(prog='PROG', add_help=False)
3504 argument_signatures = [
3505 Sig('a' * 25),
3506 Sig('b' * 25),
3507 Sig('c' * 25),
3508 ]
3509 argument_group_signatures = []
3510 usage = '''\
3511 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3512 ccccccccccccccccccccccccc
3513 '''
3514 help = usage + '''\
3515
3516 positional arguments:
3517 aaaaaaaaaaaaaaaaaaaaaaaaa
3518 bbbbbbbbbbbbbbbbbbbbbbbbb
3519 ccccccccccccccccccccccccc
3520 '''
3521 version = ''
3522
3523
3524class TestHelpVariableExpansion(HelpTestCase):
3525 """Test that variables are expanded properly in help messages"""
3526
3527 parser_signature = Sig(prog='PROG')
3528 argument_signatures = [
3529 Sig('-x', type=int,
3530 help='x %(prog)s %(default)s %(type)s %%'),
3531 Sig('-y', action='store_const', default=42, const='XXX',
3532 help='y %(prog)s %(default)s %(const)s'),
3533 Sig('--foo', choices='abc',
3534 help='foo %(prog)s %(default)s %(choices)s'),
3535 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3536 help='bar %(prog)s %(default)s %(dest)s'),
3537 Sig('spam', help='spam %(prog)s %(default)s'),
3538 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3539 ]
3540 argument_group_signatures = [
3541 (Sig('group'), [
3542 Sig('-a', help='a %(prog)s %(default)s'),
3543 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3544 ])
3545 ]
3546 usage = ('''\
3547 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3548 spam badger
3549 ''')
3550 help = usage + '''\
3551
3552 positional arguments:
3553 spam spam PROG None
3554 badger badger PROG 0.5
3555
3556 optional arguments:
3557 -h, --help show this help message and exit
3558 -x X x PROG None int %
3559 -y y PROG 42 XXX
3560 --foo {a,b,c} foo PROG None a, b, c
3561 --bar BBB bar PROG baz bar
3562
3563 group:
3564 -a A a PROG None
3565 -b B b PROG -1
3566 '''
3567 version = ''
3568
3569
3570class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3571 """Test that variables are expanded properly when usage= is present"""
3572
3573 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3574 argument_signatures = []
3575 argument_group_signatures = []
3576 usage = ('''\
3577 usage: PROG FOO
3578 ''')
3579 help = usage + '''\
3580
3581 optional arguments:
3582 -h, --help show this help message and exit
3583 '''
3584 version = ''
3585
3586
3587class TestHelpVariableExpansionNoArguments(HelpTestCase):
3588 """Test that variables are expanded properly with no arguments"""
3589
3590 parser_signature = Sig(prog='PROG', add_help=False)
3591 argument_signatures = []
3592 argument_group_signatures = []
3593 usage = ('''\
3594 usage: PROG
3595 ''')
3596 help = usage
3597 version = ''
3598
3599
3600class TestHelpSuppressUsage(HelpTestCase):
3601 """Test that items can be suppressed in usage messages"""
3602
3603 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3604 argument_signatures = [
3605 Sig('--foo', help='foo help'),
3606 Sig('spam', help='spam help'),
3607 ]
3608 argument_group_signatures = []
3609 help = '''\
3610 positional arguments:
3611 spam spam help
3612
3613 optional arguments:
3614 -h, --help show this help message and exit
3615 --foo FOO foo help
3616 '''
3617 usage = ''
3618 version = ''
3619
3620
3621class TestHelpSuppressOptional(HelpTestCase):
3622 """Test that optional arguments can be suppressed in help messages"""
3623
3624 parser_signature = Sig(prog='PROG', add_help=False)
3625 argument_signatures = [
3626 Sig('--foo', help=argparse.SUPPRESS),
3627 Sig('spam', help='spam help'),
3628 ]
3629 argument_group_signatures = []
3630 usage = '''\
3631 usage: PROG spam
3632 '''
3633 help = usage + '''\
3634
3635 positional arguments:
3636 spam spam help
3637 '''
3638 version = ''
3639
3640
3641class TestHelpSuppressOptionalGroup(HelpTestCase):
3642 """Test that optional groups can be suppressed in help messages"""
3643
3644 parser_signature = Sig(prog='PROG')
3645 argument_signatures = [
3646 Sig('--foo', help='foo help'),
3647 Sig('spam', help='spam help'),
3648 ]
3649 argument_group_signatures = [
3650 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3651 ]
3652 usage = '''\
3653 usage: PROG [-h] [--foo FOO] spam
3654 '''
3655 help = usage + '''\
3656
3657 positional arguments:
3658 spam spam help
3659
3660 optional arguments:
3661 -h, --help show this help message and exit
3662 --foo FOO foo help
3663 '''
3664 version = ''
3665
3666
3667class TestHelpSuppressPositional(HelpTestCase):
3668 """Test that positional arguments can be suppressed in help messages"""
3669
3670 parser_signature = Sig(prog='PROG')
3671 argument_signatures = [
3672 Sig('--foo', help='foo help'),
3673 Sig('spam', help=argparse.SUPPRESS),
3674 ]
3675 argument_group_signatures = []
3676 usage = '''\
3677 usage: PROG [-h] [--foo FOO]
3678 '''
3679 help = usage + '''\
3680
3681 optional arguments:
3682 -h, --help show this help message and exit
3683 --foo FOO foo help
3684 '''
3685 version = ''
3686
3687
3688class TestHelpRequiredOptional(HelpTestCase):
3689 """Test that required options don't look optional"""
3690
3691 parser_signature = Sig(prog='PROG')
3692 argument_signatures = [
3693 Sig('--foo', required=True, help='foo help'),
3694 ]
3695 argument_group_signatures = []
3696 usage = '''\
3697 usage: PROG [-h] --foo FOO
3698 '''
3699 help = usage + '''\
3700
3701 optional arguments:
3702 -h, --help show this help message and exit
3703 --foo FOO foo help
3704 '''
3705 version = ''
3706
3707
3708class TestHelpAlternatePrefixChars(HelpTestCase):
3709 """Test that options display with different prefix characters"""
3710
3711 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3712 argument_signatures = [
3713 Sig('^^foo', action='store_true', help='foo help'),
3714 Sig(';b', ';;bar', help='bar help'),
3715 ]
3716 argument_group_signatures = []
3717 usage = '''\
3718 usage: PROG [^^foo] [;b BAR]
3719 '''
3720 help = usage + '''\
3721
3722 optional arguments:
3723 ^^foo foo help
3724 ;b BAR, ;;bar BAR bar help
3725 '''
3726 version = ''
3727
3728
3729class TestHelpNoHelpOptional(HelpTestCase):
3730 """Test that the --help argument can be suppressed help messages"""
3731
3732 parser_signature = Sig(prog='PROG', add_help=False)
3733 argument_signatures = [
3734 Sig('--foo', help='foo help'),
3735 Sig('spam', help='spam help'),
3736 ]
3737 argument_group_signatures = []
3738 usage = '''\
3739 usage: PROG [--foo FOO] spam
3740 '''
3741 help = usage + '''\
3742
3743 positional arguments:
3744 spam spam help
3745
3746 optional arguments:
3747 --foo FOO foo help
3748 '''
3749 version = ''
3750
3751
3752class TestHelpVersionOptional(HelpTestCase):
3753 """Test that the --version argument can be suppressed help messages"""
3754
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003755 parser_signature = Sig(prog='PROG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003756 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003757 Sig('-v', '--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003758 Sig('--foo', help='foo help'),
3759 Sig('spam', help='spam help'),
3760 ]
3761 argument_group_signatures = []
3762 usage = '''\
3763 usage: PROG [-h] [-v] [--foo FOO] spam
3764 '''
3765 help = usage + '''\
3766
3767 positional arguments:
3768 spam spam help
3769
3770 optional arguments:
3771 -h, --help show this help message and exit
3772 -v, --version show program's version number and exit
3773 --foo FOO foo help
3774 '''
3775 version = '''\
3776 1.0
3777 '''
3778
3779
3780class TestHelpNone(HelpTestCase):
3781 """Test that no errors occur if no help is specified"""
3782
3783 parser_signature = Sig(prog='PROG')
3784 argument_signatures = [
3785 Sig('--foo'),
3786 Sig('spam'),
3787 ]
3788 argument_group_signatures = []
3789 usage = '''\
3790 usage: PROG [-h] [--foo FOO] spam
3791 '''
3792 help = usage + '''\
3793
3794 positional arguments:
3795 spam
3796
3797 optional arguments:
3798 -h, --help show this help message and exit
3799 --foo FOO
3800 '''
3801 version = ''
3802
3803
3804class TestHelpTupleMetavar(HelpTestCase):
3805 """Test specifying metavar as a tuple"""
3806
3807 parser_signature = Sig(prog='PROG')
3808 argument_signatures = [
3809 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3810 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3811 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3812 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3813 ]
3814 argument_group_signatures = []
3815 usage = '''\
3816 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3817[-z [Z1]]
3818 '''
3819 help = usage + '''\
3820
3821 optional arguments:
3822 -h, --help show this help message and exit
3823 -w W1 [W2 ...] w
3824 -x [X1 [X2 ...]] x
3825 -y Y1 Y2 Y3 y
3826 -z [Z1] z
3827 '''
3828 version = ''
3829
3830
3831class TestHelpRawText(HelpTestCase):
3832 """Test the RawTextHelpFormatter"""
3833
3834 parser_signature = Sig(
3835 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3836 description='Keep the formatting\n'
3837 ' exactly as it is written\n'
3838 '\n'
3839 'here\n')
3840
3841 argument_signatures = [
3842 Sig('--foo', help=' foo help should also\n'
3843 'appear as given here'),
3844 Sig('spam', help='spam help'),
3845 ]
3846 argument_group_signatures = [
3847 (Sig('title', description=' This text\n'
3848 ' should be indented\n'
3849 ' exactly like it is here\n'),
3850 [Sig('--bar', help='bar help')]),
3851 ]
3852 usage = '''\
3853 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3854 '''
3855 help = usage + '''\
3856
3857 Keep the formatting
3858 exactly as it is written
3859
3860 here
3861
3862 positional arguments:
3863 spam spam help
3864
3865 optional arguments:
3866 -h, --help show this help message and exit
3867 --foo FOO foo help should also
3868 appear as given here
3869
3870 title:
3871 This text
3872 should be indented
3873 exactly like it is here
3874
3875 --bar BAR bar help
3876 '''
3877 version = ''
3878
3879
3880class TestHelpRawDescription(HelpTestCase):
3881 """Test the RawTextHelpFormatter"""
3882
3883 parser_signature = Sig(
3884 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3885 description='Keep the formatting\n'
3886 ' exactly as it is written\n'
3887 '\n'
3888 'here\n')
3889
3890 argument_signatures = [
3891 Sig('--foo', help=' foo help should not\n'
3892 ' retain this odd formatting'),
3893 Sig('spam', help='spam help'),
3894 ]
3895 argument_group_signatures = [
3896 (Sig('title', description=' This text\n'
3897 ' should be indented\n'
3898 ' exactly like it is here\n'),
3899 [Sig('--bar', help='bar help')]),
3900 ]
3901 usage = '''\
3902 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3903 '''
3904 help = usage + '''\
3905
3906 Keep the formatting
3907 exactly as it is written
3908
3909 here
3910
3911 positional arguments:
3912 spam spam help
3913
3914 optional arguments:
3915 -h, --help show this help message and exit
3916 --foo FOO foo help should not retain this odd formatting
3917
3918 title:
3919 This text
3920 should be indented
3921 exactly like it is here
3922
3923 --bar BAR bar help
3924 '''
3925 version = ''
3926
3927
3928class TestHelpArgumentDefaults(HelpTestCase):
3929 """Test the ArgumentDefaultsHelpFormatter"""
3930
3931 parser_signature = Sig(
3932 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3933 description='description')
3934
3935 argument_signatures = [
3936 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3937 Sig('--bar', action='store_true', help='bar help'),
3938 Sig('spam', help='spam help'),
3939 Sig('badger', nargs='?', default='wooden', help='badger help'),
3940 ]
3941 argument_group_signatures = [
3942 (Sig('title', description='description'),
3943 [Sig('--baz', type=int, default=42, help='baz help')]),
3944 ]
3945 usage = '''\
3946 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3947 '''
3948 help = usage + '''\
3949
3950 description
3951
3952 positional arguments:
3953 spam spam help
3954 badger badger help (default: wooden)
3955
3956 optional arguments:
3957 -h, --help show this help message and exit
3958 --foo FOO foo help - oh and by the way, None
3959 --bar bar help (default: False)
3960
3961 title:
3962 description
3963
3964 --baz BAZ baz help (default: 42)
3965 '''
3966 version = ''
3967
Steven Bethard50fe5932010-05-24 03:47:38 +00003968class TestHelpVersionAction(HelpTestCase):
3969 """Test the default help for the version action"""
3970
3971 parser_signature = Sig(prog='PROG', description='description')
3972 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3973 argument_group_signatures = []
3974 usage = '''\
3975 usage: PROG [-h] [-V]
3976 '''
3977 help = usage + '''\
3978
3979 description
3980
3981 optional arguments:
3982 -h, --help show this help message and exit
3983 -V, --version show program's version number and exit
3984 '''
3985 version = ''
3986
Steven Bethard8a6a1982011-03-27 13:53:53 +02003987class TestHelpSubparsersOrdering(HelpTestCase):
3988 """Test ordering of subcommands in help matches the code"""
3989 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003990 description='display some subcommands')
3991 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02003992
3993 subparsers_signatures = [Sig(name=name)
3994 for name in ('a', 'b', 'c', 'd', 'e')]
3995
3996 usage = '''\
3997 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3998 '''
3999
4000 help = usage + '''\
4001
4002 display some subcommands
4003
4004 positional arguments:
4005 {a,b,c,d,e}
4006
4007 optional arguments:
4008 -h, --help show this help message and exit
4009 -v, --version show program's version number and exit
4010 '''
4011
4012 version = '''\
4013 0.1
4014 '''
4015
4016class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4017 """Test ordering of subcommands in help matches the code"""
4018 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004019 description='display some subcommands')
4020 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004021
4022 subcommand_data = (('a', 'a subcommand help'),
4023 ('b', 'b subcommand help'),
4024 ('c', 'c subcommand help'),
4025 ('d', 'd subcommand help'),
4026 ('e', 'e subcommand help'),
4027 )
4028
4029 subparsers_signatures = [Sig(name=name, help=help)
4030 for name, help in subcommand_data]
4031
4032 usage = '''\
4033 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4034 '''
4035
4036 help = usage + '''\
4037
4038 display some subcommands
4039
4040 positional arguments:
4041 {a,b,c,d,e}
4042 a a subcommand help
4043 b b subcommand help
4044 c c subcommand help
4045 d d subcommand help
4046 e e subcommand help
4047
4048 optional arguments:
4049 -h, --help show this help message and exit
4050 -v, --version show program's version number and exit
4051 '''
4052
4053 version = '''\
4054 0.1
4055 '''
4056
4057
Steven Bethard0331e902011-03-26 14:48:04 +01004058
4059class TestHelpMetavarTypeFormatter(HelpTestCase):
4060 """"""
4061
4062 def custom_type(string):
4063 return string
4064
4065 parser_signature = Sig(prog='PROG', description='description',
4066 formatter_class=argparse.MetavarTypeHelpFormatter)
4067 argument_signatures = [Sig('a', type=int),
4068 Sig('-b', type=custom_type),
4069 Sig('-c', type=float, metavar='SOME FLOAT')]
4070 argument_group_signatures = []
4071 usage = '''\
4072 usage: PROG [-h] [-b custom_type] [-c SOME FLOAT] int
4073 '''
4074 help = usage + '''\
4075
4076 description
4077
4078 positional arguments:
4079 int
4080
4081 optional arguments:
4082 -h, --help show this help message and exit
4083 -b custom_type
4084 -c SOME FLOAT
4085 '''
4086 version = ''
4087
4088
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004089# =====================================
4090# Optional/Positional constructor tests
4091# =====================================
4092
4093class TestInvalidArgumentConstructors(TestCase):
4094 """Test a bunch of invalid Argument constructors"""
4095
4096 def assertTypeError(self, *args, **kwargs):
4097 parser = argparse.ArgumentParser()
4098 self.assertRaises(TypeError, parser.add_argument,
4099 *args, **kwargs)
4100
4101 def assertValueError(self, *args, **kwargs):
4102 parser = argparse.ArgumentParser()
4103 self.assertRaises(ValueError, parser.add_argument,
4104 *args, **kwargs)
4105
4106 def test_invalid_keyword_arguments(self):
4107 self.assertTypeError('-x', bar=None)
4108 self.assertTypeError('-y', callback='foo')
4109 self.assertTypeError('-y', callback_args=())
4110 self.assertTypeError('-y', callback_kwargs={})
4111
4112 def test_missing_destination(self):
4113 self.assertTypeError()
4114 for action in ['append', 'store']:
4115 self.assertTypeError(action=action)
4116
4117 def test_invalid_option_strings(self):
4118 self.assertValueError('--')
4119 self.assertValueError('---')
4120
4121 def test_invalid_type(self):
4122 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004123 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004124
4125 def test_invalid_action(self):
4126 self.assertValueError('-x', action='foo')
4127 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004128 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004129 parser = argparse.ArgumentParser()
4130 try:
4131 parser.add_argument("--foo", action="store-true")
4132 except ValueError:
4133 e = sys.exc_info()[1]
4134 expected = 'unknown action'
4135 msg = 'expected %r, found %r' % (expected, e)
4136 self.assertTrue(expected in str(e), msg)
4137
4138 def test_multiple_dest(self):
4139 parser = argparse.ArgumentParser()
4140 parser.add_argument(dest='foo')
4141 try:
4142 parser.add_argument('bar', dest='baz')
4143 except ValueError:
4144 e = sys.exc_info()[1]
4145 expected = 'dest supplied twice for positional argument'
4146 msg = 'expected %r, found %r' % (expected, e)
4147 self.assertTrue(expected in str(e), msg)
4148
4149 def test_no_argument_actions(self):
4150 for action in ['store_const', 'store_true', 'store_false',
4151 'append_const', 'count']:
4152 for attrs in [dict(type=int), dict(nargs='+'),
4153 dict(choices='ab')]:
4154 self.assertTypeError('-x', action=action, **attrs)
4155
4156 def test_no_argument_no_const_actions(self):
4157 # options with zero arguments
4158 for action in ['store_true', 'store_false', 'count']:
4159
4160 # const is always disallowed
4161 self.assertTypeError('-x', const='foo', action=action)
4162
4163 # nargs is always disallowed
4164 self.assertTypeError('-x', nargs='*', action=action)
4165
4166 def test_more_than_one_argument_actions(self):
4167 for action in ['store', 'append']:
4168
4169 # nargs=0 is disallowed
4170 self.assertValueError('-x', nargs=0, action=action)
4171 self.assertValueError('spam', nargs=0, action=action)
4172
4173 # const is disallowed with non-optional arguments
4174 for nargs in [1, '*', '+']:
4175 self.assertValueError('-x', const='foo',
4176 nargs=nargs, action=action)
4177 self.assertValueError('spam', const='foo',
4178 nargs=nargs, action=action)
4179
4180 def test_required_const_actions(self):
4181 for action in ['store_const', 'append_const']:
4182
4183 # nargs is always disallowed
4184 self.assertTypeError('-x', nargs='+', action=action)
4185
4186 def test_parsers_action_missing_params(self):
4187 self.assertTypeError('command', action='parsers')
4188 self.assertTypeError('command', action='parsers', prog='PROG')
4189 self.assertTypeError('command', action='parsers',
4190 parser_class=argparse.ArgumentParser)
4191
4192 def test_required_positional(self):
4193 self.assertTypeError('foo', required=True)
4194
4195 def test_user_defined_action(self):
4196
4197 class Success(Exception):
4198 pass
4199
4200 class Action(object):
4201
4202 def __init__(self,
4203 option_strings,
4204 dest,
4205 const,
4206 default,
4207 required=False):
4208 if dest == 'spam':
4209 if const is Success:
4210 if default is Success:
4211 raise Success()
4212
4213 def __call__(self, *args, **kwargs):
4214 pass
4215
4216 parser = argparse.ArgumentParser()
4217 self.assertRaises(Success, parser.add_argument, '--spam',
4218 action=Action, default=Success, const=Success)
4219 self.assertRaises(Success, parser.add_argument, 'spam',
4220 action=Action, default=Success, const=Success)
4221
4222# ================================
4223# Actions returned by add_argument
4224# ================================
4225
4226class TestActionsReturned(TestCase):
4227
4228 def test_dest(self):
4229 parser = argparse.ArgumentParser()
4230 action = parser.add_argument('--foo')
4231 self.assertEqual(action.dest, 'foo')
4232 action = parser.add_argument('-b', '--bar')
4233 self.assertEqual(action.dest, 'bar')
4234 action = parser.add_argument('-x', '-y')
4235 self.assertEqual(action.dest, 'x')
4236
4237 def test_misc(self):
4238 parser = argparse.ArgumentParser()
4239 action = parser.add_argument('--foo', nargs='?', const=42,
4240 default=84, type=int, choices=[1, 2],
4241 help='FOO', metavar='BAR', dest='baz')
4242 self.assertEqual(action.nargs, '?')
4243 self.assertEqual(action.const, 42)
4244 self.assertEqual(action.default, 84)
4245 self.assertEqual(action.type, int)
4246 self.assertEqual(action.choices, [1, 2])
4247 self.assertEqual(action.help, 'FOO')
4248 self.assertEqual(action.metavar, 'BAR')
4249 self.assertEqual(action.dest, 'baz')
4250
4251
4252# ================================
4253# Argument conflict handling tests
4254# ================================
4255
4256class TestConflictHandling(TestCase):
4257
4258 def test_bad_type(self):
4259 self.assertRaises(ValueError, argparse.ArgumentParser,
4260 conflict_handler='foo')
4261
4262 def test_conflict_error(self):
4263 parser = argparse.ArgumentParser()
4264 parser.add_argument('-x')
4265 self.assertRaises(argparse.ArgumentError,
4266 parser.add_argument, '-x')
4267 parser.add_argument('--spam')
4268 self.assertRaises(argparse.ArgumentError,
4269 parser.add_argument, '--spam')
4270
4271 def test_resolve_error(self):
4272 get_parser = argparse.ArgumentParser
4273 parser = get_parser(prog='PROG', conflict_handler='resolve')
4274
4275 parser.add_argument('-x', help='OLD X')
4276 parser.add_argument('-x', help='NEW X')
4277 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4278 usage: PROG [-h] [-x X]
4279
4280 optional arguments:
4281 -h, --help show this help message and exit
4282 -x X NEW X
4283 '''))
4284
4285 parser.add_argument('--spam', metavar='OLD_SPAM')
4286 parser.add_argument('--spam', metavar='NEW_SPAM')
4287 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4288 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4289
4290 optional arguments:
4291 -h, --help show this help message and exit
4292 -x X NEW X
4293 --spam NEW_SPAM
4294 '''))
4295
4296
4297# =============================
4298# Help and Version option tests
4299# =============================
4300
4301class TestOptionalsHelpVersionActions(TestCase):
4302 """Test the help and version actions"""
4303
4304 def _get_error(self, func, *args, **kwargs):
4305 try:
4306 func(*args, **kwargs)
4307 except ArgumentParserError:
4308 return sys.exc_info()[1]
4309 else:
4310 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4311
4312 def assertPrintHelpExit(self, parser, args_str):
4313 self.assertEqual(
4314 parser.format_help(),
4315 self._get_error(parser.parse_args, args_str.split()).stdout)
4316
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004317 def assertArgumentParserError(self, parser, *args):
4318 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4319
4320 def test_version(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004321 parser = ErrorRaisingArgumentParser()
4322 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004323 self.assertPrintHelpExit(parser, '-h')
4324 self.assertPrintHelpExit(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004325 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004326
4327 def test_version_format(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004328 parser = ErrorRaisingArgumentParser(prog='PPP')
4329 parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004330 msg = self._get_error(parser.parse_args, ['-v']).stderr
4331 self.assertEqual('PPP 3.5\n', msg)
4332
4333 def test_version_no_help(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004334 parser = ErrorRaisingArgumentParser(add_help=False)
4335 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004336 self.assertArgumentParserError(parser, '-h')
4337 self.assertArgumentParserError(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004338 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004339
4340 def test_version_action(self):
4341 parser = ErrorRaisingArgumentParser(prog='XXX')
4342 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4343 msg = self._get_error(parser.parse_args, ['-V']).stderr
4344 self.assertEqual('XXX 3.7\n', msg)
4345
4346 def test_no_help(self):
4347 parser = ErrorRaisingArgumentParser(add_help=False)
4348 self.assertArgumentParserError(parser, '-h')
4349 self.assertArgumentParserError(parser, '--help')
4350 self.assertArgumentParserError(parser, '-v')
4351 self.assertArgumentParserError(parser, '--version')
4352
4353 def test_alternate_help_version(self):
4354 parser = ErrorRaisingArgumentParser()
4355 parser.add_argument('-x', action='help')
4356 parser.add_argument('-y', action='version')
4357 self.assertPrintHelpExit(parser, '-x')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004358 self.assertArgumentParserError(parser, '-v')
4359 self.assertArgumentParserError(parser, '--version')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004360 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004361
4362 def test_help_version_extra_arguments(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004363 parser = ErrorRaisingArgumentParser()
4364 parser.add_argument('--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004365 parser.add_argument('-x', action='store_true')
4366 parser.add_argument('y')
4367
4368 # try all combinations of valid prefixes and suffixes
4369 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4370 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4371 for prefix in valid_prefixes:
4372 for suffix in valid_suffixes:
4373 format = '%s %%s %s' % (prefix, suffix)
4374 self.assertPrintHelpExit(parser, format % '-h')
4375 self.assertPrintHelpExit(parser, format % '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004376 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004377
4378
4379# ======================
4380# str() and repr() tests
4381# ======================
4382
4383class TestStrings(TestCase):
4384 """Test str() and repr() on Optionals and Positionals"""
4385
4386 def assertStringEqual(self, obj, result_string):
4387 for func in [str, repr]:
4388 self.assertEqual(func(obj), result_string)
4389
4390 def test_optional(self):
4391 option = argparse.Action(
4392 option_strings=['--foo', '-a', '-b'],
4393 dest='b',
4394 type='int',
4395 nargs='+',
4396 default=42,
4397 choices=[1, 2, 3],
4398 help='HELP',
4399 metavar='METAVAR')
4400 string = (
4401 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4402 "nargs='+', const=None, default=42, type='int', "
4403 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4404 self.assertStringEqual(option, string)
4405
4406 def test_argument(self):
4407 argument = argparse.Action(
4408 option_strings=[],
4409 dest='x',
4410 type=float,
4411 nargs='?',
4412 default=2.5,
4413 choices=[0.5, 1.5, 2.5],
4414 help='H HH H',
4415 metavar='MV MV MV')
4416 string = (
4417 "Action(option_strings=[], dest='x', nargs='?', "
4418 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4419 "help='H HH H', metavar='MV MV MV')" % float)
4420 self.assertStringEqual(argument, string)
4421
4422 def test_namespace(self):
4423 ns = argparse.Namespace(foo=42, bar='spam')
4424 string = "Namespace(bar='spam', foo=42)"
4425 self.assertStringEqual(ns, string)
4426
4427 def test_parser(self):
4428 parser = argparse.ArgumentParser(prog='PROG')
4429 string = (
4430 "ArgumentParser(prog='PROG', usage=None, description=None, "
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004431 "formatter_class=%r, conflict_handler='error', "
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004432 "add_help=True)" % argparse.HelpFormatter)
4433 self.assertStringEqual(parser, string)
4434
4435# ===============
4436# Namespace tests
4437# ===============
4438
4439class TestNamespace(TestCase):
4440
4441 def test_constructor(self):
4442 ns = argparse.Namespace()
4443 self.assertRaises(AttributeError, getattr, ns, 'x')
4444
4445 ns = argparse.Namespace(a=42, b='spam')
4446 self.assertEqual(ns.a, 42)
4447 self.assertEqual(ns.b, 'spam')
4448
4449 def test_equality(self):
4450 ns1 = argparse.Namespace(a=1, b=2)
4451 ns2 = argparse.Namespace(b=2, a=1)
4452 ns3 = argparse.Namespace(a=1)
4453 ns4 = argparse.Namespace(b=2)
4454
4455 self.assertEqual(ns1, ns2)
4456 self.assertNotEqual(ns1, ns3)
4457 self.assertNotEqual(ns1, ns4)
4458 self.assertNotEqual(ns2, ns3)
4459 self.assertNotEqual(ns2, ns4)
4460 self.assertTrue(ns1 != ns3)
4461 self.assertTrue(ns1 != ns4)
4462 self.assertTrue(ns2 != ns3)
4463 self.assertTrue(ns2 != ns4)
4464
4465
4466# ===================
4467# File encoding tests
4468# ===================
4469
4470class TestEncoding(TestCase):
4471
4472 def _test_module_encoding(self, path):
4473 path, _ = os.path.splitext(path)
4474 path += ".py"
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00004475 with codecs.open(path, 'r', 'utf-8') as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +00004476 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004477
4478 def test_argparse_module_encoding(self):
4479 self._test_module_encoding(argparse.__file__)
4480
4481 def test_test_argparse_module_encoding(self):
4482 self._test_module_encoding(__file__)
4483
4484# ===================
4485# ArgumentError tests
4486# ===================
4487
4488class TestArgumentError(TestCase):
4489
4490 def test_argument_error(self):
4491 msg = "my error here"
4492 error = argparse.ArgumentError(None, msg)
4493 self.assertEqual(str(error), msg)
4494
4495# =======================
4496# ArgumentTypeError tests
4497# =======================
4498
R. David Murray722b5fd2010-11-20 03:48:58 +00004499class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004500
4501 def test_argument_type_error(self):
4502
4503 def spam(string):
4504 raise argparse.ArgumentTypeError('spam!')
4505
4506 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4507 parser.add_argument('x', type=spam)
4508 try:
4509 parser.parse_args(['XXX'])
4510 except ArgumentParserError:
4511 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4512 msg = sys.exc_info()[1].stderr
4513 self.assertEqual(expected, msg)
4514 else:
4515 self.fail()
4516
R David Murrayf97c59a2011-06-09 12:34:07 -04004517# =========================
4518# MessageContentError tests
4519# =========================
4520
4521class TestMessageContentError(TestCase):
4522
4523 def test_missing_argument_name_in_message(self):
4524 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4525 parser.add_argument('req_pos', type=str)
4526 parser.add_argument('-req_opt', type=int, required=True)
4527 parser.add_argument('need_one', type=str, nargs='+')
4528
4529 with self.assertRaises(ArgumentParserError) as cm:
4530 parser.parse_args([])
4531 msg = str(cm.exception)
4532 self.assertRegex(msg, 'req_pos')
4533 self.assertRegex(msg, 'req_opt')
4534 self.assertRegex(msg, 'need_one')
4535 with self.assertRaises(ArgumentParserError) as cm:
4536 parser.parse_args(['myXargument'])
4537 msg = str(cm.exception)
4538 self.assertNotIn(msg, 'req_pos')
4539 self.assertRegex(msg, 'req_opt')
4540 self.assertRegex(msg, 'need_one')
4541 with self.assertRaises(ArgumentParserError) as cm:
4542 parser.parse_args(['myXargument', '-req_opt=1'])
4543 msg = str(cm.exception)
4544 self.assertNotIn(msg, 'req_pos')
4545 self.assertNotIn(msg, 'req_opt')
4546 self.assertRegex(msg, 'need_one')
4547
4548 def test_optional_optional_not_in_message(self):
4549 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4550 parser.add_argument('req_pos', type=str)
4551 parser.add_argument('--req_opt', type=int, required=True)
4552 parser.add_argument('--opt_opt', type=bool, nargs='?',
4553 default=True)
4554 with self.assertRaises(ArgumentParserError) as cm:
4555 parser.parse_args([])
4556 msg = str(cm.exception)
4557 self.assertRegex(msg, 'req_pos')
4558 self.assertRegex(msg, 'req_opt')
4559 self.assertNotIn(msg, 'opt_opt')
4560 with self.assertRaises(ArgumentParserError) as cm:
4561 parser.parse_args(['--req_opt=1'])
4562 msg = str(cm.exception)
4563 self.assertRegex(msg, 'req_pos')
4564 self.assertNotIn(msg, 'req_opt')
4565 self.assertNotIn(msg, 'opt_opt')
4566
4567 def test_optional_positional_not_in_message(self):
4568 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4569 parser.add_argument('req_pos')
4570 parser.add_argument('optional_positional', nargs='?', default='eggs')
4571 with self.assertRaises(ArgumentParserError) as cm:
4572 parser.parse_args([])
4573 msg = str(cm.exception)
4574 self.assertRegex(msg, 'req_pos')
4575 self.assertNotIn(msg, 'optional_positional')
4576
4577
R David Murray6fb8fb12012-08-31 22:45:20 -04004578# ================================================
4579# Check that the type function is called only once
4580# ================================================
4581
4582class TestTypeFunctionCallOnlyOnce(TestCase):
4583
4584 def test_type_function_call_only_once(self):
4585 def spam(string_to_convert):
4586 self.assertEqual(string_to_convert, 'spam!')
4587 return 'foo_converted'
4588
4589 parser = argparse.ArgumentParser()
4590 parser.add_argument('--foo', type=spam, default='bar')
4591 args = parser.parse_args('--foo spam!'.split())
4592 self.assertEqual(NS(foo='foo_converted'), args)
4593
Barry Warsaweaae1b72012-09-12 14:34:50 -04004594# ==================================================================
4595# Check semantics regarding the default argument and type conversion
4596# ==================================================================
R David Murray6fb8fb12012-08-31 22:45:20 -04004597
Barry Warsaweaae1b72012-09-12 14:34:50 -04004598class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray6fb8fb12012-08-31 22:45:20 -04004599
4600 def test_type_function_call_with_non_string_default(self):
4601 def spam(int_to_convert):
4602 self.assertEqual(int_to_convert, 0)
4603 return 'foo_converted'
4604
4605 parser = argparse.ArgumentParser()
4606 parser.add_argument('--foo', type=spam, default=0)
4607 args = parser.parse_args([])
Barry Warsaweaae1b72012-09-12 14:34:50 -04004608 # foo should *not* be converted because its default is not a string.
4609 self.assertEqual(NS(foo=0), args)
4610
4611 def test_type_function_call_with_string_default(self):
4612 def spam(int_to_convert):
4613 return 'foo_converted'
4614
4615 parser = argparse.ArgumentParser()
4616 parser.add_argument('--foo', type=spam, default='0')
4617 args = parser.parse_args([])
4618 # foo is converted because its default is a string.
R David Murray6fb8fb12012-08-31 22:45:20 -04004619 self.assertEqual(NS(foo='foo_converted'), args)
4620
Barry Warsaweaae1b72012-09-12 14:34:50 -04004621 def test_no_double_type_conversion_of_default(self):
4622 def extend(str_to_convert):
4623 return str_to_convert + '*'
4624
4625 parser = argparse.ArgumentParser()
4626 parser.add_argument('--test', type=extend, default='*')
4627 args = parser.parse_args([])
4628 # The test argument will be two stars, one coming from the default
4629 # value and one coming from the type conversion being called exactly
4630 # once.
4631 self.assertEqual(NS(test='**'), args)
4632
Barry Warsaw4b2f9e92012-09-11 22:38:47 -04004633 def test_issue_15906(self):
4634 # Issue #15906: When action='append', type=str, default=[] are
4635 # providing, the dest value was the string representation "[]" when it
4636 # should have been an empty list.
4637 parser = argparse.ArgumentParser()
4638 parser.add_argument('--test', dest='test', type=str,
4639 default=[], action='append')
4640 args = parser.parse_args([])
4641 self.assertEqual(args.test, [])
4642
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004643# ======================
4644# parse_known_args tests
4645# ======================
4646
4647class TestParseKnownArgs(TestCase):
4648
R David Murrayb5228282012-09-08 12:08:01 -04004649 def test_arguments_tuple(self):
4650 parser = argparse.ArgumentParser()
4651 parser.parse_args(())
4652
4653 def test_arguments_list(self):
4654 parser = argparse.ArgumentParser()
4655 parser.parse_args([])
4656
4657 def test_arguments_tuple_positional(self):
4658 parser = argparse.ArgumentParser()
4659 parser.add_argument('x')
4660 parser.parse_args(('x',))
4661
4662 def test_arguments_list_positional(self):
4663 parser = argparse.ArgumentParser()
4664 parser.add_argument('x')
4665 parser.parse_args(['x'])
4666
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004667 def test_optionals(self):
4668 parser = argparse.ArgumentParser()
4669 parser.add_argument('--foo')
4670 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4671 self.assertEqual(NS(foo='F'), args)
4672 self.assertEqual(['--bar', '--baz'], extras)
4673
4674 def test_mixed(self):
4675 parser = argparse.ArgumentParser()
4676 parser.add_argument('-v', nargs='?', const=1, type=int)
4677 parser.add_argument('--spam', action='store_false')
4678 parser.add_argument('badger')
4679
4680 argv = ["B", "C", "--foo", "-v", "3", "4"]
4681 args, extras = parser.parse_known_args(argv)
4682 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4683 self.assertEqual(["C", "--foo", "4"], extras)
4684
Steven Bethard8d9a4622011-03-26 17:33:56 +01004685# ==========================
4686# add_argument metavar tests
4687# ==========================
4688
4689class TestAddArgumentMetavar(TestCase):
4690
4691 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4692
4693 def do_test_no_exception(self, nargs, metavar):
4694 parser = argparse.ArgumentParser()
4695 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4696
4697 def do_test_exception(self, nargs, metavar):
4698 parser = argparse.ArgumentParser()
4699 with self.assertRaises(ValueError) as cm:
4700 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4701 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4702
4703 # Unit tests for different values of metavar when nargs=None
4704
4705 def test_nargs_None_metavar_string(self):
4706 self.do_test_no_exception(nargs=None, metavar="1")
4707
4708 def test_nargs_None_metavar_length0(self):
4709 self.do_test_exception(nargs=None, metavar=tuple())
4710
4711 def test_nargs_None_metavar_length1(self):
4712 self.do_test_no_exception(nargs=None, metavar=("1"))
4713
4714 def test_nargs_None_metavar_length2(self):
4715 self.do_test_exception(nargs=None, metavar=("1", "2"))
4716
4717 def test_nargs_None_metavar_length3(self):
4718 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4719
4720 # Unit tests for different values of metavar when nargs=?
4721
4722 def test_nargs_optional_metavar_string(self):
4723 self.do_test_no_exception(nargs="?", metavar="1")
4724
4725 def test_nargs_optional_metavar_length0(self):
4726 self.do_test_exception(nargs="?", metavar=tuple())
4727
4728 def test_nargs_optional_metavar_length1(self):
4729 self.do_test_no_exception(nargs="?", metavar=("1"))
4730
4731 def test_nargs_optional_metavar_length2(self):
4732 self.do_test_exception(nargs="?", metavar=("1", "2"))
4733
4734 def test_nargs_optional_metavar_length3(self):
4735 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4736
4737 # Unit tests for different values of metavar when nargs=*
4738
4739 def test_nargs_zeroormore_metavar_string(self):
4740 self.do_test_no_exception(nargs="*", metavar="1")
4741
4742 def test_nargs_zeroormore_metavar_length0(self):
4743 self.do_test_exception(nargs="*", metavar=tuple())
4744
4745 def test_nargs_zeroormore_metavar_length1(self):
4746 self.do_test_no_exception(nargs="*", metavar=("1"))
4747
4748 def test_nargs_zeroormore_metavar_length2(self):
4749 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4750
4751 def test_nargs_zeroormore_metavar_length3(self):
4752 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4753
4754 # Unit tests for different values of metavar when nargs=+
4755
4756 def test_nargs_oneormore_metavar_string(self):
4757 self.do_test_no_exception(nargs="+", metavar="1")
4758
4759 def test_nargs_oneormore_metavar_length0(self):
4760 self.do_test_exception(nargs="+", metavar=tuple())
4761
4762 def test_nargs_oneormore_metavar_length1(self):
4763 self.do_test_no_exception(nargs="+", metavar=("1"))
4764
4765 def test_nargs_oneormore_metavar_length2(self):
4766 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4767
4768 def test_nargs_oneormore_metavar_length3(self):
4769 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4770
4771 # Unit tests for different values of metavar when nargs=...
4772
4773 def test_nargs_remainder_metavar_string(self):
4774 self.do_test_no_exception(nargs="...", metavar="1")
4775
4776 def test_nargs_remainder_metavar_length0(self):
4777 self.do_test_no_exception(nargs="...", metavar=tuple())
4778
4779 def test_nargs_remainder_metavar_length1(self):
4780 self.do_test_no_exception(nargs="...", metavar=("1"))
4781
4782 def test_nargs_remainder_metavar_length2(self):
4783 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4784
4785 def test_nargs_remainder_metavar_length3(self):
4786 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4787
4788 # Unit tests for different values of metavar when nargs=A...
4789
4790 def test_nargs_parser_metavar_string(self):
4791 self.do_test_no_exception(nargs="A...", metavar="1")
4792
4793 def test_nargs_parser_metavar_length0(self):
4794 self.do_test_exception(nargs="A...", metavar=tuple())
4795
4796 def test_nargs_parser_metavar_length1(self):
4797 self.do_test_no_exception(nargs="A...", metavar=("1"))
4798
4799 def test_nargs_parser_metavar_length2(self):
4800 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4801
4802 def test_nargs_parser_metavar_length3(self):
4803 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4804
4805 # Unit tests for different values of metavar when nargs=1
4806
4807 def test_nargs_1_metavar_string(self):
4808 self.do_test_no_exception(nargs=1, metavar="1")
4809
4810 def test_nargs_1_metavar_length0(self):
4811 self.do_test_exception(nargs=1, metavar=tuple())
4812
4813 def test_nargs_1_metavar_length1(self):
4814 self.do_test_no_exception(nargs=1, metavar=("1"))
4815
4816 def test_nargs_1_metavar_length2(self):
4817 self.do_test_exception(nargs=1, metavar=("1", "2"))
4818
4819 def test_nargs_1_metavar_length3(self):
4820 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4821
4822 # Unit tests for different values of metavar when nargs=2
4823
4824 def test_nargs_2_metavar_string(self):
4825 self.do_test_no_exception(nargs=2, metavar="1")
4826
4827 def test_nargs_2_metavar_length0(self):
4828 self.do_test_exception(nargs=2, metavar=tuple())
4829
4830 def test_nargs_2_metavar_length1(self):
4831 self.do_test_no_exception(nargs=2, metavar=("1"))
4832
4833 def test_nargs_2_metavar_length2(self):
4834 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4835
4836 def test_nargs_2_metavar_length3(self):
4837 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4838
4839 # Unit tests for different values of metavar when nargs=3
4840
4841 def test_nargs_3_metavar_string(self):
4842 self.do_test_no_exception(nargs=3, metavar="1")
4843
4844 def test_nargs_3_metavar_length0(self):
4845 self.do_test_exception(nargs=3, metavar=tuple())
4846
4847 def test_nargs_3_metavar_length1(self):
4848 self.do_test_no_exception(nargs=3, metavar=("1"))
4849
4850 def test_nargs_3_metavar_length2(self):
4851 self.do_test_exception(nargs=3, metavar=("1", "2"))
4852
4853 def test_nargs_3_metavar_length3(self):
4854 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4855
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004856# ============================
4857# from argparse import * tests
4858# ============================
4859
4860class TestImportStar(TestCase):
4861
4862 def test(self):
4863 for name in argparse.__all__:
4864 self.assertTrue(hasattr(argparse, name))
4865
Steven Bethard72c55382010-11-01 15:23:12 +00004866 def test_all_exports_everything_but_modules(self):
4867 items = [
4868 name
4869 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00004870 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00004871 if not inspect.ismodule(value)
4872 ]
4873 self.assertEqual(sorted(items), sorted(argparse.__all__))
4874
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004875def test_main():
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004876 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00004877 # Remove global references to avoid looking like we have refleaks.
4878 RFile.seen = {}
4879 WFile.seen = set()
4880
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004881
4882
4883if __name__ == '__main__':
4884 test_main()