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