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