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