blob: 915e989ddbec0425a746b35b8560dbb206ac7c25 [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):
Benjamin Peterson07f90472015-01-13 09:17:24 -0500649 """Tests an optional action that is required"""
Benjamin Petersona39e9662010-03-02 22:05:59 +0000650
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
R David Murrayaf26c152014-10-17 20:07:08 -04002729 def test_set_defaults_on_parent_and_subparser(self):
2730 parser = argparse.ArgumentParser()
2731 xparser = parser.add_subparsers().add_parser('X')
2732 parser.set_defaults(foo=1)
2733 xparser.set_defaults(foo=2)
2734 self.assertEqual(NS(foo=2), parser.parse_args(['X']))
2735
Benjamin Petersona39e9662010-03-02 22:05:59 +00002736 def test_set_defaults_same_as_add_argument(self):
2737 parser = ErrorRaisingArgumentParser()
2738 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2739 parser.add_argument('-w')
2740 parser.add_argument('-x', default='XX')
2741 parser.add_argument('y', nargs='?')
2742 parser.add_argument('z', nargs='?', default='ZZ')
2743
2744 # defaults set previously
2745 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2746 parser.parse_args([]))
2747
2748 # reset defaults
2749 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2750 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2751 parser.parse_args([]))
2752
2753 def test_set_defaults_same_as_add_argument_group(self):
2754 parser = ErrorRaisingArgumentParser()
2755 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2756 group = parser.add_argument_group('foo')
2757 group.add_argument('-w')
2758 group.add_argument('-x', default='XX')
2759 group.add_argument('y', nargs='?')
2760 group.add_argument('z', nargs='?', default='ZZ')
2761
2762
2763 # defaults set previously
2764 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2765 parser.parse_args([]))
2766
2767 # reset defaults
2768 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2769 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2770 parser.parse_args([]))
2771
2772# =================
2773# Get default tests
2774# =================
2775
2776class TestGetDefault(TestCase):
2777
2778 def test_get_default(self):
2779 parser = ErrorRaisingArgumentParser()
2780 self.assertEqual(None, parser.get_default("foo"))
2781 self.assertEqual(None, parser.get_default("bar"))
2782
2783 parser.add_argument("--foo")
2784 self.assertEqual(None, parser.get_default("foo"))
2785 self.assertEqual(None, parser.get_default("bar"))
2786
2787 parser.add_argument("--bar", type=int, default=42)
2788 self.assertEqual(None, parser.get_default("foo"))
2789 self.assertEqual(42, parser.get_default("bar"))
2790
2791 parser.set_defaults(foo="badger")
2792 self.assertEqual("badger", parser.get_default("foo"))
2793 self.assertEqual(42, parser.get_default("bar"))
2794
2795# ==========================
2796# Namespace 'contains' tests
2797# ==========================
2798
2799class TestNamespaceContainsSimple(TestCase):
2800
2801 def test_empty(self):
2802 ns = argparse.Namespace()
Ezio Melotti2623a372010-11-21 13:34:58 +00002803 self.assertEqual('' in ns, False)
2804 self.assertEqual('' not in ns, True)
2805 self.assertEqual('x' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002806
2807 def test_non_empty(self):
2808 ns = argparse.Namespace(x=1, y=2)
Ezio Melotti2623a372010-11-21 13:34:58 +00002809 self.assertEqual('x' in ns, True)
2810 self.assertEqual('x' not in ns, False)
2811 self.assertEqual('y' in ns, True)
2812 self.assertEqual('' in ns, False)
2813 self.assertEqual('xx' in ns, False)
2814 self.assertEqual('z' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002815
2816# =====================
2817# Help formatting tests
2818# =====================
2819
2820class TestHelpFormattingMetaclass(type):
2821
2822 def __init__(cls, name, bases, bodydict):
2823 if name == 'HelpTestCase':
2824 return
2825
2826 class AddTests(object):
2827
2828 def __init__(self, test_class, func_suffix, std_name):
2829 self.func_suffix = func_suffix
2830 self.std_name = std_name
2831
2832 for test_func in [self.test_format,
2833 self.test_print,
2834 self.test_print_file]:
2835 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2836
2837 def test_wrapper(self, test_func=test_func):
2838 test_func(self)
2839 try:
2840 test_wrapper.__name__ = test_name
2841 except TypeError:
2842 pass
2843 setattr(test_class, test_name, test_wrapper)
2844
2845 def _get_parser(self, tester):
2846 parser = argparse.ArgumentParser(
2847 *tester.parser_signature.args,
2848 **tester.parser_signature.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002849 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Petersona39e9662010-03-02 22:05:59 +00002850 parser.add_argument(*argument_sig.args,
2851 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002852 group_sigs = getattr(tester, 'argument_group_signatures', [])
2853 for group_sig, argument_sigs in group_sigs:
Benjamin Petersona39e9662010-03-02 22:05:59 +00002854 group = parser.add_argument_group(*group_sig.args,
2855 **group_sig.kwargs)
2856 for argument_sig in argument_sigs:
2857 group.add_argument(*argument_sig.args,
2858 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002859 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
2860 if subparsers_sigs:
2861 subparsers = parser.add_subparsers()
2862 for subparser_sig in subparsers_sigs:
2863 subparsers.add_parser(*subparser_sig.args,
2864 **subparser_sig.kwargs)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002865 return parser
2866
2867 def _test(self, tester, parser_text):
2868 expected_text = getattr(tester, self.func_suffix)
2869 expected_text = textwrap.dedent(expected_text)
2870 if expected_text != parser_text:
2871 print(repr(expected_text))
2872 print(repr(parser_text))
2873 for char1, char2 in zip(expected_text, parser_text):
2874 if char1 != char2:
2875 print('first diff: %r %r' % (char1, char2))
2876 break
2877 tester.assertEqual(expected_text, parser_text)
2878
2879 def test_format(self, tester):
2880 parser = self._get_parser(tester)
2881 format = getattr(parser, 'format_%s' % self.func_suffix)
2882 self._test(tester, format())
2883
2884 def test_print(self, tester):
2885 parser = self._get_parser(tester)
2886 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2887 old_stream = getattr(sys, self.std_name)
Michael Foord91a2c892010-04-08 00:04:24 +00002888 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Petersona39e9662010-03-02 22:05:59 +00002889 try:
2890 print_()
2891 parser_text = getattr(sys, self.std_name).getvalue()
2892 finally:
2893 setattr(sys, self.std_name, old_stream)
2894 self._test(tester, parser_text)
2895
2896 def test_print_file(self, tester):
2897 parser = self._get_parser(tester)
2898 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Michael Foord91a2c892010-04-08 00:04:24 +00002899 sfile = StdIOBuffer()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002900 print_(sfile)
2901 parser_text = sfile.getvalue()
2902 self._test(tester, parser_text)
2903
2904 # add tests for {format,print}_{usage,help,version}
2905 for func_suffix, std_name in [('usage', 'stdout'),
2906 ('help', 'stdout'),
2907 ('version', 'stderr')]:
2908 AddTests(cls, func_suffix, std_name)
2909
2910bases = TestCase,
2911HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2912
2913
2914class TestHelpBiggerOptionals(HelpTestCase):
2915 """Make sure that argument help aligns when options are longer"""
2916
2917 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2918 epilog='EPILOG', version='0.1')
2919 argument_signatures = [
2920 Sig('-x', action='store_true', help='X HELP'),
2921 Sig('--y', help='Y HELP'),
2922 Sig('foo', help='FOO HELP'),
2923 Sig('bar', help='BAR HELP'),
2924 ]
2925 argument_group_signatures = []
2926 usage = '''\
2927 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2928 '''
2929 help = usage + '''\
2930
2931 DESCRIPTION
2932
2933 positional arguments:
2934 foo FOO HELP
2935 bar BAR HELP
2936
2937 optional arguments:
2938 -h, --help show this help message and exit
2939 -v, --version show program's version number and exit
2940 -x X HELP
2941 --y Y Y HELP
2942
2943 EPILOG
2944 '''
2945 version = '''\
2946 0.1
2947 '''
2948
Serhiy Storchaka9f8621f2014-01-09 23:13:48 +02002949class TestShortColumns(HelpTestCase):
2950 '''Test extremely small number of columns.
2951
2952 TestCase prevents "COLUMNS" from being too small in the tests themselves,
2953 but we don't want any exceptions thrown in such case. Only ugly representation.
2954 '''
2955 def setUp(self):
2956 env = test_support.EnvironmentVarGuard()
2957 env.set("COLUMNS", '15')
2958 self.addCleanup(env.__exit__)
2959
2960 parser_signature = TestHelpBiggerOptionals.parser_signature
2961 argument_signatures = TestHelpBiggerOptionals.argument_signatures
2962 argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures
2963 usage = '''\
2964 usage: PROG
2965 [-h]
2966 [-v]
2967 [-x]
2968 [--y Y]
2969 foo
2970 bar
2971 '''
2972 help = usage + '''\
2973
2974 DESCRIPTION
2975
2976 positional arguments:
2977 foo
2978 FOO HELP
2979 bar
2980 BAR HELP
2981
2982 optional arguments:
2983 -h, --help
2984 show this
2985 help
2986 message and
2987 exit
2988 -v, --version
2989 show
2990 program's
2991 version
2992 number and
2993 exit
2994 -x
2995 X HELP
2996 --y Y
2997 Y HELP
2998
2999 EPILOG
3000 '''
3001 version = TestHelpBiggerOptionals.version
3002
Benjamin Petersona39e9662010-03-02 22:05:59 +00003003
3004class TestHelpBiggerOptionalGroups(HelpTestCase):
3005 """Make sure that argument help aligns when options are longer"""
3006
3007 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
3008 epilog='EPILOG', version='0.1')
3009 argument_signatures = [
3010 Sig('-x', action='store_true', help='X HELP'),
3011 Sig('--y', help='Y HELP'),
3012 Sig('foo', help='FOO HELP'),
3013 Sig('bar', help='BAR HELP'),
3014 ]
3015 argument_group_signatures = [
3016 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
3017 Sig('baz', help='BAZ HELP'),
3018 Sig('-z', nargs='+', help='Z HELP')]),
3019 ]
3020 usage = '''\
3021 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
3022 '''
3023 help = usage + '''\
3024
3025 DESCRIPTION
3026
3027 positional arguments:
3028 foo FOO HELP
3029 bar BAR HELP
3030
3031 optional arguments:
3032 -h, --help show this help message and exit
3033 -v, --version show program's version number and exit
3034 -x X HELP
3035 --y Y Y HELP
3036
3037 GROUP TITLE:
3038 GROUP DESCRIPTION
3039
3040 baz BAZ HELP
3041 -z Z [Z ...] Z HELP
3042
3043 EPILOG
3044 '''
3045 version = '''\
3046 0.1
3047 '''
3048
3049
3050class TestHelpBiggerPositionals(HelpTestCase):
3051 """Make sure that help aligns when arguments are longer"""
3052
3053 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
3054 argument_signatures = [
3055 Sig('-x', action='store_true', help='X HELP'),
3056 Sig('--y', help='Y HELP'),
3057 Sig('ekiekiekifekang', help='EKI HELP'),
3058 Sig('bar', help='BAR HELP'),
3059 ]
3060 argument_group_signatures = []
3061 usage = '''\
3062 usage: USAGE
3063 '''
3064 help = usage + '''\
3065
3066 DESCRIPTION
3067
3068 positional arguments:
3069 ekiekiekifekang EKI HELP
3070 bar BAR HELP
3071
3072 optional arguments:
3073 -h, --help show this help message and exit
3074 -x X HELP
3075 --y Y Y HELP
3076 '''
3077
3078 version = ''
3079
3080
3081class TestHelpReformatting(HelpTestCase):
3082 """Make sure that text after short names starts on the first line"""
3083
3084 parser_signature = Sig(
3085 prog='PROG',
3086 description=' oddly formatted\n'
3087 'description\n'
3088 '\n'
3089 'that is so long that it should go onto multiple '
3090 'lines when wrapped')
3091 argument_signatures = [
3092 Sig('-x', metavar='XX', help='oddly\n'
3093 ' formatted -x help'),
3094 Sig('y', metavar='yyy', help='normal y help'),
3095 ]
3096 argument_group_signatures = [
3097 (Sig('title', description='\n'
3098 ' oddly formatted group\n'
3099 '\n'
3100 'description'),
3101 [Sig('-a', action='store_true',
3102 help=' oddly \n'
3103 'formatted -a help \n'
3104 ' again, so long that it should be wrapped over '
3105 'multiple lines')]),
3106 ]
3107 usage = '''\
3108 usage: PROG [-h] [-x XX] [-a] yyy
3109 '''
3110 help = usage + '''\
3111
3112 oddly formatted description that is so long that it should go onto \
3113multiple
3114 lines when wrapped
3115
3116 positional arguments:
3117 yyy normal y help
3118
3119 optional arguments:
3120 -h, --help show this help message and exit
3121 -x XX oddly formatted -x help
3122
3123 title:
3124 oddly formatted group description
3125
3126 -a oddly formatted -a help again, so long that it should \
3127be wrapped
3128 over multiple lines
3129 '''
3130 version = ''
3131
3132
3133class TestHelpWrappingShortNames(HelpTestCase):
3134 """Make sure that text after short names starts on the first line"""
3135
3136 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3137 argument_signatures = [
3138 Sig('-x', metavar='XX', help='XHH HX' * 20),
3139 Sig('y', metavar='yyy', help='YH YH' * 20),
3140 ]
3141 argument_group_signatures = [
3142 (Sig('ALPHAS'), [
3143 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3144 ]
3145 usage = '''\
3146 usage: PROG [-h] [-x XX] [-a] yyy
3147 '''
3148 help = usage + '''\
3149
3150 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3151DD DD DD
3152 DD DD DD DD D
3153
3154 positional arguments:
3155 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3156YHYH YHYH
3157 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3158
3159 optional arguments:
3160 -h, --help show this help message and exit
3161 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3162HXXHH HXXHH
3163 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3164
3165 ALPHAS:
3166 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3167HHAAHHH
3168 HHAAHHH HHAAHHH HHA
3169 '''
3170 version = ''
3171
3172
3173class TestHelpWrappingLongNames(HelpTestCase):
3174 """Make sure that text after long names starts on the next line"""
3175
3176 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3177 version='V V'*30)
3178 argument_signatures = [
3179 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3180 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3181 ]
3182 argument_group_signatures = [
3183 (Sig('ALPHAS'), [
3184 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3185 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3186 ]
3187 usage = '''\
3188 usage: USAGE
3189 '''
3190 help = usage + '''\
3191
3192 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3193DD DD DD
3194 DD DD DD DD D
3195
3196 positional arguments:
3197 yyyyyyyyyyyyyyyyyyyyyyyyy
3198 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3199YHYH YHYH
3200 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3201
3202 optional arguments:
3203 -h, --help show this help message and exit
3204 -v, --version show program's version number and exit
3205 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3206 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3207XHXH XHXH
3208 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3209
3210 ALPHAS:
3211 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3212 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3213AHAH AHAH
3214 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3215 zzzzzzzzzzzzzzzzzzzzzzzzz
3216 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3217ZHZH ZHZH
3218 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3219 '''
3220 version = '''\
3221 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3222VV VV VV
3223 VV VV VV VV V
3224 '''
3225
3226
3227class TestHelpUsage(HelpTestCase):
3228 """Test basic usage messages"""
3229
3230 parser_signature = Sig(prog='PROG')
3231 argument_signatures = [
3232 Sig('-w', nargs='+', help='w'),
3233 Sig('-x', nargs='*', help='x'),
3234 Sig('a', help='a'),
3235 Sig('b', help='b', nargs=2),
3236 Sig('c', help='c', nargs='?'),
3237 ]
3238 argument_group_signatures = [
3239 (Sig('group'), [
3240 Sig('-y', nargs='?', help='y'),
3241 Sig('-z', nargs=3, help='z'),
3242 Sig('d', help='d', nargs='*'),
3243 Sig('e', help='e', nargs='+'),
3244 ])
3245 ]
3246 usage = '''\
3247 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3248 a b b [c] [d [d ...]] e [e ...]
3249 '''
3250 help = usage + '''\
3251
3252 positional arguments:
3253 a a
3254 b b
3255 c c
3256
3257 optional arguments:
3258 -h, --help show this help message and exit
3259 -w W [W ...] w
3260 -x [X [X ...]] x
3261
3262 group:
3263 -y [Y] y
3264 -z Z Z Z z
3265 d d
3266 e e
3267 '''
3268 version = ''
3269
3270
3271class TestHelpOnlyUserGroups(HelpTestCase):
3272 """Test basic usage messages"""
3273
3274 parser_signature = Sig(prog='PROG', add_help=False)
3275 argument_signatures = []
3276 argument_group_signatures = [
3277 (Sig('xxxx'), [
3278 Sig('-x', help='x'),
3279 Sig('a', help='a'),
3280 ]),
3281 (Sig('yyyy'), [
3282 Sig('b', help='b'),
3283 Sig('-y', help='y'),
3284 ]),
3285 ]
3286 usage = '''\
3287 usage: PROG [-x X] [-y Y] a b
3288 '''
3289 help = usage + '''\
3290
3291 xxxx:
3292 -x X x
3293 a a
3294
3295 yyyy:
3296 b b
3297 -y Y y
3298 '''
3299 version = ''
3300
3301
3302class TestHelpUsageLongProg(HelpTestCase):
3303 """Test usage messages where the prog is long"""
3304
3305 parser_signature = Sig(prog='P' * 60)
3306 argument_signatures = [
3307 Sig('-w', metavar='W'),
3308 Sig('-x', metavar='X'),
3309 Sig('a'),
3310 Sig('b'),
3311 ]
3312 argument_group_signatures = []
3313 usage = '''\
3314 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3315 [-h] [-w W] [-x X] a b
3316 '''
3317 help = usage + '''\
3318
3319 positional arguments:
3320 a
3321 b
3322
3323 optional arguments:
3324 -h, --help show this help message and exit
3325 -w W
3326 -x X
3327 '''
3328 version = ''
3329
3330
3331class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3332 """Test usage messages where the prog is long and the optionals wrap"""
3333
3334 parser_signature = Sig(prog='P' * 60)
3335 argument_signatures = [
3336 Sig('-w', metavar='W' * 25),
3337 Sig('-x', metavar='X' * 25),
3338 Sig('-y', metavar='Y' * 25),
3339 Sig('-z', metavar='Z' * 25),
3340 Sig('a'),
3341 Sig('b'),
3342 ]
3343 argument_group_signatures = []
3344 usage = '''\
3345 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3346 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3347[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3348 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3349 a b
3350 '''
3351 help = usage + '''\
3352
3353 positional arguments:
3354 a
3355 b
3356
3357 optional arguments:
3358 -h, --help show this help message and exit
3359 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3360 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3361 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3362 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3363 '''
3364 version = ''
3365
3366
3367class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3368 """Test usage messages where the prog is long and the positionals wrap"""
3369
3370 parser_signature = Sig(prog='P' * 60, add_help=False)
3371 argument_signatures = [
3372 Sig('a' * 25),
3373 Sig('b' * 25),
3374 Sig('c' * 25),
3375 ]
3376 argument_group_signatures = []
3377 usage = '''\
3378 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3379 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3380 ccccccccccccccccccccccccc
3381 '''
3382 help = usage + '''\
3383
3384 positional arguments:
3385 aaaaaaaaaaaaaaaaaaaaaaaaa
3386 bbbbbbbbbbbbbbbbbbbbbbbbb
3387 ccccccccccccccccccccccccc
3388 '''
3389 version = ''
3390
3391
3392class TestHelpUsageOptionalsWrap(HelpTestCase):
3393 """Test usage messages where the optionals wrap"""
3394
3395 parser_signature = Sig(prog='PROG')
3396 argument_signatures = [
3397 Sig('-w', metavar='W' * 25),
3398 Sig('-x', metavar='X' * 25),
3399 Sig('-y', metavar='Y' * 25),
3400 Sig('-z', metavar='Z' * 25),
3401 Sig('a'),
3402 Sig('b'),
3403 Sig('c'),
3404 ]
3405 argument_group_signatures = []
3406 usage = '''\
3407 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3408[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3409 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3410[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3411 a b c
3412 '''
3413 help = usage + '''\
3414
3415 positional arguments:
3416 a
3417 b
3418 c
3419
3420 optional arguments:
3421 -h, --help show this help message and exit
3422 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3423 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3424 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3425 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3426 '''
3427 version = ''
3428
3429
3430class TestHelpUsagePositionalsWrap(HelpTestCase):
3431 """Test usage messages where the positionals wrap"""
3432
3433 parser_signature = Sig(prog='PROG')
3434 argument_signatures = [
3435 Sig('-x'),
3436 Sig('-y'),
3437 Sig('-z'),
3438 Sig('a' * 25),
3439 Sig('b' * 25),
3440 Sig('c' * 25),
3441 ]
3442 argument_group_signatures = []
3443 usage = '''\
3444 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3445 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3446 ccccccccccccccccccccccccc
3447 '''
3448 help = usage + '''\
3449
3450 positional arguments:
3451 aaaaaaaaaaaaaaaaaaaaaaaaa
3452 bbbbbbbbbbbbbbbbbbbbbbbbb
3453 ccccccccccccccccccccccccc
3454
3455 optional arguments:
3456 -h, --help show this help message and exit
3457 -x X
3458 -y Y
3459 -z Z
3460 '''
3461 version = ''
3462
3463
3464class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3465 """Test usage messages where the optionals and positionals wrap"""
3466
3467 parser_signature = Sig(prog='PROG')
3468 argument_signatures = [
3469 Sig('-x', metavar='X' * 25),
3470 Sig('-y', metavar='Y' * 25),
3471 Sig('-z', metavar='Z' * 25),
3472 Sig('a' * 25),
3473 Sig('b' * 25),
3474 Sig('c' * 25),
3475 ]
3476 argument_group_signatures = []
3477 usage = '''\
3478 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3479[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3480 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3481 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3482 ccccccccccccccccccccccccc
3483 '''
3484 help = usage + '''\
3485
3486 positional arguments:
3487 aaaaaaaaaaaaaaaaaaaaaaaaa
3488 bbbbbbbbbbbbbbbbbbbbbbbbb
3489 ccccccccccccccccccccccccc
3490
3491 optional arguments:
3492 -h, --help show this help message and exit
3493 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3494 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3495 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3496 '''
3497 version = ''
3498
3499
3500class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3501 """Test usage messages where there are only optionals and they wrap"""
3502
3503 parser_signature = Sig(prog='PROG')
3504 argument_signatures = [
3505 Sig('-x', metavar='X' * 25),
3506 Sig('-y', metavar='Y' * 25),
3507 Sig('-z', metavar='Z' * 25),
3508 ]
3509 argument_group_signatures = []
3510 usage = '''\
3511 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3512[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3513 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3514 '''
3515 help = usage + '''\
3516
3517 optional arguments:
3518 -h, --help show this help message and exit
3519 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3520 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3521 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3522 '''
3523 version = ''
3524
3525
3526class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3527 """Test usage messages where there are only positionals and they wrap"""
3528
3529 parser_signature = Sig(prog='PROG', add_help=False)
3530 argument_signatures = [
3531 Sig('a' * 25),
3532 Sig('b' * 25),
3533 Sig('c' * 25),
3534 ]
3535 argument_group_signatures = []
3536 usage = '''\
3537 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3538 ccccccccccccccccccccccccc
3539 '''
3540 help = usage + '''\
3541
3542 positional arguments:
3543 aaaaaaaaaaaaaaaaaaaaaaaaa
3544 bbbbbbbbbbbbbbbbbbbbbbbbb
3545 ccccccccccccccccccccccccc
3546 '''
3547 version = ''
3548
3549
3550class TestHelpVariableExpansion(HelpTestCase):
3551 """Test that variables are expanded properly in help messages"""
3552
3553 parser_signature = Sig(prog='PROG')
3554 argument_signatures = [
3555 Sig('-x', type=int,
3556 help='x %(prog)s %(default)s %(type)s %%'),
3557 Sig('-y', action='store_const', default=42, const='XXX',
3558 help='y %(prog)s %(default)s %(const)s'),
3559 Sig('--foo', choices='abc',
3560 help='foo %(prog)s %(default)s %(choices)s'),
3561 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3562 help='bar %(prog)s %(default)s %(dest)s'),
3563 Sig('spam', help='spam %(prog)s %(default)s'),
3564 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3565 ]
3566 argument_group_signatures = [
3567 (Sig('group'), [
3568 Sig('-a', help='a %(prog)s %(default)s'),
3569 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3570 ])
3571 ]
3572 usage = ('''\
3573 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3574 spam badger
3575 ''')
3576 help = usage + '''\
3577
3578 positional arguments:
3579 spam spam PROG None
3580 badger badger PROG 0.5
3581
3582 optional arguments:
3583 -h, --help show this help message and exit
3584 -x X x PROG None int %
3585 -y y PROG 42 XXX
3586 --foo {a,b,c} foo PROG None a, b, c
3587 --bar BBB bar PROG baz bar
3588
3589 group:
3590 -a A a PROG None
3591 -b B b PROG -1
3592 '''
3593 version = ''
3594
3595
3596class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3597 """Test that variables are expanded properly when usage= is present"""
3598
3599 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3600 argument_signatures = []
3601 argument_group_signatures = []
3602 usage = ('''\
3603 usage: PROG FOO
3604 ''')
3605 help = usage + '''\
3606
3607 optional arguments:
3608 -h, --help show this help message and exit
3609 '''
3610 version = ''
3611
3612
3613class TestHelpVariableExpansionNoArguments(HelpTestCase):
3614 """Test that variables are expanded properly with no arguments"""
3615
3616 parser_signature = Sig(prog='PROG', add_help=False)
3617 argument_signatures = []
3618 argument_group_signatures = []
3619 usage = ('''\
3620 usage: PROG
3621 ''')
3622 help = usage
3623 version = ''
3624
3625
3626class TestHelpSuppressUsage(HelpTestCase):
3627 """Test that items can be suppressed in usage messages"""
3628
3629 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3630 argument_signatures = [
3631 Sig('--foo', help='foo help'),
3632 Sig('spam', help='spam help'),
3633 ]
3634 argument_group_signatures = []
3635 help = '''\
3636 positional arguments:
3637 spam spam help
3638
3639 optional arguments:
3640 -h, --help show this help message and exit
3641 --foo FOO foo help
3642 '''
3643 usage = ''
3644 version = ''
3645
3646
3647class TestHelpSuppressOptional(HelpTestCase):
3648 """Test that optional arguments can be suppressed in help messages"""
3649
3650 parser_signature = Sig(prog='PROG', add_help=False)
3651 argument_signatures = [
3652 Sig('--foo', help=argparse.SUPPRESS),
3653 Sig('spam', help='spam help'),
3654 ]
3655 argument_group_signatures = []
3656 usage = '''\
3657 usage: PROG spam
3658 '''
3659 help = usage + '''\
3660
3661 positional arguments:
3662 spam spam help
3663 '''
3664 version = ''
3665
3666
3667class TestHelpSuppressOptionalGroup(HelpTestCase):
3668 """Test that optional groups can be suppressed in help messages"""
3669
3670 parser_signature = Sig(prog='PROG')
3671 argument_signatures = [
3672 Sig('--foo', help='foo help'),
3673 Sig('spam', help='spam help'),
3674 ]
3675 argument_group_signatures = [
3676 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3677 ]
3678 usage = '''\
3679 usage: PROG [-h] [--foo FOO] spam
3680 '''
3681 help = usage + '''\
3682
3683 positional arguments:
3684 spam spam help
3685
3686 optional arguments:
3687 -h, --help show this help message and exit
3688 --foo FOO foo help
3689 '''
3690 version = ''
3691
3692
3693class TestHelpSuppressPositional(HelpTestCase):
3694 """Test that positional arguments can be suppressed in help messages"""
3695
3696 parser_signature = Sig(prog='PROG')
3697 argument_signatures = [
3698 Sig('--foo', help='foo help'),
3699 Sig('spam', help=argparse.SUPPRESS),
3700 ]
3701 argument_group_signatures = []
3702 usage = '''\
3703 usage: PROG [-h] [--foo FOO]
3704 '''
3705 help = usage + '''\
3706
3707 optional arguments:
3708 -h, --help show this help message and exit
3709 --foo FOO foo help
3710 '''
3711 version = ''
3712
3713
3714class TestHelpRequiredOptional(HelpTestCase):
3715 """Test that required options don't look optional"""
3716
3717 parser_signature = Sig(prog='PROG')
3718 argument_signatures = [
3719 Sig('--foo', required=True, help='foo help'),
3720 ]
3721 argument_group_signatures = []
3722 usage = '''\
3723 usage: PROG [-h] --foo FOO
3724 '''
3725 help = usage + '''\
3726
3727 optional arguments:
3728 -h, --help show this help message and exit
3729 --foo FOO foo help
3730 '''
3731 version = ''
3732
3733
3734class TestHelpAlternatePrefixChars(HelpTestCase):
3735 """Test that options display with different prefix characters"""
3736
3737 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3738 argument_signatures = [
3739 Sig('^^foo', action='store_true', help='foo help'),
3740 Sig(';b', ';;bar', help='bar help'),
3741 ]
3742 argument_group_signatures = []
3743 usage = '''\
3744 usage: PROG [^^foo] [;b BAR]
3745 '''
3746 help = usage + '''\
3747
3748 optional arguments:
3749 ^^foo foo help
3750 ;b BAR, ;;bar BAR bar help
3751 '''
3752 version = ''
3753
3754
3755class TestHelpNoHelpOptional(HelpTestCase):
3756 """Test that the --help argument can be suppressed help messages"""
3757
3758 parser_signature = Sig(prog='PROG', add_help=False)
3759 argument_signatures = [
3760 Sig('--foo', help='foo help'),
3761 Sig('spam', help='spam help'),
3762 ]
3763 argument_group_signatures = []
3764 usage = '''\
3765 usage: PROG [--foo FOO] spam
3766 '''
3767 help = usage + '''\
3768
3769 positional arguments:
3770 spam spam help
3771
3772 optional arguments:
3773 --foo FOO foo help
3774 '''
3775 version = ''
3776
3777
3778class TestHelpVersionOptional(HelpTestCase):
3779 """Test that the --version argument can be suppressed help messages"""
3780
3781 parser_signature = Sig(prog='PROG', version='1.0')
3782 argument_signatures = [
3783 Sig('--foo', help='foo help'),
3784 Sig('spam', help='spam help'),
3785 ]
3786 argument_group_signatures = []
3787 usage = '''\
3788 usage: PROG [-h] [-v] [--foo FOO] spam
3789 '''
3790 help = usage + '''\
3791
3792 positional arguments:
3793 spam spam help
3794
3795 optional arguments:
3796 -h, --help show this help message and exit
3797 -v, --version show program's version number and exit
3798 --foo FOO foo help
3799 '''
3800 version = '''\
3801 1.0
3802 '''
3803
3804
3805class TestHelpNone(HelpTestCase):
3806 """Test that no errors occur if no help is specified"""
3807
3808 parser_signature = Sig(prog='PROG')
3809 argument_signatures = [
3810 Sig('--foo'),
3811 Sig('spam'),
3812 ]
3813 argument_group_signatures = []
3814 usage = '''\
3815 usage: PROG [-h] [--foo FOO] spam
3816 '''
3817 help = usage + '''\
3818
3819 positional arguments:
3820 spam
3821
3822 optional arguments:
3823 -h, --help show this help message and exit
3824 --foo FOO
3825 '''
3826 version = ''
3827
3828
3829class TestHelpTupleMetavar(HelpTestCase):
3830 """Test specifying metavar as a tuple"""
3831
3832 parser_signature = Sig(prog='PROG')
3833 argument_signatures = [
3834 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3835 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3836 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3837 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3838 ]
3839 argument_group_signatures = []
3840 usage = '''\
3841 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3842[-z [Z1]]
3843 '''
3844 help = usage + '''\
3845
3846 optional arguments:
3847 -h, --help show this help message and exit
3848 -w W1 [W2 ...] w
3849 -x [X1 [X2 ...]] x
3850 -y Y1 Y2 Y3 y
3851 -z [Z1] z
3852 '''
3853 version = ''
3854
3855
3856class TestHelpRawText(HelpTestCase):
3857 """Test the RawTextHelpFormatter"""
3858
3859 parser_signature = Sig(
3860 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3861 description='Keep the formatting\n'
3862 ' exactly as it is written\n'
3863 '\n'
3864 'here\n')
3865
3866 argument_signatures = [
3867 Sig('--foo', help=' foo help should also\n'
3868 'appear as given here'),
3869 Sig('spam', help='spam help'),
3870 ]
3871 argument_group_signatures = [
3872 (Sig('title', description=' This text\n'
3873 ' should be indented\n'
3874 ' exactly like it is here\n'),
3875 [Sig('--bar', help='bar help')]),
3876 ]
3877 usage = '''\
3878 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3879 '''
3880 help = usage + '''\
3881
3882 Keep the formatting
3883 exactly as it is written
3884
3885 here
3886
3887 positional arguments:
3888 spam spam help
3889
3890 optional arguments:
3891 -h, --help show this help message and exit
3892 --foo FOO foo help should also
3893 appear as given here
3894
3895 title:
3896 This text
3897 should be indented
3898 exactly like it is here
3899
3900 --bar BAR bar help
3901 '''
3902 version = ''
3903
3904
3905class TestHelpRawDescription(HelpTestCase):
3906 """Test the RawTextHelpFormatter"""
3907
3908 parser_signature = Sig(
3909 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3910 description='Keep the formatting\n'
3911 ' exactly as it is written\n'
3912 '\n'
3913 'here\n')
3914
3915 argument_signatures = [
3916 Sig('--foo', help=' foo help should not\n'
3917 ' retain this odd formatting'),
3918 Sig('spam', help='spam help'),
3919 ]
3920 argument_group_signatures = [
3921 (Sig('title', description=' This text\n'
3922 ' should be indented\n'
3923 ' exactly like it is here\n'),
3924 [Sig('--bar', help='bar help')]),
3925 ]
3926 usage = '''\
3927 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3928 '''
3929 help = usage + '''\
3930
3931 Keep the formatting
3932 exactly as it is written
3933
3934 here
3935
3936 positional arguments:
3937 spam spam help
3938
3939 optional arguments:
3940 -h, --help show this help message and exit
3941 --foo FOO foo help should not retain this odd formatting
3942
3943 title:
3944 This text
3945 should be indented
3946 exactly like it is here
3947
3948 --bar BAR bar help
3949 '''
3950 version = ''
3951
3952
3953class TestHelpArgumentDefaults(HelpTestCase):
3954 """Test the ArgumentDefaultsHelpFormatter"""
3955
3956 parser_signature = Sig(
3957 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3958 description='description')
3959
3960 argument_signatures = [
3961 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3962 Sig('--bar', action='store_true', help='bar help'),
3963 Sig('spam', help='spam help'),
3964 Sig('badger', nargs='?', default='wooden', help='badger help'),
3965 ]
3966 argument_group_signatures = [
3967 (Sig('title', description='description'),
3968 [Sig('--baz', type=int, default=42, help='baz help')]),
3969 ]
3970 usage = '''\
3971 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3972 '''
3973 help = usage + '''\
3974
3975 description
3976
3977 positional arguments:
3978 spam spam help
3979 badger badger help (default: wooden)
3980
3981 optional arguments:
3982 -h, --help show this help message and exit
3983 --foo FOO foo help - oh and by the way, None
3984 --bar bar help (default: False)
3985
3986 title:
3987 description
3988
3989 --baz BAZ baz help (default: 42)
3990 '''
3991 version = ''
3992
Steven Betharddce6e1b2010-05-24 03:45:26 +00003993class TestHelpVersionAction(HelpTestCase):
3994 """Test the default help for the version action"""
3995
3996 parser_signature = Sig(prog='PROG', description='description')
3997 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3998 argument_group_signatures = []
3999 usage = '''\
4000 usage: PROG [-h] [-V]
4001 '''
4002 help = usage + '''\
4003
4004 description
4005
4006 optional arguments:
4007 -h, --help show this help message and exit
4008 -V, --version show program's version number and exit
4009 '''
4010 version = ''
4011
Steven Bethardbc3b1042011-03-27 13:57:55 +02004012class TestHelpSubparsersOrdering(HelpTestCase):
4013 """Test ordering of subcommands in help matches the code"""
4014 parser_signature = Sig(prog='PROG',
4015 description='display some subcommands',
4016 version='0.1')
4017
4018 subparsers_signatures = [Sig(name=name)
4019 for name in ('a', 'b', 'c', 'd', 'e')]
4020
4021 usage = '''\
4022 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4023 '''
4024
4025 help = usage + '''\
4026
4027 display some subcommands
4028
4029 positional arguments:
4030 {a,b,c,d,e}
4031
4032 optional arguments:
4033 -h, --help show this help message and exit
4034 -v, --version show program's version number and exit
4035 '''
4036
4037 version = '''\
4038 0.1
4039 '''
4040
4041class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4042 """Test ordering of subcommands in help matches the code"""
4043 parser_signature = Sig(prog='PROG',
4044 description='display some subcommands',
4045 version='0.1')
4046
4047 subcommand_data = (('a', 'a subcommand help'),
4048 ('b', 'b subcommand help'),
4049 ('c', 'c subcommand help'),
4050 ('d', 'd subcommand help'),
4051 ('e', 'e subcommand help'),
4052 )
4053
4054 subparsers_signatures = [Sig(name=name, help=help)
4055 for name, help in subcommand_data]
4056
4057 usage = '''\
4058 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4059 '''
4060
4061 help = usage + '''\
4062
4063 display some subcommands
4064
4065 positional arguments:
4066 {a,b,c,d,e}
4067 a a subcommand help
4068 b b subcommand help
4069 c c subcommand help
4070 d d subcommand help
4071 e e subcommand help
4072
4073 optional arguments:
4074 -h, --help show this help message and exit
4075 -v, --version show program's version number and exit
4076 '''
4077
4078 version = '''\
4079 0.1
4080 '''
4081
4082
Benjamin Petersona39e9662010-03-02 22:05:59 +00004083# =====================================
4084# Optional/Positional constructor tests
4085# =====================================
4086
4087class TestInvalidArgumentConstructors(TestCase):
4088 """Test a bunch of invalid Argument constructors"""
4089
4090 def assertTypeError(self, *args, **kwargs):
4091 parser = argparse.ArgumentParser()
4092 self.assertRaises(TypeError, parser.add_argument,
4093 *args, **kwargs)
4094
4095 def assertValueError(self, *args, **kwargs):
4096 parser = argparse.ArgumentParser()
4097 self.assertRaises(ValueError, parser.add_argument,
4098 *args, **kwargs)
4099
4100 def test_invalid_keyword_arguments(self):
4101 self.assertTypeError('-x', bar=None)
4102 self.assertTypeError('-y', callback='foo')
4103 self.assertTypeError('-y', callback_args=())
4104 self.assertTypeError('-y', callback_kwargs={})
4105
4106 def test_missing_destination(self):
4107 self.assertTypeError()
4108 for action in ['append', 'store']:
4109 self.assertTypeError(action=action)
4110
4111 def test_invalid_option_strings(self):
4112 self.assertValueError('--')
4113 self.assertValueError('---')
4114
4115 def test_invalid_type(self):
4116 self.assertValueError('--foo', type='int')
Steven Betharde3c11b42011-04-04 01:47:52 +02004117 self.assertValueError('--foo', type=(int, float))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004118
4119 def test_invalid_action(self):
4120 self.assertValueError('-x', action='foo')
4121 self.assertValueError('foo', action='baz')
Steven Betharde3c11b42011-04-04 01:47:52 +02004122 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004123 parser = argparse.ArgumentParser()
4124 try:
4125 parser.add_argument("--foo", action="store-true")
4126 except ValueError:
4127 e = sys.exc_info()[1]
4128 expected = 'unknown action'
4129 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004130 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004131
4132 def test_multiple_dest(self):
4133 parser = argparse.ArgumentParser()
4134 parser.add_argument(dest='foo')
4135 try:
4136 parser.add_argument('bar', dest='baz')
4137 except ValueError:
4138 e = sys.exc_info()[1]
4139 expected = 'dest supplied twice for positional argument'
4140 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004141 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004142
4143 def test_no_argument_actions(self):
4144 for action in ['store_const', 'store_true', 'store_false',
4145 'append_const', 'count']:
4146 for attrs in [dict(type=int), dict(nargs='+'),
4147 dict(choices='ab')]:
4148 self.assertTypeError('-x', action=action, **attrs)
4149
4150 def test_no_argument_no_const_actions(self):
4151 # options with zero arguments
4152 for action in ['store_true', 'store_false', 'count']:
4153
4154 # const is always disallowed
4155 self.assertTypeError('-x', const='foo', action=action)
4156
4157 # nargs is always disallowed
4158 self.assertTypeError('-x', nargs='*', action=action)
4159
4160 def test_more_than_one_argument_actions(self):
4161 for action in ['store', 'append']:
4162
4163 # nargs=0 is disallowed
4164 self.assertValueError('-x', nargs=0, action=action)
4165 self.assertValueError('spam', nargs=0, action=action)
4166
4167 # const is disallowed with non-optional arguments
4168 for nargs in [1, '*', '+']:
4169 self.assertValueError('-x', const='foo',
4170 nargs=nargs, action=action)
4171 self.assertValueError('spam', const='foo',
4172 nargs=nargs, action=action)
4173
4174 def test_required_const_actions(self):
4175 for action in ['store_const', 'append_const']:
4176
4177 # nargs is always disallowed
4178 self.assertTypeError('-x', nargs='+', action=action)
4179
4180 def test_parsers_action_missing_params(self):
4181 self.assertTypeError('command', action='parsers')
4182 self.assertTypeError('command', action='parsers', prog='PROG')
4183 self.assertTypeError('command', action='parsers',
4184 parser_class=argparse.ArgumentParser)
4185
4186 def test_required_positional(self):
4187 self.assertTypeError('foo', required=True)
4188
4189 def test_user_defined_action(self):
4190
4191 class Success(Exception):
4192 pass
4193
4194 class Action(object):
4195
4196 def __init__(self,
4197 option_strings,
4198 dest,
4199 const,
4200 default,
4201 required=False):
4202 if dest == 'spam':
4203 if const is Success:
4204 if default is Success:
4205 raise Success()
4206
4207 def __call__(self, *args, **kwargs):
4208 pass
4209
4210 parser = argparse.ArgumentParser()
4211 self.assertRaises(Success, parser.add_argument, '--spam',
4212 action=Action, default=Success, const=Success)
4213 self.assertRaises(Success, parser.add_argument, 'spam',
4214 action=Action, default=Success, const=Success)
4215
4216# ================================
4217# Actions returned by add_argument
4218# ================================
4219
4220class TestActionsReturned(TestCase):
4221
4222 def test_dest(self):
4223 parser = argparse.ArgumentParser()
4224 action = parser.add_argument('--foo')
4225 self.assertEqual(action.dest, 'foo')
4226 action = parser.add_argument('-b', '--bar')
4227 self.assertEqual(action.dest, 'bar')
4228 action = parser.add_argument('-x', '-y')
4229 self.assertEqual(action.dest, 'x')
4230
4231 def test_misc(self):
4232 parser = argparse.ArgumentParser()
4233 action = parser.add_argument('--foo', nargs='?', const=42,
4234 default=84, type=int, choices=[1, 2],
4235 help='FOO', metavar='BAR', dest='baz')
4236 self.assertEqual(action.nargs, '?')
4237 self.assertEqual(action.const, 42)
4238 self.assertEqual(action.default, 84)
4239 self.assertEqual(action.type, int)
4240 self.assertEqual(action.choices, [1, 2])
4241 self.assertEqual(action.help, 'FOO')
4242 self.assertEqual(action.metavar, 'BAR')
4243 self.assertEqual(action.dest, 'baz')
4244
4245
4246# ================================
4247# Argument conflict handling tests
4248# ================================
4249
4250class TestConflictHandling(TestCase):
4251
4252 def test_bad_type(self):
4253 self.assertRaises(ValueError, argparse.ArgumentParser,
4254 conflict_handler='foo')
4255
4256 def test_conflict_error(self):
4257 parser = argparse.ArgumentParser()
4258 parser.add_argument('-x')
4259 self.assertRaises(argparse.ArgumentError,
4260 parser.add_argument, '-x')
4261 parser.add_argument('--spam')
4262 self.assertRaises(argparse.ArgumentError,
4263 parser.add_argument, '--spam')
4264
4265 def test_resolve_error(self):
4266 get_parser = argparse.ArgumentParser
4267 parser = get_parser(prog='PROG', conflict_handler='resolve')
4268
4269 parser.add_argument('-x', help='OLD X')
4270 parser.add_argument('-x', help='NEW X')
4271 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4272 usage: PROG [-h] [-x X]
4273
4274 optional arguments:
4275 -h, --help show this help message and exit
4276 -x X NEW X
4277 '''))
4278
4279 parser.add_argument('--spam', metavar='OLD_SPAM')
4280 parser.add_argument('--spam', metavar='NEW_SPAM')
4281 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4282 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4283
4284 optional arguments:
4285 -h, --help show this help message and exit
4286 -x X NEW X
4287 --spam NEW_SPAM
4288 '''))
4289
4290
4291# =============================
4292# Help and Version option tests
4293# =============================
4294
4295class TestOptionalsHelpVersionActions(TestCase):
4296 """Test the help and version actions"""
4297
4298 def _get_error(self, func, *args, **kwargs):
4299 try:
4300 func(*args, **kwargs)
4301 except ArgumentParserError:
4302 return sys.exc_info()[1]
4303 else:
4304 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4305
4306 def assertPrintHelpExit(self, parser, args_str):
4307 self.assertEqual(
4308 parser.format_help(),
4309 self._get_error(parser.parse_args, args_str.split()).stdout)
4310
4311 def assertPrintVersionExit(self, parser, args_str):
4312 self.assertEqual(
4313 parser.format_version(),
4314 self._get_error(parser.parse_args, args_str.split()).stderr)
4315
4316 def assertArgumentParserError(self, parser, *args):
4317 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4318
4319 def test_version(self):
4320 parser = ErrorRaisingArgumentParser(version='1.0')
4321 self.assertPrintHelpExit(parser, '-h')
4322 self.assertPrintHelpExit(parser, '--help')
4323 self.assertPrintVersionExit(parser, '-v')
4324 self.assertPrintVersionExit(parser, '--version')
4325
4326 def test_version_format(self):
4327 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4328 msg = self._get_error(parser.parse_args, ['-v']).stderr
4329 self.assertEqual('PPP 3.5\n', msg)
4330
4331 def test_version_no_help(self):
4332 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4333 self.assertArgumentParserError(parser, '-h')
4334 self.assertArgumentParserError(parser, '--help')
4335 self.assertPrintVersionExit(parser, '-v')
4336 self.assertPrintVersionExit(parser, '--version')
4337
4338 def test_version_action(self):
4339 parser = ErrorRaisingArgumentParser(prog='XXX')
4340 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4341 msg = self._get_error(parser.parse_args, ['-V']).stderr
4342 self.assertEqual('XXX 3.7\n', msg)
4343
4344 def test_no_help(self):
4345 parser = ErrorRaisingArgumentParser(add_help=False)
4346 self.assertArgumentParserError(parser, '-h')
4347 self.assertArgumentParserError(parser, '--help')
4348 self.assertArgumentParserError(parser, '-v')
4349 self.assertArgumentParserError(parser, '--version')
4350
4351 def test_alternate_help_version(self):
4352 parser = ErrorRaisingArgumentParser()
4353 parser.add_argument('-x', action='help')
4354 parser.add_argument('-y', action='version')
4355 self.assertPrintHelpExit(parser, '-x')
4356 self.assertPrintVersionExit(parser, '-y')
4357 self.assertArgumentParserError(parser, '-v')
4358 self.assertArgumentParserError(parser, '--version')
4359
4360 def test_help_version_extra_arguments(self):
4361 parser = ErrorRaisingArgumentParser(version='1.0')
4362 parser.add_argument('-x', action='store_true')
4363 parser.add_argument('y')
4364
4365 # try all combinations of valid prefixes and suffixes
4366 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4367 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4368 for prefix in valid_prefixes:
4369 for suffix in valid_suffixes:
4370 format = '%s %%s %s' % (prefix, suffix)
4371 self.assertPrintHelpExit(parser, format % '-h')
4372 self.assertPrintHelpExit(parser, format % '--help')
4373 self.assertPrintVersionExit(parser, format % '-v')
4374 self.assertPrintVersionExit(parser, format % '--version')
4375
4376
4377# ======================
4378# str() and repr() tests
4379# ======================
4380
4381class TestStrings(TestCase):
4382 """Test str() and repr() on Optionals and Positionals"""
4383
4384 def assertStringEqual(self, obj, result_string):
4385 for func in [str, repr]:
4386 self.assertEqual(func(obj), result_string)
4387
4388 def test_optional(self):
4389 option = argparse.Action(
4390 option_strings=['--foo', '-a', '-b'],
4391 dest='b',
4392 type='int',
4393 nargs='+',
4394 default=42,
4395 choices=[1, 2, 3],
4396 help='HELP',
4397 metavar='METAVAR')
4398 string = (
4399 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4400 "nargs='+', const=None, default=42, type='int', "
4401 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4402 self.assertStringEqual(option, string)
4403
4404 def test_argument(self):
4405 argument = argparse.Action(
4406 option_strings=[],
4407 dest='x',
4408 type=float,
4409 nargs='?',
4410 default=2.5,
4411 choices=[0.5, 1.5, 2.5],
4412 help='H HH H',
4413 metavar='MV MV MV')
4414 string = (
4415 "Action(option_strings=[], dest='x', nargs='?', "
4416 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4417 "help='H HH H', metavar='MV MV MV')" % float)
4418 self.assertStringEqual(argument, string)
4419
4420 def test_namespace(self):
4421 ns = argparse.Namespace(foo=42, bar='spam')
4422 string = "Namespace(bar='spam', foo=42)"
4423 self.assertStringEqual(ns, string)
4424
4425 def test_parser(self):
4426 parser = argparse.ArgumentParser(prog='PROG')
4427 string = (
4428 "ArgumentParser(prog='PROG', usage=None, description=None, "
4429 "version=None, formatter_class=%r, conflict_handler='error', "
4430 "add_help=True)" % argparse.HelpFormatter)
4431 self.assertStringEqual(parser, string)
4432
4433# ===============
4434# Namespace tests
4435# ===============
4436
4437class TestNamespace(TestCase):
4438
4439 def test_constructor(self):
4440 ns = argparse.Namespace()
4441 self.assertRaises(AttributeError, getattr, ns, 'x')
4442
4443 ns = argparse.Namespace(a=42, b='spam')
4444 self.assertEqual(ns.a, 42)
4445 self.assertEqual(ns.b, 'spam')
4446
4447 def test_equality(self):
4448 ns1 = argparse.Namespace(a=1, b=2)
4449 ns2 = argparse.Namespace(b=2, a=1)
4450 ns3 = argparse.Namespace(a=1)
4451 ns4 = argparse.Namespace(b=2)
4452
4453 self.assertEqual(ns1, ns2)
4454 self.assertNotEqual(ns1, ns3)
4455 self.assertNotEqual(ns1, ns4)
4456 self.assertNotEqual(ns2, ns3)
4457 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004458 self.assertTrue(ns1 != ns3)
4459 self.assertTrue(ns1 != ns4)
4460 self.assertTrue(ns2 != ns3)
4461 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004462
Raymond Hettingerfb8899a2014-05-26 00:40:09 -07004463 def test_equality_returns_notimplemeted(self):
4464 # See issue 21481
4465 ns = argparse.Namespace(a=1, b=2)
4466 self.assertIs(ns.__eq__(None), NotImplemented)
4467 self.assertIs(ns.__ne__(None), NotImplemented)
4468
Benjamin Petersona39e9662010-03-02 22:05:59 +00004469
4470# ===================
4471# File encoding tests
4472# ===================
4473
4474class TestEncoding(TestCase):
4475
4476 def _test_module_encoding(self, path):
4477 path, _ = os.path.splitext(path)
4478 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004479 with codecs.open(path, 'r', 'utf8') as f:
4480 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004481
4482 def test_argparse_module_encoding(self):
4483 self._test_module_encoding(argparse.__file__)
4484
4485 def test_test_argparse_module_encoding(self):
4486 self._test_module_encoding(__file__)
4487
4488# ===================
4489# ArgumentError tests
4490# ===================
4491
4492class TestArgumentError(TestCase):
4493
4494 def test_argument_error(self):
4495 msg = "my error here"
4496 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004497 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004498
4499# =======================
4500# ArgumentTypeError tests
4501# =======================
4502
R. David Murray561b96f2011-02-11 17:25:54 +00004503class TestArgumentTypeError(TestCase):
Benjamin Petersona39e9662010-03-02 22:05:59 +00004504
4505 def test_argument_type_error(self):
4506
4507 def spam(string):
4508 raise argparse.ArgumentTypeError('spam!')
4509
4510 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4511 parser.add_argument('x', type=spam)
4512 try:
4513 parser.parse_args(['XXX'])
4514 except ArgumentParserError:
4515 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4516 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004517 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004518 else:
4519 self.fail()
4520
R David Murray20101872012-08-31 23:15:28 -04004521# ================================================
4522# Check that the type function is called only once
4523# ================================================
4524
4525class TestTypeFunctionCallOnlyOnce(TestCase):
4526
4527 def test_type_function_call_only_once(self):
4528 def spam(string_to_convert):
4529 self.assertEqual(string_to_convert, 'spam!')
4530 return 'foo_converted'
4531
4532 parser = argparse.ArgumentParser()
4533 parser.add_argument('--foo', type=spam, default='bar')
4534 args = parser.parse_args('--foo spam!'.split())
4535 self.assertEqual(NS(foo='foo_converted'), args)
4536
Barry Warsaw03937a82012-09-12 14:34:50 -04004537# ==================================================================
4538# Check semantics regarding the default argument and type conversion
4539# ==================================================================
R David Murray20101872012-08-31 23:15:28 -04004540
Barry Warsaw03937a82012-09-12 14:34:50 -04004541class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray20101872012-08-31 23:15:28 -04004542
4543 def test_type_function_call_with_non_string_default(self):
4544 def spam(int_to_convert):
4545 self.assertEqual(int_to_convert, 0)
4546 return 'foo_converted'
4547
4548 parser = argparse.ArgumentParser()
4549 parser.add_argument('--foo', type=spam, default=0)
4550 args = parser.parse_args([])
Barry Warsaw03937a82012-09-12 14:34:50 -04004551 # foo should *not* be converted because its default is not a string.
4552 self.assertEqual(NS(foo=0), args)
4553
4554 def test_type_function_call_with_string_default(self):
4555 def spam(int_to_convert):
4556 return 'foo_converted'
4557
4558 parser = argparse.ArgumentParser()
4559 parser.add_argument('--foo', type=spam, default='0')
4560 args = parser.parse_args([])
4561 # foo is converted because its default is a string.
R David Murray20101872012-08-31 23:15:28 -04004562 self.assertEqual(NS(foo='foo_converted'), args)
4563
Barry Warsaw03937a82012-09-12 14:34:50 -04004564 def test_no_double_type_conversion_of_default(self):
4565 def extend(str_to_convert):
4566 return str_to_convert + '*'
4567
4568 parser = argparse.ArgumentParser()
4569 parser.add_argument('--test', type=extend, default='*')
4570 args = parser.parse_args([])
4571 # The test argument will be two stars, one coming from the default
4572 # value and one coming from the type conversion being called exactly
4573 # once.
4574 self.assertEqual(NS(test='**'), args)
4575
Barry Warsaw03fcfbe2012-09-11 21:06:29 -04004576 def test_issue_15906(self):
4577 # Issue #15906: When action='append', type=str, default=[] are
4578 # providing, the dest value was the string representation "[]" when it
4579 # should have been an empty list.
4580 parser = argparse.ArgumentParser()
4581 parser.add_argument('--test', dest='test', type=str,
4582 default=[], action='append')
4583 args = parser.parse_args([])
4584 self.assertEqual(args.test, [])
4585
Benjamin Petersona39e9662010-03-02 22:05:59 +00004586# ======================
4587# parse_known_args tests
4588# ======================
4589
4590class TestParseKnownArgs(TestCase):
4591
R David Murraya99c7de2012-09-08 12:15:25 -04004592 def test_arguments_tuple(self):
4593 parser = argparse.ArgumentParser()
4594 parser.parse_args(())
4595
4596 def test_arguments_list(self):
4597 parser = argparse.ArgumentParser()
4598 parser.parse_args([])
4599
4600 def test_arguments_tuple_positional(self):
4601 parser = argparse.ArgumentParser()
4602 parser.add_argument('x')
4603 parser.parse_args(('x',))
4604
4605 def test_arguments_list_positional(self):
4606 parser = argparse.ArgumentParser()
4607 parser.add_argument('x')
4608 parser.parse_args(['x'])
4609
Benjamin Petersona39e9662010-03-02 22:05:59 +00004610 def test_optionals(self):
4611 parser = argparse.ArgumentParser()
4612 parser.add_argument('--foo')
4613 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004614 self.assertEqual(NS(foo='F'), args)
4615 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004616
4617 def test_mixed(self):
4618 parser = argparse.ArgumentParser()
4619 parser.add_argument('-v', nargs='?', const=1, type=int)
4620 parser.add_argument('--spam', action='store_false')
4621 parser.add_argument('badger')
4622
4623 argv = ["B", "C", "--foo", "-v", "3", "4"]
4624 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004625 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4626 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004627
Steven Bethard53958622011-03-26 17:57:52 +01004628# ==========================
4629# add_argument metavar tests
4630# ==========================
4631
4632class TestAddArgumentMetavar(TestCase):
4633
4634 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4635
4636 def do_test_no_exception(self, nargs, metavar):
4637 parser = argparse.ArgumentParser()
4638 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4639
4640 def do_test_exception(self, nargs, metavar):
4641 parser = argparse.ArgumentParser()
4642 with self.assertRaises(ValueError) as cm:
4643 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4644 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4645
4646 # Unit tests for different values of metavar when nargs=None
4647
4648 def test_nargs_None_metavar_string(self):
4649 self.do_test_no_exception(nargs=None, metavar="1")
4650
4651 def test_nargs_None_metavar_length0(self):
4652 self.do_test_exception(nargs=None, metavar=tuple())
4653
4654 def test_nargs_None_metavar_length1(self):
4655 self.do_test_no_exception(nargs=None, metavar=("1"))
4656
4657 def test_nargs_None_metavar_length2(self):
4658 self.do_test_exception(nargs=None, metavar=("1", "2"))
4659
4660 def test_nargs_None_metavar_length3(self):
4661 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4662
4663 # Unit tests for different values of metavar when nargs=?
4664
4665 def test_nargs_optional_metavar_string(self):
4666 self.do_test_no_exception(nargs="?", metavar="1")
4667
4668 def test_nargs_optional_metavar_length0(self):
4669 self.do_test_exception(nargs="?", metavar=tuple())
4670
4671 def test_nargs_optional_metavar_length1(self):
4672 self.do_test_no_exception(nargs="?", metavar=("1"))
4673
4674 def test_nargs_optional_metavar_length2(self):
4675 self.do_test_exception(nargs="?", metavar=("1", "2"))
4676
4677 def test_nargs_optional_metavar_length3(self):
4678 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4679
4680 # Unit tests for different values of metavar when nargs=*
4681
4682 def test_nargs_zeroormore_metavar_string(self):
4683 self.do_test_no_exception(nargs="*", metavar="1")
4684
4685 def test_nargs_zeroormore_metavar_length0(self):
4686 self.do_test_exception(nargs="*", metavar=tuple())
4687
4688 def test_nargs_zeroormore_metavar_length1(self):
4689 self.do_test_no_exception(nargs="*", metavar=("1"))
4690
4691 def test_nargs_zeroormore_metavar_length2(self):
4692 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4693
4694 def test_nargs_zeroormore_metavar_length3(self):
4695 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4696
4697 # Unit tests for different values of metavar when nargs=+
4698
4699 def test_nargs_oneormore_metavar_string(self):
4700 self.do_test_no_exception(nargs="+", metavar="1")
4701
4702 def test_nargs_oneormore_metavar_length0(self):
4703 self.do_test_exception(nargs="+", metavar=tuple())
4704
4705 def test_nargs_oneormore_metavar_length1(self):
4706 self.do_test_no_exception(nargs="+", metavar=("1"))
4707
4708 def test_nargs_oneormore_metavar_length2(self):
4709 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4710
4711 def test_nargs_oneormore_metavar_length3(self):
4712 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4713
4714 # Unit tests for different values of metavar when nargs=...
4715
4716 def test_nargs_remainder_metavar_string(self):
4717 self.do_test_no_exception(nargs="...", metavar="1")
4718
4719 def test_nargs_remainder_metavar_length0(self):
4720 self.do_test_no_exception(nargs="...", metavar=tuple())
4721
4722 def test_nargs_remainder_metavar_length1(self):
4723 self.do_test_no_exception(nargs="...", metavar=("1"))
4724
4725 def test_nargs_remainder_metavar_length2(self):
4726 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4727
4728 def test_nargs_remainder_metavar_length3(self):
4729 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4730
4731 # Unit tests for different values of metavar when nargs=A...
4732
4733 def test_nargs_parser_metavar_string(self):
4734 self.do_test_no_exception(nargs="A...", metavar="1")
4735
4736 def test_nargs_parser_metavar_length0(self):
4737 self.do_test_exception(nargs="A...", metavar=tuple())
4738
4739 def test_nargs_parser_metavar_length1(self):
4740 self.do_test_no_exception(nargs="A...", metavar=("1"))
4741
4742 def test_nargs_parser_metavar_length2(self):
4743 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4744
4745 def test_nargs_parser_metavar_length3(self):
4746 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4747
4748 # Unit tests for different values of metavar when nargs=1
4749
4750 def test_nargs_1_metavar_string(self):
4751 self.do_test_no_exception(nargs=1, metavar="1")
4752
4753 def test_nargs_1_metavar_length0(self):
4754 self.do_test_exception(nargs=1, metavar=tuple())
4755
4756 def test_nargs_1_metavar_length1(self):
4757 self.do_test_no_exception(nargs=1, metavar=("1"))
4758
4759 def test_nargs_1_metavar_length2(self):
4760 self.do_test_exception(nargs=1, metavar=("1", "2"))
4761
4762 def test_nargs_1_metavar_length3(self):
4763 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4764
4765 # Unit tests for different values of metavar when nargs=2
4766
4767 def test_nargs_2_metavar_string(self):
4768 self.do_test_no_exception(nargs=2, metavar="1")
4769
4770 def test_nargs_2_metavar_length0(self):
4771 self.do_test_exception(nargs=2, metavar=tuple())
4772
4773 def test_nargs_2_metavar_length1(self):
4774 self.do_test_no_exception(nargs=2, metavar=("1"))
4775
4776 def test_nargs_2_metavar_length2(self):
4777 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4778
4779 def test_nargs_2_metavar_length3(self):
4780 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4781
4782 # Unit tests for different values of metavar when nargs=3
4783
4784 def test_nargs_3_metavar_string(self):
4785 self.do_test_no_exception(nargs=3, metavar="1")
4786
4787 def test_nargs_3_metavar_length0(self):
4788 self.do_test_exception(nargs=3, metavar=tuple())
4789
4790 def test_nargs_3_metavar_length1(self):
4791 self.do_test_no_exception(nargs=3, metavar=("1"))
4792
4793 def test_nargs_3_metavar_length2(self):
4794 self.do_test_exception(nargs=3, metavar=("1", "2"))
4795
4796 def test_nargs_3_metavar_length3(self):
4797 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4798
Benjamin Petersona39e9662010-03-02 22:05:59 +00004799# ============================
4800# from argparse import * tests
4801# ============================
4802
4803class TestImportStar(TestCase):
4804
4805 def test(self):
4806 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004807 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004808
Steven Bethard931906a2010-11-01 15:24:42 +00004809 def test_all_exports_everything_but_modules(self):
4810 items = [
4811 name
4812 for name, value in vars(argparse).items()
4813 if not name.startswith("_")
4814 if not inspect.ismodule(value)
4815 ]
4816 self.assertEqual(sorted(items), sorted(argparse.__all__))
4817
Benjamin Peterson036fae32010-03-02 22:20:10 +00004818def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004819 # silence warnings about version argument - these are expected
4820 with test_support.check_warnings(
4821 ('The "version" argument to ArgumentParser is deprecated.',
4822 DeprecationWarning),
4823 ('The (format|print)_version method is deprecated',
4824 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004825 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004826 # Remove global references to avoid looking like we have refleaks.
4827 RFile.seen = {}
4828 WFile.seen = set()
4829
Benjamin Peterson036fae32010-03-02 22:20:10 +00004830
Benjamin Petersona39e9662010-03-02 22:05:59 +00004831
4832if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004833 test_main()