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