blob: a7a4b005b0075ad2b7be183a54287d6addad51ac [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'])),
R David Murray056c31f2012-07-21 22:35:00 -04001377 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Petersona39e9662010-03-02 22:05:59 +00001378 ]
1379
1380
1381class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1382 """Test reading arguments from a file"""
1383
1384 def setUp(self):
1385 super(TestArgumentsFromFileConverter, self).setUp()
1386 file_texts = [
1387 ('hello', 'hello world!\n'),
1388 ]
1389 for path, text in file_texts:
1390 file = open(path, 'w')
1391 file.write(text)
1392 file.close()
1393
1394 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1395
1396 def convert_arg_line_to_args(self, arg_line):
1397 for arg in arg_line.split():
1398 if not arg.strip():
1399 continue
1400 yield arg
1401 parser_class = FromFileConverterArgumentParser
1402 parser_signature = Sig(fromfile_prefix_chars='@')
1403 argument_signatures = [
1404 Sig('y', nargs='+'),
1405 ]
1406 failures = []
1407 successes = [
1408 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1409 ]
1410
1411
1412# =====================
1413# Type conversion tests
1414# =====================
1415
1416class TestFileTypeRepr(TestCase):
1417
1418 def test_r(self):
1419 type = argparse.FileType('r')
1420 self.assertEqual("FileType('r')", repr(type))
1421
1422 def test_wb_1(self):
1423 type = argparse.FileType('wb', 1)
1424 self.assertEqual("FileType('wb', 1)", repr(type))
1425
1426
1427class RFile(object):
1428 seen = {}
1429
1430 def __init__(self, name):
1431 self.name = name
1432
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001433 __hash__ = None
1434
Benjamin Petersona39e9662010-03-02 22:05:59 +00001435 def __eq__(self, other):
1436 if other in self.seen:
1437 text = self.seen[other]
1438 else:
1439 text = self.seen[other] = other.read()
1440 other.close()
1441 if not isinstance(text, str):
1442 text = text.decode('ascii')
1443 return self.name == other.name == text
1444
1445
1446class TestFileTypeR(TempDirMixin, ParserTestCase):
1447 """Test the FileType option/argument type for reading files"""
1448
1449 def setUp(self):
1450 super(TestFileTypeR, self).setUp()
1451 for file_name in ['foo', 'bar']:
1452 file = open(os.path.join(self.temp_dir, file_name), 'w')
1453 file.write(file_name)
1454 file.close()
Steven Bethardf8583ac2011-01-24 20:40:15 +00001455 self.create_readonly_file('readonly')
Benjamin Petersona39e9662010-03-02 22:05:59 +00001456
1457 argument_signatures = [
1458 Sig('-x', type=argparse.FileType()),
1459 Sig('spam', type=argparse.FileType('r')),
1460 ]
Steven Bethardf8583ac2011-01-24 20:40:15 +00001461 failures = ['-x', '-x bar', 'non-existent-file.txt']
Benjamin Petersona39e9662010-03-02 22:05:59 +00001462 successes = [
1463 ('foo', NS(x=None, spam=RFile('foo'))),
1464 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1465 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1466 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
Steven Bethardf8583ac2011-01-24 20:40:15 +00001467 ('readonly', NS(x=None, spam=RFile('readonly'))),
Benjamin Petersona39e9662010-03-02 22:05:59 +00001468 ]
1469
1470
1471class TestFileTypeRB(TempDirMixin, ParserTestCase):
1472 """Test the FileType option/argument type for reading files"""
1473
1474 def setUp(self):
1475 super(TestFileTypeRB, self).setUp()
1476 for file_name in ['foo', 'bar']:
1477 file = open(os.path.join(self.temp_dir, file_name), 'w')
1478 file.write(file_name)
1479 file.close()
1480
1481 argument_signatures = [
1482 Sig('-x', type=argparse.FileType('rb')),
1483 Sig('spam', type=argparse.FileType('rb')),
1484 ]
1485 failures = ['-x', '-x bar']
1486 successes = [
1487 ('foo', NS(x=None, spam=RFile('foo'))),
1488 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1489 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1490 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
1491 ]
1492
1493
1494class WFile(object):
1495 seen = set()
1496
1497 def __init__(self, name):
1498 self.name = name
1499
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001500 __hash__ = None
1501
Benjamin Petersona39e9662010-03-02 22:05:59 +00001502 def __eq__(self, other):
1503 if other not in self.seen:
1504 text = 'Check that file is writable.'
1505 if 'b' in other.mode:
1506 text = text.encode('ascii')
1507 other.write(text)
1508 other.close()
1509 self.seen.add(other)
1510 return self.name == other.name
1511
1512
Victor Stinner9d38b0d2011-11-20 23:09:09 +01001513@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1514 "non-root user required")
Benjamin Petersona39e9662010-03-02 22:05:59 +00001515class TestFileTypeW(TempDirMixin, ParserTestCase):
1516 """Test the FileType option/argument type for writing files"""
1517
Steven Bethardf8583ac2011-01-24 20:40:15 +00001518 def setUp(self):
1519 super(TestFileTypeW, self).setUp()
1520 self.create_readonly_file('readonly')
1521
Benjamin Petersona39e9662010-03-02 22:05:59 +00001522 argument_signatures = [
1523 Sig('-x', type=argparse.FileType('w')),
1524 Sig('spam', type=argparse.FileType('w')),
1525 ]
1526 failures = ['-x', '-x bar']
Steven Bethardf8583ac2011-01-24 20:40:15 +00001527 failures = ['-x', '-x bar', 'readonly']
Benjamin Petersona39e9662010-03-02 22:05:59 +00001528 successes = [
1529 ('foo', NS(x=None, spam=WFile('foo'))),
1530 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1531 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1532 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1533 ]
1534
1535
1536class TestFileTypeWB(TempDirMixin, ParserTestCase):
1537
1538 argument_signatures = [
1539 Sig('-x', type=argparse.FileType('wb')),
1540 Sig('spam', type=argparse.FileType('wb')),
1541 ]
1542 failures = ['-x', '-x bar']
1543 successes = [
1544 ('foo', NS(x=None, spam=WFile('foo'))),
1545 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1546 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1547 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1548 ]
1549
1550
1551class TestTypeCallable(ParserTestCase):
1552 """Test some callables as option/argument types"""
1553
1554 argument_signatures = [
1555 Sig('--eggs', type=complex),
1556 Sig('spam', type=float),
1557 ]
1558 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1559 successes = [
1560 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1561 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1562 ('1024.675', NS(eggs=None, spam=1024.675)),
1563 ]
1564
1565
1566class TestTypeUserDefined(ParserTestCase):
1567 """Test a user-defined option/argument type"""
1568
1569 class MyType(TestCase):
1570
1571 def __init__(self, value):
1572 self.value = value
1573
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001574 __hash__ = None
1575
Benjamin Petersona39e9662010-03-02 22:05:59 +00001576 def __eq__(self, other):
1577 return (type(self), self.value) == (type(other), other.value)
1578
1579 argument_signatures = [
1580 Sig('-x', type=MyType),
1581 Sig('spam', type=MyType),
1582 ]
1583 failures = []
1584 successes = [
1585 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1586 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1587 ]
1588
1589
1590class TestTypeClassicClass(ParserTestCase):
1591 """Test a classic class type"""
1592
1593 class C:
1594
1595 def __init__(self, value):
1596 self.value = value
1597
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001598 __hash__ = None
1599
Benjamin Petersona39e9662010-03-02 22:05:59 +00001600 def __eq__(self, other):
1601 return (type(self), self.value) == (type(other), other.value)
1602
1603 argument_signatures = [
1604 Sig('-x', type=C),
1605 Sig('spam', type=C),
1606 ]
1607 failures = []
1608 successes = [
1609 ('a -x b', NS(x=C('b'), spam=C('a'))),
1610 ('-xf g', NS(x=C('f'), spam=C('g'))),
1611 ]
1612
1613
1614class TestTypeRegistration(TestCase):
1615 """Test a user-defined type by registering it"""
1616
1617 def test(self):
1618
1619 def get_my_type(string):
1620 return 'my_type{%s}' % string
1621
1622 parser = argparse.ArgumentParser()
1623 parser.register('type', 'my_type', get_my_type)
1624 parser.add_argument('-x', type='my_type')
1625 parser.add_argument('y', type='my_type')
1626
1627 self.assertEqual(parser.parse_args('1'.split()),
1628 NS(x=None, y='my_type{1}'))
1629 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1630 NS(x='my_type{1}', y='my_type{42}'))
1631
1632
1633# ============
1634# Action tests
1635# ============
1636
1637class TestActionUserDefined(ParserTestCase):
1638 """Test a user-defined option/argument action"""
1639
1640 class OptionalAction(argparse.Action):
1641
1642 def __call__(self, parser, namespace, value, option_string=None):
1643 try:
1644 # check destination and option string
1645 assert self.dest == 'spam', 'dest: %s' % self.dest
1646 assert option_string == '-s', 'flag: %s' % option_string
1647 # when option is before argument, badger=2, and when
1648 # option is after argument, badger=<whatever was set>
1649 expected_ns = NS(spam=0.25)
1650 if value in [0.125, 0.625]:
1651 expected_ns.badger = 2
1652 elif value in [2.0]:
1653 expected_ns.badger = 84
1654 else:
1655 raise AssertionError('value: %s' % value)
1656 assert expected_ns == namespace, ('expected %s, got %s' %
1657 (expected_ns, namespace))
1658 except AssertionError:
1659 e = sys.exc_info()[1]
1660 raise ArgumentParserError('opt_action failed: %s' % e)
1661 setattr(namespace, 'spam', value)
1662
1663 class PositionalAction(argparse.Action):
1664
1665 def __call__(self, parser, namespace, value, option_string=None):
1666 try:
1667 assert option_string is None, ('option_string: %s' %
1668 option_string)
1669 # check destination
1670 assert self.dest == 'badger', 'dest: %s' % self.dest
1671 # when argument is before option, spam=0.25, and when
1672 # option is after argument, spam=<whatever was set>
1673 expected_ns = NS(badger=2)
1674 if value in [42, 84]:
1675 expected_ns.spam = 0.25
1676 elif value in [1]:
1677 expected_ns.spam = 0.625
1678 elif value in [2]:
1679 expected_ns.spam = 0.125
1680 else:
1681 raise AssertionError('value: %s' % value)
1682 assert expected_ns == namespace, ('expected %s, got %s' %
1683 (expected_ns, namespace))
1684 except AssertionError:
1685 e = sys.exc_info()[1]
1686 raise ArgumentParserError('arg_action failed: %s' % e)
1687 setattr(namespace, 'badger', value)
1688
1689 argument_signatures = [
1690 Sig('-s', dest='spam', action=OptionalAction,
1691 type=float, default=0.25),
1692 Sig('badger', action=PositionalAction,
1693 type=int, nargs='?', default=2),
1694 ]
1695 failures = []
1696 successes = [
1697 ('-s0.125', NS(spam=0.125, badger=2)),
1698 ('42', NS(spam=0.25, badger=42)),
1699 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1700 ('84 -s2', NS(spam=2.0, badger=84)),
1701 ]
1702
1703
1704class TestActionRegistration(TestCase):
1705 """Test a user-defined action supplied by registering it"""
1706
1707 class MyAction(argparse.Action):
1708
1709 def __call__(self, parser, namespace, values, option_string=None):
1710 setattr(namespace, self.dest, 'foo[%s]' % values)
1711
1712 def test(self):
1713
1714 parser = argparse.ArgumentParser()
1715 parser.register('action', 'my_action', self.MyAction)
1716 parser.add_argument('badger', action='my_action')
1717
1718 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1719 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1720
1721
1722# ================
1723# Subparsers tests
1724# ================
1725
1726class TestAddSubparsers(TestCase):
1727 """Test the add_subparsers method"""
1728
1729 def assertArgumentParserError(self, *args, **kwargs):
1730 self.assertRaises(ArgumentParserError, *args, **kwargs)
1731
R. David Murray1cbf78e2010-08-03 18:14:01 +00001732 def _get_parser(self, subparser_help=False, prefix_chars=None):
Benjamin Petersona39e9662010-03-02 22:05:59 +00001733 # create a parser with a subparsers argument
R. David Murray1cbf78e2010-08-03 18:14:01 +00001734 if prefix_chars:
1735 parser = ErrorRaisingArgumentParser(
1736 prog='PROG', description='main description', prefix_chars=prefix_chars)
1737 parser.add_argument(
1738 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1739 else:
1740 parser = ErrorRaisingArgumentParser(
1741 prog='PROG', description='main description')
1742 parser.add_argument(
1743 '--foo', action='store_true', help='foo help')
Benjamin Petersona39e9662010-03-02 22:05:59 +00001744 parser.add_argument(
1745 'bar', type=float, help='bar help')
1746
1747 # check that only one subparsers argument can be added
1748 subparsers = parser.add_subparsers(help='command help')
1749 self.assertArgumentParserError(parser.add_subparsers)
1750
1751 # add first sub-parser
1752 parser1_kwargs = dict(description='1 description')
1753 if subparser_help:
1754 parser1_kwargs['help'] = '1 help'
1755 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1756 parser1.add_argument('-w', type=int, help='w help')
1757 parser1.add_argument('x', choices='abc', help='x help')
1758
1759 # add second sub-parser
1760 parser2_kwargs = dict(description='2 description')
1761 if subparser_help:
1762 parser2_kwargs['help'] = '2 help'
1763 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1764 parser2.add_argument('-y', choices='123', help='y help')
1765 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1766
1767 # return the main parser
1768 return parser
1769
1770 def setUp(self):
Steven Bethardabacccc2010-11-01 14:09:21 +00001771 super(TestAddSubparsers, self).setUp()
Benjamin Petersona39e9662010-03-02 22:05:59 +00001772 self.parser = self._get_parser()
1773 self.command_help_parser = self._get_parser(subparser_help=True)
1774
1775 def test_parse_args_failures(self):
1776 # check some failure cases:
1777 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1778 '0.5 1 -y', '0.5 2 -w']:
1779 args = args_str.split()
1780 self.assertArgumentParserError(self.parser.parse_args, args)
1781
1782 def test_parse_args(self):
1783 # check some non-failure cases:
1784 self.assertEqual(
1785 self.parser.parse_args('0.5 1 b -w 7'.split()),
1786 NS(foo=False, bar=0.5, w=7, x='b'),
1787 )
1788 self.assertEqual(
1789 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1790 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1791 )
1792 self.assertEqual(
1793 self.parser.parse_args('--foo 0.125 1 c'.split()),
1794 NS(foo=True, bar=0.125, w=None, x='c'),
1795 )
1796
Steven Bethard2e4d4c42010-11-02 12:48:15 +00001797 def test_parse_known_args(self):
1798 self.assertEqual(
1799 self.parser.parse_known_args('0.5 1 b -w 7'.split()),
1800 (NS(foo=False, bar=0.5, w=7, x='b'), []),
1801 )
1802 self.assertEqual(
1803 self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
1804 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1805 )
1806 self.assertEqual(
1807 self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
1808 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1809 )
1810 self.assertEqual(
1811 self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
1812 (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
1813 )
1814 self.assertEqual(
1815 self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
1816 (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
1817 )
1818
Benjamin Petersona39e9662010-03-02 22:05:59 +00001819 def test_dest(self):
1820 parser = ErrorRaisingArgumentParser()
1821 parser.add_argument('--foo', action='store_true')
1822 subparsers = parser.add_subparsers(dest='bar')
1823 parser1 = subparsers.add_parser('1')
1824 parser1.add_argument('baz')
1825 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1826 parser.parse_args('1 2'.split()))
1827
1828 def test_help(self):
1829 self.assertEqual(self.parser.format_usage(),
1830 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1831 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
1832 usage: PROG [-h] [--foo] bar {1,2} ...
1833
1834 main description
1835
1836 positional arguments:
1837 bar bar help
1838 {1,2} command help
1839
1840 optional arguments:
1841 -h, --help show this help message and exit
1842 --foo foo help
1843 '''))
1844
R. David Murray1cbf78e2010-08-03 18:14:01 +00001845 def test_help_extra_prefix_chars(self):
1846 # Make sure - is still used for help if it is a non-first prefix char
1847 parser = self._get_parser(prefix_chars='+:-')
1848 self.assertEqual(parser.format_usage(),
1849 'usage: PROG [-h] [++foo] bar {1,2} ...\n')
1850 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1851 usage: PROG [-h] [++foo] bar {1,2} ...
1852
1853 main description
1854
1855 positional arguments:
1856 bar bar help
1857 {1,2} command help
1858
1859 optional arguments:
1860 -h, --help show this help message and exit
1861 ++foo foo help
1862 '''))
1863
1864
1865 def test_help_alternate_prefix_chars(self):
1866 parser = self._get_parser(prefix_chars='+:/')
1867 self.assertEqual(parser.format_usage(),
1868 'usage: PROG [+h] [++foo] bar {1,2} ...\n')
1869 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1870 usage: PROG [+h] [++foo] bar {1,2} ...
1871
1872 main description
1873
1874 positional arguments:
1875 bar bar help
1876 {1,2} command help
1877
1878 optional arguments:
1879 +h, ++help show this help message and exit
1880 ++foo foo help
1881 '''))
1882
Benjamin Petersona39e9662010-03-02 22:05:59 +00001883 def test_parser_command_help(self):
1884 self.assertEqual(self.command_help_parser.format_usage(),
1885 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1886 self.assertEqual(self.command_help_parser.format_help(),
1887 textwrap.dedent('''\
1888 usage: PROG [-h] [--foo] bar {1,2} ...
1889
1890 main description
1891
1892 positional arguments:
1893 bar bar help
1894 {1,2} command help
1895 1 1 help
1896 2 2 help
1897
1898 optional arguments:
1899 -h, --help show this help message and exit
1900 --foo foo help
1901 '''))
1902
1903 def test_subparser_title_help(self):
1904 parser = ErrorRaisingArgumentParser(prog='PROG',
1905 description='main description')
1906 parser.add_argument('--foo', action='store_true', help='foo help')
1907 parser.add_argument('bar', help='bar help')
1908 subparsers = parser.add_subparsers(title='subcommands',
1909 description='command help',
1910 help='additional text')
1911 parser1 = subparsers.add_parser('1')
1912 parser2 = subparsers.add_parser('2')
1913 self.assertEqual(parser.format_usage(),
1914 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1915 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1916 usage: PROG [-h] [--foo] bar {1,2} ...
1917
1918 main description
1919
1920 positional arguments:
1921 bar bar help
1922
1923 optional arguments:
1924 -h, --help show this help message and exit
1925 --foo foo help
1926
1927 subcommands:
1928 command help
1929
1930 {1,2} additional text
1931 '''))
1932
1933 def _test_subparser_help(self, args_str, expected_help):
1934 try:
1935 self.parser.parse_args(args_str.split())
1936 except ArgumentParserError:
1937 err = sys.exc_info()[1]
1938 if err.stdout != expected_help:
1939 print(repr(expected_help))
1940 print(repr(err.stdout))
1941 self.assertEqual(err.stdout, expected_help)
1942
1943 def test_subparser1_help(self):
1944 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
1945 usage: PROG bar 1 [-h] [-w W] {a,b,c}
1946
1947 1 description
1948
1949 positional arguments:
1950 {a,b,c} x help
1951
1952 optional arguments:
1953 -h, --help show this help message and exit
1954 -w W w help
1955 '''))
1956
1957 def test_subparser2_help(self):
1958 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
1959 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
1960
1961 2 description
1962
1963 positional arguments:
1964 z z help
1965
1966 optional arguments:
1967 -h, --help show this help message and exit
1968 -y {1,2,3} y help
1969 '''))
1970
1971# ============
1972# Groups tests
1973# ============
1974
1975class TestPositionalsGroups(TestCase):
1976 """Tests that order of group positionals matches construction order"""
1977
1978 def test_nongroup_first(self):
1979 parser = ErrorRaisingArgumentParser()
1980 parser.add_argument('foo')
1981 group = parser.add_argument_group('g')
1982 group.add_argument('bar')
1983 parser.add_argument('baz')
1984 expected = NS(foo='1', bar='2', baz='3')
1985 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001986 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001987
1988 def test_group_first(self):
1989 parser = ErrorRaisingArgumentParser()
1990 group = parser.add_argument_group('xxx')
1991 group.add_argument('foo')
1992 parser.add_argument('bar')
1993 parser.add_argument('baz')
1994 expected = NS(foo='1', bar='2', baz='3')
1995 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001996 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001997
1998 def test_interleaved_groups(self):
1999 parser = ErrorRaisingArgumentParser()
2000 group = parser.add_argument_group('xxx')
2001 parser.add_argument('foo')
2002 group.add_argument('bar')
2003 parser.add_argument('baz')
2004 group = parser.add_argument_group('yyy')
2005 group.add_argument('frell')
2006 expected = NS(foo='1', bar='2', baz='3', frell='4')
2007 result = parser.parse_args('1 2 3 4'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00002008 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002009
2010# ===================
2011# Parent parser tests
2012# ===================
2013
2014class TestParentParsers(TestCase):
2015 """Tests that parsers can be created with parent parsers"""
2016
2017 def assertArgumentParserError(self, *args, **kwargs):
2018 self.assertRaises(ArgumentParserError, *args, **kwargs)
2019
2020 def setUp(self):
Steven Bethardabacccc2010-11-01 14:09:21 +00002021 super(TestParentParsers, self).setUp()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002022 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
2023 self.wxyz_parent.add_argument('--w')
2024 x_group = self.wxyz_parent.add_argument_group('x')
2025 x_group.add_argument('-y')
2026 self.wxyz_parent.add_argument('z')
2027
2028 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
2029 self.abcd_parent.add_argument('a')
2030 self.abcd_parent.add_argument('-b')
2031 c_group = self.abcd_parent.add_argument_group('c')
2032 c_group.add_argument('--d')
2033
2034 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2035 self.w_parent.add_argument('--w')
2036
2037 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2038 self.z_parent.add_argument('z')
2039
2040 # parents with mutually exclusive groups
2041 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2042 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2043 group.add_argument('-a', action='store_true')
2044 group.add_argument('-b', action='store_true')
2045
Benjamin Peterson036fae32010-03-02 22:20:10 +00002046 self.main_program = os.path.basename(sys.argv[0])
2047
Benjamin Petersona39e9662010-03-02 22:05:59 +00002048 def test_single_parent(self):
2049 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2050 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2051 NS(w='3', y='1', z='2'))
2052
2053 def test_single_parent_mutex(self):
2054 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2055 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2056 self._test_mutex_ab(parser.parse_args)
2057
2058 def test_single_granparent_mutex(self):
2059 parents = [self.ab_mutex_parent]
2060 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2061 parser = ErrorRaisingArgumentParser(parents=[parser])
2062 self._test_mutex_ab(parser.parse_args)
2063
2064 def _test_mutex_ab(self, parse_args):
2065 self.assertEqual(parse_args([]), NS(a=False, b=False))
2066 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2067 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2068 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2069 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2070 self.assertArgumentParserError(parse_args, ['-c'])
2071 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2072 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2073
2074 def test_multiple_parents(self):
2075 parents = [self.abcd_parent, self.wxyz_parent]
2076 parser = ErrorRaisingArgumentParser(parents=parents)
2077 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2078 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2079
2080 def test_multiple_parents_mutex(self):
2081 parents = [self.ab_mutex_parent, self.wxyz_parent]
2082 parser = ErrorRaisingArgumentParser(parents=parents)
2083 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2084 NS(a=True, b=False, w='2', y=None, z='3'))
2085 self.assertArgumentParserError(
2086 parser.parse_args, '-a --w 2 3 -b'.split())
2087 self.assertArgumentParserError(
2088 parser.parse_args, '-a -b --w 2 3'.split())
2089
2090 def test_conflicting_parents(self):
2091 self.assertRaises(
2092 argparse.ArgumentError,
2093 argparse.ArgumentParser,
2094 parents=[self.w_parent, self.wxyz_parent])
2095
2096 def test_conflicting_parents_mutex(self):
2097 self.assertRaises(
2098 argparse.ArgumentError,
2099 argparse.ArgumentParser,
2100 parents=[self.abcd_parent, self.ab_mutex_parent])
2101
2102 def test_same_argument_name_parents(self):
2103 parents = [self.wxyz_parent, self.z_parent]
2104 parser = ErrorRaisingArgumentParser(parents=parents)
2105 self.assertEqual(parser.parse_args('1 2'.split()),
2106 NS(w=None, y=None, z='2'))
2107
2108 def test_subparser_parents(self):
2109 parser = ErrorRaisingArgumentParser()
2110 subparsers = parser.add_subparsers()
2111 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2112 abcde_parser.add_argument('e')
2113 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2114 NS(a='3', b='1', d='2', e='4'))
2115
2116 def test_subparser_parents_mutex(self):
2117 parser = ErrorRaisingArgumentParser()
2118 subparsers = parser.add_subparsers()
2119 parents = [self.ab_mutex_parent]
2120 abc_parser = subparsers.add_parser('foo', parents=parents)
2121 c_group = abc_parser.add_argument_group('c_group')
2122 c_group.add_argument('c')
2123 parents = [self.wxyz_parent, self.ab_mutex_parent]
2124 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2125 wxyzabe_parser.add_argument('e')
2126 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2127 NS(a=True, b=False, c='4'))
2128 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2129 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2130 self.assertArgumentParserError(
2131 parser.parse_args, 'foo -a -b 4'.split())
2132 self.assertArgumentParserError(
2133 parser.parse_args, 'bar -b -a 4'.split())
2134
2135 def test_parent_help(self):
2136 parents = [self.abcd_parent, self.wxyz_parent]
2137 parser = ErrorRaisingArgumentParser(parents=parents)
2138 parser_help = parser.format_help()
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002139 progname = self.main_program
Benjamin Petersona39e9662010-03-02 22:05:59 +00002140 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002141 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Petersona39e9662010-03-02 22:05:59 +00002142
2143 positional arguments:
2144 a
2145 z
2146
2147 optional arguments:
2148 -h, --help show this help message and exit
2149 -b B
2150 --w W
2151
2152 c:
2153 --d D
2154
2155 x:
2156 -y Y
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002157 '''.format(progname, ' ' if progname else '' )))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002158
2159 def test_groups_parents(self):
2160 parent = ErrorRaisingArgumentParser(add_help=False)
2161 g = parent.add_argument_group(title='g', description='gd')
2162 g.add_argument('-w')
2163 g.add_argument('-x')
2164 m = parent.add_mutually_exclusive_group()
2165 m.add_argument('-y')
2166 m.add_argument('-z')
2167 parser = ErrorRaisingArgumentParser(parents=[parent])
2168
2169 self.assertRaises(ArgumentParserError, parser.parse_args,
2170 ['-y', 'Y', '-z', 'Z'])
2171
2172 parser_help = parser.format_help()
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002173 progname = self.main_program
Benjamin Petersona39e9662010-03-02 22:05:59 +00002174 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002175 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Petersona39e9662010-03-02 22:05:59 +00002176
2177 optional arguments:
2178 -h, --help show this help message and exit
2179 -y Y
2180 -z Z
2181
2182 g:
2183 gd
2184
2185 -w W
2186 -x X
Terry Jan Reedycfe6deb2012-01-09 18:20:09 -05002187 '''.format(progname, ' ' if progname else '' )))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002188
2189# ==============================
2190# Mutually exclusive group tests
2191# ==============================
2192
2193class TestMutuallyExclusiveGroupErrors(TestCase):
2194
2195 def test_invalid_add_argument_group(self):
2196 parser = ErrorRaisingArgumentParser()
2197 raises = self.assertRaises
2198 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2199
2200 def test_invalid_add_argument(self):
2201 parser = ErrorRaisingArgumentParser()
2202 group = parser.add_mutually_exclusive_group()
2203 add_argument = group.add_argument
2204 raises = self.assertRaises
2205 raises(ValueError, add_argument, '--foo', required=True)
2206 raises(ValueError, add_argument, 'bar')
2207 raises(ValueError, add_argument, 'bar', nargs='+')
2208 raises(ValueError, add_argument, 'bar', nargs=1)
2209 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2210
Steven Bethard68c36782010-11-01 16:30:24 +00002211 def test_help(self):
2212 parser = ErrorRaisingArgumentParser(prog='PROG')
2213 group1 = parser.add_mutually_exclusive_group()
2214 group1.add_argument('--foo', action='store_true')
2215 group1.add_argument('--bar', action='store_false')
2216 group2 = parser.add_mutually_exclusive_group()
2217 group2.add_argument('--soup', action='store_true')
2218 group2.add_argument('--nuts', action='store_false')
2219 expected = '''\
2220 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2221
2222 optional arguments:
2223 -h, --help show this help message and exit
2224 --foo
2225 --bar
2226 --soup
2227 --nuts
2228 '''
2229 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002230
2231class MEMixin(object):
2232
2233 def test_failures_when_not_required(self):
2234 parse_args = self.get_parser(required=False).parse_args
2235 error = ArgumentParserError
2236 for args_string in self.failures:
2237 self.assertRaises(error, parse_args, args_string.split())
2238
2239 def test_failures_when_required(self):
2240 parse_args = self.get_parser(required=True).parse_args
2241 error = ArgumentParserError
2242 for args_string in self.failures + ['']:
2243 self.assertRaises(error, parse_args, args_string.split())
2244
2245 def test_successes_when_not_required(self):
2246 parse_args = self.get_parser(required=False).parse_args
2247 successes = self.successes + self.successes_when_not_required
2248 for args_string, expected_ns in successes:
2249 actual_ns = parse_args(args_string.split())
2250 self.assertEqual(actual_ns, expected_ns)
2251
2252 def test_successes_when_required(self):
2253 parse_args = self.get_parser(required=True).parse_args
2254 for args_string, expected_ns in self.successes:
2255 actual_ns = parse_args(args_string.split())
2256 self.assertEqual(actual_ns, expected_ns)
2257
2258 def test_usage_when_not_required(self):
2259 format_usage = self.get_parser(required=False).format_usage
2260 expected_usage = self.usage_when_not_required
2261 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2262
2263 def test_usage_when_required(self):
2264 format_usage = self.get_parser(required=True).format_usage
2265 expected_usage = self.usage_when_required
2266 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2267
2268 def test_help_when_not_required(self):
2269 format_help = self.get_parser(required=False).format_help
2270 help = self.usage_when_not_required + self.help
2271 self.assertEqual(format_help(), textwrap.dedent(help))
2272
2273 def test_help_when_required(self):
2274 format_help = self.get_parser(required=True).format_help
2275 help = self.usage_when_required + self.help
2276 self.assertEqual(format_help(), textwrap.dedent(help))
2277
2278
2279class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2280
2281 def get_parser(self, required=None):
2282 parser = ErrorRaisingArgumentParser(prog='PROG')
2283 group = parser.add_mutually_exclusive_group(required=required)
2284 group.add_argument('--bar', help='bar help')
2285 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2286 return parser
2287
2288 failures = ['--bar X --baz Y', '--bar X --baz']
2289 successes = [
2290 ('--bar X', NS(bar='X', baz=None)),
2291 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2292 ('--baz Y', NS(bar=None, baz='Y')),
2293 ('--baz', NS(bar=None, baz='Z')),
2294 ]
2295 successes_when_not_required = [
2296 ('', NS(bar=None, baz=None)),
2297 ]
2298
2299 usage_when_not_required = '''\
2300 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2301 '''
2302 usage_when_required = '''\
2303 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2304 '''
2305 help = '''\
2306
2307 optional arguments:
2308 -h, --help show this help message and exit
2309 --bar BAR bar help
2310 --baz [BAZ] baz help
2311 '''
2312
2313
2314class TestMutuallyExclusiveLong(MEMixin, TestCase):
2315
2316 def get_parser(self, required=None):
2317 parser = ErrorRaisingArgumentParser(prog='PROG')
2318 parser.add_argument('--abcde', help='abcde help')
2319 parser.add_argument('--fghij', help='fghij help')
2320 group = parser.add_mutually_exclusive_group(required=required)
2321 group.add_argument('--klmno', help='klmno help')
2322 group.add_argument('--pqrst', help='pqrst help')
2323 return parser
2324
2325 failures = ['--klmno X --pqrst Y']
2326 successes = [
2327 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2328 ('--abcde Y --klmno X',
2329 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2330 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2331 ('--pqrst X --fghij Y',
2332 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2333 ]
2334 successes_when_not_required = [
2335 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2336 ]
2337
2338 usage_when_not_required = '''\
2339 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2340 [--klmno KLMNO | --pqrst PQRST]
2341 '''
2342 usage_when_required = '''\
2343 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2344 (--klmno KLMNO | --pqrst PQRST)
2345 '''
2346 help = '''\
2347
2348 optional arguments:
2349 -h, --help show this help message and exit
2350 --abcde ABCDE abcde help
2351 --fghij FGHIJ fghij help
2352 --klmno KLMNO klmno help
2353 --pqrst PQRST pqrst help
2354 '''
2355
2356
2357class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2358
2359 def get_parser(self, required):
2360 parser = ErrorRaisingArgumentParser(prog='PROG')
2361 group = parser.add_mutually_exclusive_group(required=required)
2362 group.add_argument('-x', help=argparse.SUPPRESS)
2363 group.add_argument('-y', action='store_false', help='y help')
2364 return parser
2365
2366 failures = ['-x X -y']
2367 successes = [
2368 ('-x X', NS(x='X', y=True)),
2369 ('-x X -x Y', NS(x='Y', y=True)),
2370 ('-y', NS(x=None, y=False)),
2371 ]
2372 successes_when_not_required = [
2373 ('', NS(x=None, y=True)),
2374 ]
2375
2376 usage_when_not_required = '''\
2377 usage: PROG [-h] [-y]
2378 '''
2379 usage_when_required = '''\
2380 usage: PROG [-h] -y
2381 '''
2382 help = '''\
2383
2384 optional arguments:
2385 -h, --help show this help message and exit
2386 -y y help
2387 '''
2388
2389
2390class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2391
2392 def get_parser(self, required):
2393 parser = ErrorRaisingArgumentParser(prog='PROG')
2394 group = parser.add_mutually_exclusive_group(required=required)
2395 add = group.add_argument
2396 add('--spam', action='store_true', help=argparse.SUPPRESS)
2397 add('--badger', action='store_false', help=argparse.SUPPRESS)
2398 add('--bladder', help=argparse.SUPPRESS)
2399 return parser
2400
2401 failures = [
2402 '--spam --badger',
2403 '--badger --bladder B',
2404 '--bladder B --spam',
2405 ]
2406 successes = [
2407 ('--spam', NS(spam=True, badger=True, bladder=None)),
2408 ('--badger', NS(spam=False, badger=False, bladder=None)),
2409 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2410 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2411 ]
2412 successes_when_not_required = [
2413 ('', NS(spam=False, badger=True, bladder=None)),
2414 ]
2415
2416 usage_when_required = usage_when_not_required = '''\
2417 usage: PROG [-h]
2418 '''
2419 help = '''\
2420
2421 optional arguments:
2422 -h, --help show this help message and exit
2423 '''
2424
2425
2426class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2427
2428 def get_parser(self, required):
2429 parser = ErrorRaisingArgumentParser(prog='PROG')
2430 group = parser.add_mutually_exclusive_group(required=required)
2431 group.add_argument('--foo', action='store_true', help='FOO')
2432 group.add_argument('--spam', help='SPAM')
2433 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2434 return parser
2435
2436 failures = [
2437 '--foo --spam S',
2438 '--spam S X',
2439 'X --foo',
2440 'X Y Z --spam S',
2441 '--foo X Y',
2442 ]
2443 successes = [
2444 ('--foo', NS(foo=True, spam=None, badger='X')),
2445 ('--spam S', NS(foo=False, spam='S', badger='X')),
2446 ('X', NS(foo=False, spam=None, badger=['X'])),
2447 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2448 ]
2449 successes_when_not_required = [
2450 ('', NS(foo=False, spam=None, badger='X')),
2451 ]
2452
2453 usage_when_not_required = '''\
2454 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2455 '''
2456 usage_when_required = '''\
2457 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2458 '''
2459 help = '''\
2460
2461 positional arguments:
2462 badger BADGER
2463
2464 optional arguments:
2465 -h, --help show this help message and exit
2466 --foo FOO
2467 --spam SPAM SPAM
2468 '''
2469
2470
2471class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2472
2473 def get_parser(self, required):
2474 parser = ErrorRaisingArgumentParser(prog='PROG')
2475 parser.add_argument('-x', action='store_true', help='x help')
2476 group = parser.add_mutually_exclusive_group(required=required)
2477 group.add_argument('-a', action='store_true', help='a help')
2478 group.add_argument('-b', action='store_true', help='b help')
2479 parser.add_argument('-y', action='store_true', help='y help')
2480 group.add_argument('-c', action='store_true', help='c help')
2481 return parser
2482
2483 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2484 successes = [
2485 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2486 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2487 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2488 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2489 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2490 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2491 ]
2492 successes_when_not_required = [
2493 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2494 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2495 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2496 ]
2497
2498 usage_when_required = usage_when_not_required = '''\
2499 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2500 '''
2501 help = '''\
2502
2503 optional arguments:
2504 -h, --help show this help message and exit
2505 -x x help
2506 -a a help
2507 -b b help
2508 -y y help
2509 -c c help
2510 '''
2511
2512
Steven Bethard7f41b882011-01-30 14:05:38 +00002513class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2514
2515 def get_parser(self, required=None):
2516 parser = ErrorRaisingArgumentParser(prog='PROG')
2517 titled_group = parser.add_argument_group(
2518 title='Titled group', description='Group description')
2519 mutex_group = \
2520 titled_group.add_mutually_exclusive_group(required=required)
2521 mutex_group.add_argument('--bar', help='bar help')
2522 mutex_group.add_argument('--baz', help='baz help')
2523 return parser
2524
2525 failures = ['--bar X --baz Y', '--baz X --bar Y']
2526 successes = [
2527 ('--bar X', NS(bar='X', baz=None)),
2528 ('--baz Y', NS(bar=None, baz='Y')),
2529 ]
2530 successes_when_not_required = [
2531 ('', NS(bar=None, baz=None)),
2532 ]
2533
2534 usage_when_not_required = '''\
2535 usage: PROG [-h] [--bar BAR | --baz BAZ]
2536 '''
2537 usage_when_required = '''\
2538 usage: PROG [-h] (--bar BAR | --baz BAZ)
2539 '''
2540 help = '''\
2541
2542 optional arguments:
2543 -h, --help show this help message and exit
2544
2545 Titled group:
2546 Group description
2547
2548 --bar BAR bar help
2549 --baz BAZ baz help
2550 '''
2551
2552
Benjamin Petersona39e9662010-03-02 22:05:59 +00002553class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2554
2555 def get_parser(self, required):
2556 parser = ErrorRaisingArgumentParser(prog='PROG')
2557 parser.add_argument('x', help='x help')
2558 parser.add_argument('-y', action='store_true', help='y help')
2559 group = parser.add_mutually_exclusive_group(required=required)
2560 group.add_argument('a', nargs='?', help='a help')
2561 group.add_argument('-b', action='store_true', help='b help')
2562 group.add_argument('-c', action='store_true', help='c help')
2563 return parser
2564
2565 failures = ['X A -b', '-b -c', '-c X A']
2566 successes = [
2567 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2568 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2569 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2570 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2571 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2572 ]
2573 successes_when_not_required = [
2574 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2575 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2576 ]
2577
2578 usage_when_required = usage_when_not_required = '''\
2579 usage: PROG [-h] [-y] [-b] [-c] x [a]
2580 '''
2581 help = '''\
2582
2583 positional arguments:
2584 x x help
2585 a a help
2586
2587 optional arguments:
2588 -h, --help show this help message and exit
2589 -y y help
2590 -b b help
2591 -c c help
2592 '''
2593
2594# =================================================
2595# Mutually exclusive group in parent parser tests
2596# =================================================
2597
2598class MEPBase(object):
2599
2600 def get_parser(self, required=None):
2601 parent = super(MEPBase, self).get_parser(required=required)
2602 parser = ErrorRaisingArgumentParser(
2603 prog=parent.prog, add_help=False, parents=[parent])
2604 return parser
2605
2606
2607class TestMutuallyExclusiveGroupErrorsParent(
2608 MEPBase, TestMutuallyExclusiveGroupErrors):
2609 pass
2610
2611
2612class TestMutuallyExclusiveSimpleParent(
2613 MEPBase, TestMutuallyExclusiveSimple):
2614 pass
2615
2616
2617class TestMutuallyExclusiveLongParent(
2618 MEPBase, TestMutuallyExclusiveLong):
2619 pass
2620
2621
2622class TestMutuallyExclusiveFirstSuppressedParent(
2623 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2624 pass
2625
2626
2627class TestMutuallyExclusiveManySuppressedParent(
2628 MEPBase, TestMutuallyExclusiveManySuppressed):
2629 pass
2630
2631
2632class TestMutuallyExclusiveOptionalAndPositionalParent(
2633 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2634 pass
2635
2636
2637class TestMutuallyExclusiveOptionalsMixedParent(
2638 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2639 pass
2640
2641
2642class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2643 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2644 pass
2645
2646# =================
2647# Set default tests
2648# =================
2649
2650class TestSetDefaults(TestCase):
2651
2652 def test_set_defaults_no_args(self):
2653 parser = ErrorRaisingArgumentParser()
2654 parser.set_defaults(x='foo')
2655 parser.set_defaults(y='bar', z=1)
2656 self.assertEqual(NS(x='foo', y='bar', z=1),
2657 parser.parse_args([]))
2658 self.assertEqual(NS(x='foo', y='bar', z=1),
2659 parser.parse_args([], NS()))
2660 self.assertEqual(NS(x='baz', y='bar', z=1),
2661 parser.parse_args([], NS(x='baz')))
2662 self.assertEqual(NS(x='baz', y='bar', z=2),
2663 parser.parse_args([], NS(x='baz', z=2)))
2664
2665 def test_set_defaults_with_args(self):
2666 parser = ErrorRaisingArgumentParser()
2667 parser.set_defaults(x='foo', y='bar')
2668 parser.add_argument('-x', default='xfoox')
2669 self.assertEqual(NS(x='xfoox', y='bar'),
2670 parser.parse_args([]))
2671 self.assertEqual(NS(x='xfoox', y='bar'),
2672 parser.parse_args([], NS()))
2673 self.assertEqual(NS(x='baz', y='bar'),
2674 parser.parse_args([], NS(x='baz')))
2675 self.assertEqual(NS(x='1', y='bar'),
2676 parser.parse_args('-x 1'.split()))
2677 self.assertEqual(NS(x='1', y='bar'),
2678 parser.parse_args('-x 1'.split(), NS()))
2679 self.assertEqual(NS(x='1', y='bar'),
2680 parser.parse_args('-x 1'.split(), NS(x='baz')))
2681
2682 def test_set_defaults_subparsers(self):
2683 parser = ErrorRaisingArgumentParser()
2684 parser.set_defaults(x='foo')
2685 subparsers = parser.add_subparsers()
2686 parser_a = subparsers.add_parser('a')
2687 parser_a.set_defaults(y='bar')
2688 self.assertEqual(NS(x='foo', y='bar'),
2689 parser.parse_args('a'.split()))
2690
2691 def test_set_defaults_parents(self):
2692 parent = ErrorRaisingArgumentParser(add_help=False)
2693 parent.set_defaults(x='foo')
2694 parser = ErrorRaisingArgumentParser(parents=[parent])
2695 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2696
2697 def test_set_defaults_same_as_add_argument(self):
2698 parser = ErrorRaisingArgumentParser()
2699 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2700 parser.add_argument('-w')
2701 parser.add_argument('-x', default='XX')
2702 parser.add_argument('y', nargs='?')
2703 parser.add_argument('z', nargs='?', default='ZZ')
2704
2705 # defaults set previously
2706 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2707 parser.parse_args([]))
2708
2709 # reset defaults
2710 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2711 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2712 parser.parse_args([]))
2713
2714 def test_set_defaults_same_as_add_argument_group(self):
2715 parser = ErrorRaisingArgumentParser()
2716 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2717 group = parser.add_argument_group('foo')
2718 group.add_argument('-w')
2719 group.add_argument('-x', default='XX')
2720 group.add_argument('y', nargs='?')
2721 group.add_argument('z', nargs='?', default='ZZ')
2722
2723
2724 # defaults set previously
2725 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2726 parser.parse_args([]))
2727
2728 # reset defaults
2729 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2730 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2731 parser.parse_args([]))
2732
2733# =================
2734# Get default tests
2735# =================
2736
2737class TestGetDefault(TestCase):
2738
2739 def test_get_default(self):
2740 parser = ErrorRaisingArgumentParser()
2741 self.assertEqual(None, parser.get_default("foo"))
2742 self.assertEqual(None, parser.get_default("bar"))
2743
2744 parser.add_argument("--foo")
2745 self.assertEqual(None, parser.get_default("foo"))
2746 self.assertEqual(None, parser.get_default("bar"))
2747
2748 parser.add_argument("--bar", type=int, default=42)
2749 self.assertEqual(None, parser.get_default("foo"))
2750 self.assertEqual(42, parser.get_default("bar"))
2751
2752 parser.set_defaults(foo="badger")
2753 self.assertEqual("badger", parser.get_default("foo"))
2754 self.assertEqual(42, parser.get_default("bar"))
2755
2756# ==========================
2757# Namespace 'contains' tests
2758# ==========================
2759
2760class TestNamespaceContainsSimple(TestCase):
2761
2762 def test_empty(self):
2763 ns = argparse.Namespace()
Ezio Melotti2623a372010-11-21 13:34:58 +00002764 self.assertEqual('' in ns, False)
2765 self.assertEqual('' not in ns, True)
2766 self.assertEqual('x' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002767
2768 def test_non_empty(self):
2769 ns = argparse.Namespace(x=1, y=2)
Ezio Melotti2623a372010-11-21 13:34:58 +00002770 self.assertEqual('x' in ns, True)
2771 self.assertEqual('x' not in ns, False)
2772 self.assertEqual('y' in ns, True)
2773 self.assertEqual('' in ns, False)
2774 self.assertEqual('xx' in ns, False)
2775 self.assertEqual('z' in ns, False)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002776
2777# =====================
2778# Help formatting tests
2779# =====================
2780
2781class TestHelpFormattingMetaclass(type):
2782
2783 def __init__(cls, name, bases, bodydict):
2784 if name == 'HelpTestCase':
2785 return
2786
2787 class AddTests(object):
2788
2789 def __init__(self, test_class, func_suffix, std_name):
2790 self.func_suffix = func_suffix
2791 self.std_name = std_name
2792
2793 for test_func in [self.test_format,
2794 self.test_print,
2795 self.test_print_file]:
2796 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2797
2798 def test_wrapper(self, test_func=test_func):
2799 test_func(self)
2800 try:
2801 test_wrapper.__name__ = test_name
2802 except TypeError:
2803 pass
2804 setattr(test_class, test_name, test_wrapper)
2805
2806 def _get_parser(self, tester):
2807 parser = argparse.ArgumentParser(
2808 *tester.parser_signature.args,
2809 **tester.parser_signature.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002810 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Petersona39e9662010-03-02 22:05:59 +00002811 parser.add_argument(*argument_sig.args,
2812 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002813 group_sigs = getattr(tester, 'argument_group_signatures', [])
2814 for group_sig, argument_sigs in group_sigs:
Benjamin Petersona39e9662010-03-02 22:05:59 +00002815 group = parser.add_argument_group(*group_sig.args,
2816 **group_sig.kwargs)
2817 for argument_sig in argument_sigs:
2818 group.add_argument(*argument_sig.args,
2819 **argument_sig.kwargs)
Steven Bethardbc3b1042011-03-27 13:57:55 +02002820 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
2821 if subparsers_sigs:
2822 subparsers = parser.add_subparsers()
2823 for subparser_sig in subparsers_sigs:
2824 subparsers.add_parser(*subparser_sig.args,
2825 **subparser_sig.kwargs)
Benjamin Petersona39e9662010-03-02 22:05:59 +00002826 return parser
2827
2828 def _test(self, tester, parser_text):
2829 expected_text = getattr(tester, self.func_suffix)
2830 expected_text = textwrap.dedent(expected_text)
2831 if expected_text != parser_text:
2832 print(repr(expected_text))
2833 print(repr(parser_text))
2834 for char1, char2 in zip(expected_text, parser_text):
2835 if char1 != char2:
2836 print('first diff: %r %r' % (char1, char2))
2837 break
2838 tester.assertEqual(expected_text, parser_text)
2839
2840 def test_format(self, tester):
2841 parser = self._get_parser(tester)
2842 format = getattr(parser, 'format_%s' % self.func_suffix)
2843 self._test(tester, format())
2844
2845 def test_print(self, tester):
2846 parser = self._get_parser(tester)
2847 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2848 old_stream = getattr(sys, self.std_name)
Michael Foord91a2c892010-04-08 00:04:24 +00002849 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Petersona39e9662010-03-02 22:05:59 +00002850 try:
2851 print_()
2852 parser_text = getattr(sys, self.std_name).getvalue()
2853 finally:
2854 setattr(sys, self.std_name, old_stream)
2855 self._test(tester, parser_text)
2856
2857 def test_print_file(self, tester):
2858 parser = self._get_parser(tester)
2859 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Michael Foord91a2c892010-04-08 00:04:24 +00002860 sfile = StdIOBuffer()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002861 print_(sfile)
2862 parser_text = sfile.getvalue()
2863 self._test(tester, parser_text)
2864
2865 # add tests for {format,print}_{usage,help,version}
2866 for func_suffix, std_name in [('usage', 'stdout'),
2867 ('help', 'stdout'),
2868 ('version', 'stderr')]:
2869 AddTests(cls, func_suffix, std_name)
2870
2871bases = TestCase,
2872HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2873
2874
2875class TestHelpBiggerOptionals(HelpTestCase):
2876 """Make sure that argument help aligns when options are longer"""
2877
2878 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2879 epilog='EPILOG', version='0.1')
2880 argument_signatures = [
2881 Sig('-x', action='store_true', help='X HELP'),
2882 Sig('--y', help='Y HELP'),
2883 Sig('foo', help='FOO HELP'),
2884 Sig('bar', help='BAR HELP'),
2885 ]
2886 argument_group_signatures = []
2887 usage = '''\
2888 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2889 '''
2890 help = usage + '''\
2891
2892 DESCRIPTION
2893
2894 positional arguments:
2895 foo FOO HELP
2896 bar BAR HELP
2897
2898 optional arguments:
2899 -h, --help show this help message and exit
2900 -v, --version show program's version number and exit
2901 -x X HELP
2902 --y Y Y HELP
2903
2904 EPILOG
2905 '''
2906 version = '''\
2907 0.1
2908 '''
2909
2910
2911class TestHelpBiggerOptionalGroups(HelpTestCase):
2912 """Make sure that argument help aligns when options are longer"""
2913
2914 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2915 epilog='EPILOG', version='0.1')
2916 argument_signatures = [
2917 Sig('-x', action='store_true', help='X HELP'),
2918 Sig('--y', help='Y HELP'),
2919 Sig('foo', help='FOO HELP'),
2920 Sig('bar', help='BAR HELP'),
2921 ]
2922 argument_group_signatures = [
2923 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2924 Sig('baz', help='BAZ HELP'),
2925 Sig('-z', nargs='+', help='Z HELP')]),
2926 ]
2927 usage = '''\
2928 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2929 '''
2930 help = usage + '''\
2931
2932 DESCRIPTION
2933
2934 positional arguments:
2935 foo FOO HELP
2936 bar BAR HELP
2937
2938 optional arguments:
2939 -h, --help show this help message and exit
2940 -v, --version show program's version number and exit
2941 -x X HELP
2942 --y Y Y HELP
2943
2944 GROUP TITLE:
2945 GROUP DESCRIPTION
2946
2947 baz BAZ HELP
2948 -z Z [Z ...] Z HELP
2949
2950 EPILOG
2951 '''
2952 version = '''\
2953 0.1
2954 '''
2955
2956
2957class TestHelpBiggerPositionals(HelpTestCase):
2958 """Make sure that help aligns when arguments are longer"""
2959
2960 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2961 argument_signatures = [
2962 Sig('-x', action='store_true', help='X HELP'),
2963 Sig('--y', help='Y HELP'),
2964 Sig('ekiekiekifekang', help='EKI HELP'),
2965 Sig('bar', help='BAR HELP'),
2966 ]
2967 argument_group_signatures = []
2968 usage = '''\
2969 usage: USAGE
2970 '''
2971 help = usage + '''\
2972
2973 DESCRIPTION
2974
2975 positional arguments:
2976 ekiekiekifekang EKI HELP
2977 bar BAR HELP
2978
2979 optional arguments:
2980 -h, --help show this help message and exit
2981 -x X HELP
2982 --y Y Y HELP
2983 '''
2984
2985 version = ''
2986
2987
2988class TestHelpReformatting(HelpTestCase):
2989 """Make sure that text after short names starts on the first line"""
2990
2991 parser_signature = Sig(
2992 prog='PROG',
2993 description=' oddly formatted\n'
2994 'description\n'
2995 '\n'
2996 'that is so long that it should go onto multiple '
2997 'lines when wrapped')
2998 argument_signatures = [
2999 Sig('-x', metavar='XX', help='oddly\n'
3000 ' formatted -x help'),
3001 Sig('y', metavar='yyy', help='normal y help'),
3002 ]
3003 argument_group_signatures = [
3004 (Sig('title', description='\n'
3005 ' oddly formatted group\n'
3006 '\n'
3007 'description'),
3008 [Sig('-a', action='store_true',
3009 help=' oddly \n'
3010 'formatted -a help \n'
3011 ' again, so long that it should be wrapped over '
3012 'multiple lines')]),
3013 ]
3014 usage = '''\
3015 usage: PROG [-h] [-x XX] [-a] yyy
3016 '''
3017 help = usage + '''\
3018
3019 oddly formatted description that is so long that it should go onto \
3020multiple
3021 lines when wrapped
3022
3023 positional arguments:
3024 yyy normal y help
3025
3026 optional arguments:
3027 -h, --help show this help message and exit
3028 -x XX oddly formatted -x help
3029
3030 title:
3031 oddly formatted group description
3032
3033 -a oddly formatted -a help again, so long that it should \
3034be wrapped
3035 over multiple lines
3036 '''
3037 version = ''
3038
3039
3040class TestHelpWrappingShortNames(HelpTestCase):
3041 """Make sure that text after short names starts on the first line"""
3042
3043 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3044 argument_signatures = [
3045 Sig('-x', metavar='XX', help='XHH HX' * 20),
3046 Sig('y', metavar='yyy', help='YH YH' * 20),
3047 ]
3048 argument_group_signatures = [
3049 (Sig('ALPHAS'), [
3050 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3051 ]
3052 usage = '''\
3053 usage: PROG [-h] [-x XX] [-a] yyy
3054 '''
3055 help = usage + '''\
3056
3057 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3058DD DD DD
3059 DD DD DD DD D
3060
3061 positional arguments:
3062 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3063YHYH YHYH
3064 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3065
3066 optional arguments:
3067 -h, --help show this help message and exit
3068 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3069HXXHH HXXHH
3070 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3071
3072 ALPHAS:
3073 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3074HHAAHHH
3075 HHAAHHH HHAAHHH HHA
3076 '''
3077 version = ''
3078
3079
3080class TestHelpWrappingLongNames(HelpTestCase):
3081 """Make sure that text after long names starts on the next line"""
3082
3083 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3084 version='V V'*30)
3085 argument_signatures = [
3086 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3087 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3088 ]
3089 argument_group_signatures = [
3090 (Sig('ALPHAS'), [
3091 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3092 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3093 ]
3094 usage = '''\
3095 usage: USAGE
3096 '''
3097 help = usage + '''\
3098
3099 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3100DD DD DD
3101 DD DD DD DD D
3102
3103 positional arguments:
3104 yyyyyyyyyyyyyyyyyyyyyyyyy
3105 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3106YHYH YHYH
3107 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3108
3109 optional arguments:
3110 -h, --help show this help message and exit
3111 -v, --version show program's version number and exit
3112 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3113 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3114XHXH XHXH
3115 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3116
3117 ALPHAS:
3118 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3119 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3120AHAH AHAH
3121 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3122 zzzzzzzzzzzzzzzzzzzzzzzzz
3123 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3124ZHZH ZHZH
3125 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3126 '''
3127 version = '''\
3128 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3129VV VV VV
3130 VV VV VV VV V
3131 '''
3132
3133
3134class TestHelpUsage(HelpTestCase):
3135 """Test basic usage messages"""
3136
3137 parser_signature = Sig(prog='PROG')
3138 argument_signatures = [
3139 Sig('-w', nargs='+', help='w'),
3140 Sig('-x', nargs='*', help='x'),
3141 Sig('a', help='a'),
3142 Sig('b', help='b', nargs=2),
3143 Sig('c', help='c', nargs='?'),
3144 ]
3145 argument_group_signatures = [
3146 (Sig('group'), [
3147 Sig('-y', nargs='?', help='y'),
3148 Sig('-z', nargs=3, help='z'),
3149 Sig('d', help='d', nargs='*'),
3150 Sig('e', help='e', nargs='+'),
3151 ])
3152 ]
3153 usage = '''\
3154 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3155 a b b [c] [d [d ...]] e [e ...]
3156 '''
3157 help = usage + '''\
3158
3159 positional arguments:
3160 a a
3161 b b
3162 c c
3163
3164 optional arguments:
3165 -h, --help show this help message and exit
3166 -w W [W ...] w
3167 -x [X [X ...]] x
3168
3169 group:
3170 -y [Y] y
3171 -z Z Z Z z
3172 d d
3173 e e
3174 '''
3175 version = ''
3176
3177
3178class TestHelpOnlyUserGroups(HelpTestCase):
3179 """Test basic usage messages"""
3180
3181 parser_signature = Sig(prog='PROG', add_help=False)
3182 argument_signatures = []
3183 argument_group_signatures = [
3184 (Sig('xxxx'), [
3185 Sig('-x', help='x'),
3186 Sig('a', help='a'),
3187 ]),
3188 (Sig('yyyy'), [
3189 Sig('b', help='b'),
3190 Sig('-y', help='y'),
3191 ]),
3192 ]
3193 usage = '''\
3194 usage: PROG [-x X] [-y Y] a b
3195 '''
3196 help = usage + '''\
3197
3198 xxxx:
3199 -x X x
3200 a a
3201
3202 yyyy:
3203 b b
3204 -y Y y
3205 '''
3206 version = ''
3207
3208
3209class TestHelpUsageLongProg(HelpTestCase):
3210 """Test usage messages where the prog is long"""
3211
3212 parser_signature = Sig(prog='P' * 60)
3213 argument_signatures = [
3214 Sig('-w', metavar='W'),
3215 Sig('-x', metavar='X'),
3216 Sig('a'),
3217 Sig('b'),
3218 ]
3219 argument_group_signatures = []
3220 usage = '''\
3221 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3222 [-h] [-w W] [-x X] a b
3223 '''
3224 help = usage + '''\
3225
3226 positional arguments:
3227 a
3228 b
3229
3230 optional arguments:
3231 -h, --help show this help message and exit
3232 -w W
3233 -x X
3234 '''
3235 version = ''
3236
3237
3238class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3239 """Test usage messages where the prog is long and the optionals wrap"""
3240
3241 parser_signature = Sig(prog='P' * 60)
3242 argument_signatures = [
3243 Sig('-w', metavar='W' * 25),
3244 Sig('-x', metavar='X' * 25),
3245 Sig('-y', metavar='Y' * 25),
3246 Sig('-z', metavar='Z' * 25),
3247 Sig('a'),
3248 Sig('b'),
3249 ]
3250 argument_group_signatures = []
3251 usage = '''\
3252 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3253 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3254[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3255 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3256 a b
3257 '''
3258 help = usage + '''\
3259
3260 positional arguments:
3261 a
3262 b
3263
3264 optional arguments:
3265 -h, --help show this help message and exit
3266 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3267 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3268 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3269 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3270 '''
3271 version = ''
3272
3273
3274class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3275 """Test usage messages where the prog is long and the positionals wrap"""
3276
3277 parser_signature = Sig(prog='P' * 60, add_help=False)
3278 argument_signatures = [
3279 Sig('a' * 25),
3280 Sig('b' * 25),
3281 Sig('c' * 25),
3282 ]
3283 argument_group_signatures = []
3284 usage = '''\
3285 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3286 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3287 ccccccccccccccccccccccccc
3288 '''
3289 help = usage + '''\
3290
3291 positional arguments:
3292 aaaaaaaaaaaaaaaaaaaaaaaaa
3293 bbbbbbbbbbbbbbbbbbbbbbbbb
3294 ccccccccccccccccccccccccc
3295 '''
3296 version = ''
3297
3298
3299class TestHelpUsageOptionalsWrap(HelpTestCase):
3300 """Test usage messages where the optionals wrap"""
3301
3302 parser_signature = Sig(prog='PROG')
3303 argument_signatures = [
3304 Sig('-w', metavar='W' * 25),
3305 Sig('-x', metavar='X' * 25),
3306 Sig('-y', metavar='Y' * 25),
3307 Sig('-z', metavar='Z' * 25),
3308 Sig('a'),
3309 Sig('b'),
3310 Sig('c'),
3311 ]
3312 argument_group_signatures = []
3313 usage = '''\
3314 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3315[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3316 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3317[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3318 a b c
3319 '''
3320 help = usage + '''\
3321
3322 positional arguments:
3323 a
3324 b
3325 c
3326
3327 optional arguments:
3328 -h, --help show this help message and exit
3329 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3330 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3331 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3332 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3333 '''
3334 version = ''
3335
3336
3337class TestHelpUsagePositionalsWrap(HelpTestCase):
3338 """Test usage messages where the positionals wrap"""
3339
3340 parser_signature = Sig(prog='PROG')
3341 argument_signatures = [
3342 Sig('-x'),
3343 Sig('-y'),
3344 Sig('-z'),
3345 Sig('a' * 25),
3346 Sig('b' * 25),
3347 Sig('c' * 25),
3348 ]
3349 argument_group_signatures = []
3350 usage = '''\
3351 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3352 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3353 ccccccccccccccccccccccccc
3354 '''
3355 help = usage + '''\
3356
3357 positional arguments:
3358 aaaaaaaaaaaaaaaaaaaaaaaaa
3359 bbbbbbbbbbbbbbbbbbbbbbbbb
3360 ccccccccccccccccccccccccc
3361
3362 optional arguments:
3363 -h, --help show this help message and exit
3364 -x X
3365 -y Y
3366 -z Z
3367 '''
3368 version = ''
3369
3370
3371class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3372 """Test usage messages where the optionals and positionals wrap"""
3373
3374 parser_signature = Sig(prog='PROG')
3375 argument_signatures = [
3376 Sig('-x', metavar='X' * 25),
3377 Sig('-y', metavar='Y' * 25),
3378 Sig('-z', metavar='Z' * 25),
3379 Sig('a' * 25),
3380 Sig('b' * 25),
3381 Sig('c' * 25),
3382 ]
3383 argument_group_signatures = []
3384 usage = '''\
3385 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3386[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3387 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3388 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3389 ccccccccccccccccccccccccc
3390 '''
3391 help = usage + '''\
3392
3393 positional arguments:
3394 aaaaaaaaaaaaaaaaaaaaaaaaa
3395 bbbbbbbbbbbbbbbbbbbbbbbbb
3396 ccccccccccccccccccccccccc
3397
3398 optional arguments:
3399 -h, --help show this help message and exit
3400 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3401 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3402 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3403 '''
3404 version = ''
3405
3406
3407class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3408 """Test usage messages where there are only optionals and they wrap"""
3409
3410 parser_signature = Sig(prog='PROG')
3411 argument_signatures = [
3412 Sig('-x', metavar='X' * 25),
3413 Sig('-y', metavar='Y' * 25),
3414 Sig('-z', metavar='Z' * 25),
3415 ]
3416 argument_group_signatures = []
3417 usage = '''\
3418 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3419[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3420 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3421 '''
3422 help = usage + '''\
3423
3424 optional arguments:
3425 -h, --help show this help message and exit
3426 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3427 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3428 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3429 '''
3430 version = ''
3431
3432
3433class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3434 """Test usage messages where there are only positionals and they wrap"""
3435
3436 parser_signature = Sig(prog='PROG', add_help=False)
3437 argument_signatures = [
3438 Sig('a' * 25),
3439 Sig('b' * 25),
3440 Sig('c' * 25),
3441 ]
3442 argument_group_signatures = []
3443 usage = '''\
3444 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3445 ccccccccccccccccccccccccc
3446 '''
3447 help = usage + '''\
3448
3449 positional arguments:
3450 aaaaaaaaaaaaaaaaaaaaaaaaa
3451 bbbbbbbbbbbbbbbbbbbbbbbbb
3452 ccccccccccccccccccccccccc
3453 '''
3454 version = ''
3455
3456
3457class TestHelpVariableExpansion(HelpTestCase):
3458 """Test that variables are expanded properly in help messages"""
3459
3460 parser_signature = Sig(prog='PROG')
3461 argument_signatures = [
3462 Sig('-x', type=int,
3463 help='x %(prog)s %(default)s %(type)s %%'),
3464 Sig('-y', action='store_const', default=42, const='XXX',
3465 help='y %(prog)s %(default)s %(const)s'),
3466 Sig('--foo', choices='abc',
3467 help='foo %(prog)s %(default)s %(choices)s'),
3468 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3469 help='bar %(prog)s %(default)s %(dest)s'),
3470 Sig('spam', help='spam %(prog)s %(default)s'),
3471 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3472 ]
3473 argument_group_signatures = [
3474 (Sig('group'), [
3475 Sig('-a', help='a %(prog)s %(default)s'),
3476 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3477 ])
3478 ]
3479 usage = ('''\
3480 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3481 spam badger
3482 ''')
3483 help = usage + '''\
3484
3485 positional arguments:
3486 spam spam PROG None
3487 badger badger PROG 0.5
3488
3489 optional arguments:
3490 -h, --help show this help message and exit
3491 -x X x PROG None int %
3492 -y y PROG 42 XXX
3493 --foo {a,b,c} foo PROG None a, b, c
3494 --bar BBB bar PROG baz bar
3495
3496 group:
3497 -a A a PROG None
3498 -b B b PROG -1
3499 '''
3500 version = ''
3501
3502
3503class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3504 """Test that variables are expanded properly when usage= is present"""
3505
3506 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3507 argument_signatures = []
3508 argument_group_signatures = []
3509 usage = ('''\
3510 usage: PROG FOO
3511 ''')
3512 help = usage + '''\
3513
3514 optional arguments:
3515 -h, --help show this help message and exit
3516 '''
3517 version = ''
3518
3519
3520class TestHelpVariableExpansionNoArguments(HelpTestCase):
3521 """Test that variables are expanded properly with no arguments"""
3522
3523 parser_signature = Sig(prog='PROG', add_help=False)
3524 argument_signatures = []
3525 argument_group_signatures = []
3526 usage = ('''\
3527 usage: PROG
3528 ''')
3529 help = usage
3530 version = ''
3531
3532
3533class TestHelpSuppressUsage(HelpTestCase):
3534 """Test that items can be suppressed in usage messages"""
3535
3536 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3537 argument_signatures = [
3538 Sig('--foo', help='foo help'),
3539 Sig('spam', help='spam help'),
3540 ]
3541 argument_group_signatures = []
3542 help = '''\
3543 positional arguments:
3544 spam spam help
3545
3546 optional arguments:
3547 -h, --help show this help message and exit
3548 --foo FOO foo help
3549 '''
3550 usage = ''
3551 version = ''
3552
3553
3554class TestHelpSuppressOptional(HelpTestCase):
3555 """Test that optional arguments can be suppressed in help messages"""
3556
3557 parser_signature = Sig(prog='PROG', add_help=False)
3558 argument_signatures = [
3559 Sig('--foo', help=argparse.SUPPRESS),
3560 Sig('spam', help='spam help'),
3561 ]
3562 argument_group_signatures = []
3563 usage = '''\
3564 usage: PROG spam
3565 '''
3566 help = usage + '''\
3567
3568 positional arguments:
3569 spam spam help
3570 '''
3571 version = ''
3572
3573
3574class TestHelpSuppressOptionalGroup(HelpTestCase):
3575 """Test that optional groups can be suppressed in help messages"""
3576
3577 parser_signature = Sig(prog='PROG')
3578 argument_signatures = [
3579 Sig('--foo', help='foo help'),
3580 Sig('spam', help='spam help'),
3581 ]
3582 argument_group_signatures = [
3583 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3584 ]
3585 usage = '''\
3586 usage: PROG [-h] [--foo FOO] spam
3587 '''
3588 help = usage + '''\
3589
3590 positional arguments:
3591 spam spam help
3592
3593 optional arguments:
3594 -h, --help show this help message and exit
3595 --foo FOO foo help
3596 '''
3597 version = ''
3598
3599
3600class TestHelpSuppressPositional(HelpTestCase):
3601 """Test that positional arguments can be suppressed in help messages"""
3602
3603 parser_signature = Sig(prog='PROG')
3604 argument_signatures = [
3605 Sig('--foo', help='foo help'),
3606 Sig('spam', help=argparse.SUPPRESS),
3607 ]
3608 argument_group_signatures = []
3609 usage = '''\
3610 usage: PROG [-h] [--foo FOO]
3611 '''
3612 help = usage + '''\
3613
3614 optional arguments:
3615 -h, --help show this help message and exit
3616 --foo FOO foo help
3617 '''
3618 version = ''
3619
3620
3621class TestHelpRequiredOptional(HelpTestCase):
3622 """Test that required options don't look optional"""
3623
3624 parser_signature = Sig(prog='PROG')
3625 argument_signatures = [
3626 Sig('--foo', required=True, help='foo help'),
3627 ]
3628 argument_group_signatures = []
3629 usage = '''\
3630 usage: PROG [-h] --foo FOO
3631 '''
3632 help = usage + '''\
3633
3634 optional arguments:
3635 -h, --help show this help message and exit
3636 --foo FOO foo help
3637 '''
3638 version = ''
3639
3640
3641class TestHelpAlternatePrefixChars(HelpTestCase):
3642 """Test that options display with different prefix characters"""
3643
3644 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3645 argument_signatures = [
3646 Sig('^^foo', action='store_true', help='foo help'),
3647 Sig(';b', ';;bar', help='bar help'),
3648 ]
3649 argument_group_signatures = []
3650 usage = '''\
3651 usage: PROG [^^foo] [;b BAR]
3652 '''
3653 help = usage + '''\
3654
3655 optional arguments:
3656 ^^foo foo help
3657 ;b BAR, ;;bar BAR bar help
3658 '''
3659 version = ''
3660
3661
3662class TestHelpNoHelpOptional(HelpTestCase):
3663 """Test that the --help argument can be suppressed help messages"""
3664
3665 parser_signature = Sig(prog='PROG', add_help=False)
3666 argument_signatures = [
3667 Sig('--foo', help='foo help'),
3668 Sig('spam', help='spam help'),
3669 ]
3670 argument_group_signatures = []
3671 usage = '''\
3672 usage: PROG [--foo FOO] spam
3673 '''
3674 help = usage + '''\
3675
3676 positional arguments:
3677 spam spam help
3678
3679 optional arguments:
3680 --foo FOO foo help
3681 '''
3682 version = ''
3683
3684
3685class TestHelpVersionOptional(HelpTestCase):
3686 """Test that the --version argument can be suppressed help messages"""
3687
3688 parser_signature = Sig(prog='PROG', version='1.0')
3689 argument_signatures = [
3690 Sig('--foo', help='foo help'),
3691 Sig('spam', help='spam help'),
3692 ]
3693 argument_group_signatures = []
3694 usage = '''\
3695 usage: PROG [-h] [-v] [--foo FOO] spam
3696 '''
3697 help = usage + '''\
3698
3699 positional arguments:
3700 spam spam help
3701
3702 optional arguments:
3703 -h, --help show this help message and exit
3704 -v, --version show program's version number and exit
3705 --foo FOO foo help
3706 '''
3707 version = '''\
3708 1.0
3709 '''
3710
3711
3712class TestHelpNone(HelpTestCase):
3713 """Test that no errors occur if no help is specified"""
3714
3715 parser_signature = Sig(prog='PROG')
3716 argument_signatures = [
3717 Sig('--foo'),
3718 Sig('spam'),
3719 ]
3720 argument_group_signatures = []
3721 usage = '''\
3722 usage: PROG [-h] [--foo FOO] spam
3723 '''
3724 help = usage + '''\
3725
3726 positional arguments:
3727 spam
3728
3729 optional arguments:
3730 -h, --help show this help message and exit
3731 --foo FOO
3732 '''
3733 version = ''
3734
3735
3736class TestHelpTupleMetavar(HelpTestCase):
3737 """Test specifying metavar as a tuple"""
3738
3739 parser_signature = Sig(prog='PROG')
3740 argument_signatures = [
3741 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3742 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3743 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3744 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3745 ]
3746 argument_group_signatures = []
3747 usage = '''\
3748 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3749[-z [Z1]]
3750 '''
3751 help = usage + '''\
3752
3753 optional arguments:
3754 -h, --help show this help message and exit
3755 -w W1 [W2 ...] w
3756 -x [X1 [X2 ...]] x
3757 -y Y1 Y2 Y3 y
3758 -z [Z1] z
3759 '''
3760 version = ''
3761
3762
3763class TestHelpRawText(HelpTestCase):
3764 """Test the RawTextHelpFormatter"""
3765
3766 parser_signature = Sig(
3767 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3768 description='Keep the formatting\n'
3769 ' exactly as it is written\n'
3770 '\n'
3771 'here\n')
3772
3773 argument_signatures = [
3774 Sig('--foo', help=' foo help should also\n'
3775 'appear as given here'),
3776 Sig('spam', help='spam help'),
3777 ]
3778 argument_group_signatures = [
3779 (Sig('title', description=' This text\n'
3780 ' should be indented\n'
3781 ' exactly like it is here\n'),
3782 [Sig('--bar', help='bar help')]),
3783 ]
3784 usage = '''\
3785 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3786 '''
3787 help = usage + '''\
3788
3789 Keep the formatting
3790 exactly as it is written
3791
3792 here
3793
3794 positional arguments:
3795 spam spam help
3796
3797 optional arguments:
3798 -h, --help show this help message and exit
3799 --foo FOO foo help should also
3800 appear as given here
3801
3802 title:
3803 This text
3804 should be indented
3805 exactly like it is here
3806
3807 --bar BAR bar help
3808 '''
3809 version = ''
3810
3811
3812class TestHelpRawDescription(HelpTestCase):
3813 """Test the RawTextHelpFormatter"""
3814
3815 parser_signature = Sig(
3816 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3817 description='Keep the formatting\n'
3818 ' exactly as it is written\n'
3819 '\n'
3820 'here\n')
3821
3822 argument_signatures = [
3823 Sig('--foo', help=' foo help should not\n'
3824 ' retain this odd formatting'),
3825 Sig('spam', help='spam help'),
3826 ]
3827 argument_group_signatures = [
3828 (Sig('title', description=' This text\n'
3829 ' should be indented\n'
3830 ' exactly like it is here\n'),
3831 [Sig('--bar', help='bar help')]),
3832 ]
3833 usage = '''\
3834 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3835 '''
3836 help = usage + '''\
3837
3838 Keep the formatting
3839 exactly as it is written
3840
3841 here
3842
3843 positional arguments:
3844 spam spam help
3845
3846 optional arguments:
3847 -h, --help show this help message and exit
3848 --foo FOO foo help should not retain this odd formatting
3849
3850 title:
3851 This text
3852 should be indented
3853 exactly like it is here
3854
3855 --bar BAR bar help
3856 '''
3857 version = ''
3858
3859
3860class TestHelpArgumentDefaults(HelpTestCase):
3861 """Test the ArgumentDefaultsHelpFormatter"""
3862
3863 parser_signature = Sig(
3864 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3865 description='description')
3866
3867 argument_signatures = [
3868 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3869 Sig('--bar', action='store_true', help='bar help'),
3870 Sig('spam', help='spam help'),
3871 Sig('badger', nargs='?', default='wooden', help='badger help'),
3872 ]
3873 argument_group_signatures = [
3874 (Sig('title', description='description'),
3875 [Sig('--baz', type=int, default=42, help='baz help')]),
3876 ]
3877 usage = '''\
3878 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3879 '''
3880 help = usage + '''\
3881
3882 description
3883
3884 positional arguments:
3885 spam spam help
3886 badger badger help (default: wooden)
3887
3888 optional arguments:
3889 -h, --help show this help message and exit
3890 --foo FOO foo help - oh and by the way, None
3891 --bar bar help (default: False)
3892
3893 title:
3894 description
3895
3896 --baz BAZ baz help (default: 42)
3897 '''
3898 version = ''
3899
Steven Betharddce6e1b2010-05-24 03:45:26 +00003900class TestHelpVersionAction(HelpTestCase):
3901 """Test the default help for the version action"""
3902
3903 parser_signature = Sig(prog='PROG', description='description')
3904 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3905 argument_group_signatures = []
3906 usage = '''\
3907 usage: PROG [-h] [-V]
3908 '''
3909 help = usage + '''\
3910
3911 description
3912
3913 optional arguments:
3914 -h, --help show this help message and exit
3915 -V, --version show program's version number and exit
3916 '''
3917 version = ''
3918
Steven Bethardbc3b1042011-03-27 13:57:55 +02003919class TestHelpSubparsersOrdering(HelpTestCase):
3920 """Test ordering of subcommands in help matches the code"""
3921 parser_signature = Sig(prog='PROG',
3922 description='display some subcommands',
3923 version='0.1')
3924
3925 subparsers_signatures = [Sig(name=name)
3926 for name in ('a', 'b', 'c', 'd', 'e')]
3927
3928 usage = '''\
3929 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3930 '''
3931
3932 help = usage + '''\
3933
3934 display some subcommands
3935
3936 positional arguments:
3937 {a,b,c,d,e}
3938
3939 optional arguments:
3940 -h, --help show this help message and exit
3941 -v, --version show program's version number and exit
3942 '''
3943
3944 version = '''\
3945 0.1
3946 '''
3947
3948class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
3949 """Test ordering of subcommands in help matches the code"""
3950 parser_signature = Sig(prog='PROG',
3951 description='display some subcommands',
3952 version='0.1')
3953
3954 subcommand_data = (('a', 'a subcommand help'),
3955 ('b', 'b subcommand help'),
3956 ('c', 'c subcommand help'),
3957 ('d', 'd subcommand help'),
3958 ('e', 'e subcommand help'),
3959 )
3960
3961 subparsers_signatures = [Sig(name=name, help=help)
3962 for name, help in subcommand_data]
3963
3964 usage = '''\
3965 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3966 '''
3967
3968 help = usage + '''\
3969
3970 display some subcommands
3971
3972 positional arguments:
3973 {a,b,c,d,e}
3974 a a subcommand help
3975 b b subcommand help
3976 c c subcommand help
3977 d d subcommand help
3978 e e subcommand help
3979
3980 optional arguments:
3981 -h, --help show this help message and exit
3982 -v, --version show program's version number and exit
3983 '''
3984
3985 version = '''\
3986 0.1
3987 '''
3988
3989
Benjamin Petersona39e9662010-03-02 22:05:59 +00003990# =====================================
3991# Optional/Positional constructor tests
3992# =====================================
3993
3994class TestInvalidArgumentConstructors(TestCase):
3995 """Test a bunch of invalid Argument constructors"""
3996
3997 def assertTypeError(self, *args, **kwargs):
3998 parser = argparse.ArgumentParser()
3999 self.assertRaises(TypeError, parser.add_argument,
4000 *args, **kwargs)
4001
4002 def assertValueError(self, *args, **kwargs):
4003 parser = argparse.ArgumentParser()
4004 self.assertRaises(ValueError, parser.add_argument,
4005 *args, **kwargs)
4006
4007 def test_invalid_keyword_arguments(self):
4008 self.assertTypeError('-x', bar=None)
4009 self.assertTypeError('-y', callback='foo')
4010 self.assertTypeError('-y', callback_args=())
4011 self.assertTypeError('-y', callback_kwargs={})
4012
4013 def test_missing_destination(self):
4014 self.assertTypeError()
4015 for action in ['append', 'store']:
4016 self.assertTypeError(action=action)
4017
4018 def test_invalid_option_strings(self):
4019 self.assertValueError('--')
4020 self.assertValueError('---')
4021
4022 def test_invalid_type(self):
4023 self.assertValueError('--foo', type='int')
Steven Betharde3c11b42011-04-04 01:47:52 +02004024 self.assertValueError('--foo', type=(int, float))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004025
4026 def test_invalid_action(self):
4027 self.assertValueError('-x', action='foo')
4028 self.assertValueError('foo', action='baz')
Steven Betharde3c11b42011-04-04 01:47:52 +02004029 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004030 parser = argparse.ArgumentParser()
4031 try:
4032 parser.add_argument("--foo", action="store-true")
4033 except ValueError:
4034 e = sys.exc_info()[1]
4035 expected = 'unknown action'
4036 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004037 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004038
4039 def test_multiple_dest(self):
4040 parser = argparse.ArgumentParser()
4041 parser.add_argument(dest='foo')
4042 try:
4043 parser.add_argument('bar', dest='baz')
4044 except ValueError:
4045 e = sys.exc_info()[1]
4046 expected = 'dest supplied twice for positional argument'
4047 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004048 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004049
4050 def test_no_argument_actions(self):
4051 for action in ['store_const', 'store_true', 'store_false',
4052 'append_const', 'count']:
4053 for attrs in [dict(type=int), dict(nargs='+'),
4054 dict(choices='ab')]:
4055 self.assertTypeError('-x', action=action, **attrs)
4056
4057 def test_no_argument_no_const_actions(self):
4058 # options with zero arguments
4059 for action in ['store_true', 'store_false', 'count']:
4060
4061 # const is always disallowed
4062 self.assertTypeError('-x', const='foo', action=action)
4063
4064 # nargs is always disallowed
4065 self.assertTypeError('-x', nargs='*', action=action)
4066
4067 def test_more_than_one_argument_actions(self):
4068 for action in ['store', 'append']:
4069
4070 # nargs=0 is disallowed
4071 self.assertValueError('-x', nargs=0, action=action)
4072 self.assertValueError('spam', nargs=0, action=action)
4073
4074 # const is disallowed with non-optional arguments
4075 for nargs in [1, '*', '+']:
4076 self.assertValueError('-x', const='foo',
4077 nargs=nargs, action=action)
4078 self.assertValueError('spam', const='foo',
4079 nargs=nargs, action=action)
4080
4081 def test_required_const_actions(self):
4082 for action in ['store_const', 'append_const']:
4083
4084 # nargs is always disallowed
4085 self.assertTypeError('-x', nargs='+', action=action)
4086
4087 def test_parsers_action_missing_params(self):
4088 self.assertTypeError('command', action='parsers')
4089 self.assertTypeError('command', action='parsers', prog='PROG')
4090 self.assertTypeError('command', action='parsers',
4091 parser_class=argparse.ArgumentParser)
4092
4093 def test_required_positional(self):
4094 self.assertTypeError('foo', required=True)
4095
4096 def test_user_defined_action(self):
4097
4098 class Success(Exception):
4099 pass
4100
4101 class Action(object):
4102
4103 def __init__(self,
4104 option_strings,
4105 dest,
4106 const,
4107 default,
4108 required=False):
4109 if dest == 'spam':
4110 if const is Success:
4111 if default is Success:
4112 raise Success()
4113
4114 def __call__(self, *args, **kwargs):
4115 pass
4116
4117 parser = argparse.ArgumentParser()
4118 self.assertRaises(Success, parser.add_argument, '--spam',
4119 action=Action, default=Success, const=Success)
4120 self.assertRaises(Success, parser.add_argument, 'spam',
4121 action=Action, default=Success, const=Success)
4122
4123# ================================
4124# Actions returned by add_argument
4125# ================================
4126
4127class TestActionsReturned(TestCase):
4128
4129 def test_dest(self):
4130 parser = argparse.ArgumentParser()
4131 action = parser.add_argument('--foo')
4132 self.assertEqual(action.dest, 'foo')
4133 action = parser.add_argument('-b', '--bar')
4134 self.assertEqual(action.dest, 'bar')
4135 action = parser.add_argument('-x', '-y')
4136 self.assertEqual(action.dest, 'x')
4137
4138 def test_misc(self):
4139 parser = argparse.ArgumentParser()
4140 action = parser.add_argument('--foo', nargs='?', const=42,
4141 default=84, type=int, choices=[1, 2],
4142 help='FOO', metavar='BAR', dest='baz')
4143 self.assertEqual(action.nargs, '?')
4144 self.assertEqual(action.const, 42)
4145 self.assertEqual(action.default, 84)
4146 self.assertEqual(action.type, int)
4147 self.assertEqual(action.choices, [1, 2])
4148 self.assertEqual(action.help, 'FOO')
4149 self.assertEqual(action.metavar, 'BAR')
4150 self.assertEqual(action.dest, 'baz')
4151
4152
4153# ================================
4154# Argument conflict handling tests
4155# ================================
4156
4157class TestConflictHandling(TestCase):
4158
4159 def test_bad_type(self):
4160 self.assertRaises(ValueError, argparse.ArgumentParser,
4161 conflict_handler='foo')
4162
4163 def test_conflict_error(self):
4164 parser = argparse.ArgumentParser()
4165 parser.add_argument('-x')
4166 self.assertRaises(argparse.ArgumentError,
4167 parser.add_argument, '-x')
4168 parser.add_argument('--spam')
4169 self.assertRaises(argparse.ArgumentError,
4170 parser.add_argument, '--spam')
4171
4172 def test_resolve_error(self):
4173 get_parser = argparse.ArgumentParser
4174 parser = get_parser(prog='PROG', conflict_handler='resolve')
4175
4176 parser.add_argument('-x', help='OLD X')
4177 parser.add_argument('-x', help='NEW X')
4178 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4179 usage: PROG [-h] [-x X]
4180
4181 optional arguments:
4182 -h, --help show this help message and exit
4183 -x X NEW X
4184 '''))
4185
4186 parser.add_argument('--spam', metavar='OLD_SPAM')
4187 parser.add_argument('--spam', metavar='NEW_SPAM')
4188 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4189 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4190
4191 optional arguments:
4192 -h, --help show this help message and exit
4193 -x X NEW X
4194 --spam NEW_SPAM
4195 '''))
4196
4197
4198# =============================
4199# Help and Version option tests
4200# =============================
4201
4202class TestOptionalsHelpVersionActions(TestCase):
4203 """Test the help and version actions"""
4204
4205 def _get_error(self, func, *args, **kwargs):
4206 try:
4207 func(*args, **kwargs)
4208 except ArgumentParserError:
4209 return sys.exc_info()[1]
4210 else:
4211 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4212
4213 def assertPrintHelpExit(self, parser, args_str):
4214 self.assertEqual(
4215 parser.format_help(),
4216 self._get_error(parser.parse_args, args_str.split()).stdout)
4217
4218 def assertPrintVersionExit(self, parser, args_str):
4219 self.assertEqual(
4220 parser.format_version(),
4221 self._get_error(parser.parse_args, args_str.split()).stderr)
4222
4223 def assertArgumentParserError(self, parser, *args):
4224 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4225
4226 def test_version(self):
4227 parser = ErrorRaisingArgumentParser(version='1.0')
4228 self.assertPrintHelpExit(parser, '-h')
4229 self.assertPrintHelpExit(parser, '--help')
4230 self.assertPrintVersionExit(parser, '-v')
4231 self.assertPrintVersionExit(parser, '--version')
4232
4233 def test_version_format(self):
4234 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4235 msg = self._get_error(parser.parse_args, ['-v']).stderr
4236 self.assertEqual('PPP 3.5\n', msg)
4237
4238 def test_version_no_help(self):
4239 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4240 self.assertArgumentParserError(parser, '-h')
4241 self.assertArgumentParserError(parser, '--help')
4242 self.assertPrintVersionExit(parser, '-v')
4243 self.assertPrintVersionExit(parser, '--version')
4244
4245 def test_version_action(self):
4246 parser = ErrorRaisingArgumentParser(prog='XXX')
4247 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4248 msg = self._get_error(parser.parse_args, ['-V']).stderr
4249 self.assertEqual('XXX 3.7\n', msg)
4250
4251 def test_no_help(self):
4252 parser = ErrorRaisingArgumentParser(add_help=False)
4253 self.assertArgumentParserError(parser, '-h')
4254 self.assertArgumentParserError(parser, '--help')
4255 self.assertArgumentParserError(parser, '-v')
4256 self.assertArgumentParserError(parser, '--version')
4257
4258 def test_alternate_help_version(self):
4259 parser = ErrorRaisingArgumentParser()
4260 parser.add_argument('-x', action='help')
4261 parser.add_argument('-y', action='version')
4262 self.assertPrintHelpExit(parser, '-x')
4263 self.assertPrintVersionExit(parser, '-y')
4264 self.assertArgumentParserError(parser, '-v')
4265 self.assertArgumentParserError(parser, '--version')
4266
4267 def test_help_version_extra_arguments(self):
4268 parser = ErrorRaisingArgumentParser(version='1.0')
4269 parser.add_argument('-x', action='store_true')
4270 parser.add_argument('y')
4271
4272 # try all combinations of valid prefixes and suffixes
4273 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4274 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4275 for prefix in valid_prefixes:
4276 for suffix in valid_suffixes:
4277 format = '%s %%s %s' % (prefix, suffix)
4278 self.assertPrintHelpExit(parser, format % '-h')
4279 self.assertPrintHelpExit(parser, format % '--help')
4280 self.assertPrintVersionExit(parser, format % '-v')
4281 self.assertPrintVersionExit(parser, format % '--version')
4282
4283
4284# ======================
4285# str() and repr() tests
4286# ======================
4287
4288class TestStrings(TestCase):
4289 """Test str() and repr() on Optionals and Positionals"""
4290
4291 def assertStringEqual(self, obj, result_string):
4292 for func in [str, repr]:
4293 self.assertEqual(func(obj), result_string)
4294
4295 def test_optional(self):
4296 option = argparse.Action(
4297 option_strings=['--foo', '-a', '-b'],
4298 dest='b',
4299 type='int',
4300 nargs='+',
4301 default=42,
4302 choices=[1, 2, 3],
4303 help='HELP',
4304 metavar='METAVAR')
4305 string = (
4306 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4307 "nargs='+', const=None, default=42, type='int', "
4308 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4309 self.assertStringEqual(option, string)
4310
4311 def test_argument(self):
4312 argument = argparse.Action(
4313 option_strings=[],
4314 dest='x',
4315 type=float,
4316 nargs='?',
4317 default=2.5,
4318 choices=[0.5, 1.5, 2.5],
4319 help='H HH H',
4320 metavar='MV MV MV')
4321 string = (
4322 "Action(option_strings=[], dest='x', nargs='?', "
4323 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4324 "help='H HH H', metavar='MV MV MV')" % float)
4325 self.assertStringEqual(argument, string)
4326
4327 def test_namespace(self):
4328 ns = argparse.Namespace(foo=42, bar='spam')
4329 string = "Namespace(bar='spam', foo=42)"
4330 self.assertStringEqual(ns, string)
4331
4332 def test_parser(self):
4333 parser = argparse.ArgumentParser(prog='PROG')
4334 string = (
4335 "ArgumentParser(prog='PROG', usage=None, description=None, "
4336 "version=None, formatter_class=%r, conflict_handler='error', "
4337 "add_help=True)" % argparse.HelpFormatter)
4338 self.assertStringEqual(parser, string)
4339
4340# ===============
4341# Namespace tests
4342# ===============
4343
4344class TestNamespace(TestCase):
4345
4346 def test_constructor(self):
4347 ns = argparse.Namespace()
4348 self.assertRaises(AttributeError, getattr, ns, 'x')
4349
4350 ns = argparse.Namespace(a=42, b='spam')
4351 self.assertEqual(ns.a, 42)
4352 self.assertEqual(ns.b, 'spam')
4353
4354 def test_equality(self):
4355 ns1 = argparse.Namespace(a=1, b=2)
4356 ns2 = argparse.Namespace(b=2, a=1)
4357 ns3 = argparse.Namespace(a=1)
4358 ns4 = argparse.Namespace(b=2)
4359
4360 self.assertEqual(ns1, ns2)
4361 self.assertNotEqual(ns1, ns3)
4362 self.assertNotEqual(ns1, ns4)
4363 self.assertNotEqual(ns2, ns3)
4364 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004365 self.assertTrue(ns1 != ns3)
4366 self.assertTrue(ns1 != ns4)
4367 self.assertTrue(ns2 != ns3)
4368 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004369
4370
4371# ===================
4372# File encoding tests
4373# ===================
4374
4375class TestEncoding(TestCase):
4376
4377 def _test_module_encoding(self, path):
4378 path, _ = os.path.splitext(path)
4379 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004380 with codecs.open(path, 'r', 'utf8') as f:
4381 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004382
4383 def test_argparse_module_encoding(self):
4384 self._test_module_encoding(argparse.__file__)
4385
4386 def test_test_argparse_module_encoding(self):
4387 self._test_module_encoding(__file__)
4388
4389# ===================
4390# ArgumentError tests
4391# ===================
4392
4393class TestArgumentError(TestCase):
4394
4395 def test_argument_error(self):
4396 msg = "my error here"
4397 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004398 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004399
4400# =======================
4401# ArgumentTypeError tests
4402# =======================
4403
R. David Murray561b96f2011-02-11 17:25:54 +00004404class TestArgumentTypeError(TestCase):
Benjamin Petersona39e9662010-03-02 22:05:59 +00004405
4406 def test_argument_type_error(self):
4407
4408 def spam(string):
4409 raise argparse.ArgumentTypeError('spam!')
4410
4411 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4412 parser.add_argument('x', type=spam)
4413 try:
4414 parser.parse_args(['XXX'])
4415 except ArgumentParserError:
4416 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4417 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004418 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004419 else:
4420 self.fail()
4421
4422# ======================
4423# parse_known_args tests
4424# ======================
4425
4426class TestParseKnownArgs(TestCase):
4427
4428 def test_optionals(self):
4429 parser = argparse.ArgumentParser()
4430 parser.add_argument('--foo')
4431 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004432 self.assertEqual(NS(foo='F'), args)
4433 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004434
4435 def test_mixed(self):
4436 parser = argparse.ArgumentParser()
4437 parser.add_argument('-v', nargs='?', const=1, type=int)
4438 parser.add_argument('--spam', action='store_false')
4439 parser.add_argument('badger')
4440
4441 argv = ["B", "C", "--foo", "-v", "3", "4"]
4442 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004443 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4444 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004445
Steven Bethard53958622011-03-26 17:57:52 +01004446# ==========================
4447# add_argument metavar tests
4448# ==========================
4449
4450class TestAddArgumentMetavar(TestCase):
4451
4452 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4453
4454 def do_test_no_exception(self, nargs, metavar):
4455 parser = argparse.ArgumentParser()
4456 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4457
4458 def do_test_exception(self, nargs, metavar):
4459 parser = argparse.ArgumentParser()
4460 with self.assertRaises(ValueError) as cm:
4461 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4462 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4463
4464 # Unit tests for different values of metavar when nargs=None
4465
4466 def test_nargs_None_metavar_string(self):
4467 self.do_test_no_exception(nargs=None, metavar="1")
4468
4469 def test_nargs_None_metavar_length0(self):
4470 self.do_test_exception(nargs=None, metavar=tuple())
4471
4472 def test_nargs_None_metavar_length1(self):
4473 self.do_test_no_exception(nargs=None, metavar=("1"))
4474
4475 def test_nargs_None_metavar_length2(self):
4476 self.do_test_exception(nargs=None, metavar=("1", "2"))
4477
4478 def test_nargs_None_metavar_length3(self):
4479 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4480
4481 # Unit tests for different values of metavar when nargs=?
4482
4483 def test_nargs_optional_metavar_string(self):
4484 self.do_test_no_exception(nargs="?", metavar="1")
4485
4486 def test_nargs_optional_metavar_length0(self):
4487 self.do_test_exception(nargs="?", metavar=tuple())
4488
4489 def test_nargs_optional_metavar_length1(self):
4490 self.do_test_no_exception(nargs="?", metavar=("1"))
4491
4492 def test_nargs_optional_metavar_length2(self):
4493 self.do_test_exception(nargs="?", metavar=("1", "2"))
4494
4495 def test_nargs_optional_metavar_length3(self):
4496 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4497
4498 # Unit tests for different values of metavar when nargs=*
4499
4500 def test_nargs_zeroormore_metavar_string(self):
4501 self.do_test_no_exception(nargs="*", metavar="1")
4502
4503 def test_nargs_zeroormore_metavar_length0(self):
4504 self.do_test_exception(nargs="*", metavar=tuple())
4505
4506 def test_nargs_zeroormore_metavar_length1(self):
4507 self.do_test_no_exception(nargs="*", metavar=("1"))
4508
4509 def test_nargs_zeroormore_metavar_length2(self):
4510 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4511
4512 def test_nargs_zeroormore_metavar_length3(self):
4513 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4514
4515 # Unit tests for different values of metavar when nargs=+
4516
4517 def test_nargs_oneormore_metavar_string(self):
4518 self.do_test_no_exception(nargs="+", metavar="1")
4519
4520 def test_nargs_oneormore_metavar_length0(self):
4521 self.do_test_exception(nargs="+", metavar=tuple())
4522
4523 def test_nargs_oneormore_metavar_length1(self):
4524 self.do_test_no_exception(nargs="+", metavar=("1"))
4525
4526 def test_nargs_oneormore_metavar_length2(self):
4527 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4528
4529 def test_nargs_oneormore_metavar_length3(self):
4530 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4531
4532 # Unit tests for different values of metavar when nargs=...
4533
4534 def test_nargs_remainder_metavar_string(self):
4535 self.do_test_no_exception(nargs="...", metavar="1")
4536
4537 def test_nargs_remainder_metavar_length0(self):
4538 self.do_test_no_exception(nargs="...", metavar=tuple())
4539
4540 def test_nargs_remainder_metavar_length1(self):
4541 self.do_test_no_exception(nargs="...", metavar=("1"))
4542
4543 def test_nargs_remainder_metavar_length2(self):
4544 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4545
4546 def test_nargs_remainder_metavar_length3(self):
4547 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4548
4549 # Unit tests for different values of metavar when nargs=A...
4550
4551 def test_nargs_parser_metavar_string(self):
4552 self.do_test_no_exception(nargs="A...", metavar="1")
4553
4554 def test_nargs_parser_metavar_length0(self):
4555 self.do_test_exception(nargs="A...", metavar=tuple())
4556
4557 def test_nargs_parser_metavar_length1(self):
4558 self.do_test_no_exception(nargs="A...", metavar=("1"))
4559
4560 def test_nargs_parser_metavar_length2(self):
4561 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4562
4563 def test_nargs_parser_metavar_length3(self):
4564 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4565
4566 # Unit tests for different values of metavar when nargs=1
4567
4568 def test_nargs_1_metavar_string(self):
4569 self.do_test_no_exception(nargs=1, metavar="1")
4570
4571 def test_nargs_1_metavar_length0(self):
4572 self.do_test_exception(nargs=1, metavar=tuple())
4573
4574 def test_nargs_1_metavar_length1(self):
4575 self.do_test_no_exception(nargs=1, metavar=("1"))
4576
4577 def test_nargs_1_metavar_length2(self):
4578 self.do_test_exception(nargs=1, metavar=("1", "2"))
4579
4580 def test_nargs_1_metavar_length3(self):
4581 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4582
4583 # Unit tests for different values of metavar when nargs=2
4584
4585 def test_nargs_2_metavar_string(self):
4586 self.do_test_no_exception(nargs=2, metavar="1")
4587
4588 def test_nargs_2_metavar_length0(self):
4589 self.do_test_exception(nargs=2, metavar=tuple())
4590
4591 def test_nargs_2_metavar_length1(self):
4592 self.do_test_no_exception(nargs=2, metavar=("1"))
4593
4594 def test_nargs_2_metavar_length2(self):
4595 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4596
4597 def test_nargs_2_metavar_length3(self):
4598 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4599
4600 # Unit tests for different values of metavar when nargs=3
4601
4602 def test_nargs_3_metavar_string(self):
4603 self.do_test_no_exception(nargs=3, metavar="1")
4604
4605 def test_nargs_3_metavar_length0(self):
4606 self.do_test_exception(nargs=3, metavar=tuple())
4607
4608 def test_nargs_3_metavar_length1(self):
4609 self.do_test_no_exception(nargs=3, metavar=("1"))
4610
4611 def test_nargs_3_metavar_length2(self):
4612 self.do_test_exception(nargs=3, metavar=("1", "2"))
4613
4614 def test_nargs_3_metavar_length3(self):
4615 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4616
Benjamin Petersona39e9662010-03-02 22:05:59 +00004617# ============================
4618# from argparse import * tests
4619# ============================
4620
4621class TestImportStar(TestCase):
4622
4623 def test(self):
4624 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004625 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004626
Steven Bethard931906a2010-11-01 15:24:42 +00004627 def test_all_exports_everything_but_modules(self):
4628 items = [
4629 name
4630 for name, value in vars(argparse).items()
4631 if not name.startswith("_")
4632 if not inspect.ismodule(value)
4633 ]
4634 self.assertEqual(sorted(items), sorted(argparse.__all__))
4635
Benjamin Peterson036fae32010-03-02 22:20:10 +00004636def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004637 # silence warnings about version argument - these are expected
4638 with test_support.check_warnings(
4639 ('The "version" argument to ArgumentParser is deprecated.',
4640 DeprecationWarning),
4641 ('The (format|print)_version method is deprecated',
4642 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004643 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004644 # Remove global references to avoid looking like we have refleaks.
4645 RFile.seen = {}
4646 WFile.seen = set()
4647
Benjamin Peterson036fae32010-03-02 22:20:10 +00004648
Benjamin Petersona39e9662010-03-02 22:05:59 +00004649
4650if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004651 test_main()