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