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