blob: 98ccfe448434f50331f23c74f18a90a32480779f [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):
647 """Tests the an optional action that is required"""
648
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
3848class TestHelpVersionOptional(HelpTestCase):
3849 """Test that the --version argument can be suppressed help messages"""
3850
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003851 parser_signature = Sig(prog='PROG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003852 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003853 Sig('-v', '--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003854 Sig('--foo', help='foo help'),
3855 Sig('spam', help='spam help'),
3856 ]
3857 argument_group_signatures = []
3858 usage = '''\
3859 usage: PROG [-h] [-v] [--foo FOO] spam
3860 '''
3861 help = usage + '''\
3862
3863 positional arguments:
3864 spam spam help
3865
3866 optional arguments:
3867 -h, --help show this help message and exit
3868 -v, --version show program's version number and exit
3869 --foo FOO foo help
3870 '''
3871 version = '''\
3872 1.0
3873 '''
3874
3875
3876class TestHelpNone(HelpTestCase):
3877 """Test that no errors occur if no help is specified"""
3878
3879 parser_signature = Sig(prog='PROG')
3880 argument_signatures = [
3881 Sig('--foo'),
3882 Sig('spam'),
3883 ]
3884 argument_group_signatures = []
3885 usage = '''\
3886 usage: PROG [-h] [--foo FOO] spam
3887 '''
3888 help = usage + '''\
3889
3890 positional arguments:
3891 spam
3892
3893 optional arguments:
3894 -h, --help show this help message and exit
3895 --foo FOO
3896 '''
3897 version = ''
3898
3899
3900class TestHelpTupleMetavar(HelpTestCase):
3901 """Test specifying metavar as a tuple"""
3902
3903 parser_signature = Sig(prog='PROG')
3904 argument_signatures = [
3905 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3906 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3907 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3908 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3909 ]
3910 argument_group_signatures = []
3911 usage = '''\
3912 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3913[-z [Z1]]
3914 '''
3915 help = usage + '''\
3916
3917 optional arguments:
3918 -h, --help show this help message and exit
3919 -w W1 [W2 ...] w
3920 -x [X1 [X2 ...]] x
3921 -y Y1 Y2 Y3 y
3922 -z [Z1] z
3923 '''
3924 version = ''
3925
3926
3927class TestHelpRawText(HelpTestCase):
3928 """Test the RawTextHelpFormatter"""
3929
3930 parser_signature = Sig(
3931 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3932 description='Keep the formatting\n'
3933 ' exactly as it is written\n'
3934 '\n'
3935 'here\n')
3936
3937 argument_signatures = [
3938 Sig('--foo', help=' foo help should also\n'
3939 'appear as given here'),
3940 Sig('spam', help='spam help'),
3941 ]
3942 argument_group_signatures = [
3943 (Sig('title', description=' This text\n'
3944 ' should be indented\n'
3945 ' exactly like it is here\n'),
3946 [Sig('--bar', help='bar help')]),
3947 ]
3948 usage = '''\
3949 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3950 '''
3951 help = usage + '''\
3952
3953 Keep the formatting
3954 exactly as it is written
3955
3956 here
3957
3958 positional arguments:
3959 spam spam help
3960
3961 optional arguments:
3962 -h, --help show this help message and exit
3963 --foo FOO foo help should also
3964 appear as given here
3965
3966 title:
3967 This text
3968 should be indented
3969 exactly like it is here
3970
3971 --bar BAR bar help
3972 '''
3973 version = ''
3974
3975
3976class TestHelpRawDescription(HelpTestCase):
3977 """Test the RawTextHelpFormatter"""
3978
3979 parser_signature = Sig(
3980 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3981 description='Keep the formatting\n'
3982 ' exactly as it is written\n'
3983 '\n'
3984 'here\n')
3985
3986 argument_signatures = [
3987 Sig('--foo', help=' foo help should not\n'
3988 ' retain this odd formatting'),
3989 Sig('spam', help='spam help'),
3990 ]
3991 argument_group_signatures = [
3992 (Sig('title', description=' This text\n'
3993 ' should be indented\n'
3994 ' exactly like it is here\n'),
3995 [Sig('--bar', help='bar help')]),
3996 ]
3997 usage = '''\
3998 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3999 '''
4000 help = usage + '''\
4001
4002 Keep the formatting
4003 exactly as it is written
4004
4005 here
4006
4007 positional arguments:
4008 spam spam help
4009
4010 optional arguments:
4011 -h, --help show this help message and exit
4012 --foo FOO foo help should not retain this odd formatting
4013
4014 title:
4015 This text
4016 should be indented
4017 exactly like it is here
4018
4019 --bar BAR bar help
4020 '''
4021 version = ''
4022
4023
4024class TestHelpArgumentDefaults(HelpTestCase):
4025 """Test the ArgumentDefaultsHelpFormatter"""
4026
4027 parser_signature = Sig(
4028 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
4029 description='description')
4030
4031 argument_signatures = [
4032 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
4033 Sig('--bar', action='store_true', help='bar help'),
4034 Sig('spam', help='spam help'),
4035 Sig('badger', nargs='?', default='wooden', help='badger help'),
4036 ]
4037 argument_group_signatures = [
4038 (Sig('title', description='description'),
4039 [Sig('--baz', type=int, default=42, help='baz help')]),
4040 ]
4041 usage = '''\
4042 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
4043 '''
4044 help = usage + '''\
4045
4046 description
4047
4048 positional arguments:
4049 spam spam help
4050 badger badger help (default: wooden)
4051
4052 optional arguments:
4053 -h, --help show this help message and exit
4054 --foo FOO foo help - oh and by the way, None
4055 --bar bar help (default: False)
4056
4057 title:
4058 description
4059
4060 --baz BAZ baz help (default: 42)
4061 '''
4062 version = ''
4063
Steven Bethard50fe5932010-05-24 03:47:38 +00004064class TestHelpVersionAction(HelpTestCase):
4065 """Test the default help for the version action"""
4066
4067 parser_signature = Sig(prog='PROG', description='description')
4068 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
4069 argument_group_signatures = []
4070 usage = '''\
4071 usage: PROG [-h] [-V]
4072 '''
4073 help = usage + '''\
4074
4075 description
4076
4077 optional arguments:
4078 -h, --help show this help message and exit
4079 -V, --version show program's version number and exit
4080 '''
4081 version = ''
4082
Steven Bethard8a6a1982011-03-27 13:53:53 +02004083class TestHelpSubparsersOrdering(HelpTestCase):
4084 """Test ordering of subcommands in help matches the code"""
4085 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004086 description='display some subcommands')
4087 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004088
4089 subparsers_signatures = [Sig(name=name)
4090 for name in ('a', 'b', 'c', 'd', 'e')]
4091
4092 usage = '''\
4093 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4094 '''
4095
4096 help = usage + '''\
4097
4098 display some subcommands
4099
4100 positional arguments:
4101 {a,b,c,d,e}
4102
4103 optional arguments:
4104 -h, --help show this help message and exit
4105 -v, --version show program's version number and exit
4106 '''
4107
4108 version = '''\
4109 0.1
4110 '''
4111
4112class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4113 """Test ordering of subcommands in help matches the code"""
4114 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004115 description='display some subcommands')
4116 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004117
4118 subcommand_data = (('a', 'a subcommand help'),
4119 ('b', 'b subcommand help'),
4120 ('c', 'c subcommand help'),
4121 ('d', 'd subcommand help'),
4122 ('e', 'e subcommand help'),
4123 )
4124
4125 subparsers_signatures = [Sig(name=name, help=help)
4126 for name, help in subcommand_data]
4127
4128 usage = '''\
4129 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4130 '''
4131
4132 help = usage + '''\
4133
4134 display some subcommands
4135
4136 positional arguments:
4137 {a,b,c,d,e}
4138 a a subcommand help
4139 b b subcommand help
4140 c c subcommand help
4141 d d subcommand help
4142 e e subcommand help
4143
4144 optional arguments:
4145 -h, --help show this help message and exit
4146 -v, --version show program's version number and exit
4147 '''
4148
4149 version = '''\
4150 0.1
4151 '''
4152
4153
Steven Bethard0331e902011-03-26 14:48:04 +01004154
4155class TestHelpMetavarTypeFormatter(HelpTestCase):
4156 """"""
4157
4158 def custom_type(string):
4159 return string
4160
4161 parser_signature = Sig(prog='PROG', description='description',
4162 formatter_class=argparse.MetavarTypeHelpFormatter)
4163 argument_signatures = [Sig('a', type=int),
4164 Sig('-b', type=custom_type),
4165 Sig('-c', type=float, metavar='SOME FLOAT')]
4166 argument_group_signatures = []
4167 usage = '''\
4168 usage: PROG [-h] [-b custom_type] [-c SOME FLOAT] int
4169 '''
4170 help = usage + '''\
4171
4172 description
4173
4174 positional arguments:
4175 int
4176
4177 optional arguments:
4178 -h, --help show this help message and exit
4179 -b custom_type
4180 -c SOME FLOAT
4181 '''
4182 version = ''
4183
4184
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004185# =====================================
4186# Optional/Positional constructor tests
4187# =====================================
4188
4189class TestInvalidArgumentConstructors(TestCase):
4190 """Test a bunch of invalid Argument constructors"""
4191
4192 def assertTypeError(self, *args, **kwargs):
4193 parser = argparse.ArgumentParser()
4194 self.assertRaises(TypeError, parser.add_argument,
4195 *args, **kwargs)
4196
4197 def assertValueError(self, *args, **kwargs):
4198 parser = argparse.ArgumentParser()
4199 self.assertRaises(ValueError, parser.add_argument,
4200 *args, **kwargs)
4201
4202 def test_invalid_keyword_arguments(self):
4203 self.assertTypeError('-x', bar=None)
4204 self.assertTypeError('-y', callback='foo')
4205 self.assertTypeError('-y', callback_args=())
4206 self.assertTypeError('-y', callback_kwargs={})
4207
4208 def test_missing_destination(self):
4209 self.assertTypeError()
4210 for action in ['append', 'store']:
4211 self.assertTypeError(action=action)
4212
4213 def test_invalid_option_strings(self):
4214 self.assertValueError('--')
4215 self.assertValueError('---')
4216
4217 def test_invalid_type(self):
4218 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004219 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004220
4221 def test_invalid_action(self):
4222 self.assertValueError('-x', action='foo')
4223 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004224 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004225 parser = argparse.ArgumentParser()
4226 try:
4227 parser.add_argument("--foo", action="store-true")
4228 except ValueError:
4229 e = sys.exc_info()[1]
4230 expected = 'unknown action'
4231 msg = 'expected %r, found %r' % (expected, e)
4232 self.assertTrue(expected in str(e), msg)
4233
4234 def test_multiple_dest(self):
4235 parser = argparse.ArgumentParser()
4236 parser.add_argument(dest='foo')
4237 try:
4238 parser.add_argument('bar', dest='baz')
4239 except ValueError:
4240 e = sys.exc_info()[1]
4241 expected = 'dest supplied twice for positional argument'
4242 msg = 'expected %r, found %r' % (expected, e)
4243 self.assertTrue(expected in str(e), msg)
4244
4245 def test_no_argument_actions(self):
4246 for action in ['store_const', 'store_true', 'store_false',
4247 'append_const', 'count']:
4248 for attrs in [dict(type=int), dict(nargs='+'),
4249 dict(choices='ab')]:
4250 self.assertTypeError('-x', action=action, **attrs)
4251
4252 def test_no_argument_no_const_actions(self):
4253 # options with zero arguments
4254 for action in ['store_true', 'store_false', 'count']:
4255
4256 # const is always disallowed
4257 self.assertTypeError('-x', const='foo', action=action)
4258
4259 # nargs is always disallowed
4260 self.assertTypeError('-x', nargs='*', action=action)
4261
4262 def test_more_than_one_argument_actions(self):
4263 for action in ['store', 'append']:
4264
4265 # nargs=0 is disallowed
4266 self.assertValueError('-x', nargs=0, action=action)
4267 self.assertValueError('spam', nargs=0, action=action)
4268
4269 # const is disallowed with non-optional arguments
4270 for nargs in [1, '*', '+']:
4271 self.assertValueError('-x', const='foo',
4272 nargs=nargs, action=action)
4273 self.assertValueError('spam', const='foo',
4274 nargs=nargs, action=action)
4275
4276 def test_required_const_actions(self):
4277 for action in ['store_const', 'append_const']:
4278
4279 # nargs is always disallowed
4280 self.assertTypeError('-x', nargs='+', action=action)
4281
4282 def test_parsers_action_missing_params(self):
4283 self.assertTypeError('command', action='parsers')
4284 self.assertTypeError('command', action='parsers', prog='PROG')
4285 self.assertTypeError('command', action='parsers',
4286 parser_class=argparse.ArgumentParser)
4287
4288 def test_required_positional(self):
4289 self.assertTypeError('foo', required=True)
4290
4291 def test_user_defined_action(self):
4292
4293 class Success(Exception):
4294 pass
4295
4296 class Action(object):
4297
4298 def __init__(self,
4299 option_strings,
4300 dest,
4301 const,
4302 default,
4303 required=False):
4304 if dest == 'spam':
4305 if const is Success:
4306 if default is Success:
4307 raise Success()
4308
4309 def __call__(self, *args, **kwargs):
4310 pass
4311
4312 parser = argparse.ArgumentParser()
4313 self.assertRaises(Success, parser.add_argument, '--spam',
4314 action=Action, default=Success, const=Success)
4315 self.assertRaises(Success, parser.add_argument, 'spam',
4316 action=Action, default=Success, const=Success)
4317
4318# ================================
4319# Actions returned by add_argument
4320# ================================
4321
4322class TestActionsReturned(TestCase):
4323
4324 def test_dest(self):
4325 parser = argparse.ArgumentParser()
4326 action = parser.add_argument('--foo')
4327 self.assertEqual(action.dest, 'foo')
4328 action = parser.add_argument('-b', '--bar')
4329 self.assertEqual(action.dest, 'bar')
4330 action = parser.add_argument('-x', '-y')
4331 self.assertEqual(action.dest, 'x')
4332
4333 def test_misc(self):
4334 parser = argparse.ArgumentParser()
4335 action = parser.add_argument('--foo', nargs='?', const=42,
4336 default=84, type=int, choices=[1, 2],
4337 help='FOO', metavar='BAR', dest='baz')
4338 self.assertEqual(action.nargs, '?')
4339 self.assertEqual(action.const, 42)
4340 self.assertEqual(action.default, 84)
4341 self.assertEqual(action.type, int)
4342 self.assertEqual(action.choices, [1, 2])
4343 self.assertEqual(action.help, 'FOO')
4344 self.assertEqual(action.metavar, 'BAR')
4345 self.assertEqual(action.dest, 'baz')
4346
4347
4348# ================================
4349# Argument conflict handling tests
4350# ================================
4351
4352class TestConflictHandling(TestCase):
4353
4354 def test_bad_type(self):
4355 self.assertRaises(ValueError, argparse.ArgumentParser,
4356 conflict_handler='foo')
4357
4358 def test_conflict_error(self):
4359 parser = argparse.ArgumentParser()
4360 parser.add_argument('-x')
4361 self.assertRaises(argparse.ArgumentError,
4362 parser.add_argument, '-x')
4363 parser.add_argument('--spam')
4364 self.assertRaises(argparse.ArgumentError,
4365 parser.add_argument, '--spam')
4366
4367 def test_resolve_error(self):
4368 get_parser = argparse.ArgumentParser
4369 parser = get_parser(prog='PROG', conflict_handler='resolve')
4370
4371 parser.add_argument('-x', help='OLD X')
4372 parser.add_argument('-x', help='NEW X')
4373 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4374 usage: PROG [-h] [-x X]
4375
4376 optional arguments:
4377 -h, --help show this help message and exit
4378 -x X NEW X
4379 '''))
4380
4381 parser.add_argument('--spam', metavar='OLD_SPAM')
4382 parser.add_argument('--spam', metavar='NEW_SPAM')
4383 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4384 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4385
4386 optional arguments:
4387 -h, --help show this help message and exit
4388 -x X NEW X
4389 --spam NEW_SPAM
4390 '''))
4391
4392
4393# =============================
4394# Help and Version option tests
4395# =============================
4396
4397class TestOptionalsHelpVersionActions(TestCase):
4398 """Test the help and version actions"""
4399
4400 def _get_error(self, func, *args, **kwargs):
4401 try:
4402 func(*args, **kwargs)
4403 except ArgumentParserError:
4404 return sys.exc_info()[1]
4405 else:
4406 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4407
4408 def assertPrintHelpExit(self, parser, args_str):
4409 self.assertEqual(
4410 parser.format_help(),
4411 self._get_error(parser.parse_args, args_str.split()).stdout)
4412
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004413 def assertArgumentParserError(self, parser, *args):
4414 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4415
4416 def test_version(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004417 parser = ErrorRaisingArgumentParser()
4418 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004419 self.assertPrintHelpExit(parser, '-h')
4420 self.assertPrintHelpExit(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004421 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004422
4423 def test_version_format(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004424 parser = ErrorRaisingArgumentParser(prog='PPP')
4425 parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5')
Eli Benderskycdac5512013-09-06 06:49:15 -07004426 msg = self._get_error(parser.parse_args, ['-v']).stdout
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004427 self.assertEqual('PPP 3.5\n', msg)
4428
4429 def test_version_no_help(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004430 parser = ErrorRaisingArgumentParser(add_help=False)
4431 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004432 self.assertArgumentParserError(parser, '-h')
4433 self.assertArgumentParserError(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004434 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004435
4436 def test_version_action(self):
4437 parser = ErrorRaisingArgumentParser(prog='XXX')
4438 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
Eli Benderskycdac5512013-09-06 06:49:15 -07004439 msg = self._get_error(parser.parse_args, ['-V']).stdout
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004440 self.assertEqual('XXX 3.7\n', msg)
4441
4442 def test_no_help(self):
4443 parser = ErrorRaisingArgumentParser(add_help=False)
4444 self.assertArgumentParserError(parser, '-h')
4445 self.assertArgumentParserError(parser, '--help')
4446 self.assertArgumentParserError(parser, '-v')
4447 self.assertArgumentParserError(parser, '--version')
4448
4449 def test_alternate_help_version(self):
4450 parser = ErrorRaisingArgumentParser()
4451 parser.add_argument('-x', action='help')
4452 parser.add_argument('-y', action='version')
4453 self.assertPrintHelpExit(parser, '-x')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004454 self.assertArgumentParserError(parser, '-v')
4455 self.assertArgumentParserError(parser, '--version')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004456 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004457
4458 def test_help_version_extra_arguments(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004459 parser = ErrorRaisingArgumentParser()
4460 parser.add_argument('--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004461 parser.add_argument('-x', action='store_true')
4462 parser.add_argument('y')
4463
4464 # try all combinations of valid prefixes and suffixes
4465 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4466 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4467 for prefix in valid_prefixes:
4468 for suffix in valid_suffixes:
4469 format = '%s %%s %s' % (prefix, suffix)
4470 self.assertPrintHelpExit(parser, format % '-h')
4471 self.assertPrintHelpExit(parser, format % '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004472 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004473
4474
4475# ======================
4476# str() and repr() tests
4477# ======================
4478
4479class TestStrings(TestCase):
4480 """Test str() and repr() on Optionals and Positionals"""
4481
4482 def assertStringEqual(self, obj, result_string):
4483 for func in [str, repr]:
4484 self.assertEqual(func(obj), result_string)
4485
4486 def test_optional(self):
4487 option = argparse.Action(
4488 option_strings=['--foo', '-a', '-b'],
4489 dest='b',
4490 type='int',
4491 nargs='+',
4492 default=42,
4493 choices=[1, 2, 3],
4494 help='HELP',
4495 metavar='METAVAR')
4496 string = (
4497 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4498 "nargs='+', const=None, default=42, type='int', "
4499 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4500 self.assertStringEqual(option, string)
4501
4502 def test_argument(self):
4503 argument = argparse.Action(
4504 option_strings=[],
4505 dest='x',
4506 type=float,
4507 nargs='?',
4508 default=2.5,
4509 choices=[0.5, 1.5, 2.5],
4510 help='H HH H',
4511 metavar='MV MV MV')
4512 string = (
4513 "Action(option_strings=[], dest='x', nargs='?', "
4514 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4515 "help='H HH H', metavar='MV MV MV')" % float)
4516 self.assertStringEqual(argument, string)
4517
4518 def test_namespace(self):
4519 ns = argparse.Namespace(foo=42, bar='spam')
4520 string = "Namespace(bar='spam', foo=42)"
4521 self.assertStringEqual(ns, string)
4522
4523 def test_parser(self):
4524 parser = argparse.ArgumentParser(prog='PROG')
4525 string = (
4526 "ArgumentParser(prog='PROG', usage=None, description=None, "
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004527 "formatter_class=%r, conflict_handler='error', "
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004528 "add_help=True)" % argparse.HelpFormatter)
4529 self.assertStringEqual(parser, string)
4530
4531# ===============
4532# Namespace tests
4533# ===============
4534
4535class TestNamespace(TestCase):
4536
4537 def test_constructor(self):
4538 ns = argparse.Namespace()
4539 self.assertRaises(AttributeError, getattr, ns, 'x')
4540
4541 ns = argparse.Namespace(a=42, b='spam')
4542 self.assertEqual(ns.a, 42)
4543 self.assertEqual(ns.b, 'spam')
4544
4545 def test_equality(self):
4546 ns1 = argparse.Namespace(a=1, b=2)
4547 ns2 = argparse.Namespace(b=2, a=1)
4548 ns3 = argparse.Namespace(a=1)
4549 ns4 = argparse.Namespace(b=2)
4550
4551 self.assertEqual(ns1, ns2)
4552 self.assertNotEqual(ns1, ns3)
4553 self.assertNotEqual(ns1, ns4)
4554 self.assertNotEqual(ns2, ns3)
4555 self.assertNotEqual(ns2, ns4)
4556 self.assertTrue(ns1 != ns3)
4557 self.assertTrue(ns1 != ns4)
4558 self.assertTrue(ns2 != ns3)
4559 self.assertTrue(ns2 != ns4)
4560
Raymond Hettingerdea46ec2014-05-26 00:43:27 -07004561 def test_equality_returns_notimplemeted(self):
4562 # See issue 21481
4563 ns = argparse.Namespace(a=1, b=2)
4564 self.assertIs(ns.__eq__(None), NotImplemented)
4565 self.assertIs(ns.__ne__(None), NotImplemented)
4566
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004567
4568# ===================
4569# File encoding tests
4570# ===================
4571
4572class TestEncoding(TestCase):
4573
4574 def _test_module_encoding(self, path):
4575 path, _ = os.path.splitext(path)
4576 path += ".py"
Marc-André Lemburg8f36af72011-02-25 15:42:01 +00004577 with codecs.open(path, 'r', 'utf-8') as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +00004578 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004579
4580 def test_argparse_module_encoding(self):
4581 self._test_module_encoding(argparse.__file__)
4582
4583 def test_test_argparse_module_encoding(self):
4584 self._test_module_encoding(__file__)
4585
4586# ===================
4587# ArgumentError tests
4588# ===================
4589
4590class TestArgumentError(TestCase):
4591
4592 def test_argument_error(self):
4593 msg = "my error here"
4594 error = argparse.ArgumentError(None, msg)
4595 self.assertEqual(str(error), msg)
4596
4597# =======================
4598# ArgumentTypeError tests
4599# =======================
4600
R. David Murray722b5fd2010-11-20 03:48:58 +00004601class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004602
4603 def test_argument_type_error(self):
4604
4605 def spam(string):
4606 raise argparse.ArgumentTypeError('spam!')
4607
4608 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4609 parser.add_argument('x', type=spam)
4610 try:
4611 parser.parse_args(['XXX'])
4612 except ArgumentParserError:
4613 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4614 msg = sys.exc_info()[1].stderr
4615 self.assertEqual(expected, msg)
4616 else:
4617 self.fail()
4618
R David Murrayf97c59a2011-06-09 12:34:07 -04004619# =========================
4620# MessageContentError tests
4621# =========================
4622
4623class TestMessageContentError(TestCase):
4624
4625 def test_missing_argument_name_in_message(self):
4626 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4627 parser.add_argument('req_pos', type=str)
4628 parser.add_argument('-req_opt', type=int, required=True)
4629 parser.add_argument('need_one', type=str, nargs='+')
4630
4631 with self.assertRaises(ArgumentParserError) as cm:
4632 parser.parse_args([])
4633 msg = str(cm.exception)
4634 self.assertRegex(msg, 'req_pos')
4635 self.assertRegex(msg, 'req_opt')
4636 self.assertRegex(msg, 'need_one')
4637 with self.assertRaises(ArgumentParserError) as cm:
4638 parser.parse_args(['myXargument'])
4639 msg = str(cm.exception)
4640 self.assertNotIn(msg, 'req_pos')
4641 self.assertRegex(msg, 'req_opt')
4642 self.assertRegex(msg, 'need_one')
4643 with self.assertRaises(ArgumentParserError) as cm:
4644 parser.parse_args(['myXargument', '-req_opt=1'])
4645 msg = str(cm.exception)
4646 self.assertNotIn(msg, 'req_pos')
4647 self.assertNotIn(msg, 'req_opt')
4648 self.assertRegex(msg, 'need_one')
4649
4650 def test_optional_optional_not_in_message(self):
4651 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4652 parser.add_argument('req_pos', type=str)
4653 parser.add_argument('--req_opt', type=int, required=True)
4654 parser.add_argument('--opt_opt', type=bool, nargs='?',
4655 default=True)
4656 with self.assertRaises(ArgumentParserError) as cm:
4657 parser.parse_args([])
4658 msg = str(cm.exception)
4659 self.assertRegex(msg, 'req_pos')
4660 self.assertRegex(msg, 'req_opt')
4661 self.assertNotIn(msg, 'opt_opt')
4662 with self.assertRaises(ArgumentParserError) as cm:
4663 parser.parse_args(['--req_opt=1'])
4664 msg = str(cm.exception)
4665 self.assertRegex(msg, 'req_pos')
4666 self.assertNotIn(msg, 'req_opt')
4667 self.assertNotIn(msg, 'opt_opt')
4668
4669 def test_optional_positional_not_in_message(self):
4670 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4671 parser.add_argument('req_pos')
4672 parser.add_argument('optional_positional', nargs='?', default='eggs')
4673 with self.assertRaises(ArgumentParserError) as cm:
4674 parser.parse_args([])
4675 msg = str(cm.exception)
4676 self.assertRegex(msg, 'req_pos')
4677 self.assertNotIn(msg, 'optional_positional')
4678
4679
R David Murray6fb8fb12012-08-31 22:45:20 -04004680# ================================================
4681# Check that the type function is called only once
4682# ================================================
4683
4684class TestTypeFunctionCallOnlyOnce(TestCase):
4685
4686 def test_type_function_call_only_once(self):
4687 def spam(string_to_convert):
4688 self.assertEqual(string_to_convert, 'spam!')
4689 return 'foo_converted'
4690
4691 parser = argparse.ArgumentParser()
4692 parser.add_argument('--foo', type=spam, default='bar')
4693 args = parser.parse_args('--foo spam!'.split())
4694 self.assertEqual(NS(foo='foo_converted'), args)
4695
Barry Warsaweaae1b72012-09-12 14:34:50 -04004696# ==================================================================
4697# Check semantics regarding the default argument and type conversion
4698# ==================================================================
R David Murray6fb8fb12012-08-31 22:45:20 -04004699
Barry Warsaweaae1b72012-09-12 14:34:50 -04004700class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray6fb8fb12012-08-31 22:45:20 -04004701
4702 def test_type_function_call_with_non_string_default(self):
4703 def spam(int_to_convert):
4704 self.assertEqual(int_to_convert, 0)
4705 return 'foo_converted'
4706
4707 parser = argparse.ArgumentParser()
4708 parser.add_argument('--foo', type=spam, default=0)
4709 args = parser.parse_args([])
Barry Warsaweaae1b72012-09-12 14:34:50 -04004710 # foo should *not* be converted because its default is not a string.
4711 self.assertEqual(NS(foo=0), args)
4712
4713 def test_type_function_call_with_string_default(self):
4714 def spam(int_to_convert):
4715 return 'foo_converted'
4716
4717 parser = argparse.ArgumentParser()
4718 parser.add_argument('--foo', type=spam, default='0')
4719 args = parser.parse_args([])
4720 # foo is converted because its default is a string.
R David Murray6fb8fb12012-08-31 22:45:20 -04004721 self.assertEqual(NS(foo='foo_converted'), args)
4722
Barry Warsaweaae1b72012-09-12 14:34:50 -04004723 def test_no_double_type_conversion_of_default(self):
4724 def extend(str_to_convert):
4725 return str_to_convert + '*'
4726
4727 parser = argparse.ArgumentParser()
4728 parser.add_argument('--test', type=extend, default='*')
4729 args = parser.parse_args([])
4730 # The test argument will be two stars, one coming from the default
4731 # value and one coming from the type conversion being called exactly
4732 # once.
4733 self.assertEqual(NS(test='**'), args)
4734
Barry Warsaw4b2f9e92012-09-11 22:38:47 -04004735 def test_issue_15906(self):
4736 # Issue #15906: When action='append', type=str, default=[] are
4737 # providing, the dest value was the string representation "[]" when it
4738 # should have been an empty list.
4739 parser = argparse.ArgumentParser()
4740 parser.add_argument('--test', dest='test', type=str,
4741 default=[], action='append')
4742 args = parser.parse_args([])
4743 self.assertEqual(args.test, [])
4744
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004745# ======================
4746# parse_known_args tests
4747# ======================
4748
4749class TestParseKnownArgs(TestCase):
4750
R David Murrayb5228282012-09-08 12:08:01 -04004751 def test_arguments_tuple(self):
4752 parser = argparse.ArgumentParser()
4753 parser.parse_args(())
4754
4755 def test_arguments_list(self):
4756 parser = argparse.ArgumentParser()
4757 parser.parse_args([])
4758
4759 def test_arguments_tuple_positional(self):
4760 parser = argparse.ArgumentParser()
4761 parser.add_argument('x')
4762 parser.parse_args(('x',))
4763
4764 def test_arguments_list_positional(self):
4765 parser = argparse.ArgumentParser()
4766 parser.add_argument('x')
4767 parser.parse_args(['x'])
4768
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004769 def test_optionals(self):
4770 parser = argparse.ArgumentParser()
4771 parser.add_argument('--foo')
4772 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4773 self.assertEqual(NS(foo='F'), args)
4774 self.assertEqual(['--bar', '--baz'], extras)
4775
4776 def test_mixed(self):
4777 parser = argparse.ArgumentParser()
4778 parser.add_argument('-v', nargs='?', const=1, type=int)
4779 parser.add_argument('--spam', action='store_false')
4780 parser.add_argument('badger')
4781
4782 argv = ["B", "C", "--foo", "-v", "3", "4"]
4783 args, extras = parser.parse_known_args(argv)
4784 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4785 self.assertEqual(["C", "--foo", "4"], extras)
4786
Steven Bethard8d9a4622011-03-26 17:33:56 +01004787# ==========================
4788# add_argument metavar tests
4789# ==========================
4790
4791class TestAddArgumentMetavar(TestCase):
4792
4793 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4794
4795 def do_test_no_exception(self, nargs, metavar):
4796 parser = argparse.ArgumentParser()
4797 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4798
4799 def do_test_exception(self, nargs, metavar):
4800 parser = argparse.ArgumentParser()
4801 with self.assertRaises(ValueError) as cm:
4802 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4803 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4804
4805 # Unit tests for different values of metavar when nargs=None
4806
4807 def test_nargs_None_metavar_string(self):
4808 self.do_test_no_exception(nargs=None, metavar="1")
4809
4810 def test_nargs_None_metavar_length0(self):
4811 self.do_test_exception(nargs=None, metavar=tuple())
4812
4813 def test_nargs_None_metavar_length1(self):
4814 self.do_test_no_exception(nargs=None, metavar=("1"))
4815
4816 def test_nargs_None_metavar_length2(self):
4817 self.do_test_exception(nargs=None, metavar=("1", "2"))
4818
4819 def test_nargs_None_metavar_length3(self):
4820 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4821
4822 # Unit tests for different values of metavar when nargs=?
4823
4824 def test_nargs_optional_metavar_string(self):
4825 self.do_test_no_exception(nargs="?", metavar="1")
4826
4827 def test_nargs_optional_metavar_length0(self):
4828 self.do_test_exception(nargs="?", metavar=tuple())
4829
4830 def test_nargs_optional_metavar_length1(self):
4831 self.do_test_no_exception(nargs="?", metavar=("1"))
4832
4833 def test_nargs_optional_metavar_length2(self):
4834 self.do_test_exception(nargs="?", metavar=("1", "2"))
4835
4836 def test_nargs_optional_metavar_length3(self):
4837 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4838
4839 # Unit tests for different values of metavar when nargs=*
4840
4841 def test_nargs_zeroormore_metavar_string(self):
4842 self.do_test_no_exception(nargs="*", metavar="1")
4843
4844 def test_nargs_zeroormore_metavar_length0(self):
4845 self.do_test_exception(nargs="*", metavar=tuple())
4846
4847 def test_nargs_zeroormore_metavar_length1(self):
4848 self.do_test_no_exception(nargs="*", metavar=("1"))
4849
4850 def test_nargs_zeroormore_metavar_length2(self):
4851 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4852
4853 def test_nargs_zeroormore_metavar_length3(self):
4854 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4855
4856 # Unit tests for different values of metavar when nargs=+
4857
4858 def test_nargs_oneormore_metavar_string(self):
4859 self.do_test_no_exception(nargs="+", metavar="1")
4860
4861 def test_nargs_oneormore_metavar_length0(self):
4862 self.do_test_exception(nargs="+", metavar=tuple())
4863
4864 def test_nargs_oneormore_metavar_length1(self):
4865 self.do_test_no_exception(nargs="+", metavar=("1"))
4866
4867 def test_nargs_oneormore_metavar_length2(self):
4868 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4869
4870 def test_nargs_oneormore_metavar_length3(self):
4871 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4872
4873 # Unit tests for different values of metavar when nargs=...
4874
4875 def test_nargs_remainder_metavar_string(self):
4876 self.do_test_no_exception(nargs="...", metavar="1")
4877
4878 def test_nargs_remainder_metavar_length0(self):
4879 self.do_test_no_exception(nargs="...", metavar=tuple())
4880
4881 def test_nargs_remainder_metavar_length1(self):
4882 self.do_test_no_exception(nargs="...", metavar=("1"))
4883
4884 def test_nargs_remainder_metavar_length2(self):
4885 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4886
4887 def test_nargs_remainder_metavar_length3(self):
4888 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4889
4890 # Unit tests for different values of metavar when nargs=A...
4891
4892 def test_nargs_parser_metavar_string(self):
4893 self.do_test_no_exception(nargs="A...", metavar="1")
4894
4895 def test_nargs_parser_metavar_length0(self):
4896 self.do_test_exception(nargs="A...", metavar=tuple())
4897
4898 def test_nargs_parser_metavar_length1(self):
4899 self.do_test_no_exception(nargs="A...", metavar=("1"))
4900
4901 def test_nargs_parser_metavar_length2(self):
4902 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4903
4904 def test_nargs_parser_metavar_length3(self):
4905 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4906
4907 # Unit tests for different values of metavar when nargs=1
4908
4909 def test_nargs_1_metavar_string(self):
4910 self.do_test_no_exception(nargs=1, metavar="1")
4911
4912 def test_nargs_1_metavar_length0(self):
4913 self.do_test_exception(nargs=1, metavar=tuple())
4914
4915 def test_nargs_1_metavar_length1(self):
4916 self.do_test_no_exception(nargs=1, metavar=("1"))
4917
4918 def test_nargs_1_metavar_length2(self):
4919 self.do_test_exception(nargs=1, metavar=("1", "2"))
4920
4921 def test_nargs_1_metavar_length3(self):
4922 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4923
4924 # Unit tests for different values of metavar when nargs=2
4925
4926 def test_nargs_2_metavar_string(self):
4927 self.do_test_no_exception(nargs=2, metavar="1")
4928
4929 def test_nargs_2_metavar_length0(self):
4930 self.do_test_exception(nargs=2, metavar=tuple())
4931
4932 def test_nargs_2_metavar_length1(self):
4933 self.do_test_no_exception(nargs=2, metavar=("1"))
4934
4935 def test_nargs_2_metavar_length2(self):
4936 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4937
4938 def test_nargs_2_metavar_length3(self):
4939 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4940
4941 # Unit tests for different values of metavar when nargs=3
4942
4943 def test_nargs_3_metavar_string(self):
4944 self.do_test_no_exception(nargs=3, metavar="1")
4945
4946 def test_nargs_3_metavar_length0(self):
4947 self.do_test_exception(nargs=3, metavar=tuple())
4948
4949 def test_nargs_3_metavar_length1(self):
4950 self.do_test_no_exception(nargs=3, metavar=("1"))
4951
4952 def test_nargs_3_metavar_length2(self):
4953 self.do_test_exception(nargs=3, metavar=("1", "2"))
4954
4955 def test_nargs_3_metavar_length3(self):
4956 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4957
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004958# ============================
4959# from argparse import * tests
4960# ============================
4961
4962class TestImportStar(TestCase):
4963
4964 def test(self):
4965 for name in argparse.__all__:
4966 self.assertTrue(hasattr(argparse, name))
4967
Steven Bethard72c55382010-11-01 15:23:12 +00004968 def test_all_exports_everything_but_modules(self):
4969 items = [
4970 name
4971 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00004972 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00004973 if not inspect.ismodule(value)
4974 ]
4975 self.assertEqual(sorted(items), sorted(argparse.__all__))
4976
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004977def test_main():
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004978 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00004979 # Remove global references to avoid looking like we have refleaks.
4980 RFile.seen = {}
4981 WFile.seen = set()
4982
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004983
4984
4985if __name__ == '__main__':
4986 test_main()