blob: 1a5f05e30b9fab993609463fb693b4ab0ad59bc1 [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()
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002138 progname = self.main_program
Benjamin Petersona39e9662010-03-02 22:05:59 +00002139 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002140 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Petersona39e9662010-03-02 22:05:59 +00002141
2142 positional arguments:
2143 a
2144 z
2145
2146 optional arguments:
2147 -h, --help show this help message and exit
2148 -b B
2149 --w W
2150
2151 c:
2152 --d D
2153
2154 x:
2155 -y Y
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002156 '''.format(progname, ' ' if progname else '' )))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002157
2158 def test_groups_parents(self):
2159 parent = ErrorRaisingArgumentParser(add_help=False)
2160 g = parent.add_argument_group(title='g', description='gd')
2161 g.add_argument('-w')
2162 g.add_argument('-x')
2163 m = parent.add_mutually_exclusive_group()
2164 m.add_argument('-y')
2165 m.add_argument('-z')
2166 parser = ErrorRaisingArgumentParser(parents=[parent])
2167
2168 self.assertRaises(ArgumentParserError, parser.parse_args,
2169 ['-y', 'Y', '-z', 'Z'])
2170
2171 parser_help = parser.format_help()
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002172 progname = self.main_program
Benjamin Petersona39e9662010-03-02 22:05:59 +00002173 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002174 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Petersona39e9662010-03-02 22:05:59 +00002175
2176 optional arguments:
2177 -h, --help show this help message and exit
2178 -y Y
2179 -z Z
2180
2181 g:
2182 gd
2183
2184 -w W
2185 -x X
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002186 '''.format(progname, ' ' if progname else '' )))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002187
2188# ==============================
2189# Mutually exclusive group tests
2190# ==============================
2191
2192class TestMutuallyExclusiveGroupErrors(TestCase):
2193
2194 def test_invalid_add_argument_group(self):
2195 parser = ErrorRaisingArgumentParser()
2196 raises = self.assertRaises
2197 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2198
2199 def test_invalid_add_argument(self):
2200 parser = ErrorRaisingArgumentParser()
2201 group = parser.add_mutually_exclusive_group()
2202 add_argument = group.add_argument
2203 raises = self.assertRaises
2204 raises(ValueError, add_argument, '--foo', required=True)
2205 raises(ValueError, add_argument, 'bar')
2206 raises(ValueError, add_argument, 'bar', nargs='+')
2207 raises(ValueError, add_argument, 'bar', nargs=1)
2208 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2209
Steven Bethard68c36782010-11-01 16:30:24 +00002210 def test_help(self):
2211 parser = ErrorRaisingArgumentParser(prog='PROG')
2212 group1 = parser.add_mutually_exclusive_group()
2213 group1.add_argument('--foo', action='store_true')
2214 group1.add_argument('--bar', action='store_false')
2215 group2 = parser.add_mutually_exclusive_group()
2216 group2.add_argument('--soup', action='store_true')
2217 group2.add_argument('--nuts', action='store_false')
2218 expected = '''\
2219 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2220
2221 optional arguments:
2222 -h, --help show this help message and exit
2223 --foo
2224 --bar
2225 --soup
2226 --nuts
2227 '''
2228 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002229
2230class MEMixin(object):
2231
2232 def test_failures_when_not_required(self):
2233 parse_args = self.get_parser(required=False).parse_args
2234 error = ArgumentParserError
2235 for args_string in self.failures:
2236 self.assertRaises(error, parse_args, args_string.split())
2237
2238 def test_failures_when_required(self):
2239 parse_args = self.get_parser(required=True).parse_args
2240 error = ArgumentParserError
2241 for args_string in self.failures + ['']:
2242 self.assertRaises(error, parse_args, args_string.split())
2243
2244 def test_successes_when_not_required(self):
2245 parse_args = self.get_parser(required=False).parse_args
2246 successes = self.successes + self.successes_when_not_required
2247 for args_string, expected_ns in successes:
2248 actual_ns = parse_args(args_string.split())
2249 self.assertEqual(actual_ns, expected_ns)
2250
2251 def test_successes_when_required(self):
2252 parse_args = self.get_parser(required=True).parse_args
2253 for args_string, expected_ns in self.successes:
2254 actual_ns = parse_args(args_string.split())
2255 self.assertEqual(actual_ns, expected_ns)
2256
2257 def test_usage_when_not_required(self):
2258 format_usage = self.get_parser(required=False).format_usage
2259 expected_usage = self.usage_when_not_required
2260 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2261
2262 def test_usage_when_required(self):
2263 format_usage = self.get_parser(required=True).format_usage
2264 expected_usage = self.usage_when_required
2265 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2266
2267 def test_help_when_not_required(self):
2268 format_help = self.get_parser(required=False).format_help
2269 help = self.usage_when_not_required + self.help
2270 self.assertEqual(format_help(), textwrap.dedent(help))
2271
2272 def test_help_when_required(self):
2273 format_help = self.get_parser(required=True).format_help
2274 help = self.usage_when_required + self.help
2275 self.assertEqual(format_help(), textwrap.dedent(help))
2276
2277
2278class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2279
2280 def get_parser(self, required=None):
2281 parser = ErrorRaisingArgumentParser(prog='PROG')
2282 group = parser.add_mutually_exclusive_group(required=required)
2283 group.add_argument('--bar', help='bar help')
2284 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2285 return parser
2286
2287 failures = ['--bar X --baz Y', '--bar X --baz']
2288 successes = [
2289 ('--bar X', NS(bar='X', baz=None)),
2290 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2291 ('--baz Y', NS(bar=None, baz='Y')),
2292 ('--baz', NS(bar=None, baz='Z')),
2293 ]
2294 successes_when_not_required = [
2295 ('', NS(bar=None, baz=None)),
2296 ]
2297
2298 usage_when_not_required = '''\
2299 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2300 '''
2301 usage_when_required = '''\
2302 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2303 '''
2304 help = '''\
2305
2306 optional arguments:
2307 -h, --help show this help message and exit
2308 --bar BAR bar help
2309 --baz [BAZ] baz help
2310 '''
2311
2312
2313class TestMutuallyExclusiveLong(MEMixin, TestCase):
2314
2315 def get_parser(self, required=None):
2316 parser = ErrorRaisingArgumentParser(prog='PROG')
2317 parser.add_argument('--abcde', help='abcde help')
2318 parser.add_argument('--fghij', help='fghij help')
2319 group = parser.add_mutually_exclusive_group(required=required)
2320 group.add_argument('--klmno', help='klmno help')
2321 group.add_argument('--pqrst', help='pqrst help')
2322 return parser
2323
2324 failures = ['--klmno X --pqrst Y']
2325 successes = [
2326 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2327 ('--abcde Y --klmno X',
2328 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2329 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2330 ('--pqrst X --fghij Y',
2331 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2332 ]
2333 successes_when_not_required = [
2334 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2335 ]
2336
2337 usage_when_not_required = '''\
2338 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2339 [--klmno KLMNO | --pqrst PQRST]
2340 '''
2341 usage_when_required = '''\
2342 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2343 (--klmno KLMNO | --pqrst PQRST)
2344 '''
2345 help = '''\
2346
2347 optional arguments:
2348 -h, --help show this help message and exit
2349 --abcde ABCDE abcde help
2350 --fghij FGHIJ fghij help
2351 --klmno KLMNO klmno help
2352 --pqrst PQRST pqrst help
2353 '''
2354
2355
2356class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2357
2358 def get_parser(self, required):
2359 parser = ErrorRaisingArgumentParser(prog='PROG')
2360 group = parser.add_mutually_exclusive_group(required=required)
2361 group.add_argument('-x', help=argparse.SUPPRESS)
2362 group.add_argument('-y', action='store_false', help='y help')
2363 return parser
2364
2365 failures = ['-x X -y']
2366 successes = [
2367 ('-x X', NS(x='X', y=True)),
2368 ('-x X -x Y', NS(x='Y', y=True)),
2369 ('-y', NS(x=None, y=False)),
2370 ]
2371 successes_when_not_required = [
2372 ('', NS(x=None, y=True)),
2373 ]
2374
2375 usage_when_not_required = '''\
2376 usage: PROG [-h] [-y]
2377 '''
2378 usage_when_required = '''\
2379 usage: PROG [-h] -y
2380 '''
2381 help = '''\
2382
2383 optional arguments:
2384 -h, --help show this help message and exit
2385 -y y help
2386 '''
2387
2388
2389class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2390
2391 def get_parser(self, required):
2392 parser = ErrorRaisingArgumentParser(prog='PROG')
2393 group = parser.add_mutually_exclusive_group(required=required)
2394 add = group.add_argument
2395 add('--spam', action='store_true', help=argparse.SUPPRESS)
2396 add('--badger', action='store_false', help=argparse.SUPPRESS)
2397 add('--bladder', help=argparse.SUPPRESS)
2398 return parser
2399
2400 failures = [
2401 '--spam --badger',
2402 '--badger --bladder B',
2403 '--bladder B --spam',
2404 ]
2405 successes = [
2406 ('--spam', NS(spam=True, badger=True, bladder=None)),
2407 ('--badger', NS(spam=False, badger=False, bladder=None)),
2408 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2409 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2410 ]
2411 successes_when_not_required = [
2412 ('', NS(spam=False, badger=True, bladder=None)),
2413 ]
2414
2415 usage_when_required = usage_when_not_required = '''\
2416 usage: PROG [-h]
2417 '''
2418 help = '''\
2419
2420 optional arguments:
2421 -h, --help show this help message and exit
2422 '''
2423
2424
2425class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2426
2427 def get_parser(self, required):
2428 parser = ErrorRaisingArgumentParser(prog='PROG')
2429 group = parser.add_mutually_exclusive_group(required=required)
2430 group.add_argument('--foo', action='store_true', help='FOO')
2431 group.add_argument('--spam', help='SPAM')
2432 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2433 return parser
2434
2435 failures = [
2436 '--foo --spam S',
2437 '--spam S X',
2438 'X --foo',
2439 'X Y Z --spam S',
2440 '--foo X Y',
2441 ]
2442 successes = [
2443 ('--foo', NS(foo=True, spam=None, badger='X')),
2444 ('--spam S', NS(foo=False, spam='S', badger='X')),
2445 ('X', NS(foo=False, spam=None, badger=['X'])),
2446 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2447 ]
2448 successes_when_not_required = [
2449 ('', NS(foo=False, spam=None, badger='X')),
2450 ]
2451
2452 usage_when_not_required = '''\
2453 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2454 '''
2455 usage_when_required = '''\
2456 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2457 '''
2458 help = '''\
2459
2460 positional arguments:
2461 badger BADGER
2462
2463 optional arguments:
2464 -h, --help show this help message and exit
2465 --foo FOO
2466 --spam SPAM SPAM
2467 '''
2468
2469
2470class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2471
2472 def get_parser(self, required):
2473 parser = ErrorRaisingArgumentParser(prog='PROG')
2474 parser.add_argument('-x', action='store_true', help='x help')
2475 group = parser.add_mutually_exclusive_group(required=required)
2476 group.add_argument('-a', action='store_true', help='a help')
2477 group.add_argument('-b', action='store_true', help='b help')
2478 parser.add_argument('-y', action='store_true', help='y help')
2479 group.add_argument('-c', action='store_true', help='c help')
2480 return parser
2481
2482 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2483 successes = [
2484 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2485 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2486 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2487 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2488 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2489 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2490 ]
2491 successes_when_not_required = [
2492 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2493 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2494 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2495 ]
2496
2497 usage_when_required = usage_when_not_required = '''\
2498 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2499 '''
2500 help = '''\
2501
2502 optional arguments:
2503 -h, --help show this help message and exit
2504 -x x help
2505 -a a help
2506 -b b help
2507 -y y help
2508 -c c help
2509 '''
2510
2511
Steven Bethard7f41b882011-01-30 14:05:38 +00002512class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2513
2514 def get_parser(self, required=None):
2515 parser = ErrorRaisingArgumentParser(prog='PROG')
2516 titled_group = parser.add_argument_group(
2517 title='Titled group', description='Group description')
2518 mutex_group = \
2519 titled_group.add_mutually_exclusive_group(required=required)
2520 mutex_group.add_argument('--bar', help='bar help')
2521 mutex_group.add_argument('--baz', help='baz help')
2522 return parser
2523
2524 failures = ['--bar X --baz Y', '--baz X --bar Y']
2525 successes = [
2526 ('--bar X', NS(bar='X', baz=None)),
2527 ('--baz Y', NS(bar=None, baz='Y')),
2528 ]
2529 successes_when_not_required = [
2530 ('', NS(bar=None, baz=None)),
2531 ]
2532
2533 usage_when_not_required = '''\
2534 usage: PROG [-h] [--bar BAR | --baz BAZ]
2535 '''
2536 usage_when_required = '''\
2537 usage: PROG [-h] (--bar BAR | --baz BAZ)
2538 '''
2539 help = '''\
2540
2541 optional arguments:
2542 -h, --help show this help message and exit
2543
2544 Titled group:
2545 Group description
2546
2547 --bar BAR bar help
2548 --baz BAZ baz help
2549 '''
2550
2551
Benjamin Petersona39e9662010-03-02 22:05:59 +00002552class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2553
2554 def get_parser(self, required):
2555 parser = ErrorRaisingArgumentParser(prog='PROG')
2556 parser.add_argument('x', help='x help')
2557 parser.add_argument('-y', action='store_true', help='y help')
2558 group = parser.add_mutually_exclusive_group(required=required)
2559 group.add_argument('a', nargs='?', help='a help')
2560 group.add_argument('-b', action='store_true', help='b help')
2561 group.add_argument('-c', action='store_true', help='c help')
2562 return parser
2563
2564 failures = ['X A -b', '-b -c', '-c X A']
2565 successes = [
2566 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2567 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2568 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2569 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2570 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2571 ]
2572 successes_when_not_required = [
2573 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2574 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2575 ]
2576
2577 usage_when_required = usage_when_not_required = '''\
2578 usage: PROG [-h] [-y] [-b] [-c] x [a]
2579 '''
2580 help = '''\
2581
2582 positional arguments:
2583 x x help
2584 a a help
2585
2586 optional arguments:
2587 -h, --help show this help message and exit
2588 -y y help
2589 -b b help
2590 -c c help
2591 '''
2592
2593# =================================================
2594# Mutually exclusive group in parent parser tests
2595# =================================================
2596
2597class MEPBase(object):
2598
2599 def get_parser(self, required=None):
2600 parent = super(MEPBase, self).get_parser(required=required)
2601 parser = ErrorRaisingArgumentParser(
2602 prog=parent.prog, add_help=False, parents=[parent])
2603 return parser
2604
2605
2606class TestMutuallyExclusiveGroupErrorsParent(
2607 MEPBase, TestMutuallyExclusiveGroupErrors):
2608 pass
2609
2610
2611class TestMutuallyExclusiveSimpleParent(
2612 MEPBase, TestMutuallyExclusiveSimple):
2613 pass
2614
2615
2616class TestMutuallyExclusiveLongParent(
2617 MEPBase, TestMutuallyExclusiveLong):
2618 pass
2619
2620
2621class TestMutuallyExclusiveFirstSuppressedParent(
2622 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2623 pass
2624
2625
2626class TestMutuallyExclusiveManySuppressedParent(
2627 MEPBase, TestMutuallyExclusiveManySuppressed):
2628 pass
2629
2630
2631class TestMutuallyExclusiveOptionalAndPositionalParent(
2632 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2633 pass
2634
2635
2636class TestMutuallyExclusiveOptionalsMixedParent(
2637 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2638 pass
2639
2640
2641class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2642 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2643 pass
2644
2645# =================
2646# Set default tests
2647# =================
2648
2649class TestSetDefaults(TestCase):
2650
2651 def test_set_defaults_no_args(self):
2652 parser = ErrorRaisingArgumentParser()
2653 parser.set_defaults(x='foo')
2654 parser.set_defaults(y='bar', z=1)
2655 self.assertEqual(NS(x='foo', y='bar', z=1),
2656 parser.parse_args([]))
2657 self.assertEqual(NS(x='foo', y='bar', z=1),
2658 parser.parse_args([], NS()))
2659 self.assertEqual(NS(x='baz', y='bar', z=1),
2660 parser.parse_args([], NS(x='baz')))
2661 self.assertEqual(NS(x='baz', y='bar', z=2),
2662 parser.parse_args([], NS(x='baz', z=2)))
2663
2664 def test_set_defaults_with_args(self):
2665 parser = ErrorRaisingArgumentParser()
2666 parser.set_defaults(x='foo', y='bar')
2667 parser.add_argument('-x', default='xfoox')
2668 self.assertEqual(NS(x='xfoox', y='bar'),
2669 parser.parse_args([]))
2670 self.assertEqual(NS(x='xfoox', y='bar'),
2671 parser.parse_args([], NS()))
2672 self.assertEqual(NS(x='baz', y='bar'),
2673 parser.parse_args([], NS(x='baz')))
2674 self.assertEqual(NS(x='1', y='bar'),
2675 parser.parse_args('-x 1'.split()))
2676 self.assertEqual(NS(x='1', y='bar'),
2677 parser.parse_args('-x 1'.split(), NS()))
2678 self.assertEqual(NS(x='1', y='bar'),
2679 parser.parse_args('-x 1'.split(), NS(x='baz')))
2680
2681 def test_set_defaults_subparsers(self):
2682 parser = ErrorRaisingArgumentParser()
2683 parser.set_defaults(x='foo')
2684 subparsers = parser.add_subparsers()
2685 parser_a = subparsers.add_parser('a')
2686 parser_a.set_defaults(y='bar')
2687 self.assertEqual(NS(x='foo', y='bar'),
2688 parser.parse_args('a'.split()))
2689
2690 def test_set_defaults_parents(self):
2691 parent = ErrorRaisingArgumentParser(add_help=False)
2692 parent.set_defaults(x='foo')
2693 parser = ErrorRaisingArgumentParser(parents=[parent])
2694 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2695
2696 def test_set_defaults_same_as_add_argument(self):
2697 parser = ErrorRaisingArgumentParser()
2698 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2699 parser.add_argument('-w')
2700 parser.add_argument('-x', default='XX')
2701 parser.add_argument('y', nargs='?')
2702 parser.add_argument('z', nargs='?', default='ZZ')
2703
2704 # defaults set previously
2705 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2706 parser.parse_args([]))
2707
2708 # reset defaults
2709 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2710 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2711 parser.parse_args([]))
2712
2713 def test_set_defaults_same_as_add_argument_group(self):
2714 parser = ErrorRaisingArgumentParser()
2715 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2716 group = parser.add_argument_group('foo')
2717 group.add_argument('-w')
2718 group.add_argument('-x', default='XX')
2719 group.add_argument('y', nargs='?')
2720 group.add_argument('z', nargs='?', default='ZZ')
2721
2722
2723 # defaults set previously
2724 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2725 parser.parse_args([]))
2726
2727 # reset defaults
2728 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2729 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2730 parser.parse_args([]))
2731
2732# =================
2733# Get default tests
2734# =================
2735
2736class TestGetDefault(TestCase):
2737
2738 def test_get_default(self):
2739 parser = ErrorRaisingArgumentParser()
2740 self.assertEqual(None, parser.get_default("foo"))
2741 self.assertEqual(None, parser.get_default("bar"))
2742
2743 parser.add_argument("--foo")
2744 self.assertEqual(None, parser.get_default("foo"))
2745 self.assertEqual(None, parser.get_default("bar"))
2746
2747 parser.add_argument("--bar", type=int, default=42)
2748 self.assertEqual(None, parser.get_default("foo"))
2749 self.assertEqual(42, parser.get_default("bar"))
2750
2751 parser.set_defaults(foo="badger")
2752 self.assertEqual("badger", parser.get_default("foo"))
2753 self.assertEqual(42, parser.get_default("bar"))
2754
2755# ==========================
2756# Namespace 'contains' tests
2757# ==========================
2758
2759class TestNamespaceContainsSimple(TestCase):
2760
2761 def test_empty(self):
2762 ns = argparse.Namespace()
Ezio Melotti2623a372010-11-21 13:34:58 +00002763 self.assertEqual('' in ns, False)
2764 self.assertEqual('' not in ns, True)
2765 self.assertEqual('x' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002766
2767 def test_non_empty(self):
2768 ns = argparse.Namespace(x=1, y=2)
Ezio Melotti2623a372010-11-21 13:34:58 +00002769 self.assertEqual('x' in ns, True)
2770 self.assertEqual('x' not in ns, False)
2771 self.assertEqual('y' in ns, True)
2772 self.assertEqual('' in ns, False)
2773 self.assertEqual('xx' in ns, False)
2774 self.assertEqual('z' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002775
2776# =====================
2777# Help formatting tests
2778# =====================
2779
2780class TestHelpFormattingMetaclass(type):
2781
2782 def __init__(cls, name, bases, bodydict):
2783 if name == 'HelpTestCase':
2784 return
2785
2786 class AddTests(object):
2787
2788 def __init__(self, test_class, func_suffix, std_name):
2789 self.func_suffix = func_suffix
2790 self.std_name = std_name
2791
2792 for test_func in [self.test_format,
2793 self.test_print,
2794 self.test_print_file]:
2795 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2796
2797 def test_wrapper(self, test_func=test_func):
2798 test_func(self)
2799 try:
2800 test_wrapper.__name__ = test_name
2801 except TypeError:
2802 pass
2803 setattr(test_class, test_name, test_wrapper)
2804
2805 def _get_parser(self, tester):
2806 parser = argparse.ArgumentParser(
2807 *tester.parser_signature.args,
2808 **tester.parser_signature.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002809 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Petersona39e9662010-03-02 22:05:59 +00002810 parser.add_argument(*argument_sig.args,
2811 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002812 group_sigs = getattr(tester, 'argument_group_signatures', [])
2813 for group_sig, argument_sigs in group_sigs:
Benjamin Petersona39e9662010-03-02 22:05:59 +00002814 group = parser.add_argument_group(*group_sig.args,
2815 **group_sig.kwargs)
2816 for argument_sig in argument_sigs:
2817 group.add_argument(*argument_sig.args,
2818 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002819 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
2820 if subparsers_sigs:
2821 subparsers = parser.add_subparsers()
2822 for subparser_sig in subparsers_sigs:
2823 subparsers.add_parser(*subparser_sig.args,
2824 **subparser_sig.kwargs)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002825 return parser
2826
2827 def _test(self, tester, parser_text):
2828 expected_text = getattr(tester, self.func_suffix)
2829 expected_text = textwrap.dedent(expected_text)
2830 if expected_text != parser_text:
2831 print(repr(expected_text))
2832 print(repr(parser_text))
2833 for char1, char2 in zip(expected_text, parser_text):
2834 if char1 != char2:
2835 print('first diff: %r %r' % (char1, char2))
2836 break
2837 tester.assertEqual(expected_text, parser_text)
2838
2839 def test_format(self, tester):
2840 parser = self._get_parser(tester)
2841 format = getattr(parser, 'format_%s' % self.func_suffix)
2842 self._test(tester, format())
2843
2844 def test_print(self, tester):
2845 parser = self._get_parser(tester)
2846 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2847 old_stream = getattr(sys, self.std_name)
Michael Foord91a2c892010-04-08 00:04:24 +00002848 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Petersona39e9662010-03-02 22:05:59 +00002849 try:
2850 print_()
2851 parser_text = getattr(sys, self.std_name).getvalue()
2852 finally:
2853 setattr(sys, self.std_name, old_stream)
2854 self._test(tester, parser_text)
2855
2856 def test_print_file(self, tester):
2857 parser = self._get_parser(tester)
2858 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Michael Foord91a2c892010-04-08 00:04:24 +00002859 sfile = StdIOBuffer()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002860 print_(sfile)
2861 parser_text = sfile.getvalue()
2862 self._test(tester, parser_text)
2863
2864 # add tests for {format,print}_{usage,help,version}
2865 for func_suffix, std_name in [('usage', 'stdout'),
2866 ('help', 'stdout'),
2867 ('version', 'stderr')]:
2868 AddTests(cls, func_suffix, std_name)
2869
2870bases = TestCase,
2871HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2872
2873
2874class TestHelpBiggerOptionals(HelpTestCase):
2875 """Make sure that argument help aligns when options are longer"""
2876
2877 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2878 epilog='EPILOG', version='0.1')
2879 argument_signatures = [
2880 Sig('-x', action='store_true', help='X HELP'),
2881 Sig('--y', help='Y HELP'),
2882 Sig('foo', help='FOO HELP'),
2883 Sig('bar', help='BAR HELP'),
2884 ]
2885 argument_group_signatures = []
2886 usage = '''\
2887 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2888 '''
2889 help = usage + '''\
2890
2891 DESCRIPTION
2892
2893 positional arguments:
2894 foo FOO HELP
2895 bar BAR HELP
2896
2897 optional arguments:
2898 -h, --help show this help message and exit
2899 -v, --version show program's version number and exit
2900 -x X HELP
2901 --y Y Y HELP
2902
2903 EPILOG
2904 '''
2905 version = '''\
2906 0.1
2907 '''
2908
2909
2910class TestHelpBiggerOptionalGroups(HelpTestCase):
2911 """Make sure that argument help aligns when options are longer"""
2912
2913 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2914 epilog='EPILOG', version='0.1')
2915 argument_signatures = [
2916 Sig('-x', action='store_true', help='X HELP'),
2917 Sig('--y', help='Y HELP'),
2918 Sig('foo', help='FOO HELP'),
2919 Sig('bar', help='BAR HELP'),
2920 ]
2921 argument_group_signatures = [
2922 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2923 Sig('baz', help='BAZ HELP'),
2924 Sig('-z', nargs='+', help='Z HELP')]),
2925 ]
2926 usage = '''\
2927 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2928 '''
2929 help = usage + '''\
2930
2931 DESCRIPTION
2932
2933 positional arguments:
2934 foo FOO HELP
2935 bar BAR HELP
2936
2937 optional arguments:
2938 -h, --help show this help message and exit
2939 -v, --version show program's version number and exit
2940 -x X HELP
2941 --y Y Y HELP
2942
2943 GROUP TITLE:
2944 GROUP DESCRIPTION
2945
2946 baz BAZ HELP
2947 -z Z [Z ...] Z HELP
2948
2949 EPILOG
2950 '''
2951 version = '''\
2952 0.1
2953 '''
2954
2955
2956class TestHelpBiggerPositionals(HelpTestCase):
2957 """Make sure that help aligns when arguments are longer"""
2958
2959 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2960 argument_signatures = [
2961 Sig('-x', action='store_true', help='X HELP'),
2962 Sig('--y', help='Y HELP'),
2963 Sig('ekiekiekifekang', help='EKI HELP'),
2964 Sig('bar', help='BAR HELP'),
2965 ]
2966 argument_group_signatures = []
2967 usage = '''\
2968 usage: USAGE
2969 '''
2970 help = usage + '''\
2971
2972 DESCRIPTION
2973
2974 positional arguments:
2975 ekiekiekifekang EKI HELP
2976 bar BAR HELP
2977
2978 optional arguments:
2979 -h, --help show this help message and exit
2980 -x X HELP
2981 --y Y Y HELP
2982 '''
2983
2984 version = ''
2985
2986
2987class TestHelpReformatting(HelpTestCase):
2988 """Make sure that text after short names starts on the first line"""
2989
2990 parser_signature = Sig(
2991 prog='PROG',
2992 description=' oddly formatted\n'
2993 'description\n'
2994 '\n'
2995 'that is so long that it should go onto multiple '
2996 'lines when wrapped')
2997 argument_signatures = [
2998 Sig('-x', metavar='XX', help='oddly\n'
2999 ' formatted -x help'),
3000 Sig('y', metavar='yyy', help='normal y help'),
3001 ]
3002 argument_group_signatures = [
3003 (Sig('title', description='\n'
3004 ' oddly formatted group\n'
3005 '\n'
3006 'description'),
3007 [Sig('-a', action='store_true',
3008 help=' oddly \n'
3009 'formatted -a help \n'
3010 ' again, so long that it should be wrapped over '
3011 'multiple lines')]),
3012 ]
3013 usage = '''\
3014 usage: PROG [-h] [-x XX] [-a] yyy
3015 '''
3016 help = usage + '''\
3017
3018 oddly formatted description that is so long that it should go onto \
3019multiple
3020 lines when wrapped
3021
3022 positional arguments:
3023 yyy normal y help
3024
3025 optional arguments:
3026 -h, --help show this help message and exit
3027 -x XX oddly formatted -x help
3028
3029 title:
3030 oddly formatted group description
3031
3032 -a oddly formatted -a help again, so long that it should \
3033be wrapped
3034 over multiple lines
3035 '''
3036 version = ''
3037
3038
3039class TestHelpWrappingShortNames(HelpTestCase):
3040 """Make sure that text after short names starts on the first line"""
3041
3042 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3043 argument_signatures = [
3044 Sig('-x', metavar='XX', help='XHH HX' * 20),
3045 Sig('y', metavar='yyy', help='YH YH' * 20),
3046 ]
3047 argument_group_signatures = [
3048 (Sig('ALPHAS'), [
3049 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3050 ]
3051 usage = '''\
3052 usage: PROG [-h] [-x XX] [-a] yyy
3053 '''
3054 help = usage + '''\
3055
3056 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3057DD DD DD
3058 DD DD DD DD D
3059
3060 positional arguments:
3061 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3062YHYH YHYH
3063 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3064
3065 optional arguments:
3066 -h, --help show this help message and exit
3067 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3068HXXHH HXXHH
3069 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3070
3071 ALPHAS:
3072 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3073HHAAHHH
3074 HHAAHHH HHAAHHH HHA
3075 '''
3076 version = ''
3077
3078
3079class TestHelpWrappingLongNames(HelpTestCase):
3080 """Make sure that text after long names starts on the next line"""
3081
3082 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3083 version='V V'*30)
3084 argument_signatures = [
3085 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3086 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3087 ]
3088 argument_group_signatures = [
3089 (Sig('ALPHAS'), [
3090 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3091 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3092 ]
3093 usage = '''\
3094 usage: USAGE
3095 '''
3096 help = usage + '''\
3097
3098 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3099DD DD DD
3100 DD DD DD DD D
3101
3102 positional arguments:
3103 yyyyyyyyyyyyyyyyyyyyyyyyy
3104 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3105YHYH YHYH
3106 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3107
3108 optional arguments:
3109 -h, --help show this help message and exit
3110 -v, --version show program's version number and exit
3111 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3112 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3113XHXH XHXH
3114 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3115
3116 ALPHAS:
3117 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3118 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3119AHAH AHAH
3120 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3121 zzzzzzzzzzzzzzzzzzzzzzzzz
3122 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3123ZHZH ZHZH
3124 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3125 '''
3126 version = '''\
3127 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3128VV VV VV
3129 VV VV VV VV V
3130 '''
3131
3132
3133class TestHelpUsage(HelpTestCase):
3134 """Test basic usage messages"""
3135
3136 parser_signature = Sig(prog='PROG')
3137 argument_signatures = [
3138 Sig('-w', nargs='+', help='w'),
3139 Sig('-x', nargs='*', help='x'),
3140 Sig('a', help='a'),
3141 Sig('b', help='b', nargs=2),
3142 Sig('c', help='c', nargs='?'),
3143 ]
3144 argument_group_signatures = [
3145 (Sig('group'), [
3146 Sig('-y', nargs='?', help='y'),
3147 Sig('-z', nargs=3, help='z'),
3148 Sig('d', help='d', nargs='*'),
3149 Sig('e', help='e', nargs='+'),
3150 ])
3151 ]
3152 usage = '''\
3153 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3154 a b b [c] [d [d ...]] e [e ...]
3155 '''
3156 help = usage + '''\
3157
3158 positional arguments:
3159 a a
3160 b b
3161 c c
3162
3163 optional arguments:
3164 -h, --help show this help message and exit
3165 -w W [W ...] w
3166 -x [X [X ...]] x
3167
3168 group:
3169 -y [Y] y
3170 -z Z Z Z z
3171 d d
3172 e e
3173 '''
3174 version = ''
3175
3176
3177class TestHelpOnlyUserGroups(HelpTestCase):
3178 """Test basic usage messages"""
3179
3180 parser_signature = Sig(prog='PROG', add_help=False)
3181 argument_signatures = []
3182 argument_group_signatures = [
3183 (Sig('xxxx'), [
3184 Sig('-x', help='x'),
3185 Sig('a', help='a'),
3186 ]),
3187 (Sig('yyyy'), [
3188 Sig('b', help='b'),
3189 Sig('-y', help='y'),
3190 ]),
3191 ]
3192 usage = '''\
3193 usage: PROG [-x X] [-y Y] a b
3194 '''
3195 help = usage + '''\
3196
3197 xxxx:
3198 -x X x
3199 a a
3200
3201 yyyy:
3202 b b
3203 -y Y y
3204 '''
3205 version = ''
3206
3207
3208class TestHelpUsageLongProg(HelpTestCase):
3209 """Test usage messages where the prog is long"""
3210
3211 parser_signature = Sig(prog='P' * 60)
3212 argument_signatures = [
3213 Sig('-w', metavar='W'),
3214 Sig('-x', metavar='X'),
3215 Sig('a'),
3216 Sig('b'),
3217 ]
3218 argument_group_signatures = []
3219 usage = '''\
3220 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3221 [-h] [-w W] [-x X] a b
3222 '''
3223 help = usage + '''\
3224
3225 positional arguments:
3226 a
3227 b
3228
3229 optional arguments:
3230 -h, --help show this help message and exit
3231 -w W
3232 -x X
3233 '''
3234 version = ''
3235
3236
3237class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3238 """Test usage messages where the prog is long and the optionals wrap"""
3239
3240 parser_signature = Sig(prog='P' * 60)
3241 argument_signatures = [
3242 Sig('-w', metavar='W' * 25),
3243 Sig('-x', metavar='X' * 25),
3244 Sig('-y', metavar='Y' * 25),
3245 Sig('-z', metavar='Z' * 25),
3246 Sig('a'),
3247 Sig('b'),
3248 ]
3249 argument_group_signatures = []
3250 usage = '''\
3251 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3252 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3253[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3254 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3255 a b
3256 '''
3257 help = usage + '''\
3258
3259 positional arguments:
3260 a
3261 b
3262
3263 optional arguments:
3264 -h, --help show this help message and exit
3265 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3266 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3267 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3268 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3269 '''
3270 version = ''
3271
3272
3273class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3274 """Test usage messages where the prog is long and the positionals wrap"""
3275
3276 parser_signature = Sig(prog='P' * 60, add_help=False)
3277 argument_signatures = [
3278 Sig('a' * 25),
3279 Sig('b' * 25),
3280 Sig('c' * 25),
3281 ]
3282 argument_group_signatures = []
3283 usage = '''\
3284 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3285 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3286 ccccccccccccccccccccccccc
3287 '''
3288 help = usage + '''\
3289
3290 positional arguments:
3291 aaaaaaaaaaaaaaaaaaaaaaaaa
3292 bbbbbbbbbbbbbbbbbbbbbbbbb
3293 ccccccccccccccccccccccccc
3294 '''
3295 version = ''
3296
3297
3298class TestHelpUsageOptionalsWrap(HelpTestCase):
3299 """Test usage messages where the optionals wrap"""
3300
3301 parser_signature = Sig(prog='PROG')
3302 argument_signatures = [
3303 Sig('-w', metavar='W' * 25),
3304 Sig('-x', metavar='X' * 25),
3305 Sig('-y', metavar='Y' * 25),
3306 Sig('-z', metavar='Z' * 25),
3307 Sig('a'),
3308 Sig('b'),
3309 Sig('c'),
3310 ]
3311 argument_group_signatures = []
3312 usage = '''\
3313 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3314[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3315 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3316[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3317 a b c
3318 '''
3319 help = usage + '''\
3320
3321 positional arguments:
3322 a
3323 b
3324 c
3325
3326 optional arguments:
3327 -h, --help show this help message and exit
3328 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3329 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3330 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3331 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3332 '''
3333 version = ''
3334
3335
3336class TestHelpUsagePositionalsWrap(HelpTestCase):
3337 """Test usage messages where the positionals wrap"""
3338
3339 parser_signature = Sig(prog='PROG')
3340 argument_signatures = [
3341 Sig('-x'),
3342 Sig('-y'),
3343 Sig('-z'),
3344 Sig('a' * 25),
3345 Sig('b' * 25),
3346 Sig('c' * 25),
3347 ]
3348 argument_group_signatures = []
3349 usage = '''\
3350 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3351 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3352 ccccccccccccccccccccccccc
3353 '''
3354 help = usage + '''\
3355
3356 positional arguments:
3357 aaaaaaaaaaaaaaaaaaaaaaaaa
3358 bbbbbbbbbbbbbbbbbbbbbbbbb
3359 ccccccccccccccccccccccccc
3360
3361 optional arguments:
3362 -h, --help show this help message and exit
3363 -x X
3364 -y Y
3365 -z Z
3366 '''
3367 version = ''
3368
3369
3370class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3371 """Test usage messages where the optionals and positionals wrap"""
3372
3373 parser_signature = Sig(prog='PROG')
3374 argument_signatures = [
3375 Sig('-x', metavar='X' * 25),
3376 Sig('-y', metavar='Y' * 25),
3377 Sig('-z', metavar='Z' * 25),
3378 Sig('a' * 25),
3379 Sig('b' * 25),
3380 Sig('c' * 25),
3381 ]
3382 argument_group_signatures = []
3383 usage = '''\
3384 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3385[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3386 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3387 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3388 ccccccccccccccccccccccccc
3389 '''
3390 help = usage + '''\
3391
3392 positional arguments:
3393 aaaaaaaaaaaaaaaaaaaaaaaaa
3394 bbbbbbbbbbbbbbbbbbbbbbbbb
3395 ccccccccccccccccccccccccc
3396
3397 optional arguments:
3398 -h, --help show this help message and exit
3399 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3400 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3401 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3402 '''
3403 version = ''
3404
3405
3406class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3407 """Test usage messages where there are only optionals and they wrap"""
3408
3409 parser_signature = Sig(prog='PROG')
3410 argument_signatures = [
3411 Sig('-x', metavar='X' * 25),
3412 Sig('-y', metavar='Y' * 25),
3413 Sig('-z', metavar='Z' * 25),
3414 ]
3415 argument_group_signatures = []
3416 usage = '''\
3417 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3418[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3419 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3420 '''
3421 help = usage + '''\
3422
3423 optional arguments:
3424 -h, --help show this help message and exit
3425 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3426 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3427 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3428 '''
3429 version = ''
3430
3431
3432class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3433 """Test usage messages where there are only positionals and they wrap"""
3434
3435 parser_signature = Sig(prog='PROG', add_help=False)
3436 argument_signatures = [
3437 Sig('a' * 25),
3438 Sig('b' * 25),
3439 Sig('c' * 25),
3440 ]
3441 argument_group_signatures = []
3442 usage = '''\
3443 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3444 ccccccccccccccccccccccccc
3445 '''
3446 help = usage + '''\
3447
3448 positional arguments:
3449 aaaaaaaaaaaaaaaaaaaaaaaaa
3450 bbbbbbbbbbbbbbbbbbbbbbbbb
3451 ccccccccccccccccccccccccc
3452 '''
3453 version = ''
3454
3455
3456class TestHelpVariableExpansion(HelpTestCase):
3457 """Test that variables are expanded properly in help messages"""
3458
3459 parser_signature = Sig(prog='PROG')
3460 argument_signatures = [
3461 Sig('-x', type=int,
3462 help='x %(prog)s %(default)s %(type)s %%'),
3463 Sig('-y', action='store_const', default=42, const='XXX',
3464 help='y %(prog)s %(default)s %(const)s'),
3465 Sig('--foo', choices='abc',
3466 help='foo %(prog)s %(default)s %(choices)s'),
3467 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3468 help='bar %(prog)s %(default)s %(dest)s'),
3469 Sig('spam', help='spam %(prog)s %(default)s'),
3470 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3471 ]
3472 argument_group_signatures = [
3473 (Sig('group'), [
3474 Sig('-a', help='a %(prog)s %(default)s'),
3475 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3476 ])
3477 ]
3478 usage = ('''\
3479 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3480 spam badger
3481 ''')
3482 help = usage + '''\
3483
3484 positional arguments:
3485 spam spam PROG None
3486 badger badger PROG 0.5
3487
3488 optional arguments:
3489 -h, --help show this help message and exit
3490 -x X x PROG None int %
3491 -y y PROG 42 XXX
3492 --foo {a,b,c} foo PROG None a, b, c
3493 --bar BBB bar PROG baz bar
3494
3495 group:
3496 -a A a PROG None
3497 -b B b PROG -1
3498 '''
3499 version = ''
3500
3501
3502class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3503 """Test that variables are expanded properly when usage= is present"""
3504
3505 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3506 argument_signatures = []
3507 argument_group_signatures = []
3508 usage = ('''\
3509 usage: PROG FOO
3510 ''')
3511 help = usage + '''\
3512
3513 optional arguments:
3514 -h, --help show this help message and exit
3515 '''
3516 version = ''
3517
3518
3519class TestHelpVariableExpansionNoArguments(HelpTestCase):
3520 """Test that variables are expanded properly with no arguments"""
3521
3522 parser_signature = Sig(prog='PROG', add_help=False)
3523 argument_signatures = []
3524 argument_group_signatures = []
3525 usage = ('''\
3526 usage: PROG
3527 ''')
3528 help = usage
3529 version = ''
3530
3531
3532class TestHelpSuppressUsage(HelpTestCase):
3533 """Test that items can be suppressed in usage messages"""
3534
3535 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3536 argument_signatures = [
3537 Sig('--foo', help='foo help'),
3538 Sig('spam', help='spam help'),
3539 ]
3540 argument_group_signatures = []
3541 help = '''\
3542 positional arguments:
3543 spam spam help
3544
3545 optional arguments:
3546 -h, --help show this help message and exit
3547 --foo FOO foo help
3548 '''
3549 usage = ''
3550 version = ''
3551
3552
3553class TestHelpSuppressOptional(HelpTestCase):
3554 """Test that optional arguments can be suppressed in help messages"""
3555
3556 parser_signature = Sig(prog='PROG', add_help=False)
3557 argument_signatures = [
3558 Sig('--foo', help=argparse.SUPPRESS),
3559 Sig('spam', help='spam help'),
3560 ]
3561 argument_group_signatures = []
3562 usage = '''\
3563 usage: PROG spam
3564 '''
3565 help = usage + '''\
3566
3567 positional arguments:
3568 spam spam help
3569 '''
3570 version = ''
3571
3572
3573class TestHelpSuppressOptionalGroup(HelpTestCase):
3574 """Test that optional groups can be suppressed in help messages"""
3575
3576 parser_signature = Sig(prog='PROG')
3577 argument_signatures = [
3578 Sig('--foo', help='foo help'),
3579 Sig('spam', help='spam help'),
3580 ]
3581 argument_group_signatures = [
3582 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3583 ]
3584 usage = '''\
3585 usage: PROG [-h] [--foo FOO] spam
3586 '''
3587 help = usage + '''\
3588
3589 positional arguments:
3590 spam spam help
3591
3592 optional arguments:
3593 -h, --help show this help message and exit
3594 --foo FOO foo help
3595 '''
3596 version = ''
3597
3598
3599class TestHelpSuppressPositional(HelpTestCase):
3600 """Test that positional arguments can be suppressed in help messages"""
3601
3602 parser_signature = Sig(prog='PROG')
3603 argument_signatures = [
3604 Sig('--foo', help='foo help'),
3605 Sig('spam', help=argparse.SUPPRESS),
3606 ]
3607 argument_group_signatures = []
3608 usage = '''\
3609 usage: PROG [-h] [--foo FOO]
3610 '''
3611 help = usage + '''\
3612
3613 optional arguments:
3614 -h, --help show this help message and exit
3615 --foo FOO foo help
3616 '''
3617 version = ''
3618
3619
3620class TestHelpRequiredOptional(HelpTestCase):
3621 """Test that required options don't look optional"""
3622
3623 parser_signature = Sig(prog='PROG')
3624 argument_signatures = [
3625 Sig('--foo', required=True, help='foo help'),
3626 ]
3627 argument_group_signatures = []
3628 usage = '''\
3629 usage: PROG [-h] --foo FOO
3630 '''
3631 help = usage + '''\
3632
3633 optional arguments:
3634 -h, --help show this help message and exit
3635 --foo FOO foo help
3636 '''
3637 version = ''
3638
3639
3640class TestHelpAlternatePrefixChars(HelpTestCase):
3641 """Test that options display with different prefix characters"""
3642
3643 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3644 argument_signatures = [
3645 Sig('^^foo', action='store_true', help='foo help'),
3646 Sig(';b', ';;bar', help='bar help'),
3647 ]
3648 argument_group_signatures = []
3649 usage = '''\
3650 usage: PROG [^^foo] [;b BAR]
3651 '''
3652 help = usage + '''\
3653
3654 optional arguments:
3655 ^^foo foo help
3656 ;b BAR, ;;bar BAR bar help
3657 '''
3658 version = ''
3659
3660
3661class TestHelpNoHelpOptional(HelpTestCase):
3662 """Test that the --help argument can be suppressed help messages"""
3663
3664 parser_signature = Sig(prog='PROG', add_help=False)
3665 argument_signatures = [
3666 Sig('--foo', help='foo help'),
3667 Sig('spam', help='spam help'),
3668 ]
3669 argument_group_signatures = []
3670 usage = '''\
3671 usage: PROG [--foo FOO] spam
3672 '''
3673 help = usage + '''\
3674
3675 positional arguments:
3676 spam spam help
3677
3678 optional arguments:
3679 --foo FOO foo help
3680 '''
3681 version = ''
3682
3683
3684class TestHelpVersionOptional(HelpTestCase):
3685 """Test that the --version argument can be suppressed help messages"""
3686
3687 parser_signature = Sig(prog='PROG', version='1.0')
3688 argument_signatures = [
3689 Sig('--foo', help='foo help'),
3690 Sig('spam', help='spam help'),
3691 ]
3692 argument_group_signatures = []
3693 usage = '''\
3694 usage: PROG [-h] [-v] [--foo FOO] spam
3695 '''
3696 help = usage + '''\
3697
3698 positional arguments:
3699 spam spam help
3700
3701 optional arguments:
3702 -h, --help show this help message and exit
3703 -v, --version show program's version number and exit
3704 --foo FOO foo help
3705 '''
3706 version = '''\
3707 1.0
3708 '''
3709
3710
3711class TestHelpNone(HelpTestCase):
3712 """Test that no errors occur if no help is specified"""
3713
3714 parser_signature = Sig(prog='PROG')
3715 argument_signatures = [
3716 Sig('--foo'),
3717 Sig('spam'),
3718 ]
3719 argument_group_signatures = []
3720 usage = '''\
3721 usage: PROG [-h] [--foo FOO] spam
3722 '''
3723 help = usage + '''\
3724
3725 positional arguments:
3726 spam
3727
3728 optional arguments:
3729 -h, --help show this help message and exit
3730 --foo FOO
3731 '''
3732 version = ''
3733
3734
3735class TestHelpTupleMetavar(HelpTestCase):
3736 """Test specifying metavar as a tuple"""
3737
3738 parser_signature = Sig(prog='PROG')
3739 argument_signatures = [
3740 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3741 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3742 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3743 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3744 ]
3745 argument_group_signatures = []
3746 usage = '''\
3747 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3748[-z [Z1]]
3749 '''
3750 help = usage + '''\
3751
3752 optional arguments:
3753 -h, --help show this help message and exit
3754 -w W1 [W2 ...] w
3755 -x [X1 [X2 ...]] x
3756 -y Y1 Y2 Y3 y
3757 -z [Z1] z
3758 '''
3759 version = ''
3760
3761
3762class TestHelpRawText(HelpTestCase):
3763 """Test the RawTextHelpFormatter"""
3764
3765 parser_signature = Sig(
3766 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3767 description='Keep the formatting\n'
3768 ' exactly as it is written\n'
3769 '\n'
3770 'here\n')
3771
3772 argument_signatures = [
3773 Sig('--foo', help=' foo help should also\n'
3774 'appear as given here'),
3775 Sig('spam', help='spam help'),
3776 ]
3777 argument_group_signatures = [
3778 (Sig('title', description=' This text\n'
3779 ' should be indented\n'
3780 ' exactly like it is here\n'),
3781 [Sig('--bar', help='bar help')]),
3782 ]
3783 usage = '''\
3784 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3785 '''
3786 help = usage + '''\
3787
3788 Keep the formatting
3789 exactly as it is written
3790
3791 here
3792
3793 positional arguments:
3794 spam spam help
3795
3796 optional arguments:
3797 -h, --help show this help message and exit
3798 --foo FOO foo help should also
3799 appear as given here
3800
3801 title:
3802 This text
3803 should be indented
3804 exactly like it is here
3805
3806 --bar BAR bar help
3807 '''
3808 version = ''
3809
3810
3811class TestHelpRawDescription(HelpTestCase):
3812 """Test the RawTextHelpFormatter"""
3813
3814 parser_signature = Sig(
3815 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3816 description='Keep the formatting\n'
3817 ' exactly as it is written\n'
3818 '\n'
3819 'here\n')
3820
3821 argument_signatures = [
3822 Sig('--foo', help=' foo help should not\n'
3823 ' retain this odd formatting'),
3824 Sig('spam', help='spam help'),
3825 ]
3826 argument_group_signatures = [
3827 (Sig('title', description=' This text\n'
3828 ' should be indented\n'
3829 ' exactly like it is here\n'),
3830 [Sig('--bar', help='bar help')]),
3831 ]
3832 usage = '''\
3833 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3834 '''
3835 help = usage + '''\
3836
3837 Keep the formatting
3838 exactly as it is written
3839
3840 here
3841
3842 positional arguments:
3843 spam spam help
3844
3845 optional arguments:
3846 -h, --help show this help message and exit
3847 --foo FOO foo help should not retain this odd formatting
3848
3849 title:
3850 This text
3851 should be indented
3852 exactly like it is here
3853
3854 --bar BAR bar help
3855 '''
3856 version = ''
3857
3858
3859class TestHelpArgumentDefaults(HelpTestCase):
3860 """Test the ArgumentDefaultsHelpFormatter"""
3861
3862 parser_signature = Sig(
3863 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3864 description='description')
3865
3866 argument_signatures = [
3867 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3868 Sig('--bar', action='store_true', help='bar help'),
3869 Sig('spam', help='spam help'),
3870 Sig('badger', nargs='?', default='wooden', help='badger help'),
3871 ]
3872 argument_group_signatures = [
3873 (Sig('title', description='description'),
3874 [Sig('--baz', type=int, default=42, help='baz help')]),
3875 ]
3876 usage = '''\
3877 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3878 '''
3879 help = usage + '''\
3880
3881 description
3882
3883 positional arguments:
3884 spam spam help
3885 badger badger help (default: wooden)
3886
3887 optional arguments:
3888 -h, --help show this help message and exit
3889 --foo FOO foo help - oh and by the way, None
3890 --bar bar help (default: False)
3891
3892 title:
3893 description
3894
3895 --baz BAZ baz help (default: 42)
3896 '''
3897 version = ''
3898
Steven Betharddce6e1b2010-05-24 03:45:26 +00003899class TestHelpVersionAction(HelpTestCase):
3900 """Test the default help for the version action"""
3901
3902 parser_signature = Sig(prog='PROG', description='description')
3903 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3904 argument_group_signatures = []
3905 usage = '''\
3906 usage: PROG [-h] [-V]
3907 '''
3908 help = usage + '''\
3909
3910 description
3911
3912 optional arguments:
3913 -h, --help show this help message and exit
3914 -V, --version show program's version number and exit
3915 '''
3916 version = ''
3917
Steven Bethardbc3b1042011-03-27 13:57:55 +02003918class TestHelpSubparsersOrdering(HelpTestCase):
3919 """Test ordering of subcommands in help matches the code"""
3920 parser_signature = Sig(prog='PROG',
3921 description='display some subcommands',
3922 version='0.1')
3923
3924 subparsers_signatures = [Sig(name=name)
3925 for name in ('a', 'b', 'c', 'd', 'e')]
3926
3927 usage = '''\
3928 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3929 '''
3930
3931 help = usage + '''\
3932
3933 display some subcommands
3934
3935 positional arguments:
3936 {a,b,c,d,e}
3937
3938 optional arguments:
3939 -h, --help show this help message and exit
3940 -v, --version show program's version number and exit
3941 '''
3942
3943 version = '''\
3944 0.1
3945 '''
3946
3947class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
3948 """Test ordering of subcommands in help matches the code"""
3949 parser_signature = Sig(prog='PROG',
3950 description='display some subcommands',
3951 version='0.1')
3952
3953 subcommand_data = (('a', 'a subcommand help'),
3954 ('b', 'b subcommand help'),
3955 ('c', 'c subcommand help'),
3956 ('d', 'd subcommand help'),
3957 ('e', 'e subcommand help'),
3958 )
3959
3960 subparsers_signatures = [Sig(name=name, help=help)
3961 for name, help in subcommand_data]
3962
3963 usage = '''\
3964 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3965 '''
3966
3967 help = usage + '''\
3968
3969 display some subcommands
3970
3971 positional arguments:
3972 {a,b,c,d,e}
3973 a a subcommand help
3974 b b subcommand help
3975 c c subcommand help
3976 d d subcommand help
3977 e e subcommand help
3978
3979 optional arguments:
3980 -h, --help show this help message and exit
3981 -v, --version show program's version number and exit
3982 '''
3983
3984 version = '''\
3985 0.1
3986 '''
3987
3988
Benjamin Petersona39e9662010-03-02 22:05:59 +00003989# =====================================
3990# Optional/Positional constructor tests
3991# =====================================
3992
3993class TestInvalidArgumentConstructors(TestCase):
3994 """Test a bunch of invalid Argument constructors"""
3995
3996 def assertTypeError(self, *args, **kwargs):
3997 parser = argparse.ArgumentParser()
3998 self.assertRaises(TypeError, parser.add_argument,
3999 *args, **kwargs)
4000
4001 def assertValueError(self, *args, **kwargs):
4002 parser = argparse.ArgumentParser()
4003 self.assertRaises(ValueError, parser.add_argument,
4004 *args, **kwargs)
4005
4006 def test_invalid_keyword_arguments(self):
4007 self.assertTypeError('-x', bar=None)
4008 self.assertTypeError('-y', callback='foo')
4009 self.assertTypeError('-y', callback_args=())
4010 self.assertTypeError('-y', callback_kwargs={})
4011
4012 def test_missing_destination(self):
4013 self.assertTypeError()
4014 for action in ['append', 'store']:
4015 self.assertTypeError(action=action)
4016
4017 def test_invalid_option_strings(self):
4018 self.assertValueError('--')
4019 self.assertValueError('---')
4020
4021 def test_invalid_type(self):
4022 self.assertValueError('--foo', type='int')
Steven Betharde3c11b42011-04-04 01:47:52 +02004023 self.assertValueError('--foo', type=(int, float))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004024
4025 def test_invalid_action(self):
4026 self.assertValueError('-x', action='foo')
4027 self.assertValueError('foo', action='baz')
Steven Betharde3c11b42011-04-04 01:47:52 +02004028 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004029 parser = argparse.ArgumentParser()
4030 try:
4031 parser.add_argument("--foo", action="store-true")
4032 except ValueError:
4033 e = sys.exc_info()[1]
4034 expected = 'unknown action'
4035 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004036 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004037
4038 def test_multiple_dest(self):
4039 parser = argparse.ArgumentParser()
4040 parser.add_argument(dest='foo')
4041 try:
4042 parser.add_argument('bar', dest='baz')
4043 except ValueError:
4044 e = sys.exc_info()[1]
4045 expected = 'dest supplied twice for positional argument'
4046 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004047 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004048
4049 def test_no_argument_actions(self):
4050 for action in ['store_const', 'store_true', 'store_false',
4051 'append_const', 'count']:
4052 for attrs in [dict(type=int), dict(nargs='+'),
4053 dict(choices='ab')]:
4054 self.assertTypeError('-x', action=action, **attrs)
4055
4056 def test_no_argument_no_const_actions(self):
4057 # options with zero arguments
4058 for action in ['store_true', 'store_false', 'count']:
4059
4060 # const is always disallowed
4061 self.assertTypeError('-x', const='foo', action=action)
4062
4063 # nargs is always disallowed
4064 self.assertTypeError('-x', nargs='*', action=action)
4065
4066 def test_more_than_one_argument_actions(self):
4067 for action in ['store', 'append']:
4068
4069 # nargs=0 is disallowed
4070 self.assertValueError('-x', nargs=0, action=action)
4071 self.assertValueError('spam', nargs=0, action=action)
4072
4073 # const is disallowed with non-optional arguments
4074 for nargs in [1, '*', '+']:
4075 self.assertValueError('-x', const='foo',
4076 nargs=nargs, action=action)
4077 self.assertValueError('spam', const='foo',
4078 nargs=nargs, action=action)
4079
4080 def test_required_const_actions(self):
4081 for action in ['store_const', 'append_const']:
4082
4083 # nargs is always disallowed
4084 self.assertTypeError('-x', nargs='+', action=action)
4085
4086 def test_parsers_action_missing_params(self):
4087 self.assertTypeError('command', action='parsers')
4088 self.assertTypeError('command', action='parsers', prog='PROG')
4089 self.assertTypeError('command', action='parsers',
4090 parser_class=argparse.ArgumentParser)
4091
4092 def test_required_positional(self):
4093 self.assertTypeError('foo', required=True)
4094
4095 def test_user_defined_action(self):
4096
4097 class Success(Exception):
4098 pass
4099
4100 class Action(object):
4101
4102 def __init__(self,
4103 option_strings,
4104 dest,
4105 const,
4106 default,
4107 required=False):
4108 if dest == 'spam':
4109 if const is Success:
4110 if default is Success:
4111 raise Success()
4112
4113 def __call__(self, *args, **kwargs):
4114 pass
4115
4116 parser = argparse.ArgumentParser()
4117 self.assertRaises(Success, parser.add_argument, '--spam',
4118 action=Action, default=Success, const=Success)
4119 self.assertRaises(Success, parser.add_argument, 'spam',
4120 action=Action, default=Success, const=Success)
4121
4122# ================================
4123# Actions returned by add_argument
4124# ================================
4125
4126class TestActionsReturned(TestCase):
4127
4128 def test_dest(self):
4129 parser = argparse.ArgumentParser()
4130 action = parser.add_argument('--foo')
4131 self.assertEqual(action.dest, 'foo')
4132 action = parser.add_argument('-b', '--bar')
4133 self.assertEqual(action.dest, 'bar')
4134 action = parser.add_argument('-x', '-y')
4135 self.assertEqual(action.dest, 'x')
4136
4137 def test_misc(self):
4138 parser = argparse.ArgumentParser()
4139 action = parser.add_argument('--foo', nargs='?', const=42,
4140 default=84, type=int, choices=[1, 2],
4141 help='FOO', metavar='BAR', dest='baz')
4142 self.assertEqual(action.nargs, '?')
4143 self.assertEqual(action.const, 42)
4144 self.assertEqual(action.default, 84)
4145 self.assertEqual(action.type, int)
4146 self.assertEqual(action.choices, [1, 2])
4147 self.assertEqual(action.help, 'FOO')
4148 self.assertEqual(action.metavar, 'BAR')
4149 self.assertEqual(action.dest, 'baz')
4150
4151
4152# ================================
4153# Argument conflict handling tests
4154# ================================
4155
4156class TestConflictHandling(TestCase):
4157
4158 def test_bad_type(self):
4159 self.assertRaises(ValueError, argparse.ArgumentParser,
4160 conflict_handler='foo')
4161
4162 def test_conflict_error(self):
4163 parser = argparse.ArgumentParser()
4164 parser.add_argument('-x')
4165 self.assertRaises(argparse.ArgumentError,
4166 parser.add_argument, '-x')
4167 parser.add_argument('--spam')
4168 self.assertRaises(argparse.ArgumentError,
4169 parser.add_argument, '--spam')
4170
4171 def test_resolve_error(self):
4172 get_parser = argparse.ArgumentParser
4173 parser = get_parser(prog='PROG', conflict_handler='resolve')
4174
4175 parser.add_argument('-x', help='OLD X')
4176 parser.add_argument('-x', help='NEW X')
4177 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4178 usage: PROG [-h] [-x X]
4179
4180 optional arguments:
4181 -h, --help show this help message and exit
4182 -x X NEW X
4183 '''))
4184
4185 parser.add_argument('--spam', metavar='OLD_SPAM')
4186 parser.add_argument('--spam', metavar='NEW_SPAM')
4187 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4188 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4189
4190 optional arguments:
4191 -h, --help show this help message and exit
4192 -x X NEW X
4193 --spam NEW_SPAM
4194 '''))
4195
4196
4197# =============================
4198# Help and Version option tests
4199# =============================
4200
4201class TestOptionalsHelpVersionActions(TestCase):
4202 """Test the help and version actions"""
4203
4204 def _get_error(self, func, *args, **kwargs):
4205 try:
4206 func(*args, **kwargs)
4207 except ArgumentParserError:
4208 return sys.exc_info()[1]
4209 else:
4210 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4211
4212 def assertPrintHelpExit(self, parser, args_str):
4213 self.assertEqual(
4214 parser.format_help(),
4215 self._get_error(parser.parse_args, args_str.split()).stdout)
4216
4217 def assertPrintVersionExit(self, parser, args_str):
4218 self.assertEqual(
4219 parser.format_version(),
4220 self._get_error(parser.parse_args, args_str.split()).stderr)
4221
4222 def assertArgumentParserError(self, parser, *args):
4223 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4224
4225 def test_version(self):
4226 parser = ErrorRaisingArgumentParser(version='1.0')
4227 self.assertPrintHelpExit(parser, '-h')
4228 self.assertPrintHelpExit(parser, '--help')
4229 self.assertPrintVersionExit(parser, '-v')
4230 self.assertPrintVersionExit(parser, '--version')
4231
4232 def test_version_format(self):
4233 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4234 msg = self._get_error(parser.parse_args, ['-v']).stderr
4235 self.assertEqual('PPP 3.5\n', msg)
4236
4237 def test_version_no_help(self):
4238 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4239 self.assertArgumentParserError(parser, '-h')
4240 self.assertArgumentParserError(parser, '--help')
4241 self.assertPrintVersionExit(parser, '-v')
4242 self.assertPrintVersionExit(parser, '--version')
4243
4244 def test_version_action(self):
4245 parser = ErrorRaisingArgumentParser(prog='XXX')
4246 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4247 msg = self._get_error(parser.parse_args, ['-V']).stderr
4248 self.assertEqual('XXX 3.7\n', msg)
4249
4250 def test_no_help(self):
4251 parser = ErrorRaisingArgumentParser(add_help=False)
4252 self.assertArgumentParserError(parser, '-h')
4253 self.assertArgumentParserError(parser, '--help')
4254 self.assertArgumentParserError(parser, '-v')
4255 self.assertArgumentParserError(parser, '--version')
4256
4257 def test_alternate_help_version(self):
4258 parser = ErrorRaisingArgumentParser()
4259 parser.add_argument('-x', action='help')
4260 parser.add_argument('-y', action='version')
4261 self.assertPrintHelpExit(parser, '-x')
4262 self.assertPrintVersionExit(parser, '-y')
4263 self.assertArgumentParserError(parser, '-v')
4264 self.assertArgumentParserError(parser, '--version')
4265
4266 def test_help_version_extra_arguments(self):
4267 parser = ErrorRaisingArgumentParser(version='1.0')
4268 parser.add_argument('-x', action='store_true')
4269 parser.add_argument('y')
4270
4271 # try all combinations of valid prefixes and suffixes
4272 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4273 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4274 for prefix in valid_prefixes:
4275 for suffix in valid_suffixes:
4276 format = '%s %%s %s' % (prefix, suffix)
4277 self.assertPrintHelpExit(parser, format % '-h')
4278 self.assertPrintHelpExit(parser, format % '--help')
4279 self.assertPrintVersionExit(parser, format % '-v')
4280 self.assertPrintVersionExit(parser, format % '--version')
4281
4282
4283# ======================
4284# str() and repr() tests
4285# ======================
4286
4287class TestStrings(TestCase):
4288 """Test str() and repr() on Optionals and Positionals"""
4289
4290 def assertStringEqual(self, obj, result_string):
4291 for func in [str, repr]:
4292 self.assertEqual(func(obj), result_string)
4293
4294 def test_optional(self):
4295 option = argparse.Action(
4296 option_strings=['--foo', '-a', '-b'],
4297 dest='b',
4298 type='int',
4299 nargs='+',
4300 default=42,
4301 choices=[1, 2, 3],
4302 help='HELP',
4303 metavar='METAVAR')
4304 string = (
4305 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4306 "nargs='+', const=None, default=42, type='int', "
4307 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4308 self.assertStringEqual(option, string)
4309
4310 def test_argument(self):
4311 argument = argparse.Action(
4312 option_strings=[],
4313 dest='x',
4314 type=float,
4315 nargs='?',
4316 default=2.5,
4317 choices=[0.5, 1.5, 2.5],
4318 help='H HH H',
4319 metavar='MV MV MV')
4320 string = (
4321 "Action(option_strings=[], dest='x', nargs='?', "
4322 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4323 "help='H HH H', metavar='MV MV MV')" % float)
4324 self.assertStringEqual(argument, string)
4325
4326 def test_namespace(self):
4327 ns = argparse.Namespace(foo=42, bar='spam')
4328 string = "Namespace(bar='spam', foo=42)"
4329 self.assertStringEqual(ns, string)
4330
4331 def test_parser(self):
4332 parser = argparse.ArgumentParser(prog='PROG')
4333 string = (
4334 "ArgumentParser(prog='PROG', usage=None, description=None, "
4335 "version=None, formatter_class=%r, conflict_handler='error', "
4336 "add_help=True)" % argparse.HelpFormatter)
4337 self.assertStringEqual(parser, string)
4338
4339# ===============
4340# Namespace tests
4341# ===============
4342
4343class TestNamespace(TestCase):
4344
4345 def test_constructor(self):
4346 ns = argparse.Namespace()
4347 self.assertRaises(AttributeError, getattr, ns, 'x')
4348
4349 ns = argparse.Namespace(a=42, b='spam')
4350 self.assertEqual(ns.a, 42)
4351 self.assertEqual(ns.b, 'spam')
4352
4353 def test_equality(self):
4354 ns1 = argparse.Namespace(a=1, b=2)
4355 ns2 = argparse.Namespace(b=2, a=1)
4356 ns3 = argparse.Namespace(a=1)
4357 ns4 = argparse.Namespace(b=2)
4358
4359 self.assertEqual(ns1, ns2)
4360 self.assertNotEqual(ns1, ns3)
4361 self.assertNotEqual(ns1, ns4)
4362 self.assertNotEqual(ns2, ns3)
4363 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004364 self.assertTrue(ns1 != ns3)
4365 self.assertTrue(ns1 != ns4)
4366 self.assertTrue(ns2 != ns3)
4367 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004368
4369
4370# ===================
4371# File encoding tests
4372# ===================
4373
4374class TestEncoding(TestCase):
4375
4376 def _test_module_encoding(self, path):
4377 path, _ = os.path.splitext(path)
4378 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004379 with codecs.open(path, 'r', 'utf8') as f:
4380 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004381
4382 def test_argparse_module_encoding(self):
4383 self._test_module_encoding(argparse.__file__)
4384
4385 def test_test_argparse_module_encoding(self):
4386 self._test_module_encoding(__file__)
4387
4388# ===================
4389# ArgumentError tests
4390# ===================
4391
4392class TestArgumentError(TestCase):
4393
4394 def test_argument_error(self):
4395 msg = "my error here"
4396 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004397 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004398
4399# =======================
4400# ArgumentTypeError tests
4401# =======================
4402
R. David Murray561b96f2011-02-11 17:25:54 +00004403class TestArgumentTypeError(TestCase):
Benjamin Petersona39e9662010-03-02 22:05:59 +00004404
4405 def test_argument_type_error(self):
4406
4407 def spam(string):
4408 raise argparse.ArgumentTypeError('spam!')
4409
4410 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4411 parser.add_argument('x', type=spam)
4412 try:
4413 parser.parse_args(['XXX'])
4414 except ArgumentParserError:
4415 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4416 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004417 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004418 else:
4419 self.fail()
4420
4421# ======================
4422# parse_known_args tests
4423# ======================
4424
4425class TestParseKnownArgs(TestCase):
4426
4427 def test_optionals(self):
4428 parser = argparse.ArgumentParser()
4429 parser.add_argument('--foo')
4430 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004431 self.assertEqual(NS(foo='F'), args)
4432 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004433
4434 def test_mixed(self):
4435 parser = argparse.ArgumentParser()
4436 parser.add_argument('-v', nargs='?', const=1, type=int)
4437 parser.add_argument('--spam', action='store_false')
4438 parser.add_argument('badger')
4439
4440 argv = ["B", "C", "--foo", "-v", "3", "4"]
4441 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004442 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4443 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004444
Steven Bethard53958622011-03-26 17:57:52 +01004445# ==========================
4446# add_argument metavar tests
4447# ==========================
4448
4449class TestAddArgumentMetavar(TestCase):
4450
4451 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4452
4453 def do_test_no_exception(self, nargs, metavar):
4454 parser = argparse.ArgumentParser()
4455 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4456
4457 def do_test_exception(self, nargs, metavar):
4458 parser = argparse.ArgumentParser()
4459 with self.assertRaises(ValueError) as cm:
4460 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4461 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4462
4463 # Unit tests for different values of metavar when nargs=None
4464
4465 def test_nargs_None_metavar_string(self):
4466 self.do_test_no_exception(nargs=None, metavar="1")
4467
4468 def test_nargs_None_metavar_length0(self):
4469 self.do_test_exception(nargs=None, metavar=tuple())
4470
4471 def test_nargs_None_metavar_length1(self):
4472 self.do_test_no_exception(nargs=None, metavar=("1"))
4473
4474 def test_nargs_None_metavar_length2(self):
4475 self.do_test_exception(nargs=None, metavar=("1", "2"))
4476
4477 def test_nargs_None_metavar_length3(self):
4478 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4479
4480 # Unit tests for different values of metavar when nargs=?
4481
4482 def test_nargs_optional_metavar_string(self):
4483 self.do_test_no_exception(nargs="?", metavar="1")
4484
4485 def test_nargs_optional_metavar_length0(self):
4486 self.do_test_exception(nargs="?", metavar=tuple())
4487
4488 def test_nargs_optional_metavar_length1(self):
4489 self.do_test_no_exception(nargs="?", metavar=("1"))
4490
4491 def test_nargs_optional_metavar_length2(self):
4492 self.do_test_exception(nargs="?", metavar=("1", "2"))
4493
4494 def test_nargs_optional_metavar_length3(self):
4495 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4496
4497 # Unit tests for different values of metavar when nargs=*
4498
4499 def test_nargs_zeroormore_metavar_string(self):
4500 self.do_test_no_exception(nargs="*", metavar="1")
4501
4502 def test_nargs_zeroormore_metavar_length0(self):
4503 self.do_test_exception(nargs="*", metavar=tuple())
4504
4505 def test_nargs_zeroormore_metavar_length1(self):
4506 self.do_test_no_exception(nargs="*", metavar=("1"))
4507
4508 def test_nargs_zeroormore_metavar_length2(self):
4509 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4510
4511 def test_nargs_zeroormore_metavar_length3(self):
4512 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4513
4514 # Unit tests for different values of metavar when nargs=+
4515
4516 def test_nargs_oneormore_metavar_string(self):
4517 self.do_test_no_exception(nargs="+", metavar="1")
4518
4519 def test_nargs_oneormore_metavar_length0(self):
4520 self.do_test_exception(nargs="+", metavar=tuple())
4521
4522 def test_nargs_oneormore_metavar_length1(self):
4523 self.do_test_no_exception(nargs="+", metavar=("1"))
4524
4525 def test_nargs_oneormore_metavar_length2(self):
4526 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4527
4528 def test_nargs_oneormore_metavar_length3(self):
4529 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4530
4531 # Unit tests for different values of metavar when nargs=...
4532
4533 def test_nargs_remainder_metavar_string(self):
4534 self.do_test_no_exception(nargs="...", metavar="1")
4535
4536 def test_nargs_remainder_metavar_length0(self):
4537 self.do_test_no_exception(nargs="...", metavar=tuple())
4538
4539 def test_nargs_remainder_metavar_length1(self):
4540 self.do_test_no_exception(nargs="...", metavar=("1"))
4541
4542 def test_nargs_remainder_metavar_length2(self):
4543 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4544
4545 def test_nargs_remainder_metavar_length3(self):
4546 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4547
4548 # Unit tests for different values of metavar when nargs=A...
4549
4550 def test_nargs_parser_metavar_string(self):
4551 self.do_test_no_exception(nargs="A...", metavar="1")
4552
4553 def test_nargs_parser_metavar_length0(self):
4554 self.do_test_exception(nargs="A...", metavar=tuple())
4555
4556 def test_nargs_parser_metavar_length1(self):
4557 self.do_test_no_exception(nargs="A...", metavar=("1"))
4558
4559 def test_nargs_parser_metavar_length2(self):
4560 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4561
4562 def test_nargs_parser_metavar_length3(self):
4563 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4564
4565 # Unit tests for different values of metavar when nargs=1
4566
4567 def test_nargs_1_metavar_string(self):
4568 self.do_test_no_exception(nargs=1, metavar="1")
4569
4570 def test_nargs_1_metavar_length0(self):
4571 self.do_test_exception(nargs=1, metavar=tuple())
4572
4573 def test_nargs_1_metavar_length1(self):
4574 self.do_test_no_exception(nargs=1, metavar=("1"))
4575
4576 def test_nargs_1_metavar_length2(self):
4577 self.do_test_exception(nargs=1, metavar=("1", "2"))
4578
4579 def test_nargs_1_metavar_length3(self):
4580 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4581
4582 # Unit tests for different values of metavar when nargs=2
4583
4584 def test_nargs_2_metavar_string(self):
4585 self.do_test_no_exception(nargs=2, metavar="1")
4586
4587 def test_nargs_2_metavar_length0(self):
4588 self.do_test_exception(nargs=2, metavar=tuple())
4589
4590 def test_nargs_2_metavar_length1(self):
4591 self.do_test_no_exception(nargs=2, metavar=("1"))
4592
4593 def test_nargs_2_metavar_length2(self):
4594 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4595
4596 def test_nargs_2_metavar_length3(self):
4597 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4598
4599 # Unit tests for different values of metavar when nargs=3
4600
4601 def test_nargs_3_metavar_string(self):
4602 self.do_test_no_exception(nargs=3, metavar="1")
4603
4604 def test_nargs_3_metavar_length0(self):
4605 self.do_test_exception(nargs=3, metavar=tuple())
4606
4607 def test_nargs_3_metavar_length1(self):
4608 self.do_test_no_exception(nargs=3, metavar=("1"))
4609
4610 def test_nargs_3_metavar_length2(self):
4611 self.do_test_exception(nargs=3, metavar=("1", "2"))
4612
4613 def test_nargs_3_metavar_length3(self):
4614 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4615
Benjamin Petersona39e9662010-03-02 22:05:59 +00004616# ============================
4617# from argparse import * tests
4618# ============================
4619
4620class TestImportStar(TestCase):
4621
4622 def test(self):
4623 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004624 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004625
Steven Bethard931906a2010-11-01 15:24:42 +00004626 def test_all_exports_everything_but_modules(self):
4627 items = [
4628 name
4629 for name, value in vars(argparse).items()
4630 if not name.startswith("_")
4631 if not inspect.ismodule(value)
4632 ]
4633 self.assertEqual(sorted(items), sorted(argparse.__all__))
4634
Benjamin Peterson036fae32010-03-02 22:20:10 +00004635def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004636 # silence warnings about version argument - these are expected
4637 with test_support.check_warnings(
4638 ('The "version" argument to ArgumentParser is deprecated.',
4639 DeprecationWarning),
4640 ('The (format|print)_version method is deprecated',
4641 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004642 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004643 # Remove global references to avoid looking like we have refleaks.
4644 RFile.seen = {}
4645 WFile.seen = set()
4646
Benjamin Peterson036fae32010-03-02 22:20:10 +00004647
Benjamin Petersona39e9662010-03-02 22:05:59 +00004648
4649if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004650 test_main()