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