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