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