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